/*
- * Copyright (C) 2007-2015 Tobias Brunner
+ * Copyright (C) 2007-2018 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* HSR Hochschule fuer Technik Rapperswil
/**
* implements enumerator interface
*/
- enumerator_t enumerator;
+ enumerator_t public;
/**
* associated linked list
* current item
*/
element_t *current;
-
- /**
- * enumerator has enumerated all items
- */
- bool finished;
};
-METHOD(enumerator_t, enumerate, bool,
- private_enumerator_t *this, va_list args)
+/**
+ * Enumerate the current item
+ */
+static bool do_enumerate(private_enumerator_t *this, va_list args)
{
void **item;
VA_ARGS_VGET(args, item);
- if (this->finished)
- {
- return FALSE;
- }
if (!this->current)
{
- this->current = this->list->first;
- }
- else
- {
- this->current = this->current->next;
- }
- if (!this->current)
- {
- this->finished = TRUE;
return FALSE;
}
if (item)
return TRUE;
}
+METHOD(enumerator_t, enumerate_next, bool,
+ private_enumerator_t *this, va_list args)
+{
+ if (this->current)
+ {
+ this->current = this->current->next;
+ }
+ return do_enumerate(this, args);
+}
+
+METHOD(enumerator_t, enumerate_current, bool,
+ private_enumerator_t *this, va_list args)
+{
+ this->public.venumerate = _enumerate_next;
+ return do_enumerate(this, args);
+}
+
METHOD(linked_list_t, create_enumerator, enumerator_t*,
private_linked_list_t *this)
{
private_enumerator_t *enumerator;
INIT(enumerator,
- .enumerator = {
+ .public = {
.enumerate = enumerator_enumerate_default,
- .venumerate = _enumerate,
+ .venumerate = _enumerate_current,
.destroy = (void*)free,
},
.list = this,
+ .current = this->first,
);
- return &enumerator->enumerator;
+ return &enumerator->public;
}
METHOD(linked_list_t, reset_enumerator, void,
private_linked_list_t *this, private_enumerator_t *enumerator)
{
- enumerator->current = NULL;
- enumerator->finished = FALSE;
+ enumerator->current = this->first;
+ enumerator->public.venumerate = _enumerate_current;
}
METHOD(linked_list_t, get_count, int,
current = enumerator->current;
if (!current)
{
- if (enumerator->finished)
- {
- this->public.insert_last(&this->public, item);
- }
- else
- {
- this->public.insert_first(&this->public, item);
- }
+ insert_last(this, item);
return;
}
element = element_create(item);
if (enumerator->current)
{
current = enumerator->current;
- enumerator->current = current->previous;
+ enumerator->current = current->next;
+ /* the enumerator already points to the next item */
+ enumerator->public.venumerate = _enumerate_current;
remove_element(this, current);
}
}
/*
- * Copyright (C) 2007-2017 Tobias Brunner
+ * Copyright (C) 2007-2018 Tobias Brunner
* Copyright (C) 2005-2008 Martin Willi
* Copyright (C) 2005 Jan Hutter
* HSR Hochschule fuer Technik Rapperswil
/**
* Inserts a new item before the item the enumerator currently points to.
*
- * If this method is called before starting the enumeration the item is
- * inserted first. If it is called after all items have been enumerated
- * the item is inserted last. This is helpful when inserting items into
- * a sorted list.
+ * If this method is called after all items have been enumerated, the item
+ * is inserted last. This is helpful when inserting items into a sorted
+ * list.
*
- * @note The position of the enumerator is not changed.
+ * @note The position of the enumerator is not changed. So it is safe to
+ * call this before or after remove_at() to replace the item at the current
+ * position (the enumerator will continue with the next item in the list).
+ * And in particular, when inserting an item before calling enumerate(),
+ * the enumeration will continue (or start) at the item that was first in
+ * the list before any items were inserted (enumerate() will return FALSE
+ * if the list was empty before).
*
* @param enumerator enumerator with position
* @param item item value to insert in list
/**
* Remove an item from the list where the enumerator points to.
*
+ * If this method is called before calling enumerate() of the enumerator,
+ * the first item in the list, if any, will be removed. No item is removed,
+ * if the method is called after enumerating all items.
+ *
* @param enumerator enumerator with position
*/
void (*remove_at)(linked_list_t *this, enumerator_t *enumerator);
int round;
enumerator = list->create_enumerator(list);
+ /* this does not change the enumerator position, which points to 1 */
list->insert_before(list, enumerator, (void*)0);
ck_assert_int_eq(list->get_count(list), 6);
ck_assert(list->get_first(list, (void*)&x) == SUCCESS);
ck_assert_int_eq(x, 0);
- round = 0;
+ round = 1;
while (enumerator->enumerate(enumerator, &x))
{
ck_assert_int_eq(round, x);
ck_assert_int_eq(x, 1);
ck_assert(list->get_last(list, (void*)&x) == SUCCESS);
ck_assert_int_eq(x, 1);
- ck_assert(enumerator->enumerate(enumerator, &x));
+ ck_assert(!enumerator->enumerate(enumerator, &x));
+ list->insert_before(list, enumerator, (void*)2);
+ ck_assert_int_eq(list->get_count(list), 2);
+ ck_assert(list->get_first(list, (void*)&x) == SUCCESS);
ck_assert_int_eq(x, 1);
+ ck_assert(list->get_last(list, (void*)&x) == SUCCESS);
+ ck_assert_int_eq(x, 2);
ck_assert(!enumerator->enumerate(enumerator, NULL));
enumerator->destroy(enumerator);
}
}
END_TEST
+START_TEST(test_remove_at_multi)
+{
+ enumerator_t *enumerator;
+ intptr_t x;
+ int round;
+
+ round = 1;
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ ck_assert_int_eq(round, x);
+ if (round == 2 || round == 5)
+ {
+ list->remove_at(list, enumerator);
+ }
+ round++;
+ }
+ ck_assert_int_eq(list->get_count(list), 3);
+ list->reset_enumerator(list, enumerator);
+ round = 1;
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ if (round == 2)
+ { /* skip removed item */
+ round++;
+ }
+ ck_assert_int_eq(round, x);
+ list->remove_at(list, enumerator);
+ round++;
+ }
+ ck_assert_int_eq(list->get_count(list), 0);
+ list->reset_enumerator(list, enumerator);
+ ck_assert(!enumerator->enumerate(enumerator, &x));
+ enumerator->destroy(enumerator);
+}
+END_TEST
+
START_TEST(test_remove_at_ends)
{
enumerator_t *enumerator;
enumerator = list->create_enumerator(list);
list->remove_at(list, enumerator);
- ck_assert_int_eq(list->get_count(list), 5);
+ ck_assert_int_eq(list->get_count(list), 4);
ck_assert(list->get_first(list, (void*)&x) == SUCCESS);
- ck_assert_int_eq(x, 1);
+ ck_assert_int_eq(x, 2);
while (enumerator->enumerate(enumerator, &x))
{
}
list->remove_at(list, enumerator);
- ck_assert_int_eq(list->get_count(list), 5);
+ ck_assert_int_eq(list->get_count(list), 4);
ck_assert(list->get_last(list, (void*)&x) == SUCCESS);
ck_assert_int_eq(x, 5);
enumerator->destroy(enumerator);
{
ck_assert_int_eq(round, x);
if (round == 2)
- { /* this replaces the current item, as insert_before does not change
- * the enumerator position */
+ { /* this replaces the current item */
list->insert_before(list, enumerator, (void*)42);
list->remove_at(list, enumerator);
}
else if (round == 4)
- { /* this does not replace the item, as remove_at moves the enumerator
- * position to the previous item */
+ { /* same here, the order of calls does not matter */
list->remove_at(list, enumerator);
list->insert_before(list, enumerator, (void*)21);
}
{ /* check replaced item */
ck_assert_int_eq(42, x);
}
- else if (round == 3)
- { /* check misplaced item */
- ck_assert_int_eq(21, x);
- }
else if (round == 4)
- { /* check misplaced item */
- ck_assert_int_eq(3, x);
+ { /* check replace item */
+ ck_assert_int_eq(21, x);
}
else
{
tc = tcase_create("modify");
tcase_add_checked_fixture(tc, setup_list, teardown_list);
tcase_add_test(tc, test_remove_at);
+ tcase_add_test(tc, test_remove_at_multi);
tcase_add_test(tc, test_remove_at_ends);
tcase_add_test(tc, test_insert_before_remove_at);
suite_add_tcase(s, tc);