QUEUE

Section: C Library Functions (3)
Index JM Home Page roff page

BSD mandoc
4BSD  

名前

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) キュー・循環キューの実装  

書式

Fd #include <sys/queue.h> Fn LIST_ENTRY TYPE Fn LIST_HEAD HEADNAME TYPE Fn LIST_INIT LIST_HEAD *head Fn LIST_INSERT_AFTER LIST_ENTRY *listelm TYPE *elm LIST_ENTRY NAME Fn LIST_INSERT_HEAD LIST_HEAD *head TYPE *elm LIST_ENTRY NAME Fn LIST_REMOVE TYPE *elm LIST_ENTRY NAME Fn TAILQ_ENTRY TYPE Fn TAILQ_HEAD HEADNAME TYPE Fn TAILQ_INIT TAILQ_HEAD *head Fn TAILQ_INSERT_AFTER TAILQ_HEAD *head TYPE *listelm TYPE *elm TAILQ_ENTRY NAME Fn TAILQ_INSERT_HEAD TAILQ_HEAD *head TYPE *elm TAILQ_ENTRY NAME Fn TAILQ_INSERT_TAIL TAILQ_HEAD *head TYPE *elm TAILQ_ENTRY NAME Fn TAILQ_REMOVE TAILQ_HEAD *head TYPE *elm TAILQ_ENTRY NAME Fn CIRCLEQ_ENTRY TYPE Fn CIRCLEQ_HEAD HEADNAME TYPE Fn CIRCLEQ_INIT CIRCLEQ_HEAD *head Fn CIRCLEQ_INSERT_AFTER CIRCLEQ_HEAD *head TYPE *listelm TYPE *elm CIRCLEQ_ENTRY NAME Fn CIRCLEQ_INSERT_BEFORE CIRCLEQ_HEAD *head TYPE *listelm TYPE *elm CIRCLEQ_ENTRY NAME Fn CIRCLEQ_INSERT_HEAD CIRCLEQ_HEAD *head TYPE *elm CIRCLEQ_ENTRY NAME Fn CIRCLEQ_INSERT_TAIL CIRCLEQ_HEAD *head TYPE *elm CIRCLEQ_ENTRY NAME Fn CIRCLEQ_REMOVE CIRCLEQ_HEAD *head TYPE *elm CIRCLEQ_ENTRY NAME  

説明

これらのマクロは、次の 3 つのデータ構造を定義して操作する: リスト・テールキュー・循環キュー。 3 つのデータ構造すべてにおいて以下の機能がサポートされている:

  1. 新たなエントリをリストの先頭に挿入する。
  2. 新たなエントリをリストのどの要素よりも後に挿入する。
  3. リストの任意のエントリを削除する。
  4. リストを順方向に辿る。

リストは 3 つのデータ構造の中で最も単純であり、 上記の機能のみをサポートする。

テールキューは以下の機能を追加する:

  1. エントリをリストの最後に追加できる。

ただし:

  1. 全てのリスト挿入と削除において、リストの先頭を指定しなければならない。
  2. 各先頭エントリは 1 つではなく 2 つのポインタを必要とする。
  3. リストと比べて、コードサイズは 15% 大きくなり、操作は 20% 遅くなる。

循環キューは以下の機能を追加する:

  1. エントリをリストの最後に追加できる。
  2. エントリを他のエントリの前に追加できる。
  3. 逆方向に末尾から先頭へ辿ることができる。

ただし:

  1. 全てのリスト挿入と削除において、リストの先頭を指定しなければならない。
  2. 各先頭エントリは 1 つではなく 2 つのポインタを必要とする。
  3. 辿る際の終了条件がより複雑である。
  4. リストと比べて、コードサイズは 40% 大きくなり、操作は 45% 遅くなる。

マクロ定義において Fa TYPE はユーザ定義構造体の名前であり、 LIST_ENTRY TAILQ_ENTRY CIRCLEQ_ENTRY の何れか型のフィールドと 指定された Fa NAME を含まなければならない。 引き数 Fa HEADNAME はユーザ定義構造体の名前であり、 マクロ LIST_HEAD TAILQ_HEAD CIRCLEQ_HEAD を用いて宣言されなければならない。 これらのマクロがどのように使われるかについての更なる説明は、 以下の例を参照すること。  

リスト

リストの先頭には、 LIST_HEAD マクロで定義される構造体が置かれる。 この構造体はリストの最初の要素へのポインタを 1 つ含む。 要素は 2 重にリンクされており、 任意の要素はリストを辿らずに削除できる。 新しい要素は既存の要素の後またはリストの先頭に追加できる。 Fa LIST_HEAD 構造体は以下のように宣言されている:
LIST_HEAD(HEADNAME, TYPE) head;

ここで Fa HEADNAME は定義される構造体の名前であり、 Fa TYPE はリンク内でリンクされる要素の型である。 リストの先頭へのポインタは、その後で次のように宣言される:

struct HEADNAME *headp;

(名前 headheadp はユーザが選択できる。)

マクロ LIST_ENTRY はリストの要素を接続する構造体を宣言する。

マクロ LIST_INIT は Fa head で参照されるリストを初期化する。

マクロ LIST_INSERT_HEAD は新たな要素 Fa elm をリストの先頭に挿入する。

マクロ LIST_INSERT_AFTER は新たな要素 Fa elm を要素 Fa listelm の後に挿入する。

マクロ LIST_REMOVE は要素 Fa 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 マクロで定義される構造体が置かれる。 この構造体は 1 組のポインタを含んでいる。 1 つはテールキューの最初の要素へのポインタであり、 もう 1 つはテールキューの最後の要素へのポインタである。 要素は 2 重にリンクされており、 任意の要素はテールキューを辿らずに削除できる。 新しい要素は既存の要素の後またはテールキューの先頭または末尾に追加できる。 Fa TAILQ_HEAD 構造体は以下のように定義されている:
TAILQ_HEAD(HEADNAME, TYPE) head;

ここで HEADNAME は定義される構造体の名前であり、 TYPE はテールキュー内でリンクされる要素の型である。 テールキューの先頭へのポインタは、その後で次のように宣言される:

struct HEADNAME *headp;

(名前 headheadp はユーザが選択できる。)

マクロ TAILQ_ENTRY はテールキューの要素を接続する構造体を宣言する。

マクロ TAILQ_INIT は Fa head で参照されるテールキューを初期化する。

マクロ TAILQ_INSERT_HEAD は新たな要素 Fa elm をテールキューの先頭に挿入する。

マクロ TAILQ_INSERT_TAIL は新たな要素 Fa elm をテールキューの末尾に挿入する。

マクロ TAILQ_INSERT_AFTER は新たな要素 Fa elm を要素 Fa listelm の後に挿入する。

マクロ TAILQ_REMOVE は要素 Fa 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 マクロで定義される構造体が置かれる。 この構造体は 1 組のポインタを含んでいる。 1 つは循環キューの最初の要素へのポインタであり、 もう 1 つは循環キューの最後の要素へのポインタである。 要素は 2 重にリンクされており、 任意の要素はキューを辿らずに削除できる。 新しい要素は、既存の要素の後または前、またはキューの先頭または末尾に追加できる。 A Fa CIRCLEQ_HEAD 構造体は以下のように定義されている:
CIRCLEQ_HEAD(HEADNAME, TYPE) head;

ここで HEADNAME は定義される構造体の名前であり、 TYPE は循環キュー内でリンクされる要素の型である。 循環キューの先頭へのポインタは、その後で次のように宣言される:

struct HEADNAME *headp;

(名前 headheadp はユーザが選択できる。)

マクロ CIRCLEQ_ENTRY は循環キューの要素を接続する構造体を宣言する。

マクロ CIRCLEQ_INIT は Fa head で参照される循環キューを初期化する。

マクロ CIRCLEQ_INSERT_HEAD は新たな要素 Fa elm を循環キューの先頭に挿入する。

マクロ CIRCLEQ_INSERT_TAIL は新たな要素 Fa elm を循環キューの末尾に挿入する。

マクロ CIRCLEQ_INSERT_AFTER は新たな要素 Fa elm を要素 Fa listelm の後に挿入する。

マクロ CIRCLEQ_INSERT_AFTER は新たな要素 Fa elm を要素 Fa listelm の前に挿入する。

マクロ CIRCLEQ_REMOVE は要素 Fa 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 系に存在する。 queue 関数は BSD 4.4 で初めて登場した。


 

Index

名前
書式
説明
リスト
リストの例
テールキュー
テールキューの例
循環キュー
循環キューの例
準拠

This document was created by man2html, using the manual pages.
Time: 04:31:57 GMT, November 19, 2007