aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJose Bollo <jose.bollo@iot.bzh>2019-11-19 13:43:06 +0100
committerJosé Bollo <jose.bollo@iot.bzh>2019-11-29 12:48:17 +0100
commit0fd887b7ab896e47b2f7ffe78f41738f3824a962 (patch)
treec8e1e39c1969f65387543bec49d460a4787f2624
parent5ac7bb0d9d16260d2235820e97ab47943ffc307b (diff)
u16id: Add maps for identifiers id of 16 bits
These maps will shortly be used by protocol to handle tokens/sessions/events. Bug-AGL: SPEC-2968 Change-Id: Iadef7d6e01c8ef021516749524b10ccc1abec340 Signed-off-by: Jose Bollo <jose.bollo@iot.bzh>
-rw-r--r--coverage/.gitignore1
-rw-r--r--coverage/bin/Makefile7
-rwxr-xr-xcoverage/scripts/run-test.sh2
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/tests/CMakeLists.txt1
-rw-r--r--src/tests/u16id/CMakeLists.txt23
-rw-r--r--src/tests/u16id/test-u16id.c157
-rw-r--r--src/u16id.c417
-rw-r--r--src/u16id.h51
9 files changed, 659 insertions, 1 deletions
diff --git a/coverage/.gitignore b/coverage/.gitignore
index f0d02b07..364cfc35 100644
--- a/coverage/.gitignore
+++ b/coverage/.gitignore
@@ -9,6 +9,7 @@ bin/afb-daemon-nocov
bin/test-apiset
bin/test-session
bin/test-wrap-json
+bin/test-u16id
bin/*.o
bin/*.so
bin/*.gcda
diff --git a/coverage/bin/Makefile b/coverage/bin/Makefile
index 9ebfa9d7..4075e58b 100644
--- a/coverage/bin/Makefile
+++ b/coverage/bin/Makefile
@@ -22,7 +22,8 @@ bugs = $(foreach i,\
tests = \
test-apiset \
test-session \
- test-wrap-json
+ test-wrap-json \
+ test-u16id
targets = \
afb-daemon-nocov \
@@ -140,6 +141,10 @@ test-wrap-json: $(tstdir)/session/test-session.c $(afb_lib_obj)
@echo creation of $@
@gcc -o $@ $(tstdir)/wrap-json/test-wrap-json.c $(afb_lib_obj) --coverage $(tst_defs) $(tst_flags)
+test-u16id: $(tstdir)/u16id/test-u16id.c $(afb_lib_obj)
+ @echo creation of $@
+ @gcc -o $@ $(tstdir)/u16id/test-u16id.c $(afb_lib_obj) --coverage $(tst_defs) $(tst_flags)
+
#======================================================================================
# create bindings
#======================================================================================
diff --git a/coverage/scripts/run-test.sh b/coverage/scripts/run-test.sh
index 7dfb3695..e7fc1b57 100755
--- a/coverage/scripts/run-test.sh
+++ b/coverage/scripts/run-test.sh
@@ -109,6 +109,8 @@ mk $R/bin/test-session
mk $R/bin/test-wrap-json
+mk $R/bin/test-u16id
+
echo '
##########################################################
# true life test: run parts as direct client
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0d5e7122..abfd13e8 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -124,6 +124,7 @@ SET(AFB_LIB_SOURCES
sig-monitor.c
subpath.c
systemd.c
+ u16id.c
uuid.c
verbose.c
watchdog.c
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index ead6790e..ab5c6edd 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -26,6 +26,7 @@ if(check_FOUND)
add_subdirectory(apiv3)
add_subdirectory(wrap-json)
add_subdirectory(globset)
+ add_subdirectory(u16id)
else(check_FOUND)
MESSAGE(WARNING "check not found! no test!")
endif(check_FOUND)
diff --git a/src/tests/u16id/CMakeLists.txt b/src/tests/u16id/CMakeLists.txt
new file mode 100644
index 00000000..4141611e
--- /dev/null
+++ b/src/tests/u16id/CMakeLists.txt
@@ -0,0 +1,23 @@
+###########################################################################
+# Copyright (C) 2017-2019 "IoT.bzh"
+#
+# author: José Bollo <jose.bollo@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###########################################################################
+
+add_executable(test-u16id test-u16id.c)
+target_include_directories(test-u16id PRIVATE ../..)
+target_link_libraries(test-u16id afb-lib ${link_libraries})
+add_test(NAME u16id COMMAND test-u16id)
+
diff --git a/src/tests/u16id/test-u16id.c b/src/tests/u16id/test-u16id.c
new file mode 100644
index 00000000..54257414
--- /dev/null
+++ b/src/tests/u16id/test-u16id.c
@@ -0,0 +1,157 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <check.h>
+
+#include "u16id.h"
+
+/*********************************************************************/
+
+#define S 29
+
+void cbi2p(void*closure, uint16_t id, void *ptr)
+{
+ int *y = closure;
+ int ni = y[0];
+ ck_assert((ni >> id) & 1);
+ ck_assert((uintptr_t)ptr == (uintptr_t)(ni + id));
+ y[1]++;
+}
+
+void test_i2ptr(struct u16id2ptr **pi2p)
+{
+ int i, ni, n, x, y[2];
+ uint16_t j;
+ void *p;
+
+ i = 0;
+ while (!(i >> S)) {
+ ni = i * 3 + 1;
+ n = 0;
+ for (j = 0 ; j < S ; j++) {
+ if ((i >> j) & 1) {
+ ck_assert_int_eq(1, u16id2ptr_has(*pi2p, j));
+ ck_assert_int_eq(0, u16id2ptr_get(*pi2p, j, &p));
+ ck_assert((uintptr_t)p == (uintptr_t)(i + j));
+ ck_assert_int_eq(-1, u16id2ptr_add(pi2p, j, p));
+ ck_assert_int_eq(0, u16id2ptr_put(*pi2p, j, p));
+ } else {
+ ck_assert_int_eq(0, u16id2ptr_has(*pi2p, j));
+ ck_assert_int_eq(-1, u16id2ptr_get(*pi2p, j, &p));
+ ck_assert_int_eq(-1, u16id2ptr_put(*pi2p, j, p));
+ }
+ if ((ni >> j) & 1) {
+ p = (void*)(uintptr_t)(ni + j);
+ ck_assert_int_eq(0, u16id2ptr_set(pi2p, j, p));
+ n++;
+ } else if ((i >> j) & 1) {
+ ck_assert_int_eq(0, u16id2ptr_drop(pi2p, j, &p));
+ ck_assert((uintptr_t)p == (uintptr_t)(i + j));
+ } else {
+ ck_assert_int_eq(-1, u16id2ptr_drop(pi2p, j, NULL));
+ }
+ }
+ ck_assert_int_eq(n, u16id2ptr_count(*pi2p));
+ for (x = 0 ; x < n ; x++) {
+ ck_assert_int_eq(0, u16id2ptr_at(*pi2p, x, &j, &p));
+ ck_assert((ni >> j) & 1);
+ ck_assert((uintptr_t)p == (uintptr_t)(ni + j));
+ }
+ y[0] = ni;
+ y[1] = 0;
+ u16id2ptr_forall(*pi2p, cbi2p, y);
+ ck_assert_int_eq(n, y[1]);
+ i = ni;
+ }
+}
+
+START_TEST (check_u16id2ptr)
+{
+ struct u16id2ptr *i2p;
+
+ i2p = NULL;
+ test_i2ptr(&i2p);
+ ck_assert(i2p);
+ u16id2ptr_destroy(&i2p);
+ ck_assert(!i2p);
+ ck_assert_int_eq(0, u16id2ptr_create(&i2p));
+ test_i2ptr(&i2p);
+ ck_assert(i2p);
+ u16id2ptr_destroy(&i2p);
+ ck_assert(!i2p);
+}
+END_TEST
+
+/*********************************************************************/
+
+void test_i2bool(struct u16id2bool **pi2b)
+{
+ int i, j, ni, v;
+ uint16_t x;
+
+ i = 0;
+ while (!(i >> S)) {
+ ni = i * 3 + 1;
+ for (j = 0 ; j < S ; j++) {
+ x = (uint16_t)(j * 5);
+ v = (i >> j) & 1;
+ ck_assert_int_eq(v, u16id2bool_get(*pi2b, x));
+ ck_assert_int_eq(v, u16id2bool_set(pi2b, x, (ni >> j) & 1));
+ }
+ i = ni;
+ }
+ for (j = 0 ; j < S ; j++) {
+ x = (uint16_t)(j * 5);
+ v = (i >> j) & 1;
+ ck_assert_int_eq(v, u16id2bool_get(*pi2b, x));
+ ck_assert_int_eq(v, u16id2bool_set(pi2b, x, 0));
+ }
+}
+
+START_TEST (check_u16id2bool)
+{
+ struct u16id2bool *i2b;
+
+ i2b = NULL;
+ test_i2bool(&i2b);
+ ck_assert(i2b);
+ u16id2bool_destroy(&i2b);
+ ck_assert(!i2b);
+ ck_assert_int_eq(0, u16id2bool_create(&i2b));
+ test_i2bool(&i2b);
+ ck_assert(i2b);
+ u16id2bool_destroy(&i2b);
+ ck_assert(!i2b);
+}
+END_TEST
+
+/*********************************************************************/
+
+static Suite *suite;
+static TCase *tcase;
+
+void mksuite(const char *name) { suite = suite_create(name); }
+void addtcase(const char *name) { tcase = tcase_create(name); suite_add_tcase(suite, tcase); tcase_set_timeout(tcase, 120); }
+void addtest(TFun fun) { tcase_add_test(tcase, fun); }
+int srun()
+{
+ int nerr;
+ SRunner *srunner = srunner_create(suite);
+ srunner_run_all(srunner, CK_NORMAL);
+ nerr = srunner_ntests_failed(srunner);
+ srunner_free(srunner);
+ return nerr;
+}
+
+int main(int ac, char **av)
+{
+ mksuite("u16id");
+ addtcase("u16id");
+ addtest(check_u16id2ptr);
+ addtest(check_u16id2bool);
+ return !!srun();
+}
diff --git a/src/u16id.c b/src/u16id.c
new file mode 100644
index 00000000..e7532b92
--- /dev/null
+++ b/src/u16id.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2015-2019 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <malloc.h>
+#include <errno.h>
+
+#include "u16id.h"
+
+/* compute P, the count of bits of pointers */
+#if UINTPTR_MAX == (18446744073709551615UL)
+# define P 64
+#elif UINTPTR_MAX == (4294967295U)
+# define P 32
+#elif UINTPTR_MAX == (65535U)
+# define P 16
+#else
+# error "Unsupported pointer size"
+#endif
+
+/* granule of allocation */
+#define N 4
+
+/*
+ * The u16id maps are made of a single block of memory structured
+ * as an array of uint16_t followed by an array of void*. To ensure
+ * that void* pointers are correctly aligned, the array of uint16_t
+ * at head is a multiple of N items, with N being a multiple of 2
+ * if void* is 32 bits or 4 if void* is 64 bits.
+ *
+ * The first item of the array of uint16_t is used to record the
+ * upper index of valid uint16_t ids.
+ *
+ * +-----+-----+-----+-----+ - - - - - - - - +-----+-----+-----+-----+ - - - - - - - -
+ * |upper| id1 | id2 | id3 | | ptr1 |
+ * +-----+-----+-----+-----+ - - - - - - - - +-----+-----+-----+-----+ - - - - - - - -
+ */
+
+static inline uint16_t get_capacity(uint16_t upper)
+{
+ /* capacity is the smallest kN-1 such that kN-1 >= upper) */
+#if N == 2 || N == 4 || N == 8 || N == 16
+ return upper | (N - 1);
+#else
+# error "not supported"
+#endif
+}
+
+typedef struct {
+ uint16_t upper;
+ uint16_t capacity;
+ uint16_t *ids;
+ void **ptrs;
+} flat_t;
+
+static void flatofup(flat_t *flat, void *base, uint16_t up)
+{
+ uint16_t cap, *ids;
+
+ flat->upper = up;
+ flat->capacity = cap = get_capacity(up);
+ flat->ids = ids = base;
+ flat->ptrs = ((void**)(&ids[cap + 1])) - 1;
+}
+
+static void flatof(flat_t *flat, void *base)
+{
+ if (base)
+ flatofup(flat, base, *(uint16_t*)base);
+ else {
+ flat->upper = flat->capacity = 0;
+ flat->ids = NULL;
+ flat->ptrs = NULL;
+ }
+}
+
+static inline size_t size(uint16_t capacity)
+{
+ return sizeof(uint16_t) * (capacity + 1)
+ + sizeof(void*) * capacity;
+}
+
+static inline uint16_t search(flat_t *flat, uint16_t id)
+{
+ uint16_t *ids = flat->ids;
+ uint16_t r = flat->upper;
+ while(r && ids[r] != id)
+ r--;
+ return r;
+}
+
+static void *add(flat_t *flat, uint16_t id, void *ptr)
+{
+ void *grown, *result;
+ flat_t oflat;
+ uint16_t nupper, oupper;
+
+ oupper = flat->upper;
+ nupper = (uint16_t)(oupper + 1);
+ result = flat->ids;
+ if (nupper > flat->capacity) {
+ grown = realloc(result, size(get_capacity(nupper)));
+ if (grown == NULL)
+ return NULL;
+ result = grown;
+ flatofup(flat, grown, nupper);
+ if (oupper) {
+ flatofup(&oflat, grown, oupper);
+ while (oupper) {
+ flat->ptrs[oupper] = oflat.ptrs[oupper];
+ oupper--;
+ }
+ }
+ }
+ /* flat->upper = nupper; NOT DONE BECAUSE NOT NEEDED */
+ flat->ids[0] = nupper;
+ flat->ids[nupper] = id;
+ flat->ptrs[nupper] = ptr;
+ return result;
+}
+
+static void *drop(flat_t *flat, uint16_t index)
+{
+ void **ptrs, *result;
+ uint16_t upper, idx, capa;
+
+ upper = flat->upper;
+ if (index != upper) {
+ flat->ids[index] = flat->ids[upper];
+ flat->ptrs[index] = flat->ptrs[upper];
+ }
+ flat->ids[0] = --upper;
+ capa = get_capacity(upper);
+ result = flat->ids;
+ if (capa != flat->capacity) {
+ ptrs = flat->ptrs;
+ flatofup(flat, result, upper);
+ idx = 1;
+ while(idx <= upper) {
+ flat->ptrs[idx] = ptrs[idx];
+ idx++;
+ }
+#if U16ID_ALWAYS_SHRINK
+ result = realloc(flat->ids, size(capa));
+ if (result == NULL)
+ result = flat->ids;
+#endif
+ }
+ return result;
+}
+
+static void dropall(void **pbase)
+{
+ void *base;
+
+ base = *pbase;
+ if (base)
+ *(uint16_t*)base = 0;
+}
+
+static void destroy(void **pbase)
+{
+ void *base;
+
+ base = *pbase;
+ *pbase = NULL;
+ free(base);
+}
+
+static int create(void **pbase)
+{
+ void *base;
+
+ *pbase = base = malloc(size(get_capacity(0)));
+ if (base == NULL)
+ return -1;
+ *(uint16_t*)base = 0;
+ return 0;
+}
+
+/**********************************************************************/
+/** u16id2ptr **/
+/**********************************************************************/
+
+int u16id2ptr_create(struct u16id2ptr **pi2p)
+{
+ return create((void**)pi2p);
+}
+
+void u16id2ptr_destroy(struct u16id2ptr **pi2p)
+{
+ destroy((void**)pi2p);
+}
+
+void u16id2ptr_dropall(struct u16id2ptr **pi2p)
+{
+ dropall((void**)pi2p);
+}
+
+int u16id2ptr_has(struct u16id2ptr *i2p, uint16_t id)
+{
+ flat_t flat;
+
+ flatof(&flat, i2p);
+ return search(&flat, id) != 0;
+}
+
+int u16id2ptr_add(struct u16id2ptr **pi2p, uint16_t id, void *ptr)
+{
+ struct u16id2ptr *i2p;
+ uint16_t index;
+ flat_t flat;
+
+ i2p = *pi2p;
+ flatof(&flat, i2p);
+ index = search(&flat, id);
+ if (index) {
+ errno = EEXIST;
+ return -1;
+ }
+ i2p = add(&flat, id, ptr);
+ if (!i2p)
+ return -1;
+ *pi2p = i2p;
+ return 0;
+}
+
+int u16id2ptr_set(struct u16id2ptr **pi2p, uint16_t id, void *ptr)
+{
+ struct u16id2ptr *i2p;
+ uint16_t index;
+ flat_t flat;
+
+ i2p = *pi2p;
+ flatof(&flat, i2p);
+ index = search(&flat, id);
+ if (index)
+ flat.ptrs[index] = ptr;
+ else {
+ i2p = add(&flat, id, ptr);
+ if (!i2p)
+ return -1;
+ *pi2p = i2p;
+ }
+ return 0;
+}
+
+int u16id2ptr_put(struct u16id2ptr *i2p, uint16_t id, void *ptr)
+{
+ uint16_t index;
+ flat_t flat;
+
+ flatof(&flat, i2p);
+ index = search(&flat, id);
+ if (index) {
+ flat.ptrs[index] = ptr;
+ return 0;
+ }
+ errno = ENOENT;
+ return -1;
+}
+
+int u16id2ptr_get(struct u16id2ptr *i2p, uint16_t id, void **pptr)
+{
+ uint16_t index;
+ flat_t flat;
+
+ flatof(&flat, i2p);
+ index = search(&flat, id);
+ if (index) {
+ *pptr = flat.ptrs[index];
+ return 0;
+ }
+ errno = ENOENT;
+ return -1;
+}
+
+int u16id2ptr_drop(struct u16id2ptr **pi2p, uint16_t id, void **pptr)
+{
+ struct u16id2ptr *i2p;
+ uint16_t index;
+ flat_t flat;
+
+ i2p = *pi2p;
+ flatof(&flat, i2p);
+ index = search(&flat, id);
+ if (!index) {
+ errno = ENOENT;
+ return -1;
+ }
+ if (pptr)
+ *pptr = flat.ptrs[index];
+ i2p = drop(&flat, index);
+ if (!i2p)
+ return -1;
+ *pi2p = i2p;
+ return 0;
+}
+
+int u16id2ptr_count(struct u16id2ptr *i2p)
+{
+ return i2p ? ((int)*(uint16_t*)i2p) : 0;
+}
+
+int u16id2ptr_at(struct u16id2ptr *i2p, int index, uint16_t *pid, void **pptr)
+{
+ flat_t flat;
+
+ flatof(&flat, i2p);
+ if (index >= 0 && index < (int)flat.upper) {
+ *pid = flat.ids[index + 1];
+ *pptr = flat.ptrs[index + 1];
+ return 0;
+ }
+ errno = EINVAL;
+ return -1;
+}
+
+void u16id2ptr_forall(struct u16id2ptr *i2p, void (*callback)(void*closure, uint16_t id, void *ptr), void *closure)
+{
+ flat_t flat;
+
+ flatof(&flat, i2p);
+ while (flat.upper) {
+ callback(closure, flat.ids[flat.upper], flat.ptrs[flat.upper]);
+ flat.upper--;
+ }
+}
+
+/**********************************************************************/
+/** u16id2bool **/
+/**********************************************************************/
+
+int u16id2bool_create(struct u16id2bool **pi2b)
+{
+ return create((void**)pi2b);
+}
+
+void u16id2bool_destroy(struct u16id2bool **pi2b)
+{
+ destroy((void**)pi2b);
+}
+
+void u16id2bool_clearall(struct u16id2bool **pi2b)
+{
+ dropall((void**)pi2b);
+}
+
+int u16id2bool_get(struct u16id2bool *i2b, uint16_t id)
+{
+ uintptr_t mask, field;
+ uint16_t index, idm;
+ flat_t flat;
+
+ flatof(&flat, i2b);
+ idm = (uint16_t)(id & ~(P - 1));
+ index = search(&flat, idm);
+ if (!index)
+ return 0;
+
+ field = (uintptr_t)flat.ptrs[index];
+ mask = (uintptr_t)((uintptr_t)1 << (id & (P - 1)));
+ return (field & mask) != 0;
+}
+
+int u16id2bool_set(struct u16id2bool **pi2b, uint16_t id, int value)
+{
+ struct u16id2bool *i2b;
+ uintptr_t mask, field, ofield;
+ uint16_t index, idm;
+ flat_t flat;
+
+ i2b = *pi2b;
+ flatof(&flat, i2b);
+ idm = (uint16_t)(id & ~(P - 1));
+ index = search(&flat, idm);
+ ofield = index ? (uintptr_t)flat.ptrs[index] : 0;
+ mask = (uintptr_t)((uintptr_t)1 << (id & (P - 1)));
+ if (value)
+ field = ofield | mask;
+ else
+ field = ofield & ~mask;
+ if (field != ofield) {
+ if (field) {
+ if (index)
+ flat.ptrs[index] = (void*)field;
+ else {
+ i2b = add(&flat, idm, (void*)field);
+ if (!i2b)
+ return -1;
+ *pi2b = i2b;
+ }
+ } else {
+ if (index) {
+ i2b = drop(&flat, index);
+ if (!i2b)
+ return -1;
+ *pi2b = i2b;
+ }
+ }
+ }
+ return (ofield & mask) != 0;
+}
diff --git a/src/u16id.h b/src/u16id.h
new file mode 100644
index 00000000..3e70982a
--- /dev/null
+++ b/src/u16id.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015-2019 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+struct u16id2ptr;
+struct u16id2bool;
+
+/**********************************************************************/
+/** u16id2ptr **/
+/**********************************************************************/
+
+extern int u16id2ptr_create(struct u16id2ptr **pi2p);
+extern void u16id2ptr_destroy(struct u16id2ptr **pi2p);
+extern void u16id2ptr_dropall(struct u16id2ptr **pi2p);
+extern int u16id2ptr_has(struct u16id2ptr *i2p, uint16_t id);
+extern int u16id2ptr_add(struct u16id2ptr **pi2p, uint16_t id, void *ptr);
+extern int u16id2ptr_set(struct u16id2ptr **pi2p, uint16_t id, void *ptr);
+extern int u16id2ptr_put(struct u16id2ptr *i2p, uint16_t id, void *ptr);
+extern int u16id2ptr_get(struct u16id2ptr *i2p, uint16_t id, void **ptr);
+extern int u16id2ptr_drop(struct u16id2ptr **pi2p, uint16_t id, void **ptr);
+extern int u16id2ptr_count(struct u16id2ptr *i2p);
+extern int u16id2ptr_at(struct u16id2ptr *i2p, int index, uint16_t *pid, void **pptr);
+extern void u16id2ptr_forall(
+ struct u16id2ptr *i2p,
+ void (*callback)(void*closure, uint16_t id, void *ptr),
+ void *closure);
+
+/**********************************************************************/
+/** u16id2bool **/
+/**********************************************************************/
+
+extern int u16id2bool_create(struct u16id2bool **pi2b);
+extern void u16id2bool_destroy(struct u16id2bool **pi2b);
+extern void u16id2bool_clearall(struct u16id2bool **pi2b);
+extern int u16id2bool_get(struct u16id2bool *i2b, uint16_t id);
+extern int u16id2bool_set(struct u16id2bool **pi2b, uint16_t id, int value);