QUEUE(3)

ИМЯ
LIST_ENTRY, LIST_HEAD, LIST_INIT, LIST_INSERT_AFTER, LIST_INSERT_HEAD, LIST_REMOVE, TAILQ_ENTRY, TAILQ_HEAD, TAILQ_INIT, TAILQ_INSERT_AFTER, TAILQ_INSERT_HEAD, TAILQ_INSERT_TAIL, TAILQ_REMOVE, CIRCLEQ_ENTRY, CIRCLEQ_HEAD, CIRCLEQ_INIT, CIRCLEQ_INSERT_AFTER, CIRCLEQ_INSERT_BEFORE, CIRCLEQ_INSERT_HEAD, CIRCLEQ_INSERT_TAIL, CIRCLEQ_REMOVE - реализации списков, хвостовых очередей (tail queue) и кольцевых очередей (circular queue)

ОБЗОР
#include <sys/queue.h>
LIST_ENTRY(TYPE);
LIST_HEAD(HEADNAME, TYPE);
LIST_INIT(LIST_HEAD *head);
LIST_INSERT_AFTER(LIST_ENTRY *listelm,
                TYPE *elm, LIST_ENTRY NAME);
LIST_INSERT_HEAD(LIST_HEAD *head,
                TYPE *elm, LIST_ENTRY NAME);
LIST_REMOVE(TYPE *elm, LIST_ENTRY NAME);
TAILQ_ENTRY(TYPE);
TAILQ_HEAD(HEADNAME, TYPE);
TAILQ_INIT(TAILQ_HEAD *head);
TAILQ_INSERT_AFTER(TAILQ_HEAD *head, TYPE *listelm,
                TYPE *elm, TAILQ_ENTRY NAME);
TAILQ_INSERT_HEAD(TAILQ_HEAD *head,
                TYPE *elm, TAILQ_ENTRY NAME);
TAILQ_INSERT_TAIL(TAILQ_HEAD *head,
                TYPE *elm, TAILQ_ENTRY NAME);
TAILQ_REMOVE(TAILQ_HEAD *head, TYPE *elm, TAILQ_ENTRY NAME);
CIRCLEQ_ENTRY(TYPE);
CIRCLEQ_HEAD(HEADNAME, TYPE);
CIRCLEQ_INIT(CIRCLEQ_HEAD *head);
CIRCLEQ_INSERT_AFTER(CIRCLEQ_HEAD *head, TYPE *listelm,
                TYPE *elm, CIRCLEQ_ENTRY NAME);
CIRCLEQ_INSERT_BEFORE(CIRCLEQ_HEAD *head, TYPE *listelm,
                TYPE *elm, CIRCLEQ_ENTRY NAME);
CIRCLEQ_INSERT_HEAD(CIRCLEQ_HEAD *head,
                TYPE *elm, CIRCLEQ_ENTRY NAME);
CIRCLEQ_INSERT_TAIL(CIRCLEQ_HEAD *head,
                TYPE *elm, CIRCLEQ_ENTRY NAME);
CIRCLEQ_REMOVE(CIRCLEQ_HEAD *head,
                TYPE *elm, CIRCLEQ_ENTRY NAME);

ОПИСАНИЕ
Эти макросы определяют и управляют тремя типами структур данных: списками, хвостовыми очередями и кольцевыми очередями. Все три структуры поддерживают следующие возможности:

    *   Вставка нового элемента в начало списка.
    *   Вставка нового элемента после любого элемента списка.
    *   Удаление любого элемента списка.
    *   Прямой обход списка.

Списки — самая простая из этих трёх структур данных и поддерживает только указанные выше возможности. Хвостовые очереди добавляют следующую возможность:

    *   Элементы могут быть добавлены в конец списка.

Однако:

    1.  При вставке и удалении элементов нужно указывать начало списка.
    2.  Каждый начальный элемент требует двух указателей вместо одного.
    3.  Код примерно на 15% больше и на 20% медленнее, чем в списках.

Кольцевые очереди добавляют следующие возможности:

    *   Элементы могут быть добавлены в конец списка.
    *   Элементы могут добавляться перед другим элементом.
    *   Обход может идти в обратном направлении, от конца к началу.

Однако:

    1.  При вставке и удалении элементов нужно указывать начало списка.
    2.  Каждый начальный элемент требует двух указателей вместо одного.
    3.  Условие завершения обхода более сложное.
    4.  Код примерно на 40% больше и на 45% медленнее, чем в списках.

В определениях макросов TYPE является именем структуры, определённой пользователем, которая должна содержать поле типа LIST_ENTRY, TAILQ_ENTRY или CIRCLEQ_ENTRY, названное NAME. Аргумент HEADNAME является именем структуры, определённой пользователем, которая должна быть объявлена, используя макрос LIST_HEAD, TAILQ_HEAD или CIRCLEQ_HEAD. Смотрите примеры ниже для дальнейшего объяснения использования этих макросов.

  Списки
Список начинается структурой, определённой макросом LIST_HEAD. Эта структура содержит единственный указатель на первый элемент списка. Элементы дважды связаны, поэтому произвольный элемент можно удалить без обхода списка. Новые элементы могут быть добавлены в список после существующего элемента или в начало списка. Структура LIST_HEAD объявляется следующим образом:
LIST_HEAD(HEADNAME, TYPE) head;

где HEADNAME — имя определяемой структуры, а TYPE — тип связанных элементов в списке. Указатель на начало списка может в дальнейшем быть объявлен, как:
struct HEADNAME *headp;

(Имена head и headp выбираются пользователем.)

Макрос LIST_ENTRY объявляет структуру, которая подключает элементы в список.

Макрос LIST_INIT инициализирует список, на который ссылается head.

Макрос LIST_INSERT_HEAD вставляет новый элемент elm в начало списка.

Макрос LIST_INSERT_AFTER вставляет новый элемент elm за элементом listelm.

Макрос LIST_REMOVE удаляет элемент elm из списка.

  Пример списка
LIST_HEAD(listhead, entry) head;
struct listhead *headp;                 /* начало списка */
struct entry {
    ...
    LIST_ENTRY(entry) entries;          /* список */
    ...
} *n1, *n2, *np;
LIST_INIT(&head);                       /* инициализация списка */
n1 = malloc(sizeof(struct entry));      /* вставка в начало */
LIST_INSERT_HEAD(&head, n1, entries);
n2 = malloc(sizeof(struct entry));      /* вставка после */
LIST_INSERT_AFTER(n1, n2, entries);
                                        /* вперёд до конца */
for (np = head.lh_first; np != NULL; np = np->entries.le_next)
    np-> ...
while (head.lh_first != NULL)           /* удаление */
    LIST_REMOVE(head.lh_first, entries);

  Хвостовые очереди
Хвостовая очередь задается структурой, определяемой макросом TAILQ_HEAD. Эта структура содержит пару указателей, один для первого элемента хвостовой очереди, а другой для последнего элемента хвостовой очереди. Элементы связаны дважды так, что любой элемент может быть удалён без прохождения по всей очереди. Новые элементы могут быть добавлены в хвостовую очередь после существующего элемента, в конец или в начало очереди. Структура TAILQ_HEAD объявляется следующим образом:
TAILQ_HEAD(HEADNAME, TYPE) head;

где HEADNAME — имя определяемой структуры, а TYPE — тип связанных элементов в хвостовой очереди. Указатель на начало хвостовой очереди может в дальнейшем быть объявлен как:
struct HEADNAME *headp;

(Имена head и headp выбираются пользователем.)

Макрос TAILQ_ENTRY объявляет структуру, которая подключает элементы в хвостовую очередь.

Макрос TAILQ_INIT инициализирует хвостовую очередь, на которую ссылается head.

Макрос TAILQ_INSERT_HEAD вставляет новый элемент elm в начало хвостовой очереди.

Макрос TAILQ_INSERT_TAIL вставляет новый элемент elm в конец хвостовой очереди.

Макрос TAILQ_INSERT_AFTER вставляет новый элемент elm за элементом listelm.

Макрос TAILQ_REMOVE удаляет элемент elm из хвостовой очереди.

  Пример хвостовой очереди
TAILQ_HEAD(tailhead, entry) head;
struct tailhead *headp;                 /* заголовок хвостовой очереди */
struct entry {
    ...
    TAILQ_ENTRY(entry) entries;         /* хвостовая очередь */
    ...
} *n1, *n2, *np;
TAILQ_INIT(&head);                      /* инициализация очереди */
n1 = malloc(sizeof(struct entry));      /* вставка в начало */
TAILQ_INSERT_HEAD(&head, n1, entries);
n1 = malloc(sizeof(struct entry));      /* вставка в хвост */
TAILQ_INSERT_TAIL(&head, n1, entries);
n2 = malloc(sizeof(struct entry));      /* вставка после */
TAILQ_INSERT_AFTER(&head, n1, n2, entries);
                                        /* вперед по очереди */
for (np = head.tqh_first; np != NULL; np = np->entries.tqe_next)
    np-> ...
                                        /* удаление */
while (head.tqh_first != NULL)
    TAILQ_REMOVE(&head, head.tqh_first, entries);

  Циклические очереди
Циклическая очередь задается структурой, определяемой макросом CIRCLEQ_HEAD. Эта структура содержит пару указателей, один для первого элемента циклической очереди, а другой для последнего элемента циклической очереди. Элементы связаны дважды так, что любой элемент может быть удалён без прохождения по всей очереди. Новые элементы могут быть добавлены в очередь после существующего элемента, перед существующем элементом, в конец или в начало очереди. Структура CIRCLEQ_HEAD объявляется так:
CIRCLEQ_HEAD(HEADNAME, TYPE) head;

где HEADNAME — имя определяемой структуры, а TYPE — тип связанных элементов в циклической очереди. Указатель на начало циклической очереди может в дальнейшем быть объявлен как:
struct HEADNAME *headp;

(Имена head и headp выбираются пользователем.)

Макрос CIRCLEQ_ENTRY объявляет структуру, которая подключает элементы в циклическую очередь.

Макрос CIRCLEQ_INIT инициализирует циклическую очередь, на которую ссылается head.

Макрос CIRCLEQ_INSERT_HEAD вставляет новый элемент elm в начало циклической очереди.

Макрос CIRCLEQ_INSERT_TAIL вставляет новый элемент elm в конец циклической очереди.

Макрос CIRCLEQ_INSERT_AFTER вставляет новый элемент elm за элементом listelm.

Макрос CIRCLEQ_INSERT_BEFORE вставляет новый элемент elm перед элементом listelm.

Макрос CIRCLEQ_REMOVE удаляет элемент elm из циклической очереди.

  Пример циклической очереди
CIRCLEQ_HEAD(circleq, entry) head;
struct circleq *headp;              /* заголовок циклической очереди */
struct entry {
    ...
    CIRCLEQ_ENTRY(entry) entries;   /* циклическая очередь */
    ...
} *n1, *n2, *np;
CIRCLEQ_INIT(&head);                /* инициализация циклической
                                       очереди */
n1 = malloc(sizeof(struct entry));  /* вставка в начало */
CIRCLEQ_INSERT_HEAD(&head, n1, entries);
n1 = malloc(sizeof(struct entry));  /* вставка в хвост */
CIRCLEQ_INSERT_TAIL(&head, n1, entries);
n2 = malloc(sizeof(struct entry));  /* вставка после */
CIRCLEQ_INSERT_AFTER(&head, n1, n2, entries);
n2 = malloc(sizeof(struct entry));  /* вставка перед */
CIRCLEQ_INSERT_BEFORE(&head, n1, n2, entries);
                                    /* вперёд по очереди */
for (np = head.cqh_first; np != (void *)&head;
        np = np->entries.cqe_next)
    np-> ...
                                    /* назад по очереди */
for (np = head.cqh_last; np != (void *)&head; np = np->entries.cqe_prev)
    np-> ...
                                    /* удаление */
while (head.cqh_first != (void *)&head)
    CIRCLEQ_REMOVE(&head, head.cqh_first, entries);

СООТВЕТСТВИЕ СТАНДАРТАМ
Не является частью POSIX.1-2001. Присутствует в BSD. Впервые появились в 4.4BSD.