Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d5895a3c authored by Andre Eisenbach's avatar Andre Eisenbach
Browse files

Make list_foreach() more useful

- Changed |callback| return type to bool to be able to interrupt
  iteration (to find specific elements for example).
- Added new |extra| parameter for |callback| so a pointer can be passed
  in to receive output values or to pass in criteria etc.
- Also added unit tests.

Change-Id: Id1ddcbabf55292f701d0277f2a1e9ec261b9fbde
parent ecc2dbae
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -10,7 +10,12 @@ struct list_t;
typedef struct list_t list_t;

typedef void (*list_free_cb)(void *data);
typedef bool (*list_iter_cb)(void *data);

// Iterator callback prototype used for |list_foreach|.
// |data| represents the list item currently being iterated, |context| is a
// user defined value passed into |list_foreach|.
// Callback must return true to continue iterating or false to stop iterating.
typedef bool (*list_iter_cb)(void *data, void *context);

// Returns a new, empty list. Returns NULL if not enough memory could be allocated
// for the list structure. The returned list must be freed with |list_free|. The
@@ -73,12 +78,15 @@ bool list_remove(list_t *list, void *data);
// same state it was in after |list_new|. |list| may not be NULL.
void list_clear(list_t *list);

// Iterates through the entire |list| and calls |callback| for each data element.
// Iterates through the |list| and calls |callback| for each data element. Iteration
// continues until |callback| returns false. The function returns the result of the
// last executed |callback| or true if the list is empty. |context| is passed to
// |callback| on each iteration.
// If the list is empty, |callback| will never be called. It is safe to mutate the
// list inside the callback. If an element is added before the node being visited,
// there will be no callback for the newly-inserted node. Neither |list| nor
// |callback| may be NULL.
void list_foreach(const list_t *list, list_iter_cb callback);
bool list_foreach(const list_t *list, list_iter_cb callback, void *context);

// Returns an iterator to the first element in |list|. |list| may not be NULL.
// The returned iterator is valid as long as it does not equal the value returned
+4 −2
Original line number Diff line number Diff line
@@ -168,15 +168,17 @@ void list_clear(list_t *list) {
  list->length = 0;
}

void list_foreach(const list_t *list, list_iter_cb callback) {
bool list_foreach(const list_t *list, list_iter_cb callback, void *context) {
  assert(list != NULL);
  assert(callback != NULL);

  for (list_node_t *node = list->head; node; ) {
    list_node_t *next = node->next;
    callback(node->data);
    if (!callback(node->data, context))
      return false;
    node = next;
  }
  return true;
}

list_node_t *list_begin(const list_t *list) {
+62 −0
Original line number Diff line number Diff line
@@ -146,3 +146,65 @@ TEST_F(ListTest, test_list_next) {
  EXPECT_EQ(list_next(list_begin(list)), list_end(list));
  list_free(list);
}

static bool list_callback_sum(void *data, void *context) {
  assert(data);
  assert(context);
  int *sum = (int *)context;
  int *value = (int *)data;
  *sum += *value;
  return true;
}

static bool list_callback_find_int(void *data, void *context) {
  assert(data);
  assert(context);
  return (*(int *)data != *(int *)context);
}

TEST_F(ListTest, test_list_foreach_full) {
  list_t *list = list_new(NULL);

  // Fill in test data
  int x[] = { 1, 2, 3, 4, 5 };
  for (size_t i = 0; i < ARRAY_SIZE(x); ++i)
    list_append(list, &x[i]);
  EXPECT_EQ(list_length(list), 5);

  // Test complete iteration
  int sum = 0;
  bool rc = list_foreach(list, list_callback_sum, &sum);
  EXPECT_EQ(sum, 15);
  EXPECT_TRUE(rc);

  list_free(list);
}

TEST_F(ListTest, test_list_foreach_partial) {
  list_t *list = list_new(NULL);

  // Fill in test data
  int x[] = { 1, 2, 3, 4, 5 };
  for (size_t i = 0; i < ARRAY_SIZE(x); ++i)
    list_append(list, &x[i]);
  EXPECT_EQ(list_length(list), 5);

  // Test partial iteration
  int find = 4;
  bool rc = list_foreach(list, list_callback_find_int, &find);
  EXPECT_FALSE(rc);

  find = 1;
  rc = list_foreach(list, list_callback_find_int, &find);
  EXPECT_FALSE(rc);

  find = 5;
  rc = list_foreach(list, list_callback_find_int, &find);
  EXPECT_FALSE(rc);

  find = 0;
  rc = list_foreach(list, list_callback_find_int, &find);
  EXPECT_TRUE(rc);

  list_free(list);
}