return parent;
}
+
+bool typed_rb_member(const struct typed_rb_root *rbt,
+ const struct typed_rb_entry *rbe)
+{
+ while (rbe->rbt_parent)
+ rbe = rbe->rbt_parent;
+ return rbe == rbt->rbt_root;
+}
const struct typed_rb_entry *b));
struct typed_rb_entry *typed_rb_min(const struct typed_rb_root *rbt);
struct typed_rb_entry *typed_rb_next(const struct typed_rb_entry *rbe);
+bool typed_rb_member(const struct typed_rb_root *rbt,
+ const struct typed_rb_entry *rbe);
#define _PREDECL_RBTREE(prefix) \
struct prefix ## _head { struct typed_rb_root rr; }; \
{ \
return h->rr.count; \
} \
+macro_pure bool prefix ## _member(const struct prefix##_head *h, \
+ const type *item) \
+{ \
+ return typed_rb_member(&h->rr, &item->field.re); \
+} \
MACRO_REQUIRE_SEMICOLON() /* end */
#define PREDECL_RBTREE_UNIQ(prefix) \
DEFINE_MTYPE_STATIC(LIB, SKIPLIST_OFLOW, "Skiplist overflow");
DEFINE_MTYPE_STATIC(LIB, HEAP_ARRAY, "Typed-heap array");
+bool typesafe_list_member(const struct slist_head *head,
+ const struct slist_item *item)
+{
+ struct slist_item *fromhead = head->first;
+ struct slist_item **fromnext = (struct slist_item **)&item->next;
+
+ while (fromhead) {
+ if (fromhead == item || fromnext == head->last_next)
+ return true;
+
+ fromhead = fromhead->next;
+ if (!*fromnext)
+ break;
+ fromnext = &(*fromnext)->next;
+ }
+
+ return false;
+}
+
+bool typesafe_dlist_member(const struct dlist_head *head,
+ const struct dlist_item *item)
+{
+ const struct dlist_item *fromhead = head->hitem.next;
+ const struct dlist_item *fromitem = item->next;
+
+ if (!item->prev || !item->next)
+ return false;
+
+ while (fromhead != &head->hitem && fromitem != item) {
+ if (fromitem == &head->hitem || fromhead == item)
+ return true;
+ fromhead = fromhead->next;
+ fromitem = fromitem->next;
+ }
+
+ return false;
+}
+
#if 0
static void hash_consistency_check(struct thash_head *head)
{
} \
/* ... */
+/* *_member via find - when there is no better membership check than find() */
+#define TYPESAFE_MEMBER_VIA_FIND(prefix, type) \
+macro_inline bool prefix ## _member(struct prefix##_head *h, \
+ const type *item) \
+{ \
+ return item == prefix ## _const_find(h, item); \
+} \
+/* ... */
+
+/* *_member via find_gteq - same for non-unique containers */
+#define TYPESAFE_MEMBER_VIA_FIND_GTEQ(prefix, type, cmpfn) \
+macro_inline bool prefix ## _member(struct prefix##_head *h, \
+ const type *item) \
+{ \
+ const type *iter; \
+ for (iter = prefix ## _const_find_gteq(h, item); iter; \
+ iter = prefix ## _const_next(h, iter)) { \
+ if (iter == item) \
+ return true; \
+ if (cmpfn(iter, item) > 0) \
+ break; \
+ } \
+ return false; \
+} \
+/* ... */
+
/* SWAP_ALL_SIMPLE = for containers where the items don't point back to the
- * head *AND* the head doesn'T points to itself (= everything except LIST,
+ * head *AND* the head doesn't point to itself (= everything except LIST,
* DLIST and SKIPLIST), just switch out the entire head
*/
#define TYPESAFE_SWAP_ALL_SIMPLE(prefix) \
head->count++;
}
+extern bool typesafe_list_member(const struct slist_head *head,
+ const struct slist_item *item);
+
/* use as:
*
* PREDECL_LIST(namelist);
{ \
return h->sh.count; \
} \
+macro_pure bool prefix ## _member(const struct prefix##_head *h, \
+ const type *item) \
+{ \
+ return typesafe_list_member(&h->sh, &item->field.si); \
+} \
MACRO_REQUIRE_SEMICOLON() /* end */
/* don't use these structs directly */
}
}
+extern bool typesafe_dlist_member(const struct dlist_head *head,
+ const struct dlist_item *item);
+
/* double-linked list, for fast item deletion
*/
#define PREDECL_DLIST(prefix) \
{ \
return h->dh.count; \
} \
+macro_pure bool prefix ## _member(const struct prefix##_head *h, \
+ const type *item) \
+{ \
+ return typesafe_dlist_member(&h->dh, &item->field.di); \
+} \
MACRO_REQUIRE_SEMICOLON() /* end */
/* note: heap currently caps out at 4G items */
{ \
return h->hh.count; \
} \
+macro_pure bool prefix ## _member(const struct prefix##_head *h, \
+ const type *item) \
+{ \
+ uint32_t idx = item->field.hi.index; \
+ if (idx >= h->hh.count) \
+ return false; \
+ return h->hh.array[idx] == &item->field.hi; \
+} \
MACRO_REQUIRE_SEMICOLON() /* end */
extern void typesafe_heap_resize(struct heap_head *head, bool grow);
return container_of(sitem, type, field.si); \
} \
TYPESAFE_FIND(prefix, type) \
+TYPESAFE_MEMBER_VIA_FIND(prefix, type) \
MACRO_REQUIRE_SEMICOLON() /* end */
#define DECLARE_SORTLIST_NONUNIQ(prefix, type, field, cmpfn) \
return 0; \
} \
_DECLARE_SORTLIST(prefix, type, field, cmpfn, _ ## prefix ## _cmp); \
+TYPESAFE_MEMBER_VIA_FIND_GTEQ(prefix, type, cmpfn) \
MACRO_REQUIRE_SEMICOLON() /* end */
{ \
return h->hh.count; \
} \
+macro_pure bool prefix ## _member(const struct prefix##_head *h, \
+ const type *item) \
+{ \
+ uint32_t hval = item->field.hi.hashval, hbits = HASH_KEY(h->hh, hval); \
+ const struct thash_item *hitem = h->hh.entries[hbits]; \
+ while (hitem && hitem->hashval < hval) \
+ hitem = hitem->next; \
+ for (hitem = h->hh.entries[hbits]; hitem && hitem->hashval <= hval; \
+ hitem = hitem->next) \
+ if (hitem == &item->field.hi) \
+ return true; \
+ return false; \
+} \
MACRO_REQUIRE_SEMICOLON() /* end */
/* skiplist, sorted.
return container_of_null(sitem, type, field.si); \
} \
TYPESAFE_FIND(prefix, type) \
+TYPESAFE_MEMBER_VIA_FIND(prefix, type) \
\
_DECLARE_SKIPLIST(prefix, type, field, \
prefix ## __cmp, prefix ## __cmp); \
\
_DECLARE_SKIPLIST(prefix, type, field, \
prefix ## __cmp, prefix ## __cmp_uq); \
+TYPESAFE_MEMBER_VIA_FIND_GTEQ(prefix, type, cmpfn) \
MACRO_REQUIRE_SEMICOLON() /* end */
#define list_find concat(TYPE, _find)
#define list_find_lt concat(TYPE, _find_lt)
#define list_find_gteq concat(TYPE, _find_gteq)
+#define list_member concat(TYPE, _member)
#define list_del concat(TYPE, _del)
#define list_pop concat(TYPE, _pop)
#define list_swap_all concat(TYPE, _swap_all)
#elif IS_HEAP(REALTYPE)
/* heap - partially sorted. */
prev = NULL;
- l = k / 2;
+ l = k / 4;
for (i = 0; i < l; i++) {
item = list_pop(&head);
if (prev)
k--;
prev = item;
}
- ts_hash("pop", NULL);
+ ts_hash("pop#1", NULL);
+
+ for (i = 0; i < NITEM; i++)
+ assertf(list_member(&head, &itm[i]) == itm[i].scratchpad,
+ "%zu should:%d is:%d", i, itm[i].scratchpad,
+ list_member(&head, &itm[i]));
+ ts_hash("member", NULL);
+
+ l = k / 2;
+ for (; i < l; i++) {
+ item = list_pop(&head);
+ if (prev)
+ assert(prev->val < item->val);
+ item->scratchpad = 0;
+ k--;
+ prev = item;
+ }
+ ts_hash("pop#2", NULL);
#else /* !IS_UNIQ(REALTYPE) && !IS_HEAP(REALTYPE) */
for (i = 0; i < NITEM; i++) {
assert(l + list_count(&head) == k);
ts_hashx("del", "cb2e5d80f08a803ef7b56c15e981b681adcea214bebc2f55e12e0bfb242b07ca");
+#if !IS_ATOMIC(REALTYPE)
+ for (i = 0; i < NITEM; i++)
+ assertf(list_member(&head, &itm[i]) == itm[i].scratchpad,
+ "%zu should:%d is:%d", i, itm[i].scratchpad,
+ list_member(&head, &itm[i]));
+ ts_hashx("member", "cb2e5d80f08a803ef7b56c15e981b681adcea214bebc2f55e12e0bfb242b07ca");
+#endif
+
frr_each_safe(list, &head, item) {
assert(item->scratchpad != 0);
}
ts_hash("del-prng", "86d568a95eb429dab3162976c5a5f3f75aabc835932cd682aa280b6923549564");
+#if !IS_ATOMIC(REALTYPE)
+ for (i = 0; i < NITEM; i++)
+ assertf(list_member(&head, &itm[i]) == itm[i].scratchpad,
+ "%zu should:%d is:%d", i, itm[i].scratchpad,
+ list_member(&head, &itm[i]));
+ ts_hash("member", "86d568a95eb429dab3162976c5a5f3f75aabc835932cd682aa280b6923549564");
+#endif
+
l = 0;
+ while (l < (k / 4) && (prev = list_pop(&head))) {
+ assert(prev->scratchpad != 0);
+
+ prev->scratchpad = 0;
+ l++;
+ }
+ ts_hash("pop#1", "42b8950c880535b2d2e0c980f9845f7841ecf675c0fb9801aec4170d2036349d");
+
+#if !IS_ATOMIC(REALTYPE)
+ for (i = 0; i < NITEM; i++)
+ assertf(list_member(&head, &itm[i]) == itm[i].scratchpad,
+ "%zu should:%d is:%d", i, itm[i].scratchpad,
+ list_member(&head, &itm[i]));
+ ts_hash("member", "42b8950c880535b2d2e0c980f9845f7841ecf675c0fb9801aec4170d2036349d");
+#endif
+
while ((item = list_pop(&head))) {
assert(item->scratchpad != 0);
assert(l == k);
assert(list_count(&head) == 0);
assert(list_first(&head) == NULL);
- ts_hash("pop", "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119");
+ ts_hash("pop#2", "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119");
prng_free(prng);
prng = prng_new(0x1e5a2d69);
#undef list_find
#undef list_find_lt
#undef list_find_gteq
+#undef list_member
#undef list_del
#undef list_pop
#undef list_swap_all