1 /* 2 * SPDX-FileCopyrightText: 2015-2022 The Apache Software Foundation (ASF) 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * SPDX-FileContributor: 2019-2022 Espressif Systems (Shanghai) CO LTD 7 */ 8 /* 9 * Licensed to the Apache Software Foundation (ASF) under one 10 * or more contributor license agreements. See the NOTICE file 11 * distributed with this work for additional information 12 * regarding copyright ownership. The ASF licenses this file 13 * to you under the Apache License, Version 2.0 (the 14 * "License"); you may not use this file except in compliance 15 * with the License. You may obtain a copy of the License at 16 * 17 * http://www.apache.org/licenses/LICENSE-2.0 18 * 19 * Unless required by applicable law or agreed to in writing, 20 * software distributed under the License is distributed on an 21 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 22 * KIND, either express or implied. See the License for the 23 * specific language governing permissions and limitations 24 * under the License. 25 */ 26 27 #ifndef _QUEUE_H_ 28 #define _QUEUE_H_ 29 30 /* The common BSD linked list queue macros are already defined here for ESP-IDF */ 31 #include <sys/queue.h> 32 33 #ifdef __cplusplus 34 extern "C" { 35 #endif 36 37 /* 38 * This file defines circular queues. The other types of data structures: 39 * singly-linked lists, singly-linked tail queues, lists and tail queues 40 * are used from sys/queue.h 41 * 42 * A singly-linked list is headed by a single forward pointer. The elements 43 * are singly linked for minimum space and pointer manipulation overhead at 44 * the expense of O(n) removal for arbitrary elements. New elements can be 45 * added to the list after an existing element or at the head of the list. 46 * Elements being removed from the head of the list should use the explicit 47 * macro for this purpose for optimum efficiency. A singly-linked list may 48 * only be traversed in the forward direction. Singly-linked lists are ideal 49 * for applications with large datasets and few or no removals or for 50 * implementing a LIFO queue. 51 * 52 * A singly-linked tail queue is headed by a pair of pointers, one to the 53 * head of the list and the other to the tail of the list. The elements are 54 * singly linked for minimum space and pointer manipulation overhead at the 55 * expense of O(n) removal for arbitrary elements. New elements can be added 56 * to the list after an existing element, at the head of the list, or at the 57 * end of the list. Elements being removed from the head of the tail queue 58 * should use the explicit macro for this purpose for optimum efficiency. 59 * A singly-linked tail queue may only be traversed in the forward direction. 60 * Singly-linked tail queues are ideal for applications with large datasets 61 * and few or no removals or for implementing a FIFO queue. 62 * 63 * A list is headed by a single forward pointer (or an array of forward 64 * pointers for a hash table header). The elements are doubly linked 65 * so that an arbitrary element can be removed without a need to 66 * traverse the list. New elements can be added to the list before 67 * or after an existing element or at the head of the list. A list 68 * may only be traversed in the forward direction. 69 * 70 * A tail queue is headed by a pair of pointers, one to the head of the 71 * list and the other to the tail of the list. The elements are doubly 72 * linked so that an arbitrary element can be removed without a need to 73 * traverse the list. New elements can be added to the list before or 74 * after an existing element, at the head of the list, or at the end of 75 * the list. A tail queue may be traversed in either direction. 76 * 77 * A circle queue is headed by a pair of pointers, one to the head of the 78 * list and the other to the tail of the list. The elements are doubly 79 * linked so that an arbitrary element can be removed without a need to 80 * traverse the list. New elements can be added to the list before or after 81 * an existing element, at the head of the list, or at the end of the list. 82 * A circle queue may be traversed in either direction, but has a more 83 * complex end of list detection. 84 * 85 * For details on the use of these macros, see the queue(3) manual page. 86 * 87 * 88 * SLIST LIST STAILQ TAILQ CIRCLEQ 89 * _HEAD + + + + + 90 * _HEAD_INITIALIZER + + + + + 91 * _ENTRY + + + + + 92 * _INIT + + + + + 93 * _EMPTY + + + + + 94 * _FIRST + + + + + 95 * _NEXT + + + + + 96 * _PREV - - - + + 97 * _LAST - - + + + 98 * _FOREACH + + + + + 99 * _FOREACH_REVERSE - - - + + 100 * _INSERT_HEAD + + + + + 101 * _INSERT_BEFORE - + - + + 102 * _INSERT_AFTER + + + + + 103 * _INSERT_TAIL - - + + + 104 * _REMOVE_HEAD + - + - - 105 * _REMOVE + + + + + 106 * 107 */ 108 109 /* 110 * Circular queue declarations. 111 */ 112 #define CIRCLEQ_HEAD(name, type) \ 113 struct name { \ 114 struct type *cqh_first; /* first element */ \ 115 struct type *cqh_last; /* last element */ \ 116 } 117 118 #define CIRCLEQ_HEAD_INITIALIZER(head) \ 119 { (void *)&(head), (void *)&(head) } 120 121 #define CIRCLEQ_ENTRY(type) \ 122 struct { \ 123 struct type *cqe_next; /* next element */ \ 124 struct type *cqe_prev; /* previous element */ \ 125 } 126 127 /* 128 * Circular queue functions. 129 */ 130 #define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) 131 132 #define CIRCLEQ_FIRST(head) ((head)->cqh_first) 133 134 #define CIRCLEQ_FOREACH(var, head, field) \ 135 for ((var) = CIRCLEQ_FIRST((head)); \ 136 (var) != (void *)(head) || ((var) = NULL); \ 137 (var) = CIRCLEQ_NEXT((var), field)) 138 139 #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ 140 for ((var) = CIRCLEQ_LAST((head)); \ 141 (var) != (void *)(head) || ((var) = NULL); \ 142 (var) = CIRCLEQ_PREV((var), field)) 143 144 #define CIRCLEQ_INIT(head) do { \ 145 CIRCLEQ_FIRST((head)) = (void *)(head); \ 146 CIRCLEQ_LAST((head)) = (void *)(head); \ 147 } while (0) 148 149 #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ 150 CIRCLEQ_NEXT((elm), field) = CIRCLEQ_NEXT((listelm), field); \ 151 CIRCLEQ_PREV((elm), field) = (listelm); \ 152 if (CIRCLEQ_NEXT((listelm), field) == (void *)(head)) \ 153 CIRCLEQ_LAST((head)) = (elm); \ 154 else \ 155 CIRCLEQ_PREV(CIRCLEQ_NEXT((listelm), field), field) = (elm);\ 156 CIRCLEQ_NEXT((listelm), field) = (elm); \ 157 } while (0) 158 159 #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ 160 CIRCLEQ_NEXT((elm), field) = (listelm); \ 161 CIRCLEQ_PREV((elm), field) = CIRCLEQ_PREV((listelm), field); \ 162 if (CIRCLEQ_PREV((listelm), field) == (void *)(head)) \ 163 CIRCLEQ_FIRST((head)) = (elm); \ 164 else \ 165 CIRCLEQ_NEXT(CIRCLEQ_PREV((listelm), field), field) = (elm);\ 166 CIRCLEQ_PREV((listelm), field) = (elm); \ 167 } while (0) 168 169 #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ 170 CIRCLEQ_NEXT((elm), field) = CIRCLEQ_FIRST((head)); \ 171 CIRCLEQ_PREV((elm), field) = (void *)(head); \ 172 if (CIRCLEQ_LAST((head)) == (void *)(head)) \ 173 CIRCLEQ_LAST((head)) = (elm); \ 174 else \ 175 CIRCLEQ_PREV(CIRCLEQ_FIRST((head)), field) = (elm); \ 176 CIRCLEQ_FIRST((head)) = (elm); \ 177 } while (0) 178 179 #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ 180 CIRCLEQ_NEXT((elm), field) = (void *)(head); \ 181 CIRCLEQ_PREV((elm), field) = CIRCLEQ_LAST((head)); \ 182 if (CIRCLEQ_FIRST((head)) == (void *)(head)) \ 183 CIRCLEQ_FIRST((head)) = (elm); \ 184 else \ 185 CIRCLEQ_NEXT(CIRCLEQ_LAST((head)), field) = (elm); \ 186 CIRCLEQ_LAST((head)) = (elm); \ 187 } while (0) 188 189 #define CIRCLEQ_LAST(head) ((head)->cqh_last) 190 191 #define CIRCLEQ_NEXT(elm,field) ((elm)->field.cqe_next) 192 193 #define CIRCLEQ_PREV(elm,field) ((elm)->field.cqe_prev) 194 195 #define CIRCLEQ_REMOVE(head, elm, field) do { \ 196 if (CIRCLEQ_NEXT((elm), field) == (void *)(head)) \ 197 CIRCLEQ_LAST((head)) = CIRCLEQ_PREV((elm), field); \ 198 else \ 199 CIRCLEQ_PREV(CIRCLEQ_NEXT((elm), field), field) = \ 200 CIRCLEQ_PREV((elm), field); \ 201 if (CIRCLEQ_PREV((elm), field) == (void *)(head)) \ 202 CIRCLEQ_FIRST((head)) = CIRCLEQ_NEXT((elm), field); \ 203 else \ 204 CIRCLEQ_NEXT(CIRCLEQ_PREV((elm), field), field) = \ 205 CIRCLEQ_NEXT((elm), field); \ 206 } while (0) 207 208 #ifdef __cplusplus 209 } 210 #endif 211 212 #endif /* !_SYS_QUEUE_H_ */ 213