- introduce bitset

- add hash_block()
This commit is contained in:
Rongsong Shen 2026-02-13 11:01:23 +08:00
parent 2cf636e607
commit 48ea4a0205
8 changed files with 607 additions and 6 deletions

8
src/flake.lock generated
View file

@ -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"
},

17
src/include/bitset.h Normal file
View file

@ -0,0 +1,17 @@
#if !defined(_BITSET_H_)
#define _BITSET_H_ 1
#include "config.h"
#include <rtti.h>
/* 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

View file

@ -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

350
src/lib/bitset.c Normal file
View file

@ -0,0 +1,350 @@
#include <errno.h>
#include <rtti.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#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 } }
};

View file

@ -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],

View file

@ -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();
}

View file

@ -0,0 +1,213 @@
#include <rtti.h>
#include <stdio.h>
#include <stdlib.h>
#include <unity/unity.h>
#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);
}

View file

@ -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;