Разработка программы для создания и работы с двусвязным списком, состоящим из структур. (Структура содержит фамилию и год рождения), страница 7

*=====================================================================================*/

LL_Error LL_SubscribeOnItemRemovingNotification(LL_LinkedList *list, LL_ItemRemovingNotification callback)

{

    if (NULL == list || NULL == callback)

    {

        return LL_ERR_BADPARAM;

    }

    list->ItemRemovingNotification = callback;

    return LL_ERR_OK;

}

/*=======================================================================================

* Подписаться на нотификацию о сортировке. Данные пользователя для модуля непрозрачны

* поэтому сравнивать он их не может. Сравнивать пары элементов пользователь должен

* самостоятельно и возвращать результаты сравнения.

*=====================================================================================*/

LL_Error LL_SubscribeOnSortNotification(LL_LinkedList *list, LL_CompareItems_cb callback)

{

    if (NULL == list || NULL == callback)

    {

        return LL_ERR_BADPARAM;

    }

    list->ItemSortNotification = callback;

    return LL_ERR_OK;

}

/*========================================================================================

* Сортировать лист. Для использования этой функциональности внешний модуль должен

* подписать на нотификацию о сортировке. См. LL_SubscribeOnSortNotification()

*======================================================================================*/

LL_Error LL_SortList(LL_LinkedList *list, LL_SortOreder order)

{

    LL_Item *item = NULL;

    boolean  continueSort = TRUE; //флаг необходимости продолжения сортировки

    void    *t = NULL;            //временная переменная при смене элементов местами

    int cmp = 0;

    cmp = order == LL_SORT_DECREASE ? -1 : 1; //определение порядка сортировки

    //проверка входных данных

    if (NULL == list || NULL == list->ItemSortNotification)

    {

        return LL_ERR_BADPARAM;

    }

    // сортировка методом пузырька

    while (continueSort)

    {

        continueSort = FALSE;    //сбросить флаг продолжения сортировки

        item = list->first;

        while (NULL != item->next)

        {

            //сравнение двух элементов – вызов пользовательского «колбэка»

            int res = list->ItemSortNotification(item->data, item->next->data);

            if ((cmp < 0 && res < 0) || (cmp > 0 && res >0))

            {

                t = item->data;

                item->data = item->next->data;

                item->next->data = t;

                continueSort = TRUE;  //установка флага продолжения сортировки

            }

            item = item->next;

        }

    }

    return LL_ERR_OK;

}

/*========================================================================================

* Очистка памяти – удаление всех элементов списка и LL_LinkedList.

* Пользователь должен быть подписан на нотификацию об удалении элемента (см.

* LL_SubscribeOnItemRemovingNotification), иначе функция вернет предупреждение о возможной

* утечке памяти - LL_ERR_MEMORYLEAK. Если пользователь уверен, что его данные не содержат

* в своей структуре указателей, он может выставить флажок disableWarning в TRUE

* (это отключит предупреждение о возможной утечке памяти LL_ERR_MEMORYLEAK).

*======================================================================================*/

LL_Error LL_RemoveAll(LL_LinkedList **list, boolean disableWarning)

{

    LL_Error err = LL_ERR_OK;

    LL_Item *tofree = NULL;

    // проверка корректности входных данных

    if (NULL == list || NULL == (*list) || NULL == (*list)->first || NULL == (*list)->last || NULL == (*list)->current)

    {

        return LL_ERR_BADPARAM;

    }

    //установка предупреждения о возможной утечке памяти (функция продолжает выполняться)

    if (!disableWarning && NULL == (*list)->ItemRemovingNotification)

    {

        err = LL_ERR_MEMORYLEAK;

    }

    // удаление элементов из памяти

    LL_MoveToItem(*list, LL_MOVETO_FIRST);

    do

    {

        tofree = (*list)->current;

        (*list)->current = tofree->next;

        if (NULL != (*list)->ItemRemovingNotification)

        {

            //запрос пользовательского «колбэка» на удаление указателей в его данных

            (*list)->ItemRemovingNotification(tofree->data);

        }

        //пользователь должен удалить только указатели внутри своей структуры

        //удаление же самой структуры данных пользователя происходит здесь

        if (tofree->data) free(tofree->data);   //удаление пользовательских данных

        free(tofree);                           //удаление элемента

    } while (NULL != (*list)->current);

    // удаление LL_LinkedList (связного списка)

    free((*list));             

    (*list) = NULL;  //пользователю возвращают очищенные данные

    return err;

}

4.3.  Листинги заголовочных файлов

«LListcmn.h» ­– общий заголовочный файл для модуля двусвязного списка и внешних модулей.

#ifndef __LLISTCMN_H__

#define __LLISTCMN_H__

#include "macro.h"

typedef enum LL_Error

{

    LL_ERR_OK,

    LL_ERR_BADPARAM         = -1, //некорректные входные параметры

    LL_ERR_NOMEMORY         = -2, //отказ в выделении памяти

    LL_ERR_ENDLIST          = -3, //уведомление: достигнут конец списка (начало/конец)

    LL_ERR_MEMORYLEAK       = -4, //предупреждение: возможна утечка памяти

    LL_ERR_MEMORYCORRUPTION = -5  //предупреждение: возможно повреждение памяти (утечка памяти уже случилась)

} LL_Error;

typedef enum LL_MoveTo    //директивы передвижения по списку

{

    LL_MOVETO_FIRST,

    LL_MOVETO_PREV,

    LL_MOVETO_NEXT,

    LL_MOVETO_LAST

} LL_MoveTo;

typedef enum LL_SortOreder //порядок сортировки

{

    LL_SORT_NOTSORTED,

    LL_SORT_INCREASE,

    LL_SORT_DECREASE

} LL_SortOreder;

/*=====================================================================================

* «Колбэк» для нотификации об удалении элемента. См. LL_SubscribeOnItemRemovingNotification