diff --git a/src/flake.lock b/src/flake.lock index 05436399..a6005710 100644 --- a/src/flake.lock +++ b/src/flake.lock @@ -117,11 +117,11 @@ "xbuild": "xbuild" }, "locked": { - "lastModified": 1770000148, - "narHash": "sha256-sZP7UjAQ3nRbYNtDOpoNLcVoBq4fC1bhsmmHtpUTZig=", + "lastModified": 1770950940, + "narHash": "sha256-pVnwAEaB6s2vIwkktL1xOP0pyV4VcPyfQYoIXKmv6Yk=", "ref": "master", - "rev": "00080a95f3fb9912fc7a57b0b89ee205ec3e9b16", - "revCount": 4, + "rev": "6f6bb5b4e0b706de2358de462a1fc4889f40c7a1", + "revCount": 8, "type": "git", "url": "ssh://forgejo@gitea.shenrs.eu/rshen/librtti" }, diff --git a/src/include/bitset.h b/src/include/bitset.h new file mode 100644 index 00000000..66cd3362 --- /dev/null +++ b/src/include/bitset.h @@ -0,0 +1,17 @@ +#if !defined(_BITSET_H_) + +#define _BITSET_H_ 1 + +#include "config.h" + +#include + +/* iter over clear bits */ +#define BITSET_ITER_OVER_0 (0) + +/* iter over set bits */ +#define BITSET_ITER_OVER_1 (1) + +extern typeinfo_t bitset_type; + +#endif diff --git a/src/include/utils.h b/src/include/utils.h index 9c4cc27e..39bb2c5b 100644 --- a/src/include/utils.h +++ b/src/include/utils.h @@ -134,5 +134,6 @@ extern void block_sig(int); extern uint32_t hash4(uint32_t, uint32_t, uint32_t, uint32_t); extern uint32_t hash64(uint64_t); extern uint32_t hash_string(const char*); +extern uint32_t hash_block(char*, size_t); #endif diff --git a/src/lib/bitset.c b/src/lib/bitset.c new file mode 100644 index 00000000..339abc7e --- /dev/null +++ b/src/lib/bitset.c @@ -0,0 +1,350 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "bitset.h" +#include "utils.h" + +#if defined(__GNUC__) +#define FFSL(x) __builtin_ffsl(x) +#else +#define FFSL(x) ffsl(x) +#endif + +typedef unsigned long bitset_page_data_t; + +#define BITSET_PAGE_SIZE (4096) + +#define BITSET_ITEM_BITS (sizeof(bitset_page_data_t) * 8) + +#define BITSET_PAGE_ITEMS (BITSET_PAGE_SIZE / sizeof(bitset_page_data_t)) + +#define BITSET_PAGE_BITS (BITSET_PAGE_SIZE * 8) + +typedef struct { + bitset_page_data_t data[BITSET_PAGE_ITEMS]; +} bitset_page_t; + +#define BIT_PAGE(idx) ((idx) / BITSET_PAGE_BITS) +#define BIT_OFFSET(idx) (((idx) % BITSET_PAGE_BITS) / BITSET_ITEM_BITS) +#define BIT_BIT(idx) ((idx) % BITSET_ITEM_BITS) + +#define BIT_IDX(pg, offset, bit) \ + ((pg) * BITSET_PAGE_BITS + (offset) * BITSET_ITEM_BITS + (bit)) + +typedef struct { + int npages; + bitset_page_t** pages; +} bitset_t; + +static size_t bitset_datasize(va_list ap) +{ + size_t size = sizeof(bitset_t); + + return size; +} + +static int bitset_init(meta_obj_t* obj, va_list ap) +{ + int max_pages = va_arg(ap, int); + bitset_t* bitset = RTTI_OBJ_TO_DATA(bitset_t, obj); + + if (max_pages <= 0) { + return -EINVAL; + } + + bitset->pages = (bitset_page_t**)calloc(max_pages, sizeof(bitset_page_t*)); + if (bitset->pages == NULL) { + return -ENOMEM; + } + + bitset->npages = max_pages; + + return 1; +} + +static void bitset_destroy(meta_obj_t* obj) +{ + bitset_t* bitset = RTTI_OBJ_TO_DATA(bitset_t, obj); + int i; + + if (bitset->pages == NULL) { + return; + } + + for (i = 0; i < bitset->npages; i++) { + FREEUP(bitset->pages[i]); + } + + FREEUP(bitset->pages); +} + +static int bitset_test(meta_obj_t* obj, unsigned long idx) +{ + bitset_t* bitset = RTTI_OBJ_TO_DATA(bitset_t, obj); + int pg = BIT_PAGE(idx); + int offset = BIT_OFFSET(idx); + int bit = BIT_BIT(idx); + bitset_page_t* page = NULL; + + if (pg >= bitset->npages) { + return -EINVAL; + } + + page = bitset->pages[pg]; + if (page == NULL) { + return 0; + } + + if (page->data[offset] == 0) { + return 0; + } + + return ((page->data[offset] & (((bitset_page_data_t)0x01) << bit)) != 0); +} + +static int bitset_set(meta_obj_t* obj, unsigned long idx) +{ + bitset_t* bitset = RTTI_OBJ_TO_DATA(bitset_t, obj); + int pg = BIT_PAGE(idx); + int offset = BIT_OFFSET(idx); + int bit = BIT_BIT(idx); + bitset_page_t* page = NULL; + + if (pg >= bitset->npages) { + return -EINVAL; + } + + page = bitset->pages[pg]; + if (page == NULL) { + page = (bitset_page_t*)calloc(1, sizeof(*page)); + if (page == NULL) { + return -ENOMEM; + } + + bitset->pages[pg] = page; + } + + page->data[offset] + = page->data[offset] | (((bitset_page_data_t)0x01) << bit); + + return 1; +} + +static int bitset_clr(meta_obj_t* obj, unsigned long idx) +{ + bitset_t* bitset = RTTI_OBJ_TO_DATA(bitset_t, obj); + int pg = BIT_PAGE(idx); + int offset = BIT_OFFSET(idx); + int bit = BIT_BIT(idx); + bitset_page_t* page = NULL; + + if (pg >= bitset->npages) { + return -EINVAL; + } + + page = bitset->pages[pg]; + if (page == NULL) { + return 0; + } + + page->data[offset] + = page->data[offset] & ~(((bitset_page_data_t)0x01) << bit); + + return 1; +} + +static int bitset_clrall(meta_obj_t* obj) +{ + bitset_t* bitset = RTTI_OBJ_TO_DATA(bitset_t, obj); + int pg = 0; + + for (pg = 0; pg < bitset->npages; pg++) { + bitset_page_t* page = bitset->pages[pg]; + + if (page == NULL) { + continue; + } + + memset(page, 0x0, sizeof(*page)); + } + return 0; +} + +typedef struct { + int overbit; + int pg; + int offset; + int bit; +} iterator_data_t; + +static int bitset_iter_make(iterator_t* iter, va_list ap) +{ + int overbit = va_arg(ap, int); + iterator_data_t* p = NULL; + + if ((overbit != BITSET_ITER_OVER_0) && (overbit != BITSET_ITER_OVER_1)) { + return -EINVAL; + } + + p = (iterator_data_t*)calloc(1, sizeof(*p)); + if (p == NULL) { + return -ENOMEM; + } + + p->overbit = overbit; + p->pg = 0; + p->offset = 0; + p->bit = 0; + + iter->data = (void*)p; + + return 0; +} + +static unsigned long bitset_next_over0(bitset_t* bitset, int pg, int offset, + int bit) +{ + while (pg < bitset->npages) { + while (offset < BITSET_PAGE_ITEMS) { + bitset_page_data_t val = ~(bitset->pages[pg]->data[offset] >> bit); + bitset_page_data_t mask = ((~(bitset_page_data_t)0) >> bit); + + val = val & mask; + + if (val != 0) { + int bit1 = FFSL(val); + + if (bit1 != 0) { + return BIT_IDX(pg, offset, bit + bit1 - 1); + } + } + + offset++; + bit = 0; + } + + pg++; + offset = 0; + bit = 0; + } + + return BIT_IDX(bitset->npages, 0, 0); +} + +static unsigned long bitset_next_over1(bitset_t* bitset, int pg, int offset, + int bit) +{ + while (pg < bitset->npages) { + while (offset < BITSET_PAGE_ITEMS) { + bitset_page_data_t val = (bitset->pages[pg]->data[offset] >> bit) + & (((~((bitset_page_data_t)0)) >> bit)); + if (val != 0) { + int bit1 = FFSL(val); + + if (bit1 != 0) { + return BIT_IDX(pg, offset, bit + bit1 - 1); + } + } + + offset++; + bit = 0; + } + + pg++; + offset = 0; + bit = 0; + } + + return BIT_IDX(bitset->npages, 0, 0); +} + +static int bitset_iter_next(iterator_t* iter, void** data) +{ + unsigned long pos = 0; + iterator_data_t* p = (iterator_data_t*)iter->data; + bitset_t* bitset = RTTI_OBJ_TO_DATA(bitset_t, iter->obj); + + if ((p == NULL) || (bitset == NULL)) { + return -EINVAL; + } + + if (p->pg >= bitset->npages) { + return RTTI_ITER_NO_DATA; + } + + switch (p->overbit) { + case BITSET_ITER_OVER_0: + pos = bitset_next_over0(bitset, p->pg, p->offset, p->bit); + break; + case BITSET_ITER_OVER_1: + pos = bitset_next_over1(bitset, p->pg, p->offset, p->bit); + break; + default: + return -EINVAL; + } + + if (BIT_PAGE(pos) >= bitset->npages) { + /* exceed the last page */ + p->pg = bitset->npages; + p->offset = 0; + p->bit = 0; + + return RTTI_ITER_NO_DATA; + } + + p->pg = BIT_PAGE(pos + 1); + p->offset = BIT_OFFSET(pos + 1); + p->bit = BIT_BIT(pos + 1); + + *data = (void*)pos; + + return RTTI_ITER_OK; +} + +static int bitset_iter_reset(iterator_t* iter) +{ + iterator_data_t* p = (iterator_data_t*)iter->data; + + if (p == NULL) { + return -EINVAL; + } + + p->pg = 0; + p->offset = 0; + p->bit = 0; + + return 1; +} + +static void bitset_iter_destroy(iterator_t* iter) +{ + iterator_data_t* p = (iterator_data_t*)iter->data; + + FREEUP(p); + + return; +} + +typeinfo_t bitset_type = { + .name = "bitset", + .privateSize = 0, + .dataSize = (datasize_fn_t)bitset_datasize, + .init = (obj_init_fn_t)bitset_init, + .destroy = (obj_destroy_fn_t)bitset_destroy, + .interfaces + = { .bitmap = &(intf_bitmap_t) { .test = (bit_test_fn_t)bitset_test, + .set = (bit_set_fn_t)bitset_set, + .clr = (bit_clr_fn_t)bitset_clr, + .clrall = (bit_clrall_fn_t)bitset_clrall }, + .iter + = &(intf_iterator_t) { .make = (iter_make_fn_t)bitset_iter_make, + .next = (iter_next_fn_t)bitset_iter_next, + .reset = (iter_reset_fn_t)bitset_iter_reset, + .destroy + = (iter_destroy_fn_t)bitset_iter_destroy } } +}; diff --git a/src/lib/meson.build b/src/lib/meson.build index c04aec22..3eb6bb03 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -82,6 +82,7 @@ libxce_src = [ gen_srcs[0], 'xvec.c', 'helper.c', 'resreq.c', + 'bitset.c', ] incdir = include_directories('../include') @@ -133,9 +134,10 @@ libxce_test_src = ['testsuite/test.c', 'testsuite/test_limit.c', 'testsuite/test_xvec.c', 'testsuite/test_resreq.c', + 'testsuite/test_bitset.c', ] -libxce_test_deps = [libxce_deps, unity_dep, libxce_dep] +libxce_test_deps = [libxce_deps, librtti_dep, unity_dep, libxce_dep] libxce_test = executable('xcelib_test', libxce_test_src, include_directories: [incdir, build_inc], diff --git a/src/lib/testsuite/test.c b/src/lib/testsuite/test.c index 7485c24d..b7a9957f 100644 --- a/src/lib/testsuite/test.c +++ b/src/lib/testsuite/test.c @@ -22,6 +22,7 @@ extern void test_xlist(void); extern void test_limit(void); extern void test_xvec(void); extern void test_resreq(void); +extern void test_bitset(void); void setUp(void) { return; } @@ -113,6 +114,7 @@ int main(int argc, char* argv[]) TEST(test_limit); TEST(test_xvec); TEST(test_resreq); + TEST(test_bitset); return UNITY_END(); } diff --git a/src/lib/testsuite/test_bitset.c b/src/lib/testsuite/test_bitset.c new file mode 100644 index 00000000..cd21c21f --- /dev/null +++ b/src/lib/testsuite/test_bitset.c @@ -0,0 +1,213 @@ +#include +#include +#include +#include + +#include "bitset.h" + +static void test_bitset_create(void) +{ + var bitset = makeInstance(&bitset_type, 1); + + TEST_ASSERT_TRUE(bitset != NULL); + TEST_ASSERT_TRUE(is_rtti_obj(bitset)); + destroy(bitset); +} + +static void test_bitset_set(void) +{ + var bitset = makeInstance(&bitset_type, 1); + int bits[] = { 1, 3, 5, 7, 11, 19, 23 }; + int i; + + TEST_ASSERT_TRUE(bitset != NULL); + TEST_ASSERT_TRUE(is_rtti_obj(bitset)); + + for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++) { + int rc; + + rc = bit_test(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc == 0); + + rc = bit_set(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc >= 0); + + rc = bit_test(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc > 0); + } + + destroy(bitset); +} + +static void test_bitset_clr(void) +{ + var bitset = makeInstance(&bitset_type, 1); + int bits[] = { 1, 3, 5, 7, 11, 19, 23 }; + int i; + + TEST_ASSERT_TRUE(bitset != NULL); + TEST_ASSERT_TRUE(is_rtti_obj(bitset)); + + for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++) { + int rc; + + rc = bit_test(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc == 0); + + rc = bit_set(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc >= 0); + + rc = bit_test(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc > 0); + + rc = bit_clr(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc >= 0); + + rc = bit_test(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc == 0); + } + + destroy(bitset); +} + +static void test_bitset_clrall(void) +{ + var bitset = makeInstance(&bitset_type, 1); + int bits[] = { 1, 3, 5, 7, 11, 19, 23 }; + int i; + int rc; + + TEST_ASSERT_TRUE(bitset != NULL); + TEST_ASSERT_TRUE(is_rtti_obj(bitset)); + + for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++) { + rc = bit_test(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc == 0); + + rc = bit_set(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc >= 0); + + rc = bit_test(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc > 0); + } + + rc = bit_clrall(bitset); + TEST_ASSERT_TRUE(rc >= 0); + + for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++) { + rc = bit_test(bitset, (unsigned long)bits[i]); + + TEST_ASSERT_TRUE(rc == 0); + } + destroy(bitset); +} + +static void test_bitset_iter_over1(void) +{ + var bitset = makeInstance(&bitset_type, 1); + int bits[] = { 0, 1, 3, 5, 7, 11, 19, 23, 64, 128, 139 }; + int i; + int rc; + iterator_t it; + void* data; + + TEST_ASSERT_TRUE(bitset != NULL); + TEST_ASSERT_TRUE(is_rtti_obj(bitset)); + + for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++) { + rc = bit_test(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc == 0); + + rc = bit_set(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc >= 0); + + rc = bit_test(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc > 0); + } + + rc = iter_make(&it, bitset, BITSET_ITER_OVER_1); + TEST_ASSERT_TRUE(rc >= 0); + + i = 0; + + for (;;) { + rc = iter_next(&it, &data); + TEST_ASSERT_TRUE(rc >= 0); + + if (rc == RTTI_ITER_NO_DATA) { + break; + } + + TEST_ASSERT_TRUE((int)((long)data) == bits[i]); + i++; + } + + TEST_ASSERT_TRUE(i == sizeof(bits) / sizeof(bits[0])); + + iter_destroy(&it); + destroy(bitset); +} + +static void test_bitset_iter_over0(void) +{ + var bitset = makeInstance(&bitset_type, 1); + int bits[] = { 0, 1, 3, 5, 7, 11, 19, 23, 64, 128, 139 }; + int i; + int rc; + iterator_t it; + void* data; + + TEST_ASSERT_TRUE(bitset != NULL); + TEST_ASSERT_TRUE(is_rtti_obj(bitset)); + + /* set all bits to 1 */ + for(i =0; i < 4096*8 ; i ++) { + rc = bit_set(bitset, (unsigned long)i); + TEST_ASSERT_TRUE(rc >= 0); + + rc = bit_test(bitset, (unsigned long)i); + TEST_ASSERT_TRUE(rc > 0); + } + + for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++) { + rc = bit_clr(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc >= 0); + + rc = bit_test(bitset, (unsigned long)bits[i]); + TEST_ASSERT_TRUE(rc == 0); + } + + rc = iter_make(&it, bitset, BITSET_ITER_OVER_0); + TEST_ASSERT_TRUE(rc >= 0); + + i = 0; + + for (;;) { + rc = iter_next(&it, &data); + TEST_ASSERT_TRUE(rc >= 0); + + if (rc == RTTI_ITER_NO_DATA) { + break; + } + + TEST_ASSERT_TRUE((int)((long)data) == bits[i]); + i++; + } + + TEST_ASSERT_TRUE(i == sizeof(bits) / sizeof(bits[0])); + + iter_destroy(&it); + destroy(bitset); +} + +void test_bitset(void) +{ + printf("\n>> bitset test\n\n"); + + RUN_TEST(test_bitset_create); + RUN_TEST(test_bitset_set); + RUN_TEST(test_bitset_clr); + RUN_TEST(test_bitset_clrall); + RUN_TEST(test_bitset_iter_over1); + RUN_TEST(test_bitset_iter_over0); +} diff --git a/src/lib/utils.c b/src/lib/utils.c index 50e83c7d..d5537e45 100644 --- a/src/lib/utils.c +++ b/src/lib/utils.c @@ -651,13 +651,29 @@ uint32_t hash64(uint64_t x) return hash4(a, b, c, d); } +#define RUN_HASH(hc, c) (((hc) << 5) + (hc) + (c)) + +uint32_t hash_block(char* buf, size_t len) +{ + uint32_t hc = 5381; + int i; + + for (i = 0; i < len; i++) { + int c = (int)buf[i]; + + hc = RUN_HASH(hc, c); + } + + return hc; +} + uint32_t hash_string(const char* key) { uint32_t hc = 5381; int c; while ((c = *key++)) { - hc = ((hc << 5) + hc) + c; + hc = RUN_HASH(hc, c); } return hc;