diff --git a/include/villas/bitset.h b/include/villas/bitset.h new file mode 100644 index 000000000..c92a95187 --- /dev/null +++ b/include/villas/bitset.h @@ -0,0 +1,48 @@ +/** A datastructure storing bitsets of arbitrary dimensions. + * + * @file + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#pragma once + +#include +#include + +struct bitset { + char *set; + size_t dimension; +}; + +int bitset_init(struct bitset *b, size_t dim); +int bitset_destroy(struct bitset *b); + + +int bitset_set(struct bitset *b, size_t bit); +int bitset_clear(struct bitset *b, size_t bit); + +void bitset_set_all(struct bitset *b); +void bitset_clear_all(struct bitset *b); + +int bitset_test(struct bitset *b, size_t bit); + +int bitset_cmp(struct bitset *a, struct bitset *b); + +char * bitset_dump(struct bitset *b); diff --git a/lib/Makefile.villas.inc b/lib/Makefile.villas.inc index 8d600e212..8bca34b8a 100644 --- a/lib/Makefile.villas.inc +++ b/lib/Makefile.villas.inc @@ -33,7 +33,7 @@ LIB_SRCS += $(addprefix lib/kernel/, kernel.c rt.c) \ utils.c super_node.c hist.c timing.c pool.c list.c queue.c \ queue_signalled.c memory.c advio.c plugin.c node_type.c stats.c \ mapping.c io.c shmem.c config_helper.c crypt.c compat.c \ - log_helper.c io_format.c task.c buffer.c table.c \ + log_helper.c io_format.c task.c buffer.c table.c bitset.c \ ) LIB_LDFLAGS = -shared diff --git a/lib/bitset.c b/lib/bitset.c new file mode 100644 index 000000000..a08e4b995 --- /dev/null +++ b/lib/bitset.c @@ -0,0 +1,140 @@ +/** A datastructure storing bitsets of arbitrary dimensions. + * + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#include +#include + +#include "bitset.h" +#include "utils.h" + +#define bitset_mask(b) (1 << ((b) % CHAR_BIT)) +#define bitset_slot(b) ((b) / CHAR_BIT) +#define bitset_nslots(nb) ((nb + CHAR_BIT - 1) / CHAR_BIT) + +int bitset_init(struct bitset *b, size_t dim) +{ + int s = bitset_nslots(dim); + + b->set = alloc(s * CHAR_BIT); + b->dimension = dim; + + return 0; +} + +int bitset_destroy(struct bitset *b) +{ + free(b->set); + + return 0; +} + +int bitset_set(struct bitset *b, size_t bit) +{ + int s = bitset_slot(bit); + char m = bitset_mask(bit); + + if (bit >= b->dimension) + return -1; + + b->set[s] |= m; + + return 0; +} + +int bitset_clear(struct bitset *b, size_t bit) +{ + int s = bitset_slot(bit); + char m = bitset_mask(bit); + + if (bit >= b->dimension) + return -1; + + b->set[s] &= ~m; + + return 0; +} + +int bitset_test(struct bitset *b, size_t bit) +{ + int s = bitset_slot(bit); + char m = bitset_mask(bit); + + if (bit >= b->dimension) + return -1; + + return b->set[s] & m ? 1 : 0; +} + +void bitset_set_all(struct bitset *b) +{ + int s = b->dimension / CHAR_BIT; + + if (b->dimension % CHAR_BIT) { + char m = (1 << (b->dimension % CHAR_BIT)) - 1; + + b->set[s] |= m; + } + + memset(b->set, ~0, s); +} + +void bitset_clear_all(struct bitset *b) +{ + int s = b->dimension / CHAR_BIT; + + /* Clear last byte */ + if (b->dimension % CHAR_BIT) { + char m = (1 << (b->dimension % CHAR_BIT)) - 1; + + b->set[s] &= ~m; + } + + memset(b->set, 0x00, s); +} + +int bitset_cmp(struct bitset *a, struct bitset *b) +{ + int s = a->dimension / CHAR_BIT; + + if (a->dimension != b->dimension) + return -1; + + /* Compare last byte with mask */ + if (a->dimension % CHAR_BIT) { + char m = (1 << (a->dimension % CHAR_BIT)) - 1; + + if ((a->set[s] & m) != (b->set[s] & m)) + return -1; + } + + return memcmp(a->set, b->set, s); +} + +char * bitset_dump(struct bitset *b) +{ + char *str = NULL; + + for (int i = 0; i < b->dimension; i++) + strcatf(&str, "%d", bitset_test(b, i)); + + return str; +} diff --git a/tests/unit/bitset.c b/tests/unit/bitset.c new file mode 100644 index 000000000..4fce6bca1 --- /dev/null +++ b/tests/unit/bitset.c @@ -0,0 +1,130 @@ +/** Unit tests for advio + * + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#include + +#include +#include + +#define LEN 1027 + +Test(bitset, simple) +{ + int ret; + struct bitset bs; + + int bits[] = { 23, 223, 25, 111, 252, 86, 222, 454, LEN-1 }; + + ret = bitset_init(&bs, LEN); + cr_assert_eq(ret, 0); + + for (int i = 0; i < ARRAY_LEN(bits); i++) { + bitset_set(&bs, bits[i]); + cr_assert_eq(ret, 0); + } + + for (int i = 0; i < ARRAY_LEN(bits); i++) { + ret = bitset_test(&bs, bits[i]); + cr_assert_eq(ret, 1, "Failed at bit %d", i); + } + + for (int i = 0; i < ARRAY_LEN(bits); i++) { + ret = bitset_clear(&bs, bits[i]); + cr_assert_eq(ret, 0, "Failed at bit %d", i); + } + + for (int i = 0; i < LEN; i++) { + ret = bitset_test(&bs, i); + cr_assert_eq(ret, 0); + } + + ret = bitset_destroy(&bs); + cr_assert_eq(ret, 0); +} + +Test(bitset, outofbounds) +{ + int ret; + struct bitset bs; + + ret = bitset_init(&bs, LEN); + cr_assert_eq(ret, 0); + + ret = bitset_set(&bs, LEN+1); + cr_assert_eq(ret, -1); + + ret = bitset_test(&bs, LEN+1); + cr_assert_eq(ret, -1); + + ret = bitset_destroy(&bs); + cr_assert_eq(ret, 0); +} + +Test(bitset, cmp) +{ + int ret; + struct bitset bs1, bs2; + + ret = bitset_init(&bs1, LEN); + cr_assert_eq(ret, 0); + + ret = bitset_init(&bs2, LEN); + cr_assert_eq(ret, 0); + + ret = bitset_set(&bs1, 525); + cr_assert_eq(ret, 0); + + ret = bitset_set(&bs2, 525); + cr_assert_eq(ret, 0); + + ret = bitset_cmp(&bs1, &bs2); + cr_assert_eq(ret, 0); + + ret = bitset_clear(&bs2, 525); + cr_assert_eq(ret, 0); + + ret = bitset_cmp(&bs1, &bs2); + cr_assert_neq(ret, 0); + + ret = bitset_destroy(&bs1); + cr_assert_eq(ret, 0); + + ret = bitset_destroy(&bs2); + cr_assert_eq(ret, 0); +} + +Test(bitset, all) +{ + int ret; + struct bitset bs; + + ret = bitset_init(&bs, LEN); + cr_assert_eq(ret, 0); + + for (int i = 0; i < LEN; i++) { + bitset_test(&bs, i); + cr_assert_eq(ret, 0); + } + + ret = bitset_destroy(&bs); + cr_assert_eq(ret, 0); +}