libsysprof-capture: Rewrite list_files() to avoid GHashTable/GPtrArray

This changes its API and ABI: it now returns an allocated array of const
strings, rather than an allocated array of allocated strings.

The call sites in the source tree have been adjusted accordingly.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Helps: #40
This commit is contained in:
Philip Withnall
2020-07-02 12:38:32 +01:00
parent 13b1e79901
commit 75b69d0a89
4 changed files with 71 additions and 19 deletions

View File

@ -62,6 +62,7 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
@ -1273,20 +1274,60 @@ sysprof_capture_reader_read_file (SysprofCaptureReader *self)
return file_chunk; return file_chunk;
} }
char ** static bool
array_append (const char ***files,
size_t *n_files,
size_t *n_files_allocated,
const char *new_element)
{
if (*n_files == *n_files_allocated)
{
const char **new_files;
*n_files_allocated = (*n_files_allocated > 0) ? 2 * *n_files_allocated : 4;
new_files = reallocarray (*files, *n_files_allocated, sizeof (**files));
if (new_files == NULL)
return false;
*files = new_files;
}
(*files)[*n_files] = new_element;
*n_files = *n_files + 1;
assert (*n_files <= *n_files_allocated);
return true;
}
static void
array_deduplicate (const char **files,
size_t *n_files)
{
size_t last_written, next_to_read;
if (*n_files == 0)
return;
for (last_written = 0, next_to_read = 1; last_written <= next_to_read && next_to_read < *n_files;)
{
if (strcmp (files[next_to_read], files[last_written]) == 0)
next_to_read++;
else
files[++last_written] = files[next_to_read++];
}
assert (last_written + 1 <= *n_files);
*n_files = last_written + 1;
}
const char **
sysprof_capture_reader_list_files (SysprofCaptureReader *self) sysprof_capture_reader_list_files (SysprofCaptureReader *self)
{ {
g_autoptr(GHashTable) files = NULL; const char **files = NULL;
g_autoptr(GPtrArray) ar = NULL; size_t n_files = 0, n_files_allocated = 0;
SysprofCaptureFrameType type; SysprofCaptureFrameType type;
GHashTableIter iter;
const gchar *key;
assert (self != NULL); assert (self != NULL);
ar = g_ptr_array_new_with_free_func (g_free);
files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
while (sysprof_capture_reader_peek_type (self, &type)) while (sysprof_capture_reader_peek_type (self, &type))
{ {
const SysprofCaptureFileChunk *file; const SysprofCaptureFileChunk *file;
@ -1300,16 +1341,27 @@ sysprof_capture_reader_list_files (SysprofCaptureReader *self)
if (!(file = sysprof_capture_reader_read_file (self))) if (!(file = sysprof_capture_reader_read_file (self)))
break; break;
if (!g_hash_table_contains (files, file->path)) if (!array_append (&files, &n_files, &n_files_allocated, file->path))
g_hash_table_insert (files, g_strdup (file->path), NULL); {
free (files);
errno = ENOMEM;
return NULL;
}
} }
g_hash_table_iter_init (&iter, files); /* Sort and deduplicate the files array. */
while (g_hash_table_iter_next (&iter, (gpointer *)&key, NULL)) qsort (files, n_files, sizeof (*files), (int (*)(const void *, const void *)) strcmp);
g_ptr_array_add (ar, g_strdup (key)); array_deduplicate (files, &n_files);
g_ptr_array_add (ar, NULL);
return (char **)g_ptr_array_free (sysprof_steal_pointer (&ar), FALSE); /* Add a null terminator */
if (!array_append (&files, &n_files, &n_files_allocated, NULL))
{
free (files);
errno = ENOMEM;
return NULL;
}
return sysprof_steal_pointer (&files);
} }
bool bool

View File

@ -144,7 +144,7 @@ SYSPROF_AVAILABLE_IN_ALL
const SysprofCaptureFileChunk *sysprof_capture_reader_find_file (SysprofCaptureReader *self, const SysprofCaptureFileChunk *sysprof_capture_reader_find_file (SysprofCaptureReader *self,
const char *path); const char *path);
SYSPROF_AVAILABLE_IN_ALL SYSPROF_AVAILABLE_IN_ALL
char **sysprof_capture_reader_list_files (SysprofCaptureReader *self); const char **sysprof_capture_reader_list_files (SysprofCaptureReader *self);
SYSPROF_AVAILABLE_IN_ALL SYSPROF_AVAILABLE_IN_ALL
bool sysprof_capture_reader_read_file_fd (SysprofCaptureReader *self, bool sysprof_capture_reader_read_file_fd (SysprofCaptureReader *self,
const char *path, const char *path,

View File

@ -747,7 +747,7 @@ test_reader_writer_file (void)
{ {
g_autofree gchar *data = NULL; g_autofree gchar *data = NULL;
GByteArray *buf = g_byte_array_new (); GByteArray *buf = g_byte_array_new ();
g_auto(GStrv) files = NULL; g_autofree const gchar **files = NULL;
SysprofCaptureWriter *writer; SysprofCaptureWriter *writer;
SysprofCaptureReader *reader; SysprofCaptureReader *reader;
SysprofCaptureFrameType type; SysprofCaptureFrameType type;

View File

@ -64,9 +64,9 @@ main (gint argc,
if (list_files) if (list_files)
{ {
g_auto(GStrv) files = sysprof_capture_reader_list_files (reader); g_autofree const gchar **files = sysprof_capture_reader_list_files (reader);
for (guint i = 0; files[i]; i++) for (gsize i = 0; files[i]; i++)
g_print ("%s\n", files[i]); g_print ("%s\n", files[i]);
return EXIT_SUCCESS; return EXIT_SUCCESS;