forked from Mirror/frr
lib: add const iteration & find to typesafe lists
Based on work originally by Mark Stapp <mjs@voltanet.io>. Make it possible to iterate the typesafe lists in a const context, as well as find items from them. Signed-off-by: Mark Stapp <mjs@voltanet.io> [above signoff was for the original version before modification] Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
parent
15e9c561b2
commit
daf3441d2b
|
@ -105,7 +105,8 @@ Functions provided:
|
||||||
+====================================+======+======+======+=========+============+
|
+====================================+======+======+======+=========+============+
|
||||||
| _init, _fini | yes | yes | yes | yes | yes |
|
| _init, _fini | yes | yes | yes | yes | yes |
|
||||||
+------------------------------------+------+------+------+---------+------------+
|
+------------------------------------+------+------+------+---------+------------+
|
||||||
| _first, _next, _next_safe | yes | yes | yes | yes | yes |
|
| _first, _next, _next_safe, | yes | yes | yes | yes | yes |
|
||||||
|
| _const_first, _const_next | | | | | |
|
||||||
+------------------------------------+------+------+------+---------+------------+
|
+------------------------------------+------+------+------+---------+------------+
|
||||||
| _add_head, _add_tail, _add_after | yes | -- | -- | -- | -- |
|
| _add_head, _add_tail, _add_after | yes | -- | -- | -- | -- |
|
||||||
+------------------------------------+------+------+------+---------+------------+
|
+------------------------------------+------+------+------+---------+------------+
|
||||||
|
@ -113,9 +114,10 @@ Functions provided:
|
||||||
+------------------------------------+------+------+------+---------+------------+
|
+------------------------------------+------+------+------+---------+------------+
|
||||||
| _del, _pop | yes | yes | yes | yes | yes |
|
| _del, _pop | yes | yes | yes | yes | yes |
|
||||||
+------------------------------------+------+------+------+---------+------------+
|
+------------------------------------+------+------+------+---------+------------+
|
||||||
| _find | -- | -- | yes | yes | -- |
|
| _find, _const_find | -- | -- | yes | yes | -- |
|
||||||
+------------------------------------+------+------+------+---------+------------+
|
+------------------------------------+------+------+------+---------+------------+
|
||||||
| _find_lt, _find_gteq | -- | -- | -- | yes | yes |
|
| _find_lt, _find_gteq, | -- | -- | -- | yes | yes |
|
||||||
|
| _const_find_lt, _const_find_gteq | | | | | |
|
||||||
+------------------------------------+------+------+------+---------+------------+
|
+------------------------------------+------+------+------+---------+------------+
|
||||||
| use with frr_each() macros | yes | yes | yes | yes | yes |
|
| use with frr_each() macros | yes | yes | yes | yes | yes |
|
||||||
+------------------------------------+------+------+------+---------+------------+
|
+------------------------------------+------+------+------+---------+------------+
|
||||||
|
@ -226,6 +228,10 @@ The following iteration macros work across all data structures:
|
||||||
resume iteration after breaking out of the loop by keeping the ``from``
|
resume iteration after breaking out of the loop by keeping the ``from``
|
||||||
value persistent and reusing it for the next loop.
|
value persistent and reusing it for the next loop.
|
||||||
|
|
||||||
|
To iterate over ``const`` pointers, add ``_const`` to the name of the
|
||||||
|
datastructure (``Z`` above), e.g. ``frr_each (mylist, head, item)`` becomes
|
||||||
|
``frr_each (mylist_const, head, item)``.
|
||||||
|
|
||||||
Common API
|
Common API
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
@ -248,7 +254,7 @@ The following documentation assumes that a list has been defined using
|
||||||
|
|
||||||
This function may ``assert()`` if the list is not empty.
|
This function may ``assert()`` if the list is not empty.
|
||||||
|
|
||||||
.. c:function:: size_t Z_count(struct Z_head *)
|
.. c:function:: size_t Z_count(const struct Z_head *)
|
||||||
|
|
||||||
Returns the number of items in a structure. All structures store a
|
Returns the number of items in a structure. All structures store a
|
||||||
counter in their `Z_head` so that calling this function completes
|
counter in their `Z_head` so that calling this function completes
|
||||||
|
@ -260,6 +266,7 @@ The following documentation assumes that a list has been defined using
|
||||||
outdated by the time this function returns and can therefore only be
|
outdated by the time this function returns and can therefore only be
|
||||||
used as an estimate.
|
used as an estimate.
|
||||||
|
|
||||||
|
.. c:function:: const itemtype *Z_const_first(const struct Z_head *)
|
||||||
.. c:function:: itemtype *Z_first(struct Z_head *)
|
.. c:function:: itemtype *Z_first(struct Z_head *)
|
||||||
|
|
||||||
Returns the first item in the structure, or ``NULL`` if the structure is
|
Returns the first item in the structure, or ``NULL`` if the structure is
|
||||||
|
@ -288,6 +295,7 @@ The following documentation assumes that a list has been defined using
|
||||||
affected by the "modification while iterating" problem. To remove
|
affected by the "modification while iterating" problem. To remove
|
||||||
all items from a hash table, use the loop demonstrated above.
|
all items from a hash table, use the loop demonstrated above.
|
||||||
|
|
||||||
|
.. c:function:: const itemtype *Z_next(const struct Z_head *, const itemtype *prev)
|
||||||
.. c:function:: itemtype *Z_next(struct Z_head *, itemtype *prev)
|
.. c:function:: itemtype *Z_next(struct Z_head *, itemtype *prev)
|
||||||
|
|
||||||
Return the item that follows after ``prev``, or ``NULL`` if ``prev`` is
|
Return the item that follows after ``prev``, or ``NULL`` if ``prev`` is
|
||||||
|
@ -421,6 +429,7 @@ sorted lists can be searched for a value.
|
||||||
For ``_NONUNIQ`` lists, this function always returns NULL since ``item``
|
For ``_NONUNIQ`` lists, this function always returns NULL since ``item``
|
||||||
can always be successfully added to the list.
|
can always be successfully added to the list.
|
||||||
|
|
||||||
|
.. c:function:: const itemtype *Z_find(const struct Z_head *, const itemtype *ref)
|
||||||
.. c:function:: itemtype *Z_find(struct Z_head *, const itemtype *ref)
|
.. c:function:: itemtype *Z_find(struct Z_head *, const itemtype *ref)
|
||||||
|
|
||||||
Search the list for an item that compares equal to ``ref``. If no equal
|
Search the list for an item that compares equal to ``ref``. If no equal
|
||||||
|
@ -442,11 +451,13 @@ sorted lists can be searched for a value.
|
||||||
containing non-unique items, more than one item may compare as equal to
|
containing non-unique items, more than one item may compare as equal to
|
||||||
the item that is searched for.
|
the item that is searched for.
|
||||||
|
|
||||||
|
.. c:function:: const itemtype *Z_find_gteq(const struct Z_head *, const itemtype *ref)
|
||||||
.. c:function:: itemtype *Z_find_gteq(struct Z_head *, const itemtype *ref)
|
.. c:function:: itemtype *Z_find_gteq(struct Z_head *, const itemtype *ref)
|
||||||
|
|
||||||
Search the list for an item that compares greater or equal to
|
Search the list for an item that compares greater or equal to
|
||||||
``ref``. See :c:func:`Z_find()` above.
|
``ref``. See :c:func:`Z_find()` above.
|
||||||
|
|
||||||
|
.. c:function:: const itemtype *Z_find_lt(const struct Z_head *, const itemtype *ref)
|
||||||
.. c:function:: itemtype *Z_find_lt(struct Z_head *, const itemtype *ref)
|
.. c:function:: itemtype *Z_find_lt(struct Z_head *, const itemtype *ref)
|
||||||
|
|
||||||
Search the list for an item that compares less than
|
Search the list for an item that compares less than
|
||||||
|
@ -616,21 +627,9 @@ Head removal (pop) and deallocation:
|
||||||
FAQ
|
FAQ
|
||||||
---
|
---
|
||||||
|
|
||||||
Why is the list head not ``const`` in the list APIs?
|
What are the semantics of ``const`` in the list APIs?
|
||||||
The semantics that a ``const`` list head would imply are not obvious. It
|
``const`` pointers to list heads and/or items are interpreted to mean that
|
||||||
could mean any of the following:
|
both the list itself as well as the data items are read-only.
|
||||||
|
|
||||||
* the list just shouldn't be allocated/deallocated, but may be modified.
|
|
||||||
This doesn't actually work since the list head needs to be modified for
|
|
||||||
inserting or deleting items.
|
|
||||||
|
|
||||||
* the list shouldn't be modified, but items can. This may make sense for
|
|
||||||
iterating, but it's not exactly consistent - an item might be on more
|
|
||||||
than one list, does it apply to all of them? If not, which one?
|
|
||||||
|
|
||||||
* neither the list nor the items should be modified. This is consistent,
|
|
||||||
but hard to do without creating a ``const`` copy of every single list
|
|
||||||
function. Ease of use trumps this.
|
|
||||||
|
|
||||||
Why is there no "is this item on a/the list" test?
|
Why is there no "is this item on a/the list" test?
|
||||||
It's slow for several of the data structures, and the work of adding it
|
It's slow for several of the data structures, and the work of adding it
|
||||||
|
|
19
lib/typerb.c
19
lib/typerb.c
|
@ -377,12 +377,13 @@ struct typed_rb_entry *typed_rb_insert(struct rbt_tree *rbt,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finds the node with the same key as elm */
|
/* Finds the node with the same key as elm */
|
||||||
struct rb_entry *typed_rb_find(struct rbt_tree *rbt, const struct rb_entry *key,
|
const struct rb_entry *typed_rb_find(const struct rbt_tree *rbt,
|
||||||
|
const struct rb_entry *key,
|
||||||
int (*cmpfn)(
|
int (*cmpfn)(
|
||||||
const struct typed_rb_entry *a,
|
const struct typed_rb_entry *a,
|
||||||
const struct typed_rb_entry *b))
|
const struct typed_rb_entry *b))
|
||||||
{
|
{
|
||||||
struct rb_entry *tmp = RBH_ROOT(rbt);
|
const struct rb_entry *tmp = RBH_ROOT(rbt);
|
||||||
int comp;
|
int comp;
|
||||||
|
|
||||||
while (tmp != NULL) {
|
while (tmp != NULL) {
|
||||||
|
@ -398,13 +399,13 @@ struct rb_entry *typed_rb_find(struct rbt_tree *rbt, const struct rb_entry *key,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rb_entry *typed_rb_find_gteq(struct rbt_tree *rbt,
|
const struct rb_entry *typed_rb_find_gteq(const struct rbt_tree *rbt,
|
||||||
const struct rb_entry *key,
|
const struct rb_entry *key,
|
||||||
int (*cmpfn)(
|
int (*cmpfn)(
|
||||||
const struct typed_rb_entry *a,
|
const struct typed_rb_entry *a,
|
||||||
const struct typed_rb_entry *b))
|
const struct typed_rb_entry *b))
|
||||||
{
|
{
|
||||||
struct rb_entry *tmp = RBH_ROOT(rbt), *best = NULL;
|
const struct rb_entry *tmp = RBH_ROOT(rbt), *best = NULL;
|
||||||
int comp;
|
int comp;
|
||||||
|
|
||||||
while (tmp != NULL) {
|
while (tmp != NULL) {
|
||||||
|
@ -421,13 +422,13 @@ struct rb_entry *typed_rb_find_gteq(struct rbt_tree *rbt,
|
||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rb_entry *typed_rb_find_lt(struct rbt_tree *rbt,
|
const struct rb_entry *typed_rb_find_lt(const struct rbt_tree *rbt,
|
||||||
const struct rb_entry *key,
|
const struct rb_entry *key,
|
||||||
int (*cmpfn)(
|
int (*cmpfn)(
|
||||||
const struct typed_rb_entry *a,
|
const struct typed_rb_entry *a,
|
||||||
const struct typed_rb_entry *b))
|
const struct typed_rb_entry *b))
|
||||||
{
|
{
|
||||||
struct rb_entry *tmp = RBH_ROOT(rbt), *best = NULL;
|
const struct rb_entry *tmp = RBH_ROOT(rbt), *best = NULL;
|
||||||
int comp;
|
int comp;
|
||||||
|
|
||||||
while (tmp != NULL) {
|
while (tmp != NULL) {
|
||||||
|
@ -443,8 +444,10 @@ struct rb_entry *typed_rb_find_lt(struct rbt_tree *rbt,
|
||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rb_entry *typed_rb_next(struct rb_entry *rbe)
|
struct rb_entry *typed_rb_next(const struct rb_entry *rbe_const)
|
||||||
{
|
{
|
||||||
|
struct rb_entry *rbe = (struct rb_entry *)rbe_const;
|
||||||
|
|
||||||
if (RBE_RIGHT(rbe) != NULL) {
|
if (RBE_RIGHT(rbe) != NULL) {
|
||||||
rbe = RBE_RIGHT(rbe);
|
rbe = RBE_RIGHT(rbe);
|
||||||
while (RBE_LEFT(rbe) != NULL)
|
while (RBE_LEFT(rbe) != NULL)
|
||||||
|
@ -463,7 +466,7 @@ struct rb_entry *typed_rb_next(struct rb_entry *rbe)
|
||||||
return rbe;
|
return rbe;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rb_entry *typed_rb_min(struct rbt_tree *rbt)
|
struct rb_entry *typed_rb_min(const struct rbt_tree *rbt)
|
||||||
{
|
{
|
||||||
struct rb_entry *rbe = RBH_ROOT(rbt);
|
struct rb_entry *rbe = RBH_ROOT(rbt);
|
||||||
struct rb_entry *parent = NULL;
|
struct rb_entry *parent = NULL;
|
||||||
|
|
39
lib/typerb.h
39
lib/typerb.h
|
@ -45,23 +45,23 @@ struct typed_rb_entry *typed_rb_insert(struct typed_rb_root *rbt,
|
||||||
const struct typed_rb_entry *b));
|
const struct typed_rb_entry *b));
|
||||||
struct typed_rb_entry *typed_rb_remove(struct typed_rb_root *rbt,
|
struct typed_rb_entry *typed_rb_remove(struct typed_rb_root *rbt,
|
||||||
struct typed_rb_entry *rbe);
|
struct typed_rb_entry *rbe);
|
||||||
struct typed_rb_entry *typed_rb_find(struct typed_rb_root *rbt,
|
const struct typed_rb_entry *typed_rb_find(const struct typed_rb_root *rbt,
|
||||||
const struct typed_rb_entry *rbe,
|
const struct typed_rb_entry *rbe,
|
||||||
int (*cmpfn)(
|
int (*cmpfn)(
|
||||||
const struct typed_rb_entry *a,
|
const struct typed_rb_entry *a,
|
||||||
const struct typed_rb_entry *b));
|
const struct typed_rb_entry *b));
|
||||||
struct typed_rb_entry *typed_rb_find_gteq(struct typed_rb_root *rbt,
|
const struct typed_rb_entry *typed_rb_find_gteq(const struct typed_rb_root *rbt,
|
||||||
const struct typed_rb_entry *rbe,
|
const struct typed_rb_entry *rbe,
|
||||||
int (*cmpfn)(
|
int (*cmpfn)(
|
||||||
const struct typed_rb_entry *a,
|
const struct typed_rb_entry *a,
|
||||||
const struct typed_rb_entry *b));
|
const struct typed_rb_entry *b));
|
||||||
struct typed_rb_entry *typed_rb_find_lt(struct typed_rb_root *rbt,
|
const struct typed_rb_entry *typed_rb_find_lt(const struct typed_rb_root *rbt,
|
||||||
const struct typed_rb_entry *rbe,
|
const struct typed_rb_entry *rbe,
|
||||||
int (*cmpfn)(
|
int (*cmpfn)(
|
||||||
const struct typed_rb_entry *a,
|
const struct typed_rb_entry *a,
|
||||||
const struct typed_rb_entry *b));
|
const struct typed_rb_entry *b));
|
||||||
struct typed_rb_entry *typed_rb_min(struct typed_rb_root *rbt);
|
struct typed_rb_entry *typed_rb_min(const struct typed_rb_root *rbt);
|
||||||
struct typed_rb_entry *typed_rb_next(struct typed_rb_entry *rbe);
|
struct typed_rb_entry *typed_rb_next(const struct typed_rb_entry *rbe);
|
||||||
|
|
||||||
#define _PREDECL_RBTREE(prefix) \
|
#define _PREDECL_RBTREE(prefix) \
|
||||||
struct prefix ## _head { struct typed_rb_root rr; }; \
|
struct prefix ## _head { struct typed_rb_root rr; }; \
|
||||||
|
@ -86,20 +86,21 @@ macro_inline type *prefix ## _add(struct prefix##_head *h, type *item) \
|
||||||
re = typed_rb_insert(&h->rr, &item->field.re, cmpfn_uq); \
|
re = typed_rb_insert(&h->rr, &item->field.re, cmpfn_uq); \
|
||||||
return container_of_null(re, type, field.re); \
|
return container_of_null(re, type, field.re); \
|
||||||
} \
|
} \
|
||||||
macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \
|
macro_inline const type *prefix ## _const_find_gteq( \
|
||||||
const type *item) \
|
const struct prefix##_head *h, const type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct typed_rb_entry *re; \
|
const struct typed_rb_entry *re; \
|
||||||
re = typed_rb_find_gteq(&h->rr, &item->field.re, cmpfn_nuq); \
|
re = typed_rb_find_gteq(&h->rr, &item->field.re, cmpfn_nuq); \
|
||||||
return container_of_null(re, type, field.re); \
|
return container_of_null(re, type, field.re); \
|
||||||
} \
|
} \
|
||||||
macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
|
macro_inline const type *prefix ## _const_find_lt( \
|
||||||
const type *item) \
|
const struct prefix##_head *h, const type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct typed_rb_entry *re; \
|
const struct typed_rb_entry *re; \
|
||||||
re = typed_rb_find_lt(&h->rr, &item->field.re, cmpfn_nuq); \
|
re = typed_rb_find_lt(&h->rr, &item->field.re, cmpfn_nuq); \
|
||||||
return container_of_null(re, type, field.re); \
|
return container_of_null(re, type, field.re); \
|
||||||
} \
|
} \
|
||||||
|
TYPESAFE_FIND_CMP(prefix, type) \
|
||||||
macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
|
macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct typed_rb_entry *re; \
|
struct typed_rb_entry *re; \
|
||||||
|
@ -115,18 +116,20 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
|
||||||
typed_rb_remove(&h->rr, re); \
|
typed_rb_remove(&h->rr, re); \
|
||||||
return container_of(re, type, field.re); \
|
return container_of(re, type, field.re); \
|
||||||
} \
|
} \
|
||||||
macro_pure type *prefix ## _first(struct prefix##_head *h) \
|
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
|
||||||
{ \
|
{ \
|
||||||
struct typed_rb_entry *re; \
|
const struct typed_rb_entry *re; \
|
||||||
re = typed_rb_min(&h->rr); \
|
re = typed_rb_min(&h->rr); \
|
||||||
return container_of_null(re, type, field.re); \
|
return container_of_null(re, type, field.re); \
|
||||||
} \
|
} \
|
||||||
macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \
|
macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
|
||||||
|
const type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct typed_rb_entry *re; \
|
const struct typed_rb_entry *re; \
|
||||||
re = typed_rb_next(&item->field.re); \
|
re = typed_rb_next(&item->field.re); \
|
||||||
return container_of_null(re, type, field.re); \
|
return container_of_null(re, type, field.re); \
|
||||||
} \
|
} \
|
||||||
|
TYPESAFE_FIRST_NEXT(prefix, type) \
|
||||||
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
|
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct typed_rb_entry *re; \
|
struct typed_rb_entry *re; \
|
||||||
|
@ -149,12 +152,14 @@ macro_inline int prefix ## __cmp(const struct typed_rb_entry *a, \
|
||||||
return cmpfn(container_of(a, type, field.re), \
|
return cmpfn(container_of(a, type, field.re), \
|
||||||
container_of(b, type, field.re)); \
|
container_of(b, type, field.re)); \
|
||||||
} \
|
} \
|
||||||
macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
|
macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \
|
||||||
|
const type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct typed_rb_entry *re; \
|
const struct typed_rb_entry *re; \
|
||||||
re = typed_rb_find(&h->rr, &item->field.re, &prefix ## __cmp); \
|
re = typed_rb_find(&h->rr, &item->field.re, &prefix ## __cmp); \
|
||||||
return container_of_null(re, type, field.re); \
|
return container_of_null(re, type, field.re); \
|
||||||
} \
|
} \
|
||||||
|
TYPESAFE_FIND(prefix, type) \
|
||||||
\
|
\
|
||||||
_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp) \
|
_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp) \
|
||||||
/* ... */
|
/* ... */
|
||||||
|
|
|
@ -158,7 +158,7 @@ void typesafe_hash_shrink(struct thash_head *head)
|
||||||
|
|
||||||
/* skiplist */
|
/* skiplist */
|
||||||
|
|
||||||
static inline struct sskip_item *sl_level_get(struct sskip_item *item,
|
static inline struct sskip_item *sl_level_get(const struct sskip_item *item,
|
||||||
size_t level)
|
size_t level)
|
||||||
{
|
{
|
||||||
if (level < SKIPLIST_OVERFLOW)
|
if (level < SKIPLIST_OVERFLOW)
|
||||||
|
@ -263,13 +263,14 @@ struct sskip_item *typesafe_skiplist_add(struct sskip_head *head,
|
||||||
|
|
||||||
/* NOTE: level counting below is 1-based since that makes the code simpler! */
|
/* NOTE: level counting below is 1-based since that makes the code simpler! */
|
||||||
|
|
||||||
struct sskip_item *typesafe_skiplist_find(struct sskip_head *head,
|
const struct sskip_item *typesafe_skiplist_find(
|
||||||
|
const struct sskip_head *head,
|
||||||
const struct sskip_item *item, int (*cmpfn)(
|
const struct sskip_item *item, int (*cmpfn)(
|
||||||
const struct sskip_item *a,
|
const struct sskip_item *a,
|
||||||
const struct sskip_item *b))
|
const struct sskip_item *b))
|
||||||
{
|
{
|
||||||
size_t level = SKIPLIST_MAXDEPTH;
|
size_t level = SKIPLIST_MAXDEPTH;
|
||||||
struct sskip_item *prev = &head->hitem, *next;
|
const struct sskip_item *prev = &head->hitem, *next;
|
||||||
int cmpval;
|
int cmpval;
|
||||||
|
|
||||||
while (level) {
|
while (level) {
|
||||||
|
@ -290,13 +291,14 @@ struct sskip_item *typesafe_skiplist_find(struct sskip_head *head,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sskip_item *typesafe_skiplist_find_gteq(struct sskip_head *head,
|
const struct sskip_item *typesafe_skiplist_find_gteq(
|
||||||
|
const struct sskip_head *head,
|
||||||
const struct sskip_item *item, int (*cmpfn)(
|
const struct sskip_item *item, int (*cmpfn)(
|
||||||
const struct sskip_item *a,
|
const struct sskip_item *a,
|
||||||
const struct sskip_item *b))
|
const struct sskip_item *b))
|
||||||
{
|
{
|
||||||
size_t level = SKIPLIST_MAXDEPTH;
|
size_t level = SKIPLIST_MAXDEPTH;
|
||||||
struct sskip_item *prev = &head->hitem, *next;
|
const struct sskip_item *prev = &head->hitem, *next;
|
||||||
int cmpval;
|
int cmpval;
|
||||||
|
|
||||||
while (level) {
|
while (level) {
|
||||||
|
@ -317,13 +319,14 @@ struct sskip_item *typesafe_skiplist_find_gteq(struct sskip_head *head,
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sskip_item *typesafe_skiplist_find_lt(struct sskip_head *head,
|
const struct sskip_item *typesafe_skiplist_find_lt(
|
||||||
|
const struct sskip_head *head,
|
||||||
const struct sskip_item *item, int (*cmpfn)(
|
const struct sskip_item *item, int (*cmpfn)(
|
||||||
const struct sskip_item *a,
|
const struct sskip_item *a,
|
||||||
const struct sskip_item *b))
|
const struct sskip_item *b))
|
||||||
{
|
{
|
||||||
size_t level = SKIPLIST_MAXDEPTH;
|
size_t level = SKIPLIST_MAXDEPTH;
|
||||||
struct sskip_item *prev = &head->hitem, *next, *best = NULL;
|
const struct sskip_item *prev = &head->hitem, *next, *best = NULL;
|
||||||
int cmpval;
|
int cmpval;
|
||||||
|
|
||||||
while (level) {
|
while (level) {
|
||||||
|
|
138
lib/typesafe.h
138
lib/typesafe.h
|
@ -44,6 +44,41 @@ extern "C" {
|
||||||
item; \
|
item; \
|
||||||
item = from, from = prefix##_next_safe(head, from))
|
item = from, from = prefix##_next_safe(head, from))
|
||||||
|
|
||||||
|
|
||||||
|
/* non-const variants. these wrappers are the same for all the types, so
|
||||||
|
* bundle them together here.
|
||||||
|
*/
|
||||||
|
#define TYPESAFE_FIRST_NEXT(prefix, type) \
|
||||||
|
macro_pure type *prefix ## _first(struct prefix##_head *h) \
|
||||||
|
{ \
|
||||||
|
return (type *)prefix ## _const_first(h); \
|
||||||
|
} \
|
||||||
|
macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \
|
||||||
|
{ \
|
||||||
|
return (type *)prefix ## _const_next(h, item); \
|
||||||
|
} \
|
||||||
|
/* ... */
|
||||||
|
#define TYPESAFE_FIND(prefix, type) \
|
||||||
|
macro_inline type *prefix ## _find(struct prefix##_head *h, \
|
||||||
|
const type *item) \
|
||||||
|
{ \
|
||||||
|
return (type *)prefix ## _const_find(h, item); \
|
||||||
|
} \
|
||||||
|
/* ... */
|
||||||
|
#define TYPESAFE_FIND_CMP(prefix, type) \
|
||||||
|
macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
|
||||||
|
const type *item) \
|
||||||
|
{ \
|
||||||
|
return (type *)prefix ## _const_find_lt(h, item); \
|
||||||
|
} \
|
||||||
|
macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \
|
||||||
|
const type *item) \
|
||||||
|
{ \
|
||||||
|
return (type *)prefix ## _const_find_gteq(h, item); \
|
||||||
|
} \
|
||||||
|
/* ... */
|
||||||
|
|
||||||
|
|
||||||
/* single-linked list, unsorted/arbitrary.
|
/* single-linked list, unsorted/arbitrary.
|
||||||
* can be used as queue with add_tail / pop
|
* can be used as queue with add_tail / pop
|
||||||
*/
|
*/
|
||||||
|
@ -133,15 +168,17 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
|
||||||
h->sh.last_next = &h->sh.first; \
|
h->sh.last_next = &h->sh.first; \
|
||||||
return container_of(sitem, type, field.si); \
|
return container_of(sitem, type, field.si); \
|
||||||
} \
|
} \
|
||||||
macro_pure type *prefix ## _first(struct prefix##_head *h) \
|
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
|
||||||
{ \
|
{ \
|
||||||
return container_of_null(h->sh.first, type, field.si); \
|
return container_of_null(h->sh.first, type, field.si); \
|
||||||
} \
|
} \
|
||||||
macro_pure type *prefix ## _next(struct prefix##_head * h, type *item) \
|
macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
|
||||||
|
const type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct slist_item *sitem = &item->field.si; \
|
const struct slist_item *sitem = &item->field.si; \
|
||||||
return container_of_null(sitem->next, type, field.si); \
|
return container_of_null(sitem->next, type, field.si); \
|
||||||
} \
|
} \
|
||||||
|
TYPESAFE_FIRST_NEXT(prefix, type) \
|
||||||
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
|
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct slist_item *sitem; \
|
struct slist_item *sitem; \
|
||||||
|
@ -232,20 +269,22 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
|
||||||
h->dh.count--; \
|
h->dh.count--; \
|
||||||
return container_of(ditem, type, field.di); \
|
return container_of(ditem, type, field.di); \
|
||||||
} \
|
} \
|
||||||
macro_pure type *prefix ## _first(struct prefix##_head *h) \
|
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
|
||||||
{ \
|
{ \
|
||||||
struct dlist_item *ditem = h->dh.hitem.next; \
|
const struct dlist_item *ditem = h->dh.hitem.next; \
|
||||||
if (ditem == &h->dh.hitem) \
|
if (ditem == &h->dh.hitem) \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
return container_of(ditem, type, field.di); \
|
return container_of(ditem, type, field.di); \
|
||||||
} \
|
} \
|
||||||
macro_pure type *prefix ## _next(struct prefix##_head * h, type *item) \
|
macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
|
||||||
|
const type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct dlist_item *ditem = &item->field.di; \
|
const struct dlist_item *ditem = &item->field.di; \
|
||||||
if (ditem->next == &h->dh.hitem) \
|
if (ditem->next == &h->dh.hitem) \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
return container_of(ditem->next, type, field.di); \
|
return container_of(ditem->next, type, field.di); \
|
||||||
} \
|
} \
|
||||||
|
TYPESAFE_FIRST_NEXT(prefix, type) \
|
||||||
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
|
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
|
||||||
{ \
|
{ \
|
||||||
if (!item) \
|
if (!item) \
|
||||||
|
@ -338,19 +377,21 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
|
||||||
typesafe_heap_resize(&h->hh, false); \
|
typesafe_heap_resize(&h->hh, false); \
|
||||||
return container_of(hitem, type, field.hi); \
|
return container_of(hitem, type, field.hi); \
|
||||||
} \
|
} \
|
||||||
macro_pure type *prefix ## _first(struct prefix##_head *h) \
|
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
|
||||||
{ \
|
{ \
|
||||||
if (h->hh.count == 0) \
|
if (h->hh.count == 0) \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
return container_of(h->hh.array[0], type, field.hi); \
|
return container_of(h->hh.array[0], type, field.hi); \
|
||||||
} \
|
} \
|
||||||
macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \
|
macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
|
||||||
|
const type *item) \
|
||||||
{ \
|
{ \
|
||||||
uint32_t idx = item->field.hi.index + 1; \
|
uint32_t idx = item->field.hi.index + 1; \
|
||||||
if (idx >= h->hh.count) \
|
if (idx >= h->hh.count) \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
return container_of(h->hh.array[idx], type, field.hi); \
|
return container_of(h->hh.array[idx], type, field.hi); \
|
||||||
} \
|
} \
|
||||||
|
TYPESAFE_FIRST_NEXT(prefix, type) \
|
||||||
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
|
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
|
||||||
{ \
|
{ \
|
||||||
if (!item) \
|
if (!item) \
|
||||||
|
@ -431,26 +472,27 @@ macro_inline type *prefix ## _add(struct prefix##_head *h, type *item) \
|
||||||
h->sh.count++; \
|
h->sh.count++; \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \
|
macro_inline const type *prefix ## _const_find_gteq( \
|
||||||
const type *item) \
|
const struct prefix##_head *h, const type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct ssort_item *sitem = h->sh.first; \
|
const struct ssort_item *sitem = h->sh.first; \
|
||||||
int cmpval = 0; \
|
int cmpval = 0; \
|
||||||
while (sitem && (cmpval = cmpfn_nuq( \
|
while (sitem && (cmpval = cmpfn_nuq( \
|
||||||
container_of(sitem, type, field.si), item)) < 0) \
|
container_of(sitem, type, field.si), item)) < 0) \
|
||||||
sitem = sitem->next; \
|
sitem = sitem->next; \
|
||||||
return container_of_null(sitem, type, field.si); \
|
return container_of_null(sitem, type, field.si); \
|
||||||
} \
|
} \
|
||||||
macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
|
macro_inline const type *prefix ## _const_find_lt( \
|
||||||
const type *item) \
|
const struct prefix##_head *h, const type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct ssort_item *prev = NULL, *sitem = h->sh.first; \
|
const struct ssort_item *prev = NULL, *sitem = h->sh.first; \
|
||||||
int cmpval = 0; \
|
int cmpval = 0; \
|
||||||
while (sitem && (cmpval = cmpfn_nuq( \
|
while (sitem && (cmpval = cmpfn_nuq( \
|
||||||
container_of(sitem, type, field.si), item)) < 0) \
|
container_of(sitem, type, field.si), item)) < 0) \
|
||||||
sitem = (prev = sitem)->next; \
|
sitem = (prev = sitem)->next; \
|
||||||
return container_of_null(prev, type, field.si); \
|
return container_of_null(prev, type, field.si); \
|
||||||
} \
|
} \
|
||||||
|
TYPESAFE_FIND_CMP(prefix, type) \
|
||||||
/* TODO: del_hint */ \
|
/* TODO: del_hint */ \
|
||||||
macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
|
macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -472,15 +514,17 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
|
||||||
h->sh.first = sitem->next; \
|
h->sh.first = sitem->next; \
|
||||||
return container_of(sitem, type, field.si); \
|
return container_of(sitem, type, field.si); \
|
||||||
} \
|
} \
|
||||||
macro_pure type *prefix ## _first(struct prefix##_head *h) \
|
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
|
||||||
{ \
|
{ \
|
||||||
return container_of_null(h->sh.first, type, field.si); \
|
return container_of_null(h->sh.first, type, field.si); \
|
||||||
} \
|
} \
|
||||||
macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \
|
macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
|
||||||
|
const type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct ssort_item *sitem = &item->field.si; \
|
const struct ssort_item *sitem = &item->field.si; \
|
||||||
return container_of_null(sitem->next, type, field.si); \
|
return container_of_null(sitem->next, type, field.si); \
|
||||||
} \
|
} \
|
||||||
|
TYPESAFE_FIRST_NEXT(prefix, type) \
|
||||||
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
|
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct ssort_item *sitem; \
|
struct ssort_item *sitem; \
|
||||||
|
@ -498,9 +542,10 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
|
||||||
#define DECLARE_SORTLIST_UNIQ(prefix, type, field, cmpfn) \
|
#define DECLARE_SORTLIST_UNIQ(prefix, type, field, cmpfn) \
|
||||||
_DECLARE_SORTLIST(prefix, type, field, cmpfn, cmpfn) \
|
_DECLARE_SORTLIST(prefix, type, field, cmpfn, cmpfn) \
|
||||||
\
|
\
|
||||||
macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
|
macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \
|
||||||
|
const type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct ssort_item *sitem = h->sh.first; \
|
const struct ssort_item *sitem = h->sh.first; \
|
||||||
int cmpval = 0; \
|
int cmpval = 0; \
|
||||||
while (sitem && (cmpval = cmpfn( \
|
while (sitem && (cmpval = cmpfn( \
|
||||||
container_of(sitem, type, field.si), item)) < 0) \
|
container_of(sitem, type, field.si), item)) < 0) \
|
||||||
|
@ -509,6 +554,7 @@ macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
return container_of(sitem, type, field.si); \
|
return container_of(sitem, type, field.si); \
|
||||||
} \
|
} \
|
||||||
|
TYPESAFE_FIND(prefix, type) \
|
||||||
/* ... */
|
/* ... */
|
||||||
|
|
||||||
#define DECLARE_SORTLIST_NONUNIQ(prefix, type, field, cmpfn) \
|
#define DECLARE_SORTLIST_NONUNIQ(prefix, type, field, cmpfn) \
|
||||||
|
@ -606,12 +652,13 @@ macro_inline type *prefix ## _add(struct prefix##_head *h, type *item) \
|
||||||
*np = &item->field.hi; \
|
*np = &item->field.hi; \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
|
macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \
|
||||||
|
const type *item) \
|
||||||
{ \
|
{ \
|
||||||
if (!h->hh.tabshift) \
|
if (!h->hh.tabshift) \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
uint32_t hval = hashfn(item), hbits = HASH_KEY(h->hh, hval); \
|
uint32_t hval = hashfn(item), hbits = HASH_KEY(h->hh, hval); \
|
||||||
struct thash_item *hitem = h->hh.entries[hbits]; \
|
const struct thash_item *hitem = h->hh.entries[hbits]; \
|
||||||
while (hitem && hitem->hashval < hval) \
|
while (hitem && hitem->hashval < hval) \
|
||||||
hitem = hitem->next; \
|
hitem = hitem->next; \
|
||||||
while (hitem && hitem->hashval == hval) { \
|
while (hitem && hitem->hashval == hval) { \
|
||||||
|
@ -621,6 +668,7 @@ macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
|
||||||
} \
|
} \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
|
TYPESAFE_FIND(prefix, type) \
|
||||||
macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
|
macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
|
||||||
{ \
|
{ \
|
||||||
if (!h->hh.tabshift) \
|
if (!h->hh.tabshift) \
|
||||||
|
@ -655,7 +703,7 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
|
||||||
} \
|
} \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
macro_pure type *prefix ## _first(struct prefix##_head *h) \
|
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
|
||||||
{ \
|
{ \
|
||||||
uint32_t i; \
|
uint32_t i; \
|
||||||
for (i = 0; i < HASH_SIZE(h->hh); i++) \
|
for (i = 0; i < HASH_SIZE(h->hh); i++) \
|
||||||
|
@ -663,9 +711,10 @@ macro_pure type *prefix ## _first(struct prefix##_head *h) \
|
||||||
return container_of(h->hh.entries[i], type, field.hi); \
|
return container_of(h->hh.entries[i], type, field.hi); \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \
|
macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
|
||||||
|
const type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct thash_item *hitem = &item->field.hi; \
|
const struct thash_item *hitem = &item->field.hi; \
|
||||||
if (hitem->next) \
|
if (hitem->next) \
|
||||||
return container_of(hitem->next, type, field.hi); \
|
return container_of(hitem->next, type, field.hi); \
|
||||||
uint32_t i = HASH_KEY(h->hh, hitem->hashval) + 1; \
|
uint32_t i = HASH_KEY(h->hh, hitem->hashval) + 1; \
|
||||||
|
@ -674,6 +723,7 @@ macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \
|
||||||
return container_of(h->hh.entries[i], type, field.hi); \
|
return container_of(h->hh.entries[i], type, field.hi); \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
|
TYPESAFE_FIRST_NEXT(prefix, type) \
|
||||||
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
|
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
|
||||||
{ \
|
{ \
|
||||||
if (!item) \
|
if (!item) \
|
||||||
|
@ -742,20 +792,21 @@ macro_inline type *prefix ## _add(struct prefix##_head *h, type *item) \
|
||||||
si = typesafe_skiplist_add(&h->sh, &item->field.si, cmpfn_uq); \
|
si = typesafe_skiplist_add(&h->sh, &item->field.si, cmpfn_uq); \
|
||||||
return container_of_null(si, type, field.si); \
|
return container_of_null(si, type, field.si); \
|
||||||
} \
|
} \
|
||||||
macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \
|
macro_inline const type *prefix ## _const_find_gteq( \
|
||||||
const type *item) \
|
const struct prefix##_head *h, const type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct sskip_item *sitem = typesafe_skiplist_find_gteq(&h->sh, \
|
const struct sskip_item *sitem = typesafe_skiplist_find_gteq(&h->sh, \
|
||||||
&item->field.si, cmpfn_nuq); \
|
&item->field.si, cmpfn_nuq); \
|
||||||
return container_of_null(sitem, type, field.si); \
|
return container_of_null(sitem, type, field.si); \
|
||||||
} \
|
} \
|
||||||
macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
|
macro_inline const type *prefix ## _const_find_lt( \
|
||||||
const type *item) \
|
const struct prefix##_head *h, const type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct sskip_item *sitem = typesafe_skiplist_find_lt(&h->sh, \
|
const struct sskip_item *sitem = typesafe_skiplist_find_lt(&h->sh, \
|
||||||
&item->field.si, cmpfn_nuq); \
|
&item->field.si, cmpfn_nuq); \
|
||||||
return container_of_null(sitem, type, field.si); \
|
return container_of_null(sitem, type, field.si); \
|
||||||
} \
|
} \
|
||||||
|
TYPESAFE_FIND_CMP(prefix, type) \
|
||||||
macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
|
macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct sskip_item *sitem = typesafe_skiplist_del(&h->sh, \
|
struct sskip_item *sitem = typesafe_skiplist_del(&h->sh, \
|
||||||
|
@ -767,16 +818,18 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
|
||||||
struct sskip_item *sitem = typesafe_skiplist_pop(&h->sh); \
|
struct sskip_item *sitem = typesafe_skiplist_pop(&h->sh); \
|
||||||
return container_of_null(sitem, type, field.si); \
|
return container_of_null(sitem, type, field.si); \
|
||||||
} \
|
} \
|
||||||
macro_pure type *prefix ## _first(struct prefix##_head *h) \
|
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
|
||||||
{ \
|
{ \
|
||||||
struct sskip_item *first = h->sh.hitem.next[0]; \
|
const struct sskip_item *first = h->sh.hitem.next[0]; \
|
||||||
return container_of_null(first, type, field.si); \
|
return container_of_null(first, type, field.si); \
|
||||||
} \
|
} \
|
||||||
macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \
|
macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
|
||||||
|
const type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct sskip_item *next = item->field.si.next[0]; \
|
const struct sskip_item *next = item->field.si.next[0]; \
|
||||||
return container_of_null(next, type, field.si); \
|
return container_of_null(next, type, field.si); \
|
||||||
} \
|
} \
|
||||||
|
TYPESAFE_FIRST_NEXT(prefix, type) \
|
||||||
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
|
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct sskip_item *next; \
|
struct sskip_item *next; \
|
||||||
|
@ -799,12 +852,14 @@ macro_inline int prefix ## __cmp(const struct sskip_item *a, \
|
||||||
return cmpfn(container_of(a, type, field.si), \
|
return cmpfn(container_of(a, type, field.si), \
|
||||||
container_of(b, type, field.si)); \
|
container_of(b, type, field.si)); \
|
||||||
} \
|
} \
|
||||||
macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
|
macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \
|
||||||
|
const type *item) \
|
||||||
{ \
|
{ \
|
||||||
struct sskip_item *sitem = typesafe_skiplist_find(&h->sh, \
|
const struct sskip_item *sitem = typesafe_skiplist_find(&h->sh, \
|
||||||
&item->field.si, &prefix ## __cmp); \
|
&item->field.si, &prefix ## __cmp); \
|
||||||
return container_of_null(sitem, type, field.si); \
|
return container_of_null(sitem, type, field.si); \
|
||||||
} \
|
} \
|
||||||
|
TYPESAFE_FIND(prefix, type) \
|
||||||
\
|
\
|
||||||
_DECLARE_SKIPLIST(prefix, type, field, \
|
_DECLARE_SKIPLIST(prefix, type, field, \
|
||||||
prefix ## __cmp, prefix ## __cmp) \
|
prefix ## __cmp, prefix ## __cmp) \
|
||||||
|
@ -843,15 +898,18 @@ extern struct sskip_item *typesafe_skiplist_add(struct sskip_head *head,
|
||||||
struct sskip_item *item, int (*cmpfn)(
|
struct sskip_item *item, int (*cmpfn)(
|
||||||
const struct sskip_item *a,
|
const struct sskip_item *a,
|
||||||
const struct sskip_item *b));
|
const struct sskip_item *b));
|
||||||
extern struct sskip_item *typesafe_skiplist_find(struct sskip_head *head,
|
extern const struct sskip_item *typesafe_skiplist_find(
|
||||||
|
const struct sskip_head *head,
|
||||||
const struct sskip_item *item, int (*cmpfn)(
|
const struct sskip_item *item, int (*cmpfn)(
|
||||||
const struct sskip_item *a,
|
const struct sskip_item *a,
|
||||||
const struct sskip_item *b));
|
const struct sskip_item *b));
|
||||||
extern struct sskip_item *typesafe_skiplist_find_gteq(struct sskip_head *head,
|
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 *item, int (*cmpfn)(
|
||||||
const struct sskip_item *a,
|
const struct sskip_item *a,
|
||||||
const struct sskip_item *b));
|
const struct sskip_item *b));
|
||||||
extern struct sskip_item *typesafe_skiplist_find_lt(struct sskip_head *head,
|
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 *item, int (*cmpfn)(
|
||||||
const struct sskip_item *a,
|
const struct sskip_item *a,
|
||||||
const struct sskip_item *b));
|
const struct sskip_item *b));
|
||||||
|
|
|
@ -25,7 +25,9 @@
|
||||||
#define list_hash concat(TYPE, _hash)
|
#define list_hash concat(TYPE, _hash)
|
||||||
#define list_init concat(TYPE, _init)
|
#define list_init concat(TYPE, _init)
|
||||||
#define list_fini concat(TYPE, _fini)
|
#define list_fini concat(TYPE, _fini)
|
||||||
|
#define list_const_first concat(TYPE, _const_first)
|
||||||
#define list_first concat(TYPE, _first)
|
#define list_first concat(TYPE, _first)
|
||||||
|
#define list_const_next concat(TYPE, _const_next)
|
||||||
#define list_next concat(TYPE, _next)
|
#define list_next concat(TYPE, _next)
|
||||||
#define list_next_safe concat(TYPE, _next_safe)
|
#define list_next_safe concat(TYPE, _next_safe)
|
||||||
#define list_count concat(TYPE, _count)
|
#define list_count concat(TYPE, _count)
|
||||||
|
@ -177,18 +179,29 @@ static void concat(test_, TYPE)(void)
|
||||||
ts_hashx("fill", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838");
|
ts_hashx("fill", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838");
|
||||||
|
|
||||||
k = 0;
|
k = 0;
|
||||||
prev = NULL;
|
|
||||||
frr_each(list, &head, item) {
|
#if IS_ATOMIC(REALTYPE)
|
||||||
|
struct list_head *chead = &head;
|
||||||
|
struct item *citem, *cprev = NULL;
|
||||||
|
|
||||||
|
frr_each(list, chead, citem) {
|
||||||
|
#else
|
||||||
|
const struct list_head *chead = &head;
|
||||||
|
const struct item *citem, *cprev = NULL;
|
||||||
|
|
||||||
|
frr_each(list_const, chead, citem) {
|
||||||
|
#endif
|
||||||
|
|
||||||
#if IS_HASH(REALTYPE) || IS_HEAP(REALTYPE)
|
#if IS_HASH(REALTYPE) || IS_HEAP(REALTYPE)
|
||||||
/* hash table doesn't give sorting */
|
/* hash table doesn't give sorting */
|
||||||
(void)prev;
|
(void)cprev;
|
||||||
#else
|
#else
|
||||||
assert(!prev || prev->val < item->val);
|
assert(!cprev || cprev->val < citem->val);
|
||||||
#endif
|
#endif
|
||||||
prev = item;
|
cprev = citem;
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
assert(list_count(&head) == k);
|
assert(list_count(chead) == k);
|
||||||
ts_ref("walk");
|
ts_ref("walk");
|
||||||
|
|
||||||
#if IS_UNIQ(REALTYPE)
|
#if IS_UNIQ(REALTYPE)
|
||||||
|
|
Loading…
Reference in a new issue