err = LL_ERR_NOMEMORY;
}
return err;
}
/*=======================================================================================
* Добавляет новый элемент в конец списка.
* data – данные пользователя, которые будут храниться в новом элементе
*=====================================================================================*/
LL_Error LL_PushLast(LL_LinkedList *list, void *data)
{
LL_Item *newItem = NULL;
if (NULL == list || NULL == data)
{
return LL_ERR_BADPARAM;
}
// выделение памяти для
newItem = (LL_Item*)malloc(sizeof(LL_Item));
if (NULL == newItem)
{
return LL_ERR_NOMEMORY;
}
// инициализация полей данных нового элемента
newItem->prev = list->last;
newItem->next = NULL;
newItem->data = data;
// если новый элемент не первый в списке (последний элемент уже существует)
if (NULL != list->last)
{
list->last->next = newItem;
}
// добавить новый элемент в конец списка
list->last = newItem;
// если новый элемент первый в списке (единственный)
if (NULL == list->first)
{
list->first = newItem;
list->current = newItem;
}
return LL_ERR_OK;
}
/*========================================================================================
* Добавить новый элемент в соответствии с сортировкой списка. Для использования этой
* функциональности внешний модуль должен подписать на нотификацию о сортировке.
* См. LL_SubscribeOnSortNotification()
*======================================================================================*/
LL_Error LL_PushInSortOrder(LL_LinkedList *list, LL_SortOreder order, void *data)
{
LL_Item *item = NULL;
LL_Item *newItem = NULL;
int cmp = order == LL_SORT_DECREASE ? 1 : -1; //определение порядка сортировки
if (NULL == list || NULL == list->ItemSortNotification)
{
return LL_ERR_BADPARAM;
}
// выделение памяти для нового элемента
newItem = (LL_Item*)malloc(sizeof(LL_Item));
if (NULL == newItem)
{
return LL_ERR_NOMEMORY;
}
// поиск места для нового места в соответствии с заданным порядком сортировки
item = list->first;
while (NULL != item)
{
// вызов пользовательского «колбэка» для получения результата сравнения данных
int res = list->ItemSortNotification(data, item->data);
if ((cmp < 0 && res < 0) || (cmp > 0 && res >0))
{
break;
}
item = item->next;
}
// добавление нового элемента в список
if (NULL != item) // добавление в начало или середину списка
{
newItem->prev = item->prev;
newItem->next = item;
newItem->data = data;
item->prev = newItem;
if (item == list->first) //если элемент добавляется в начало
{
list->first = newItem;
}
else if (NULL != newItem->prev) //если в середину
{
newItem->prev->next = newItem;
}
}
else if (NULL != list->last) //добавление в конец списка
{
newItem->prev = list->last;
newItem->next = NULL;
newItem->data = data;
list->last = newItem;
newItem->prev->next = newItem;
}
else //если это первый (единственный) элемент в списке
{
newItem->prev = NULL;
newItem->next = NULL;
newItem->data = data;
list->first = newItem;
list->current = newItem;
}
return LL_ERR_OK;
}
/*=======================================================================================
* Движение по списку. Элемент, на котором остановилось движение запоминается в
* LL_LinkedList::current
*======================================================================================*/
LL_Error LL_MoveToItem(LL_LinkedList *list, LL_MoveTo dir)
{
LL_Error err = LL_ERR_ENDLIST;
if (NULL == list || NULL == list->first || NULL == list->last || NULL == list->current)
{
return LL_ERR_BADPARAM;
}
switch (dir)
{
case LL_MOVETO_FIRST: //перейти к первому элементу
list->current = list->first;
break;
case LL_MOVETO_PREV: //к предыдущему (если он есть)
if (NULL != list->current->prev)
{
list->current = list->current->prev;
err = LL_ERR_OK;
}
break;
case LL_MOVETO_NEXT: //к следующему (если он есть)
if (NULL != list->current->next)
{
list->current = list->current->next;
err = LL_ERR_OK;
}
break;
case LL_MOVETO_LAST: //к последнему
list->current = list->last;
break;
}
return err;
}
/*========================================================================================
* Получить данные из элемента на котором остановилось движение (LL_LinkedList::current).
* См. LL_MoveToItem()
*======================================================================================*/
void* LL_GetData(LL_LinkedList *list)
{
if (NULL == list || NULL == list->current)
{
return NULL;
}
return list->current->data;
}
/*======================================================================================
* Подписаться на нотификацию об удалении элемента. Это необходимо если данные
* пользователя содержат в своей структуре указатели. Для данного модуля, данные
* пользователя непрозрачны, поэтому пользователем обязан сам удалять указатели в
* своих данных. Нотификация приходит на удалении каждого отдельного элемента.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.