linked-list: Order of insert_before/remove_at calls doesn't matter anymore

This was quite confusing previously:  While calling insert_before()
and then remove_at() properly replaced the current item, calling them the
other way around inserted the new item before the previous item because
remove_at() changed the enumerator's position to the previous item.

The behavior in corner cases (calling the methods before or after
enumeration) is also changed slightly.
This commit is contained in:
Tobias Brunner
2018-06-26 15:11:02 +02:00
parent 91640baf6d
commit 2c02b02589
3 changed files with 101 additions and 57 deletions
+33 -36
View File
@@ -1,5 +1,5 @@
/*
* 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
@@ -111,7 +111,7 @@ struct private_enumerator_t {
/**
* implements enumerator interface
*/
enumerator_t enumerator;
enumerator_t public;
/**
* associated linked list
@@ -122,35 +122,19 @@ struct private_enumerator_t {
* 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)
@@ -160,28 +144,46 @@ METHOD(enumerator_t, enumerate, bool,
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,
@@ -298,14 +300,7 @@ METHOD(linked_list_t, insert_before, void,
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);
@@ -377,7 +372,9 @@ METHOD(linked_list_t, remove_at, void,
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);
}
}
+15 -6
View File
@@ -1,5 +1,5 @@
/*
* 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
@@ -102,12 +102,17 @@ struct linked_list_t {
/**
* 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
@@ -118,6 +123,10 @@ struct linked_list_t {
/**
* 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);