| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| extern "C" { |
| |
| |
| |
| |
| |
| for (item = prefix |
| item = prefix |
| |
| for (typeof(prefix |
| prefix |
| (item = prefix |
| item; \ |
| item = prefix |
| prefix |
| |
| for (item = from, from = prefix |
| item; \ |
| item = from, from = prefix |
| |
| |
| |
| |
| |
| |
| macro_pure type *prefix |
| { \ |
| return (type *)prefix |
| } \ |
| macro_pure type *prefix |
| { \ |
| return (type *)prefix |
| } \ |
| |
| |
| macro_inline type *prefix |
| const type *item) \ |
| { \ |
| return (type *)prefix |
| } \ |
| |
| |
| macro_inline type *prefix |
| const type *item) \ |
| { \ |
| return (type *)prefix |
| } \ |
| macro_inline type *prefix |
| const type *item) \ |
| { \ |
| return (type *)prefix |
| } \ |
| |
| |
| |
| |
| |
| |
| |
| |
| struct slist_item { |
| struct slist_item *next; |
| }; |
| |
| struct slist_head { |
| struct slist_item *first, **last_next; |
| size_t count; |
| }; |
| |
| static inline void typesafe_list_add(struct slist_head *head, |
| struct slist_item **pos, struct slist_item *item) |
| { |
| item->next = *pos; |
| *pos = item; |
| if (pos == head->last_next) |
| head->last_next = &item->next; |
| head->count++; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| struct prefix |
| struct prefix |
| |
| |
| |
| |
| \ |
| macro_inline void prefix |
| { \ |
| memset(h, 0, sizeof(*h)); \ |
| h->sh.last_next = &h->sh.first; \ |
| } \ |
| macro_inline void prefix |
| { \ |
| memset(h, 0, sizeof(*h)); \ |
| } \ |
| macro_inline void prefix |
| { \ |
| typesafe_list_add(&h->sh, &h->sh.first, &item->field.si); \ |
| } \ |
| macro_inline void prefix |
| { \ |
| typesafe_list_add(&h->sh, h->sh.last_next, &item->field.si); \ |
| } \ |
| macro_inline void prefix |
| type *after, type *item) \ |
| { \ |
| struct slist_item **nextp; \ |
| nextp = after ? &after->field.si.next : &h->sh.first; \ |
| typesafe_list_add(&h->sh, nextp, &item->field.si); \ |
| } \ |
| \ |
| macro_inline type *prefix |
| { \ |
| struct slist_item **iter = &h->sh.first; \ |
| while (*iter && *iter != &item->field.si) \ |
| iter = &(*iter)->next; \ |
| if (!*iter) \ |
| return NULL; \ |
| h->sh.count--; \ |
| *iter = item->field.si.next; \ |
| if (!item->field.si.next) \ |
| h->sh.last_next = iter; \ |
| return item; \ |
| } \ |
| macro_inline type *prefix |
| { \ |
| struct slist_item *sitem = h->sh.first; \ |
| if (!sitem) \ |
| return NULL; \ |
| h->sh.count--; \ |
| h->sh.first = sitem->next; \ |
| if (h->sh.first == NULL) \ |
| h->sh.last_next = &h->sh.first; \ |
| return container_of(sitem, type, field.si); \ |
| } \ |
| macro_pure const type *prefix |
| { \ |
| return container_of_null(h->sh.first, type, field.si); \ |
| } \ |
| macro_pure const type *prefix |
| const type *item) \ |
| { \ |
| const struct slist_item *sitem = &item->field.si; \ |
| return container_of_null(sitem->next, type, field.si); \ |
| } \ |
| TYPESAFE_FIRST_NEXT(prefix, type) \ |
| macro_pure type *prefix |
| { \ |
| struct slist_item *sitem; \ |
| if (!item) \ |
| return NULL; \ |
| sitem = &item->field.si; \ |
| return container_of_null(sitem->next, type, field.si); \ |
| } \ |
| macro_pure size_t prefix |
| { \ |
| return h->sh.count; \ |
| } \ |
| |
| |
| |
| struct dlist_item { |
| struct dlist_item *next; |
| struct dlist_item *prev; |
| }; |
| |
| struct dlist_head { |
| struct dlist_item hitem; |
| size_t count; |
| }; |
| |
| static inline void typesafe_dlist_add(struct dlist_head *head, |
| struct dlist_item *prev, struct dlist_item *item) |
| { |
| item->next = prev->next; |
| item->next->prev = item; |
| item->prev = prev; |
| prev->next = item; |
| head->count++; |
| } |
| |
| |
| |
| |
| struct prefix |
| struct prefix |
| |
| |
| .hitem = { &var.dh.hitem, &var.dh.hitem }, }, } |
| |
| |
| \ |
| macro_inline void prefix |
| { \ |
| memset(h, 0, sizeof(*h)); \ |
| h->dh.hitem.prev = &h->dh.hitem; \ |
| h->dh.hitem.next = &h->dh.hitem; \ |
| } \ |
| macro_inline void prefix |
| { \ |
| memset(h, 0, sizeof(*h)); \ |
| } \ |
| macro_inline void prefix |
| { \ |
| typesafe_dlist_add(&h->dh, &h->dh.hitem, &item->field.di); \ |
| } \ |
| macro_inline void prefix |
| { \ |
| typesafe_dlist_add(&h->dh, h->dh.hitem.prev, &item->field.di); \ |
| } \ |
| macro_inline void prefix |
| type *after, type *item) \ |
| { \ |
| struct dlist_item *prev; \ |
| prev = after ? &after->field.di : &h->dh.hitem; \ |
| typesafe_dlist_add(&h->dh, prev, &item->field.di); \ |
| } \ |
| macro_inline type *prefix |
| { \ |
| struct dlist_item *ditem = &item->field.di; \ |
| ditem->prev->next = ditem->next; \ |
| ditem->next->prev = ditem->prev; \ |
| h->dh.count--; \ |
| ditem->prev = ditem->next = NULL; \ |
| return item; \ |
| } \ |
| macro_inline type *prefix |
| { \ |
| struct dlist_item *ditem = h->dh.hitem.next; \ |
| if (ditem == &h->dh.hitem) \ |
| return NULL; \ |
| ditem->prev->next = ditem->next; \ |
| ditem->next->prev = ditem->prev; \ |
| h->dh.count--; \ |
| return container_of(ditem, type, field.di); \ |
| } \ |
| macro_pure const type *prefix |
| { \ |
| const struct dlist_item *ditem = h->dh.hitem.next; \ |
| if (ditem == &h->dh.hitem) \ |
| return NULL; \ |
| return container_of(ditem, type, field.di); \ |
| } \ |
| macro_pure const type *prefix |
| const type *item) \ |
| { \ |
| const struct dlist_item *ditem = &item->field.di; \ |
| if (ditem->next == &h->dh.hitem) \ |
| return NULL; \ |
| return container_of(ditem->next, type, field.di); \ |
| } \ |
| TYPESAFE_FIRST_NEXT(prefix, type) \ |
| macro_pure type *prefix |
| { \ |
| if (!item) \ |
| return NULL; \ |
| return prefix |
| } \ |
| macro_pure size_t prefix |
| { \ |
| return h->dh.count; \ |
| } \ |
| |
| |
| |
| |
| |
| typedef uint32_t heap_index_i; |
| |
| struct heap_item { |
| uint32_t index; |
| }; |
| |
| struct heap_head { |
| struct heap_item **array; |
| uint32_t arraysz, count; |
| }; |
| |
| |
| (h->hh.count + 1 >= h->hh.arraysz) |
| |
| (h->hh.count == 0 || \ |
| h->hh.arraysz - h->hh.count > (h->hh.count + 1024) / 2) |
| |
| |
| struct prefix |
| struct prefix |
| |
| |
| |
| |
| \ |
| macro_inline void prefix |
| { \ |
| memset(h, 0, sizeof(*h)); \ |
| } \ |
| macro_inline void prefix |
| { \ |
| assert(h->hh.count == 0); \ |
| memset(h, 0, sizeof(*h)); \ |
| } \ |
| macro_inline int prefix |
| const struct heap_item *b) \ |
| { \ |
| return cmpfn(container_of(a, type, field.hi), \ |
| container_of(b, type, field.hi)); \ |
| } \ |
| macro_inline type *prefix |
| { \ |
| if (HEAP_RESIZE_TRESH_UP(h)) \ |
| typesafe_heap_resize(&h->hh, true); \ |
| typesafe_heap_pullup(&h->hh, h->hh.count, &item->field.hi, \ |
| prefix |
| h->hh.count++; \ |
| return NULL; \ |
| } \ |
| macro_inline type *prefix |
| { \ |
| struct heap_item *other; \ |
| uint32_t index = item->field.hi.index; \ |
| assert(h->hh.array[index] == &item->field.hi); \ |
| h->hh.count--; \ |
| other = h->hh.array[h->hh.count]; \ |
| if (cmpfn(container_of(other, type, field.hi), item) < 0) \ |
| typesafe_heap_pullup(&h->hh, index, other, prefix |
| else \ |
| typesafe_heap_pushdown(&h->hh, index, other, prefix |
| if (HEAP_RESIZE_TRESH_DN(h)) \ |
| typesafe_heap_resize(&h->hh, false); \ |
| return item; \ |
| } \ |
| macro_inline type *prefix |
| { \ |
| struct heap_item *hitem, *other; \ |
| if (h->hh.count == 0) \ |
| return NULL; \ |
| hitem = h->hh.array[0]; \ |
| h->hh.count--; \ |
| other = h->hh.array[h->hh.count]; \ |
| typesafe_heap_pushdown(&h->hh, 0, other, prefix |
| if (HEAP_RESIZE_TRESH_DN(h)) \ |
| typesafe_heap_resize(&h->hh, false); \ |
| return container_of(hitem, type, field.hi); \ |
| } \ |
| macro_pure const type *prefix |
| { \ |
| if (h->hh.count == 0) \ |
| return NULL; \ |
| return container_of(h->hh.array[0], type, field.hi); \ |
| } \ |
| macro_pure const type *prefix |
| const type *item) \ |
| { \ |
| uint32_t idx = item->field.hi.index + 1; \ |
| if (idx >= h->hh.count) \ |
| return NULL; \ |
| return container_of(h->hh.array[idx], type, field.hi); \ |
| } \ |
| TYPESAFE_FIRST_NEXT(prefix, type) \ |
| macro_pure type *prefix |
| { \ |
| if (!item) \ |
| return NULL; \ |
| return prefix |
| } \ |
| macro_pure size_t prefix |
| { \ |
| return h->hh.count; \ |
| } \ |
| |
| |
| extern void typesafe_heap_resize(struct heap_head *head, bool grow); |
| extern void typesafe_heap_pushdown(struct heap_head *head, uint32_t index, |
| struct heap_item *item, |
| int (*cmpfn)(const struct heap_item *a, |
| const struct heap_item *b)); |
| extern void typesafe_heap_pullup(struct heap_head *head, uint32_t index, |
| struct heap_item *item, |
| int (*cmpfn)(const struct heap_item *a, |
| const struct heap_item *b)); |
| |
| |
| |
| |
| |
| |
| struct ssort_item { |
| struct ssort_item *next; |
| }; |
| |
| struct ssort_head { |
| struct ssort_item *first; |
| size_t count; |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| struct prefix |
| struct prefix |
| |
| |
| |
| |
| |
| _PREDECL_SORTLIST(prefix) |
| |
| _PREDECL_SORTLIST(prefix) |
| |
| |
| \ |
| macro_inline void prefix |
| { \ |
| memset(h, 0, sizeof(*h)); \ |
| } \ |
| macro_inline void prefix |
| { \ |
| memset(h, 0, sizeof(*h)); \ |
| } \ |
| macro_inline type *prefix |
| { \ |
| struct ssort_item **np = &h->sh.first; \ |
| int c = 1; \ |
| while (*np && (c = cmpfn_uq( \ |
| container_of(*np, type, field.si), item)) < 0) \ |
| np = &(*np)->next; \ |
| if (c == 0) \ |
| return container_of(*np, type, field.si); \ |
| item->field.si.next = *np; \ |
| *np = &item->field.si; \ |
| h->sh.count++; \ |
| return NULL; \ |
| } \ |
| macro_inline const type *prefix |
| const struct prefix |
| { \ |
| const struct ssort_item *sitem = h->sh.first; \ |
| int cmpval = 0; \ |
| while (sitem && (cmpval = cmpfn_nuq( \ |
| container_of(sitem, type, field.si), item)) < 0) \ |
| sitem = sitem->next; \ |
| return container_of_null(sitem, type, field.si); \ |
| } \ |
| macro_inline const type *prefix |
| const struct prefix |
| { \ |
| const struct ssort_item *prev = NULL, *sitem = h->sh.first; \ |
| int cmpval = 0; \ |
| while (sitem && (cmpval = cmpfn_nuq( \ |
| container_of(sitem, type, field.si), item)) < 0) \ |
| sitem = (prev = sitem)->next; \ |
| return container_of_null(prev, type, field.si); \ |
| } \ |
| TYPESAFE_FIND_CMP(prefix, type) \ |
| \ |
| macro_inline type *prefix |
| { \ |
| struct ssort_item **iter = &h->sh.first; \ |
| while (*iter && *iter != &item->field.si) \ |
| iter = &(*iter)->next; \ |
| if (!*iter) \ |
| return NULL; \ |
| h->sh.count--; \ |
| *iter = item->field.si.next; \ |
| return item; \ |
| } \ |
| macro_inline type *prefix |
| { \ |
| struct ssort_item *sitem = h->sh.first; \ |
| if (!sitem) \ |
| return NULL; \ |
| h->sh.count--; \ |
| h->sh.first = sitem->next; \ |
| return container_of(sitem, type, field.si); \ |
| } \ |
| macro_pure const type *prefix |
| { \ |
| return container_of_null(h->sh.first, type, field.si); \ |
| } \ |
| macro_pure const type *prefix |
| const type *item) \ |
| { \ |
| const struct ssort_item *sitem = &item->field.si; \ |
| return container_of_null(sitem->next, type, field.si); \ |
| } \ |
| TYPESAFE_FIRST_NEXT(prefix, type) \ |
| macro_pure type *prefix |
| { \ |
| struct ssort_item *sitem; \ |
| if (!item) \ |
| return NULL; \ |
| sitem = &item->field.si; \ |
| return container_of_null(sitem->next, type, field.si); \ |
| } \ |
| macro_pure size_t prefix |
| { \ |
| return h->sh.count; \ |
| } \ |
| |
| |
| |
| _DECLARE_SORTLIST(prefix, type, field, cmpfn, cmpfn) \ |
| \ |
| macro_inline const type *prefix |
| const type *item) \ |
| { \ |
| const struct ssort_item *sitem = h->sh.first; \ |
| int cmpval = 0; \ |
| while (sitem && (cmpval = cmpfn( \ |
| container_of(sitem, type, field.si), item)) < 0) \ |
| sitem = sitem->next; \ |
| if (!sitem || cmpval > 0) \ |
| return NULL; \ |
| return container_of(sitem, type, field.si); \ |
| } \ |
| TYPESAFE_FIND(prefix, type) \ |
| |
| |
| |
| macro_inline int _ |
| { \ |
| int cmpval = cmpfn(a, b); \ |
| if (cmpval) \ |
| return cmpval; \ |
| if (a < b) \ |
| return -1; \ |
| if (a > b) \ |
| return 1; \ |
| return 0; \ |
| } \ |
| _DECLARE_SORTLIST(prefix, type, field, cmpfn, _ |
| |
| |
| |
| |
| |
| |
| |
| struct thash_item { |
| struct thash_item *next; |
| uint32_t hashval; |
| }; |
| |
| struct thash_head { |
| struct thash_item **entries; |
| uint32_t count; |
| |
| uint8_t tabshift; |
| uint8_t minshift, maxshift; |
| }; |
| |
| |
| ((1U << (tabshift)) >> 1) |
| |
| _HASH_SIZE((head).tabshift) |
| |
| ((val) >> (33 - (tabshift))) |
| |
| _HASH_KEY((head).tabshift, val) |
| |
| ((head).count >= HASH_SIZE(head)) |
| |
| ((head).count <= (HASH_SIZE(head) - 1) / 2) |
| |
| extern void typesafe_hash_grow(struct thash_head *head); |
| extern void typesafe_hash_shrink(struct thash_head *head); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| struct prefix |
| struct prefix |
| |
| |
| |
| |
| \ |
| macro_inline void prefix |
| { \ |
| memset(h, 0, sizeof(*h)); \ |
| } \ |
| macro_inline void prefix |
| { \ |
| assert(h->hh.count == 0); \ |
| h->hh.minshift = 0; \ |
| typesafe_hash_shrink(&h->hh); \ |
| memset(h, 0, sizeof(*h)); \ |
| } \ |
| macro_inline type *prefix |
| { \ |
| h->hh.count++; \ |
| if (!h->hh.tabshift || HASH_GROW_THRESHOLD(h->hh)) \ |
| typesafe_hash_grow(&h->hh); \ |
| \ |
| uint32_t hval = hashfn(item), hbits = HASH_KEY(h->hh, hval); \ |
| item->field.hi.hashval = hval; \ |
| struct thash_item **np = &h->hh.entries[hbits]; \ |
| while (*np && (*np)->hashval < hval) \ |
| np = &(*np)->next; \ |
| if (*np && cmpfn(container_of(*np, type, field.hi), item) == 0) { \ |
| h->hh.count--; \ |
| return container_of(*np, type, field.hi); \ |
| } \ |
| item->field.hi.next = *np; \ |
| *np = &item->field.hi; \ |
| return NULL; \ |
| } \ |
| macro_inline const type *prefix |
| const type *item) \ |
| { \ |
| if (!h->hh.tabshift) \ |
| return NULL; \ |
| uint32_t hval = hashfn(item), hbits = HASH_KEY(h->hh, hval); \ |
| const struct thash_item *hitem = h->hh.entries[hbits]; \ |
| while (hitem && hitem->hashval < hval) \ |
| hitem = hitem->next; \ |
| while (hitem && hitem->hashval == hval) { \ |
| if (!cmpfn(container_of(hitem, type, field.hi), item)) \ |
| return container_of(hitem, type, field.hi); \ |
| hitem = hitem->next; \ |
| } \ |
| return NULL; \ |
| } \ |
| TYPESAFE_FIND(prefix, type) \ |
| macro_inline type *prefix |
| { \ |
| if (!h->hh.tabshift) \ |
| return NULL; \ |
| uint32_t hval = item->field.hi.hashval, hbits = HASH_KEY(h->hh, hval); \ |
| struct thash_item **np = &h->hh.entries[hbits]; \ |
| while (*np && (*np)->hashval < hval) \ |
| np = &(*np)->next; \ |
| while (*np && *np != &item->field.hi && (*np)->hashval == hval) \ |
| np = &(*np)->next; \ |
| if (*np != &item->field.hi) \ |
| return NULL; \ |
| *np = item->field.hi.next; \ |
| item->field.hi.next = NULL; \ |
| h->hh.count--; \ |
| if (HASH_SHRINK_THRESHOLD(h->hh)) \ |
| typesafe_hash_shrink(&h->hh); \ |
| return item; \ |
| } \ |
| macro_inline type *prefix |
| { \ |
| uint32_t i; \ |
| for (i = 0; i < HASH_SIZE(h->hh); i++) \ |
| if (h->hh.entries[i]) { \ |
| struct thash_item *hitem = h->hh.entries[i]; \ |
| h->hh.entries[i] = hitem->next; \ |
| h->hh.count--; \ |
| hitem->next = NULL; \ |
| if (HASH_SHRINK_THRESHOLD(h->hh)) \ |
| typesafe_hash_shrink(&h->hh); \ |
| return container_of(hitem, type, field.hi); \ |
| } \ |
| return NULL; \ |
| } \ |
| macro_pure const type *prefix |
| { \ |
| uint32_t i; \ |
| for (i = 0; i < HASH_SIZE(h->hh); i++) \ |
| if (h->hh.entries[i]) \ |
| return container_of(h->hh.entries[i], type, field.hi); \ |
| return NULL; \ |
| } \ |
| macro_pure const type *prefix |
| const type *item) \ |
| { \ |
| const struct thash_item *hitem = &item->field.hi; \ |
| if (hitem->next) \ |
| return container_of(hitem->next, type, field.hi); \ |
| uint32_t i = HASH_KEY(h->hh, hitem->hashval) + 1; \ |
| for (; i < HASH_SIZE(h->hh); i++) \ |
| if (h->hh.entries[i]) \ |
| return container_of(h->hh.entries[i], type, field.hi); \ |
| return NULL; \ |
| } \ |
| TYPESAFE_FIRST_NEXT(prefix, type) \ |
| macro_pure type *prefix |
| { \ |
| if (!item) \ |
| return NULL; \ |
| return prefix |
| } \ |
| macro_pure size_t prefix |
| { \ |
| return h->hh.count; \ |
| } \ |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| struct sskip_item { |
| struct sskip_item *next[SKIPLIST_EMBED]; |
| }; |
| |
| struct sskip_overflow { |
| struct sskip_item *next[SKIPLIST_MAXDEPTH - SKIPLIST_OVERFLOW]; |
| }; |
| |
| struct sskip_head { |
| struct sskip_item hitem; |
| struct sskip_item *overflow[SKIPLIST_MAXDEPTH - SKIPLIST_OVERFLOW]; |
| size_t count; |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| struct prefix |
| struct prefix |
| |
| |
| |
| |
| |
| \ |
| macro_inline void prefix |
| { \ |
| memset(h, 0, sizeof(*h)); \ |
| h->sh.hitem.next[SKIPLIST_OVERFLOW] = (struct sskip_item *) \ |
| ((uintptr_t)h->sh.overflow | 1); \ |
| } \ |
| macro_inline void prefix |
| { \ |
| memset(h, 0, sizeof(*h)); \ |
| } \ |
| macro_inline type *prefix |
| { \ |
| struct sskip_item *si; \ |
| si = typesafe_skiplist_add(&h->sh, &item->field.si, cmpfn_uq); \ |
| return container_of_null(si, type, field.si); \ |
| } \ |
| macro_inline const type *prefix |
| const struct prefix |
| { \ |
| const struct sskip_item *sitem = typesafe_skiplist_find_gteq(&h->sh, \ |
| &item->field.si, cmpfn_nuq); \ |
| return container_of_null(sitem, type, field.si); \ |
| } \ |
| macro_inline const type *prefix |
| const struct prefix |
| { \ |
| const struct sskip_item *sitem = typesafe_skiplist_find_lt(&h->sh, \ |
| &item->field.si, cmpfn_nuq); \ |
| return container_of_null(sitem, type, field.si); \ |
| } \ |
| TYPESAFE_FIND_CMP(prefix, type) \ |
| macro_inline type *prefix |
| { \ |
| struct sskip_item *sitem = typesafe_skiplist_del(&h->sh, \ |
| &item->field.si, cmpfn_uq); \ |
| return container_of_null(sitem, type, field.si); \ |
| } \ |
| macro_inline type *prefix |
| { \ |
| struct sskip_item *sitem = typesafe_skiplist_pop(&h->sh); \ |
| return container_of_null(sitem, type, field.si); \ |
| } \ |
| macro_pure const type *prefix |
| { \ |
| const struct sskip_item *first = h->sh.hitem.next[0]; \ |
| return container_of_null(first, type, field.si); \ |
| } \ |
| macro_pure const type *prefix |
| const type *item) \ |
| { \ |
| const struct sskip_item *next = item->field.si.next[0]; \ |
| return container_of_null(next, type, field.si); \ |
| } \ |
| TYPESAFE_FIRST_NEXT(prefix, type) \ |
| macro_pure type *prefix |
| { \ |
| struct sskip_item *next; \ |
| next = item ? item->field.si.next[0] : NULL; \ |
| return container_of_null(next, type, field.si); \ |
| } \ |
| macro_pure size_t prefix |
| { \ |
| return h->sh.count; \ |
| } \ |
| |
| |
| |
| _PREDECL_SKIPLIST(prefix) |
| |
| \ |
| macro_inline int prefix |
| const struct sskip_item *b) \ |
| { \ |
| return cmpfn(container_of(a, type, field.si), \ |
| container_of(b, type, field.si)); \ |
| } \ |
| macro_inline const type *prefix |
| const type *item) \ |
| { \ |
| const struct sskip_item *sitem = typesafe_skiplist_find(&h->sh, \ |
| &item->field.si, &prefix |
| return container_of_null(sitem, type, field.si); \ |
| } \ |
| TYPESAFE_FIND(prefix, type) \ |
| \ |
| _DECLARE_SKIPLIST(prefix, type, field, \ |
| prefix |
| |
| |
| |
| _PREDECL_SKIPLIST(prefix) |
| |
| \ |
| macro_inline int prefix |
| const struct sskip_item *b) \ |
| { \ |
| return cmpfn(container_of(a, type, field.si), \ |
| container_of(b, type, field.si)); \ |
| } \ |
| macro_inline int prefix |
| const struct sskip_item *b) \ |
| { \ |
| int cmpval = cmpfn(container_of(a, type, field.si), \ |
| container_of(b, type, field.si)); \ |
| if (cmpval) \ |
| return cmpval; \ |
| if (a < b) \ |
| return -1; \ |
| if (a > b) \ |
| return 1; \ |
| return 0; \ |
| } \ |
| \ |
| _DECLARE_SKIPLIST(prefix, type, field, \ |
| prefix |
| |
| |
| |
| extern struct sskip_item *typesafe_skiplist_add(struct sskip_head *head, |
| struct sskip_item *item, int (*cmpfn)( |
| const struct sskip_item *a, |
| const struct sskip_item *b)); |
| extern const struct sskip_item *typesafe_skiplist_find( |
| const struct sskip_head *head, |
| const struct sskip_item *item, int (*cmpfn)( |
| const struct sskip_item *a, |
| const struct sskip_item *b)); |
| extern const struct sskip_item *typesafe_skiplist_find_gteq( |
| const struct sskip_head *head, |
| const struct sskip_item *item, int (*cmpfn)( |
| const struct sskip_item *a, |
| const struct sskip_item *b)); |
| extern const struct sskip_item *typesafe_skiplist_find_lt( |
| const struct sskip_head *head, |
| const struct sskip_item *item, int (*cmpfn)( |
| const struct sskip_item *a, |
| const struct sskip_item *b)); |
| extern struct sskip_item *typesafe_skiplist_del( |
| struct sskip_head *head, struct sskip_item *item, int (*cmpfn)( |
| const struct sskip_item *a, |
| const struct sskip_item *b)); |
| extern struct sskip_item *typesafe_skiplist_pop(struct sskip_head *head); |
| |
| |
| } |
| |
| |
| |
| |
| |
| |
| |
| |