PageRenderTime 21ms CodeModel.GetById 1ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 1ms

/src/rt/uthash/utlist.h

http://github.com/jruderman/rust
C Header | 280 lines | 188 code | 20 blank | 72 comment | 80 complexity | 46e17b096ad08131da73e6a2258645de MD5 | raw file
  1/*
  2Copyright (c) 2007-2009, Troy D. Hanson
  3All rights reserved.
  4
  5Redistribution and use in source and binary forms, with or without
  6modification, are permitted provided that the following conditions are met:
  7
  8    * Redistributions of source code must retain the above copyright
  9      notice, this list of conditions and the following disclaimer.
 10
 11THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 12IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 13TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 14PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 15OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 16EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 17PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 18PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 19LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 20NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 21SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 22*/
 23
 24#ifndef UTLIST_H
 25#define UTLIST_H
 26
 27#define UTLIST_VERSION 1.0
 28
 29/* C++ requires extra stringent casting */
 30#if defined __cplusplus
 31#define LTYPEOF(x) (typeof(x))
 32#else
 33#define LTYPEOF(x)
 34#endif
 35/* 
 36 * This file contains macros to manipulate singly and doubly-linked lists.
 37 *
 38 * 1. LL_ macros:  singly-linked lists.
 39 * 2. DL_ macros:  doubly-linked lists.
 40 * 3. CDL_ macros: circular doubly-linked lists.
 41 *
 42 * To use singly-linked lists, your structure must have a "next" pointer.
 43 * To use doubly-linked lists, your structure must "prev" and "next" pointers.
 44 * Either way, the pointer to the head of the list must be initialized to NULL.
 45 * 
 46 * ----------------.EXAMPLE -------------------------
 47 * struct item {
 48 *      int id;
 49 *      struct item *prev, *next;
 50 * }
 51 *
 52 * struct item *list = NULL:
 53 *
 54 * int main() {
 55 *      struct item *item;
 56 *      ... allocate and populate item ...
 57 *      DL_APPEND(list, item);
 58 * }
 59 * --------------------------------------------------
 60 *
 61 * For doubly-linked lists, the append and delete macros are O(1)
 62 * For singly-linked lists, append and delete are O(n) but prepend is O(1)
 63 * The sort macro is O(n log(n)) for all types of single/double/circular lists.
 64 */
 65
 66/******************************************************************************
 67 * The SORT macros                                                            *
 68 *****************************************************************************/
 69#define LL_SORT(l,cmp)                                                           \
 70 LISTSORT(l,0,0,FIELD_OFFSET(l,next),cmp)
 71#define DL_SORT(l,cmp)                                                           \
 72 LISTSORT(l,0,FIELD_OFFSET(l,prev),FIELD_OFFSET(l,next),cmp)
 73#define CDL_SORT(l,cmp)                                                          \
 74 LISTSORT(l,1,FIELD_OFFSET(l,prev),FIELD_OFFSET(l,next),cmp)
 75
 76/* The macros can't assume or cast to the caller's list element type. So we use
 77 * a couple tricks when we need to deal with those element's prev/next pointers.
 78 * Basically we use char pointer arithmetic to get those field offsets. */
 79#define FIELD_OFFSET(ptr,field) ((char*)&((ptr)->field) - (char*)(ptr))
 80#define LNEXT(e,no) (*(char**)(((char*)e) + no))
 81#define LPREV(e,po) (*(char**)(((char*)e) + po))
 82/******************************************************************************
 83 * The LISTSORT macro is an adaptation of Simon Tatham's O(n log(n)) mergesort*
 84 * Unwieldy variable names used here to avoid shadowing passed-in variables.  *
 85 *****************************************************************************/
 86#define LISTSORT(list, is_circular, po, no, cmp)                                 \
 87do {                                                                             \
 88  void *_ls_p, *_ls_q, *_ls_e, *_ls_tail, *_ls_oldhead;                          \
 89  int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;         \
 90  int _ls_is_double = (po==0) ? 0 : 1;                                           \
 91  if (list) {                                                                    \
 92    _ls_insize = 1;                                                              \
 93    _ls_looping = 1;                                                             \
 94    while (_ls_looping) {                                                        \
 95      _ls_p = list;                                                              \
 96      _ls_oldhead = list;                                                        \
 97      list = NULL;                                                               \
 98      _ls_tail = NULL;                                                           \
 99      _ls_nmerges = 0;                                                           \
100      while (_ls_p) {                                                            \
101        _ls_nmerges++;                                                           \
102        _ls_q = _ls_p;                                                           \
103        _ls_psize = 0;                                                           \
104        for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                           \
105          _ls_psize++;                                                           \
106          if (is_circular)  {                                                    \
107            _ls_q = ((LNEXT(_ls_q,no) == _ls_oldhead) ? NULL : LNEXT(_ls_q,no)); \
108          } else  {                                                              \
109            _ls_q = LNEXT(_ls_q,no);                                             \
110          }                                                                      \
111          if (!_ls_q) break;                                                     \
112        }                                                                        \
113        _ls_qsize = _ls_insize;                                                  \
114        while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                      \
115          if (_ls_psize == 0) {                                                  \
116            _ls_e = _ls_q; _ls_q = LNEXT(_ls_q,no); _ls_qsize--;                 \
117            if (is_circular && _ls_q == _ls_oldhead) { _ls_q = NULL; }           \
118          } else if (_ls_qsize == 0 || !_ls_q) {                                 \
119            _ls_e = _ls_p; _ls_p = LNEXT(_ls_p,no); _ls_psize--;                 \
120            if (is_circular && (_ls_p == _ls_oldhead)) { _ls_p = NULL; }         \
121          } else if (cmp(LTYPEOF(list)_ls_p,LTYPEOF(list)_ls_q) <= 0) {          \
122            _ls_e = _ls_p; _ls_p = LNEXT(_ls_p,no); _ls_psize--;                 \
123            if (is_circular && (_ls_p == _ls_oldhead)) { _ls_p = NULL; }         \
124          } else {                                                               \
125            _ls_e = _ls_q; _ls_q = LNEXT(_ls_q,no); _ls_qsize--;                 \
126            if (is_circular && (_ls_q == _ls_oldhead)) { _ls_q = NULL; }         \
127          }                                                                      \
128          if (_ls_tail) {                                                        \
129            LNEXT(_ls_tail,no) = (char*)_ls_e;                                   \
130          } else {                                                               \
131            list = LTYPEOF(list)_ls_e;                                           \
132          }                                                                      \
133          if (_ls_is_double) {                                                   \
134            LPREV(_ls_e,po) = (char*)_ls_tail;                                   \
135          }                                                                      \
136          _ls_tail = _ls_e;                                                      \
137        }                                                                        \
138        _ls_p = _ls_q;                                                           \
139      }                                                                          \
140      if (is_circular) {                                                         \
141        LNEXT(_ls_tail,no) = (char*)list;                                        \
142        if (_ls_is_double) {                                                     \
143          LPREV(list,po) = (char*)_ls_tail;                                      \
144        }                                                                        \
145      } else  {                                                                  \
146        LNEXT(_ls_tail,no) = NULL;                                               \
147      }                                                                          \
148      if (_ls_nmerges <= 1) {                                                    \
149        _ls_looping=0;                                                           \
150      }                                                                          \
151      _ls_insize *= 2;                                                           \
152    }                                                                            \
153  }                                                                              \
154} while (0)
155
156/******************************************************************************
157 * singly linked list macros (non-circular)                                   *
158 *****************************************************************************/
159#define LL_PREPEND(head,add)                                                     \
160do {                                                                             \
161  (add)->next = head;                                                            \
162  head = add;                                                                    \
163} while (0)
164
165#define LL_APPEND(head,add)                                                      \
166do {                                                                             \
167  (add)->next=NULL;                                                              \
168  if (head) {                                                                    \
169    char *_lla_el = (char*)(head);                                               \
170    unsigned _lla_no = FIELD_OFFSET(head,next);                                  \
171    while (LNEXT(_lla_el,_lla_no)) { _lla_el = LNEXT(_lla_el,_lla_no); }         \
172    LNEXT(_lla_el,_lla_no)=(char*)(add);                                         \
173  } else {                                                                       \
174    (head)=(add);                                                                \
175  }                                                                              \
176} while (0)
177
178#define LL_DELETE(head,del)                                                      \
179do {                                                                             \
180  if ((head) == (del)) {                                                         \
181    (head)=(head)->next;                                                         \
182  } else {                                                                       \
183    char *_lld_el = (char*)(head);                                               \
184    unsigned _lld_no = FIELD_OFFSET(head,next);                                  \
185    while (LNEXT(_lld_el,_lld_no) && (LNEXT(_lld_el,_lld_no) != (char*)(del))) { \
186      _lld_el = LNEXT(_lld_el,_lld_no);                                          \
187    }                                                                            \
188    if (LNEXT(_lld_el,_lld_no)) {                                                \
189      LNEXT(_lld_el,_lld_no) = (char*)((del)->next);                             \
190    }                                                                            \
191  }                                                                              \
192} while (0)
193
194#define LL_FOREACH(head,el)                                                      \
195    for(el=head;el;el=el->next)
196
197/******************************************************************************
198 * doubly linked list macros (non-circular)                                   *
199 *****************************************************************************/
200#define DL_PREPEND(head,add)                                                     \
201do {                                                                             \
202 (add)->next = head;                                                             \
203 if (head) {                                                                     \
204   (add)->prev = (head)->prev;                                                   \
205   (head)->prev = (add);                                                         \
206 } else {                                                                        \
207   (add)->prev = (add);                                                          \
208 }                                                                               \
209 (head) = (add);                                                                 \
210} while (0)
211
212#define DL_APPEND(head,add)                                                      \
213do {                                                                             \
214  if (head) {                                                                    \
215      (add)->prev = (head)->prev;                                                \
216      (head)->prev->next = (add);                                                \
217      (head)->prev = (add);                                                      \
218      (add)->next = NULL;                                                        \
219  } else {                                                                       \
220      (head)=(add);                                                              \
221      (head)->prev = (head);                                                     \
222      (head)->next = NULL;                                                       \
223  }                                                                              \
224} while (0);
225
226#define DL_DELETE(head,del)                                                      \
227do {                                                                             \
228  if ((del)->prev == (del)) {                                                    \
229      (head)=NULL;                                                               \
230  } else if ((del)==(head)) {                                                    \
231      (del)->next->prev = (del)->prev;                                           \
232      (head) = (del)->next;                                                      \
233  } else {                                                                       \
234      (del)->prev->next = (del)->next;                                           \
235      if ((del)->next) {                                                         \
236          (del)->next->prev = (del)->prev;                                       \
237      } else {                                                                   \
238          (head)->prev = (del)->prev;                                            \
239      }                                                                          \
240  }                                                                              \
241} while (0);
242
243
244#define DL_FOREACH(head,el)                                                      \
245    for(el=head;el;el=el->next)
246
247/******************************************************************************
248 * circular doubly linked list macros                                         *
249 *****************************************************************************/
250#define CDL_PREPEND(head,add)                                                    \
251do {                                                                             \
252 if (head) {                                                                     \
253   (add)->prev = (head)->prev;                                                   \
254   (add)->next = (head);                                                         \
255   (head)->prev = (add);                                                         \
256   (add)->prev->next = (add);                                                    \
257 } else {                                                                        \
258   (add)->prev = (add);                                                          \
259   (add)->next = (add);                                                          \
260 }                                                                               \
261(head)=(add);                                                                    \
262} while (0)
263
264#define CDL_DELETE(head,del)                                                     \
265do {                                                                             \
266  if ( ((head)==(del)) && ((head)->next == (head))) {                            \
267      (head) = 0L;                                                               \
268  } else {                                                                       \
269     (del)->next->prev = (del)->prev;                                            \
270     (del)->prev->next = (del)->next;                                            \
271     if ((del) == (head)) (head)=(del)->next;                                    \
272  }                                                                              \
273} while (0);
274
275#define CDL_FOREACH(head,el)                                                     \
276    for(el=head;el;el= (el->next==head ? 0L : el->next)) 
277
278
279#endif /* UTLIST_H */
280