├── .gitignore ├── Makefile.am ├── README.md ├── autogen.sh ├── bitset.pc.in ├── bitset.png ├── configure.ac ├── include ├── Makefile.am └── bitset │ ├── bitset.h │ ├── estimate.h │ ├── malloc.h │ ├── operation.h │ └── vector.h ├── lib ├── Makefile.am ├── bitset.c ├── estimate.c ├── operation.c └── vector.c ├── m4 ├── ax_cc_maxopt.m4 ├── ax_check_compile_flag.m4 ├── ax_compiler_vendor.m4 ├── ax_gcc_archflag.m4 ├── ax_gcc_x86_cpuid.m4 ├── jemalloc.m4 └── tcmalloc.m4 └── test ├── Makefile.am ├── stress.c ├── test.c └── test.h /.gitignore: -------------------------------------------------------------------------------- 1 | lib/*.o 2 | lib/*.lo 3 | test/*.o 4 | */.* 5 | .deps 6 | .libs 7 | .AppleDouble 8 | lib/libbitset.* 9 | 10 | Makefile.in 11 | Makefile 12 | 13 | /autom4te.cache 14 | /aclocal.m4 15 | /compile 16 | /configure 17 | /depcomp 18 | /install-sh 19 | /missing 20 | /config.* 21 | /libtool 22 | /ltmain.sh 23 | /stamp-h* 24 | /m4/l*.m4 25 | test-driver 26 | 27 | test/stress 28 | test/test 29 | test/*.log 30 | test/*.trs 31 | 32 | bitset-*.tar.gz 33 | bitset.pc 34 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS=-I m4 2 | 3 | SUBDIRS=include lib test 4 | 5 | EXTRA_DIST= README.md 6 | 7 | MAINTAINERCLEANFILES = Makefile.in lib/Makefile.in include/Makefile.in \ 8 | test/Makefile.in m4/config.guess m4/config.sub m4/depcomp m4/install-sh \ 9 | m4/libtool.m4 m4/ltmain.sh m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 \ 10 | m4/lt~obsolete.m4 m4/missing config.guess config.h.in config.h.in~ \ 11 | configure depcomp install-sh ltmain.sh missing config.sub aclocal.m4 \ 12 | test-driver 13 | 14 | pkgconfigdir = $(libdir)/pkgconfig 15 | pkgconfig_DATA = bitset.pc 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Bitset](bitset.png) 2 | 3 | The bitset structure uses [word-aligned run-length encoding](include/bitset/bitset.h#L12-29) to compress sets of unsigned integers. 64-bit offsets are supported for very sparse sets. Unlike most succinct data structures which are immutable and append-only, the included bitset structure is mutable after construction. 4 | 5 | The library includes a vector abstraction (vector of bitsets) which can be used to represent another dimension 6 | such as time. Bitsets are packed together [contiguously](include/bitset/vector.h#L7-23) to improve cache locality. 7 | 8 | See the [headers](include/bitset) for usage details. 9 | 10 | ## Installation 11 | 12 | ```bash 13 | $ ./configure 14 | $ make 15 | $ sudo make install 16 | ``` 17 | 18 | ## Tests 19 | 20 | Tests and benchmarks can be run with 21 | 22 | ```bash 23 | $ make check 24 | ``` 25 | 26 | There's also a stress test available: 27 | 28 | ```bash 29 | $ cd test 30 | $ make stress && ./stress 31 | ``` 32 | 33 | ## Credits 34 | 35 | The symbol in the logo is from the [helveticons](http://helveticons.ch) library 36 | 37 | ## License 38 | 39 | **LGPL** - Copyright (c) 2013 Chris O'Hara 40 | 41 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if test -f Makefile; then 4 | make maintainer-clean 5 | fi 6 | 7 | autoreconf -f -i -------------------------------------------------------------------------------- /bitset.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | includedir=@includedir@ 4 | libdir=@libdir@ 5 | 6 | Name: Bitset 7 | Description: Compressed bitsets with supporting algorithms and structures 8 | URL: http://github.com/chriso/bitset 9 | Version: @version@ 10 | Libs: -L${libdir} -lbitset 11 | Cflags: -I${includedir} 12 | -------------------------------------------------------------------------------- /bitset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chriso/bitset/8f0be8ea00bcf612e7602dc9c71636e82f2f28ba/bitset.png -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.60]) 2 | 3 | # See http://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info 4 | m4_define([ver], [2.8.4]) 5 | m4_define([l_ver], [3:2:2]) 6 | 7 | AC_INIT([bitset], [ver], [http://github.com/chriso/bitset]) 8 | AC_CONFIG_HEADERS([config.h]) 9 | 10 | AC_CONFIG_AUX_DIR([.]) 11 | AC_CONFIG_MACRO_DIR([m4]) 12 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 13 | 14 | AC_PROG_CC 15 | AC_CHECK_PROG(MAKE,gmake,gmake,make) 16 | AC_PROG_MAKE_SET 17 | AC_CANONICAL_HOST 18 | 19 | AM_INIT_AUTOMAKE([foreign 1.11]) 20 | 21 | define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl 22 | define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl 23 | LT_INIT([dlopen disable-static]) 24 | 25 | AC_CHECK_HEADERS([limits.h stdint.h stdlib.h string.h]) 26 | 27 | TS_CHECK_JEMALLOC 28 | TS_CHECK_TCMALLOC 29 | 30 | AC_HEADER_STDBOOL 31 | AC_C_INLINE 32 | AC_TYPE_SIZE_T 33 | AC_TYPE_UINT32_T 34 | 35 | AC_FUNC_MALLOC 36 | AC_FUNC_REALLOC 37 | AC_CHECK_FUNCS([memmove]) 38 | AC_CHECK_SIZEOF([void *]) 39 | 40 | AC_ARG_ENABLE(optimisation, 41 | [AC_HELP_STRING( 42 | [--enable-optimisation], 43 | [Enable compile time optimisation flags @<:@default=yes@:>@] 44 | )], 45 | [enable_optimiser="$enableval"], 46 | [enable_optimiser="yes"] 47 | ) 48 | 49 | if test "${enable_optimiser}" = "yes" ; then 50 | AX_CC_MAXOPT 51 | CFLAGS="${CFLAGS} -DNDEBUG" 52 | fi 53 | 54 | AC_ARG_ENABLE(debug, 55 | [AC_HELP_STRING( 56 | [--enable-debug], 57 | [Build with debug flags @<:@default=no@:>@] 58 | )], 59 | [test x"$enableval" = "xyes" && CFLAGS="-DDEBUG -O0 -g"] 60 | ) 61 | 62 | version="ver" 63 | library_version="l_ver" 64 | 65 | AC_SUBST([library_version]) 66 | AC_SUBST([version]) 67 | 68 | AC_SUBST([CFLAGS]) 69 | AC_SUBST([LDFLAGS]) 70 | AC_SUBST([LIBS]) 71 | AC_SUBST([LIBTOOL_LINK_FLAGS]) 72 | 73 | case "$host" in 74 | *-*-linux*) 75 | CFLAGS="${CFLAGS} -DLINUX" 76 | ;; 77 | esac 78 | 79 | AC_CONFIG_FILES([Makefile include/Makefile lib/Makefile test/Makefile bitset.pc]) 80 | AC_OUTPUT 81 | -------------------------------------------------------------------------------- /include/Makefile.am: -------------------------------------------------------------------------------- 1 | pkginclude_HEADERS = bitset/bitset.h bitset/estimate.h \ 2 | bitset/operation.h bitset/vector.h bitset/malloc.h 3 | 4 | -------------------------------------------------------------------------------- /include/bitset/bitset.h: -------------------------------------------------------------------------------- 1 | #ifndef BITSET_BITSET_H_ 2 | #define BITSET_BITSET_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | /** 13 | * The bitset structure uses word-aligned run-length encoding. 14 | * 15 | * The compression technique is optimised for sparse bitsets where runs of 16 | * empty words are typically followed by a word with only one set bit. We 17 | * can exploit the fact that runs are usually less than 2^25 words long and 18 | * use the extra space in the previous word to encode the position of this bit. 19 | * 20 | * There are two types of words identified by the most significant bit 21 | * 22 | * Literal word: 0XXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX 23 | * Fill word: 1PPPPPLL LLLLLLLL LLLLLLLL LLLLLLLL 24 | * 25 | * X = Uncompressed bits 26 | * L = represents the length of the span of clean words 27 | * P = if the word proceeding the span contains only 1 bit, this 5-bit length 28 | * stores the position of the bit so that the next literal can be omitted 29 | */ 30 | 31 | typedef uint32_t bitset_word; 32 | #define BITSET_WORD_BYTES 4 33 | 34 | #define BITSET_WORD_LENGTH (sizeof(bitset_word) * 8) 35 | #define BITSET_POSITION_LENGTH BITSET_LOG2(BITSET_WORD_LENGTH) 36 | #define BITSET_FILL_BIT (1 << (BITSET_WORD_LENGTH - 1)) 37 | #define BITSET_SPAN_LENGTH (BITSET_WORD_LENGTH - BITSET_POSITION_LENGTH - 1) 38 | #define BITSET_POSITION_MASK (((1 << (BITSET_POSITION_LENGTH)) - 1) << (BITSET_SPAN_LENGTH)) 39 | #define BITSET_LENGTH_MASK ((1 << (BITSET_SPAN_LENGTH)) - 1) 40 | #define BITSET_LITERAL_LENGTH (BITSET_WORD_LENGTH - 1) 41 | 42 | #define BITSET_IS_FILL_WORD(word) ((word) & BITSET_FILL_BIT) 43 | #define BITSET_IS_LITERAL_WORD(word) (((word) & BITSET_FILL_BIT) == 0) 44 | #define BITSET_GET_LENGTH(word) ((word) & BITSET_LENGTH_MASK) 45 | #define BITSET_SET_LENGTH(word, len) ((word) | (len)) 46 | #define BITSET_GET_POSITION(word) (((word) & BITSET_POSITION_MASK) >> BITSET_SPAN_LENGTH) 47 | #define BITSET_SET_POSITION(word, pos) ((word) | ((pos) << BITSET_SPAN_LENGTH)) 48 | #define BITSET_UNSET_POSITION(word) ((word) & ~BITSET_POSITION_MASK) 49 | #define BITSET_CREATE_FILL(len, pos) BITSET_SET_POSITION(BITSET_FILL_BIT | (len), (pos) + 1) 50 | #define BITSET_CREATE_EMPTY_FILL(len) (BITSET_FILL_BIT | (len)) 51 | #define BITSET_CREATE_LITERAL(bit) ((1 << (BITSET_WORD_LENGTH - 2)) >> (bit)) 52 | #define BITSET_MAX_LENGTH BITSET_LENGTH_MASK 53 | 54 | #define BITSET_TMPVAR(i, line) BITSET_TMPVAR_(i, line) 55 | #define BITSET_TMPVAR_(a,b) a##b 56 | 57 | #define BITSET_IS_TAGGED_POINTER(p) ((uintptr_t)p & 1) 58 | #define BITSET_TAG_POINTER(p) ((uintptr_t)p | 1) 59 | #define BITSET_UNTAG_POINTER(p) ((uintptr_t)p & ~((uintptr_t)1)) 60 | #define BITSET_UINT_IN_POINTER(u) (((uintptr_t)u << 1) | 1) 61 | #define BITSET_UINT_FROM_POINTER(u) ((uintptr_t)u >> 1) 62 | #define BITSET_UINT_CAN_TAG(u) (u < (sizeof(void*)==4 ? 1U<<31 : 1LLU<<63)) 63 | 64 | #define BITSET_MAX(a, b) ((a) > (b) ? (a) : (b)); 65 | #define BITSET_MIN(a, b) ((a) < (b) ? (a) : (b)); 66 | #define BITSET_IS_POW2(word) ((word & (word - 1)) == 0) 67 | #define BITSET_LOG2(v) (8 - 90/(((v)/4+14)|1) - 2/((v)/2+1)) 68 | #define BITSET_NEXT_POW2(d,s) d=s;d--;d|=d>>1;d|=d>>2;d|=d>>4;d|=d>>8;d|=d>>16;d++; 69 | #define BITSET_POP_COUNT(c,w) w&=P1;w-=(w>>1)&P2;w=(w&P3)+((w>>2)&P3);w=(w+(w>>4))\ 70 | &P4;c+=(w*P5)>>(BITSET_WORD_LENGTH-8); 71 | #define P1 0x7FFFFFFF 72 | #define P2 0x55555555 73 | #define P3 0x33333333 74 | #define P4 0x0F0F0F0F 75 | #define P5 0x01010101 76 | 77 | /** 78 | * 64-bit offsets are supported using -DBITSET_64BIT_OFFSETS. 79 | */ 80 | 81 | #ifndef BITSET_64BIT_OFFSETS 82 | typedef uint32_t bitset_offset; 83 | #define bitset_format "%u" 84 | #else 85 | typedef uint64_t bitset_offset; 86 | #define bitset_format "%llu" 87 | #endif 88 | 89 | /** 90 | * Bitset types. 91 | */ 92 | 93 | typedef struct bitset_s { 94 | bitset_word *buffer; 95 | size_t length; 96 | } bitset_t; 97 | 98 | typedef struct bitset_iterator_s { 99 | bitset_offset *offsets; 100 | size_t length; 101 | } bitset_iterator_t; 102 | 103 | /** 104 | * Create a new bitset. 105 | */ 106 | 107 | bitset_t *bitset_new(void); 108 | 109 | /** 110 | * Clear the specified bitset. 111 | */ 112 | 113 | void bitset_clear(bitset_t *); 114 | 115 | /** 116 | * Free the specified bitset. 117 | */ 118 | 119 | void bitset_free(bitset_t *); 120 | 121 | /** 122 | * Resize the bitset buffer. 123 | */ 124 | 125 | void bitset_resize(bitset_t *, size_t); 126 | 127 | /** 128 | * Get the byte length of the bitset buffer. 129 | */ 130 | 131 | size_t bitset_length(const bitset_t *); 132 | 133 | /** 134 | * Create a new bitset from an existing buffer. 135 | */ 136 | 137 | bitset_t *bitset_new_buffer(const char *, size_t); 138 | 139 | /** 140 | * Create a new bitset from an array of bits. 141 | */ 142 | 143 | bitset_t *bitset_new_bits(bitset_offset *, size_t); 144 | 145 | /** 146 | * A helper for creating bitsets: BITSET_NEW(b1, 1, 10, 100); 147 | */ 148 | 149 | #define BITSET_NEW(name, ...) \ 150 | bitset_offset BITSET_TMPVAR(o, __LINE__)[] = { __VA_ARGS__ }; \ 151 | bitset_t *name = bitset_new_bits((bitset_offset*)BITSET_TMPVAR(o, __LINE__), \ 152 | sizeof(BITSET_TMPVAR(o, __LINE__))/sizeof(BITSET_TMPVAR(o, __LINE__)[0])); 153 | 154 | /** 155 | * Create a copy of the specified bitset. 156 | */ 157 | 158 | bitset_t *bitset_copy(const bitset_t *); 159 | 160 | /** 161 | * Check whether a bit is set. 162 | */ 163 | 164 | bool bitset_get(const bitset_t *, bitset_offset); 165 | 166 | /** 167 | * Get the population count of the bitset (number of set bits). 168 | */ 169 | 170 | bitset_offset bitset_count(const bitset_t *); 171 | 172 | /** 173 | * Set or unset the specified bit. 174 | */ 175 | 176 | bool bitset_set_to(bitset_t *, bitset_offset, bool); 177 | 178 | /** 179 | * Set the specified bit. 180 | */ 181 | 182 | bool bitset_set(bitset_t *, bitset_offset); 183 | 184 | /** 185 | * Unset the specified bit. 186 | */ 187 | 188 | bool bitset_unset(bitset_t *, bitset_offset); 189 | 190 | /** 191 | * Find the lowest set bit in the bitset. 192 | */ 193 | 194 | bitset_offset bitset_min(const bitset_t *); 195 | 196 | /** 197 | * Find the highest set bit in the bitset. 198 | */ 199 | 200 | bitset_offset bitset_max(const bitset_t *); 201 | 202 | /** 203 | * Create a new bitset iterator. 204 | */ 205 | 206 | bitset_iterator_t *bitset_iterator_new(const bitset_t *); 207 | 208 | /** 209 | * Iterate over all bits. 210 | */ 211 | 212 | #define BITSET_FOREACH(iterator, offset) \ 213 | for (size_t BITSET_TMPVAR(i, __LINE__) = 0; \ 214 | BITSET_TMPVAR(i, __LINE__) < iterator->length \ 215 | ? (offset = iterator->offsets[BITSET_TMPVAR(i, __LINE__)]), 1 : 0; \ 216 | BITSET_TMPVAR(i, __LINE__)++) 217 | 218 | /** 219 | * Free the bitset iterator. 220 | */ 221 | 222 | void bitset_iterator_free(bitset_iterator_t *); 223 | 224 | /** 225 | * Custom out of memory behaviour. 226 | */ 227 | 228 | #define BITSET_FATAL(msg) \ 229 | fprintf(stderr, "bitset error: " msg "\n"); \ 230 | exit(EXIT_FAILURE) 231 | 232 | #ifndef bitset_oom 233 | # define bitset_oom() BITSET_FATAL("out of memory") 234 | #endif 235 | 236 | #ifdef __cplusplus 237 | } //extern "C" 238 | #endif 239 | 240 | #endif 241 | 242 | -------------------------------------------------------------------------------- /include/bitset/estimate.h: -------------------------------------------------------------------------------- 1 | #ifndef BITSET_PROBABILISTIC_H 2 | #define BITSET_PROBABILISTIC_H 3 | 4 | #include "bitset/bitset.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | /** 11 | * Bitset linear counting type. 12 | */ 13 | 14 | typedef struct bitset_linear_s { 15 | bitset_word *words; 16 | unsigned count; 17 | size_t size; 18 | } bitset_linear_t; 19 | 20 | /** 21 | * Bitset count N type. 22 | */ 23 | 24 | typedef struct bitset_countn_s { 25 | bitset_word **words; 26 | unsigned n; 27 | size_t size; 28 | } bitset_countn_t; 29 | 30 | /** 31 | * Estimate unique bits using an uncompressed bitset of the specified size 32 | * (bloom filter where n=1). 33 | */ 34 | 35 | bitset_linear_t *bitset_linear_new(size_t); 36 | 37 | /** 38 | * Estimate unique bits in the bitset. 39 | */ 40 | 41 | void bitset_linear_add(bitset_linear_t *, const bitset_t *); 42 | 43 | /** 44 | * Get the estimated unique bit count. 45 | */ 46 | 47 | unsigned bitset_linear_count(const bitset_linear_t *); 48 | 49 | /** 50 | * Free the linear counter. 51 | */ 52 | 53 | void bitset_linear_free(bitset_linear_t *); 54 | 55 | /** 56 | * Estimate the number of bits that occur N times. 57 | */ 58 | 59 | bitset_countn_t *bitset_countn_new(unsigned, size_t); 60 | 61 | /** 62 | * Add a bitset to the counter. 63 | */ 64 | 65 | void bitset_countn_add(bitset_countn_t *, const bitset_t *); 66 | 67 | /** 68 | * Count the number of bits that occur N times. 69 | */ 70 | 71 | unsigned bitset_countn_count(const bitset_countn_t *); 72 | 73 | /** 74 | * Count the number of bits that occur 0..N times. 75 | */ 76 | 77 | unsigned *bitset_countn_count_all(const bitset_countn_t *); 78 | 79 | /** 80 | * Count the number of bits that occur 0..N times using a mask. 81 | */ 82 | 83 | unsigned *bitset_countn_count_mask(const bitset_countn_t *, const bitset_t *); 84 | 85 | /** 86 | * Free the result of a count_all or count_mask. 87 | */ 88 | 89 | void bitset_countn_count_free(unsigned *); 90 | 91 | /** 92 | * Free the counter. 93 | */ 94 | 95 | void bitset_countn_free(bitset_countn_t *); 96 | 97 | #ifdef __cplusplus 98 | } //extern "C" 99 | #endif 100 | 101 | #endif 102 | 103 | -------------------------------------------------------------------------------- /include/bitset/malloc.h: -------------------------------------------------------------------------------- 1 | #ifndef BITSET_MALLOC_H_ 2 | #define BITSET_MALLOC_H_ 3 | 4 | #ifdef HAVE_CONFIG_H 5 | # include "config.h" 6 | #endif 7 | 8 | #if defined(has_tcmalloc) 9 | # include 10 | # define BITSET_MALLOC_PREFIX tc_ 11 | #elif defined(has_jemalloc) 12 | # include 13 | # define BITSET_MALLOC_PREFIX prefix_jemalloc 14 | #else 15 | # include 16 | # define BITSET_MALLOC_PREFIX 17 | # if defined(LINUX) 18 | # include //for mallopt() 19 | # endif 20 | #endif 21 | 22 | #define bitset_malloc(size) \ 23 | BITSET_MALLOC_CALL(malloc)(size) 24 | 25 | #define bitset_malloc_free(ptr) \ 26 | BITSET_MALLOC_CALL(free)(ptr) 27 | 28 | #define bitset_calloc(count, size) \ 29 | BITSET_MALLOC_CALL(calloc)(count, size) 30 | 31 | #define bitset_realloc(ptr, size) \ 32 | BITSET_MALLOC_CALL(realloc)(ptr, size) 33 | 34 | #if !defined(has_jemalloc) && !defined(has_tcmalloc) && defined(LINUX) 35 | # define bitset_mallopt(param, val) return mallopt(param, value); 36 | #else 37 | # define bitset_mallopt(param, val) 1 38 | #endif 39 | 40 | #define BITSET_MALLOC_CALL(fn) \ 41 | BITSET_MALLOC_CONCAT(BITSET_MALLOC_PREFIX, fn) 42 | 43 | #define BITSET_MALLOC_CONCAT(a,b) \ 44 | BITSET_MALLOC_CONCAT_(a,b) 45 | 46 | #define BITSET_MALLOC_CONCAT_(a,b) \ 47 | a##b 48 | 49 | #endif 50 | 51 | -------------------------------------------------------------------------------- /include/bitset/operation.h: -------------------------------------------------------------------------------- 1 | #ifndef BITSET_OPERATION_H 2 | #define BITSET_OPERATION_H 3 | 4 | #include "bitset/bitset.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | /** 11 | * Bitset hash types. 12 | */ 13 | 14 | typedef struct bucket_ { 15 | bitset_offset offset; 16 | bitset_word word; 17 | struct bucket_ *next; 18 | } bitset_hash_bucket_t; 19 | 20 | typedef struct hash_ { 21 | bitset_hash_bucket_t **buckets; 22 | bitset_word *buffer; 23 | size_t size; 24 | unsigned count; 25 | } bitset_hash_t; 26 | 27 | /** 28 | * Bitset operation types. 29 | */ 30 | 31 | enum bitset_operation_type { 32 | BITSET_AND, 33 | BITSET_OR, 34 | BITSET_XOR, 35 | BITSET_ANDNOT 36 | }; 37 | 38 | typedef struct bitset_operation_s bitset_operation_t; 39 | 40 | typedef struct bitset_operation_step_s { 41 | union { 42 | bitset_t bitset; 43 | bitset_operation_t *nested; 44 | } data; 45 | bool is_nested; 46 | bool is_operation; 47 | enum bitset_operation_type type; 48 | } bitset_operation_step_t; 49 | 50 | struct bitset_operation_s { 51 | bitset_operation_step_t **steps; 52 | size_t length; 53 | }; 54 | 55 | /** 56 | * Create a new bitset operation. 57 | */ 58 | 59 | bitset_operation_t *bitset_operation_new(bitset_t *b); 60 | 61 | /** 62 | * Free the bitset operation. 63 | */ 64 | 65 | void bitset_operation_free(bitset_operation_t *); 66 | 67 | /** 68 | * Add a bitset to the operation. 69 | */ 70 | 71 | void bitset_operation_add(bitset_operation_t *, bitset_t *, enum bitset_operation_type); 72 | 73 | /** 74 | * Add a bitset buffer to the operation. 75 | */ 76 | 77 | void bitset_operation_add_buffer(bitset_operation_t *, bitset_word *, size_t length, enum bitset_operation_type); 78 | 79 | /** 80 | * Add a nested operation. 81 | */ 82 | 83 | void bitset_operation_add_nested(bitset_operation_t *, bitset_operation_t *, enum bitset_operation_type); 84 | 85 | /** 86 | * Execute the operation and return the result. 87 | */ 88 | 89 | bitset_t *bitset_operation_exec(bitset_operation_t *); 90 | 91 | /** 92 | * Get the population count of the operation result without using 93 | * a temporary bitset. 94 | */ 95 | 96 | bitset_offset bitset_operation_count(bitset_operation_t *); 97 | 98 | #ifdef __cplusplus 99 | } //extern "C" 100 | #endif 101 | 102 | #endif 103 | 104 | -------------------------------------------------------------------------------- /include/bitset/vector.h: -------------------------------------------------------------------------------- 1 | #ifndef BITSET_VECTOR_H_ 2 | #define BITSET_VECTOR_H_ 3 | 4 | #include "bitset/operation.h" 5 | #include "bitset/estimate.h" 6 | 7 | /** 8 | * Bitset buffers can be packed together into a vector which is compressed 9 | * using length encoding. Each vector buffer consists of zero or more bitsets 10 | * prefixed with their offset and length 11 | * 12 | * ... 13 | * 14 | * For example, adding a bitset with a length of 12 bytes at position 3 15 | * followed by a bitset with a length of 4 bytes at position 12 would result in 16 | * 17 | * 18 | * 19 | * Offsets and lengths are encoded using the following format 20 | * 21 | * |0xxxxxxx|xxxxxxxx| 15 bit length 22 | * |1xxxxxxx|xxxxxxxx|xxxxxxxx|xxxxxxxx| 31 bit length 23 | */ 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | /** 30 | * Bitset vector types. 31 | */ 32 | 33 | typedef struct bitset_vector_s { 34 | char *buffer; 35 | size_t length; 36 | size_t size; 37 | unsigned tail_offset; 38 | } bitset_vector_t; 39 | 40 | typedef struct bitset_vector_operation_s bitset_vector_operation_t; 41 | 42 | typedef struct bitset_vector_operation_step_s { 43 | union { 44 | bitset_vector_t *vector; 45 | bitset_vector_operation_t *operation; 46 | } data; 47 | void *userdata; 48 | bool is_nested; 49 | bool is_operation; 50 | enum bitset_operation_type type; 51 | } bitset_vector_operation_step_t; 52 | 53 | struct bitset_vector_operation_s { 54 | bitset_vector_operation_step_t **steps; 55 | unsigned min; 56 | unsigned max; 57 | size_t length; 58 | }; 59 | 60 | #define BITSET_VECTOR_START 0 61 | #define BITSET_VECTOR_END 0 62 | 63 | /** 64 | * Create a new bitset vector. 65 | */ 66 | 67 | bitset_vector_t *bitset_vector_new(void); 68 | 69 | /** 70 | * Create a new bitset vector based on an existing buffer. 71 | */ 72 | 73 | bitset_vector_t *bitset_vector_import(const char *, size_t); 74 | 75 | /** 76 | * Free the specified vector. 77 | */ 78 | 79 | void bitset_vector_free(bitset_vector_t *); 80 | 81 | /** 82 | * Copy a vector. 83 | */ 84 | 85 | bitset_vector_t *bitset_vector_copy(const bitset_vector_t *); 86 | 87 | /** 88 | * Get the vector buffer. 89 | */ 90 | 91 | char *bitset_vector_export(const bitset_vector_t *); 92 | 93 | /** 94 | * Get the byte length of the vector buffer. 95 | */ 96 | 97 | size_t bitset_vector_length(const bitset_vector_t *); 98 | 99 | /** 100 | * Get the number of bitsets in the vector. 101 | */ 102 | 103 | unsigned bitset_vector_bitsets(const bitset_vector_t *); 104 | 105 | /** 106 | * Push a bitset on to the end of the vector. 107 | */ 108 | 109 | void bitset_vector_push(bitset_vector_t *, const bitset_t *, unsigned); 110 | 111 | /** 112 | * Resize the vector buffer. 113 | */ 114 | 115 | void bitset_vector_resize(bitset_vector_t *, size_t); 116 | 117 | /** 118 | * Iterate over all bitsets. 119 | */ 120 | 121 | #define BITSET_VECTOR_FOREACH(vector, bitset, offset) \ 122 | bitset_t BITSET_TMPVAR(tmp, __LINE__); \ 123 | bitset = &BITSET_TMPVAR(tmp, __LINE__); \ 124 | offset = 0; \ 125 | char *BITSET_TMPVAR(buffer, __LINE__) = vector->buffer; \ 126 | while (BITSET_TMPVAR(buffer, __LINE__) < (vector->buffer + vector->length) \ 127 | ? (BITSET_TMPVAR(buffer, __LINE__) = bitset_vector_advance(BITSET_TMPVAR(buffer, __LINE__), \ 128 | bitset, &offset), 1) : 0) 129 | 130 | char *bitset_vector_advance(char *buffer, bitset_t *, unsigned *); 131 | 132 | /** 133 | * Concatenate an vector to another at the specified offset. The vector can optionally be 134 | * sliced by start and end before being concatted. Pass BITSET_VECTOR_START and 135 | * BITSET_VECTOR_END to both parameters to concat the entire vector. 136 | */ 137 | 138 | void bitset_vector_concat(bitset_vector_t *, const bitset_vector_t *, unsigned offset, 139 | unsigned start, unsigned end); 140 | 141 | /** 142 | * Get a raw and unique count for set items in the vector. 143 | */ 144 | 145 | void bitset_vector_cardinality(const bitset_vector_t *, unsigned *, unsigned *); 146 | 147 | /** 148 | * Merge (bitwise OR) each vector bitset. 149 | */ 150 | 151 | bitset_t *bitset_vector_merge(const bitset_vector_t *); 152 | 153 | /** 154 | * Create a new vector operation. 155 | */ 156 | 157 | bitset_vector_operation_t *bitset_vector_operation_new(bitset_vector_t *); 158 | 159 | /** 160 | * Free the specified vector operation. By default vector operands will not be 161 | * freed. Use the second function before calling free() to free vectors. 162 | */ 163 | 164 | void bitset_vector_operation_free(bitset_vector_operation_t *); 165 | void bitset_vector_operation_free_operands(bitset_vector_operation_t *); 166 | 167 | /** 168 | * Add a vector to the operation. 169 | */ 170 | 171 | void bitset_vector_operation_add(bitset_vector_operation_t *, 172 | bitset_vector_t *, enum bitset_operation_type); 173 | 174 | /** 175 | * Add a nested operation. 176 | */ 177 | 178 | void bitset_vector_operation_add_nested(bitset_vector_operation_t *, 179 | bitset_vector_operation_t *, enum bitset_operation_type); 180 | 181 | /** 182 | * Execute the operation and return the result. 183 | */ 184 | 185 | bitset_vector_t *bitset_vector_operation_exec(bitset_vector_operation_t *); 186 | 187 | /** 188 | * Provide a way to associate user data with each step and use the data to lazily 189 | * lookup vectors. 190 | */ 191 | 192 | void bitset_vector_operation_add_data(bitset_vector_operation_t *, 193 | void *data, enum bitset_operation_type); 194 | 195 | void bitset_vector_operation_resolve_data(bitset_vector_operation_t *, 196 | bitset_vector_t *(*)(void *data, void *context), void *context); 197 | 198 | void bitset_vector_operation_free_data(bitset_vector_operation_t *, void (*)(void *data)); 199 | 200 | /** 201 | * Misc functions. 202 | */ 203 | 204 | void bitset_vector_init(bitset_vector_t *); 205 | 206 | #ifdef __cplusplus 207 | } //extern "C" 208 | #endif 209 | 210 | #endif 211 | 212 | -------------------------------------------------------------------------------- /lib/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I$(top_srcdir)/include 2 | AM_CFLAGS= -std=c99 -Wall 3 | 4 | lib_LTLIBRARIES = libbitset.la 5 | libbitset_la_SOURCES = bitset.c estimate.c operation.c vector.c 6 | libbitset_la_LDFLAGS = $(AM_LDFLAGS) \ 7 | -version-info @library_version@ \ 8 | -no-undefined 9 | -------------------------------------------------------------------------------- /lib/bitset.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "bitset/malloc.h" 6 | #include "bitset/operation.h" 7 | 8 | bitset_t *bitset_new() { 9 | bitset_t *bitset = bitset_malloc(sizeof(bitset_t)); 10 | if (!bitset) { 11 | bitset_oom(); 12 | } 13 | bitset->length = 0; 14 | bitset->buffer = NULL; 15 | return bitset; 16 | } 17 | 18 | void bitset_free(bitset_t *bitset) { 19 | if (bitset->length) { 20 | bitset_malloc_free(bitset->buffer); 21 | } 22 | bitset_malloc_free(bitset); 23 | } 24 | 25 | void bitset_resize(bitset_t *bitset, size_t length) { 26 | size_t current_size, next_size; 27 | BITSET_NEXT_POW2(next_size, length); 28 | if (!bitset->length) { 29 | bitset->buffer = bitset_malloc(sizeof(bitset_word) * next_size); 30 | } else { 31 | BITSET_NEXT_POW2(current_size, bitset->length); 32 | if (next_size > current_size) { 33 | bitset->buffer = bitset_realloc(bitset->buffer, sizeof(bitset_word) * next_size); 34 | } 35 | } 36 | if (!bitset->buffer) { 37 | bitset_oom(); 38 | } 39 | bitset->length = length; 40 | } 41 | 42 | void bitset_clear(bitset_t *bitset) { 43 | bitset->length = 0; 44 | } 45 | 46 | size_t bitset_length(const bitset_t *bitset) { 47 | return bitset->length * sizeof(bitset_word); 48 | } 49 | 50 | bitset_t *bitset_copy(const bitset_t *bitset) { 51 | bitset_t *copy = bitset_calloc(1, sizeof(bitset_t)); 52 | if (!copy) { 53 | bitset_oom(); 54 | } 55 | if (bitset->length) { 56 | size_t size; 57 | BITSET_NEXT_POW2(size, bitset->length); 58 | copy->buffer = bitset_malloc(sizeof(bitset_word) * size); 59 | if (!copy->buffer) { 60 | bitset_oom(); 61 | } 62 | memcpy(copy->buffer, bitset->buffer, bitset->length * sizeof(bitset_word)); 63 | copy->length = bitset->length; 64 | } 65 | return copy; 66 | } 67 | 68 | bool bitset_get(const bitset_t *bitset, bitset_offset bit) { 69 | if (!bitset->length) { 70 | return false; 71 | } 72 | bitset_offset length, word_offset = bit / BITSET_LITERAL_LENGTH; 73 | bit %= BITSET_LITERAL_LENGTH; 74 | for (size_t i = 0; i < bitset->length; i++) { 75 | if (BITSET_IS_FILL_WORD(bitset->buffer[i])) { 76 | length = BITSET_GET_LENGTH(bitset->buffer[i]); 77 | unsigned position = BITSET_GET_POSITION(bitset->buffer[i]); 78 | if (word_offset < length) { 79 | return false; 80 | } else if (position) { 81 | if (word_offset == length) { 82 | return position == bit + 1; 83 | } 84 | word_offset--; 85 | } 86 | word_offset -= length; 87 | } else if (!word_offset--) { 88 | return bitset->buffer[i] & BITSET_CREATE_LITERAL(bit); 89 | } 90 | } 91 | return false; 92 | } 93 | 94 | bitset_offset bitset_count(const bitset_t *bitset) { 95 | bitset_offset count = 0; 96 | for (size_t i = 0; i < bitset->length; i++) { 97 | if (BITSET_IS_FILL_WORD(bitset->buffer[i])) { 98 | if (BITSET_GET_POSITION(bitset->buffer[i])) { 99 | count += 1; 100 | } 101 | } else { 102 | bitset_word word = bitset->buffer[i]; 103 | BITSET_POP_COUNT(count, word); 104 | } 105 | } 106 | return count; 107 | } 108 | 109 | static inline unsigned char bitset_fls(bitset_word word) { 110 | static char table[64] = { 111 | 32, 31, 0, 16, 0, 30, 3, 0, 15, 0, 0, 0, 29, 10, 2, 0, 112 | 0, 0, 12, 14, 21, 0, 19, 0, 0, 28, 0, 25, 0, 9, 1, 0, 113 | 17, 0, 4, 0, 0, 0, 11, 0, 13, 22, 20, 0, 26, 0, 0, 18, 114 | 5, 0, 0, 23, 0, 27, 0, 6, 0, 24, 7, 0, 8, 0, 0, 0 115 | }; 116 | word = word | (word >> 1); 117 | word = word | (word >> 2); 118 | word = word | (word >> 4); 119 | word = word | (word >> 8); 120 | word = word | (word >> 16); 121 | word = (word << 3) - word; 122 | word = (word << 8) - word; 123 | word = (word << 8) - word; 124 | word = (word << 8) - word; 125 | return table[word >> 26] - 1; 126 | } 127 | 128 | static inline unsigned char bitset_ffs(bitset_word word) { 129 | static char table[32] = { 130 | 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 131 | 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 132 | }; 133 | return table[((bitset_word)((word & -word) * 0x077CB531U)) >> 27] + 1; 134 | } 135 | 136 | bitset_offset bitset_min(const bitset_t *bitset) { 137 | bitset_offset offset = 0; 138 | for (size_t i = 0; i < bitset->length; i++) { 139 | if (BITSET_IS_FILL_WORD(bitset->buffer[i])) { 140 | offset += BITSET_GET_LENGTH(bitset->buffer[i]); 141 | unsigned position = BITSET_GET_POSITION(bitset->buffer[i]); 142 | if (position) { 143 | return offset * BITSET_LITERAL_LENGTH + position - 1; 144 | } 145 | } else { 146 | return offset * BITSET_LITERAL_LENGTH + bitset_fls(bitset->buffer[i]); 147 | } 148 | } 149 | return 0; 150 | } 151 | 152 | bitset_offset bitset_max(const bitset_t *bitset) { 153 | if (!bitset->length) { 154 | return 0; 155 | } 156 | bitset_offset offset = 0; 157 | for (size_t i = 0; i < bitset->length; i++) { 158 | if (BITSET_IS_FILL_WORD(bitset->buffer[i])) { 159 | offset += BITSET_GET_LENGTH(bitset->buffer[i]); 160 | if (BITSET_GET_POSITION(bitset->buffer[i])) { 161 | offset += 1; 162 | } 163 | } else { 164 | offset += 1; 165 | } 166 | } 167 | bitset_word last = bitset->buffer[bitset->length-1]; 168 | offset = (offset - 1) * BITSET_LITERAL_LENGTH; 169 | if (BITSET_IS_FILL_WORD(last)) { 170 | return offset + BITSET_GET_POSITION(last) - 1; 171 | } 172 | return offset + BITSET_LITERAL_LENGTH - bitset_ffs(last); 173 | } 174 | 175 | bool bitset_set(bitset_t *bitset, bitset_offset bit) { 176 | return bitset_set_to(bitset, bit, true); 177 | } 178 | 179 | bool bitset_unset(bitset_t *bitset, bitset_offset bit) { 180 | return bitset_set_to(bitset, bit, false); 181 | } 182 | 183 | bool bitset_set_to(bitset_t *bitset, bitset_offset bit, bool value) { 184 | bitset_offset word_offset = bit / BITSET_LITERAL_LENGTH; 185 | bit %= BITSET_LITERAL_LENGTH; 186 | if (bitset->length) { 187 | bitset_word word; 188 | bitset_offset fill_length; 189 | unsigned position; 190 | for (size_t i = 0; i < bitset->length; i++) { 191 | word = bitset->buffer[i]; 192 | if (BITSET_IS_FILL_WORD(word)) { 193 | position = BITSET_GET_POSITION(word); 194 | fill_length = BITSET_GET_LENGTH(word); 195 | if (word_offset == fill_length - 1) { 196 | if (position) { 197 | bitset_resize(bitset, bitset->length + 1); 198 | if (i < bitset->length - 1) { 199 | memmove(bitset->buffer+i+2, bitset->buffer+i+1, 200 | sizeof(bitset_word) * (bitset->length - i - 2)); 201 | } 202 | bitset->buffer[i+1] = BITSET_CREATE_LITERAL(position - 1); 203 | if (word_offset) { 204 | bitset->buffer[i] = BITSET_CREATE_FILL(fill_length - 1, bit); 205 | } else { 206 | bitset->buffer[i] = BITSET_CREATE_LITERAL(bit); 207 | } 208 | } else { 209 | if (fill_length - 1 > 0) { 210 | bitset->buffer[i] = BITSET_CREATE_FILL(fill_length - 1, bit); 211 | } else { 212 | bitset->buffer[i] = BITSET_CREATE_LITERAL(bit); 213 | } 214 | } 215 | return false; 216 | } else if (word_offset < fill_length) { 217 | bitset_resize(bitset, bitset->length + 1); 218 | if (i < bitset->length - 1) { 219 | memmove(bitset->buffer+i+2, bitset->buffer+i+1, 220 | sizeof(bitset_word) * (bitset->length - i - 2)); 221 | } 222 | if (!word_offset) { 223 | bitset->buffer[i] = BITSET_CREATE_LITERAL(bit); 224 | } else { 225 | bitset->buffer[i] = BITSET_CREATE_FILL(word_offset, bit); 226 | } 227 | bitset->buffer[i+1] = BITSET_CREATE_FILL(fill_length - word_offset - 1, position - 1); 228 | return false; 229 | } 230 | word_offset -= fill_length; 231 | if (position) { 232 | if (!word_offset) { 233 | if (position == bit + 1) { 234 | if (!value) { 235 | bitset->buffer[i] = BITSET_UNSET_POSITION(word); 236 | } 237 | return true; 238 | } else { 239 | bitset_resize(bitset, bitset->length + 1); 240 | if (i < bitset->length - 1) { 241 | memmove(bitset->buffer+i+2, bitset->buffer+i+1, 242 | sizeof(bitset_word) * (bitset->length - i - 2)); 243 | } 244 | bitset->buffer[i] = BITSET_UNSET_POSITION(word); 245 | bitset_word literal = 0; 246 | literal |= BITSET_CREATE_LITERAL(position - 1); 247 | literal |= BITSET_CREATE_LITERAL(bit); 248 | bitset->buffer[i+1] = literal; 249 | return false; 250 | } 251 | } 252 | word_offset--; 253 | } else if (!word_offset && i == bitset->length - 1) { 254 | bitset->buffer[i] = BITSET_SET_POSITION(word, bit + 1); 255 | return false; 256 | } 257 | } else if (!word_offset--) { 258 | bitset_word mask = BITSET_CREATE_LITERAL(bit); 259 | bool previous = word & mask; 260 | if (value) { 261 | bitset->buffer[i] |= mask; 262 | } else { 263 | bitset->buffer[i] &= ~mask; 264 | } 265 | return previous; 266 | } 267 | } 268 | } 269 | if (value) { 270 | if (word_offset > BITSET_MAX_LENGTH) { 271 | bitset_offset fills = word_offset / BITSET_MAX_LENGTH; 272 | word_offset %= BITSET_MAX_LENGTH; 273 | bitset_resize(bitset, bitset->length + fills); 274 | bitset_word fill = BITSET_CREATE_EMPTY_FILL(BITSET_MAX_LENGTH); 275 | for (bitset_offset i = 0; i < fills; i++) { 276 | bitset->buffer[bitset->length - fills + i] = fill; 277 | } 278 | } 279 | bitset_resize(bitset, bitset->length + 1); 280 | if (word_offset) { 281 | bitset->buffer[bitset->length - 1] = BITSET_CREATE_FILL(word_offset, bit); 282 | } else { 283 | bitset->buffer[bitset->length - 1] = BITSET_CREATE_LITERAL(bit); 284 | } 285 | } 286 | return false; 287 | } 288 | 289 | bitset_t *bitset_new_buffer(const char *buffer, size_t length) { 290 | bitset_t *bitset = bitset_malloc(sizeof(bitset_t)); 291 | if (!bitset) { 292 | bitset_oom(); 293 | } 294 | bitset->buffer = bitset_malloc(length * sizeof(char)); 295 | if (!bitset->buffer) { 296 | bitset_oom(); 297 | } 298 | memcpy(bitset->buffer, buffer, length * sizeof(char)); 299 | bitset->length = length / sizeof(bitset_word); 300 | return bitset; 301 | } 302 | 303 | static int bitset_new_bits_sort(const void *a, const void *b) { 304 | bitset_offset al = *(bitset_offset *)a, bl = *(bitset_offset *)b; 305 | return al > bl ? 1 : -1; 306 | } 307 | 308 | bitset_t *bitset_new_bits(bitset_offset *bits, size_t count) { 309 | bitset_t *bitset = bitset_new(); 310 | if (!count) { 311 | return bitset; 312 | } 313 | unsigned pos = 0, rem, next_rem, i; 314 | bitset_offset word_offset = 0, div, next_div, fills, last_bit; 315 | bitset_word fill = BITSET_CREATE_EMPTY_FILL(BITSET_MAX_LENGTH); 316 | qsort(bits, count, sizeof(bitset_offset), bitset_new_bits_sort); 317 | last_bit = bits[0]; 318 | div = bits[0] / BITSET_LITERAL_LENGTH; 319 | rem = bits[0] % BITSET_LITERAL_LENGTH; 320 | bitset_resize(bitset, 1); 321 | bitset->buffer[0] = 0; 322 | for (i = 1; i < count; i++) { 323 | if (bits[i] == last_bit) { 324 | continue; 325 | } 326 | last_bit = bits[i]; 327 | next_div = bits[i] / BITSET_LITERAL_LENGTH; 328 | next_rem = bits[i] % BITSET_LITERAL_LENGTH; 329 | if (div == word_offset) { 330 | bitset->buffer[pos] |= BITSET_CREATE_LITERAL(rem); 331 | if (div != next_div) { 332 | bitset_resize(bitset, bitset->length + 1); 333 | bitset->buffer[++pos] = 0; 334 | word_offset = div + 1; 335 | } 336 | } else { 337 | bitset_resize(bitset, bitset->length + 1); 338 | if (div == next_div) { 339 | bitset->buffer[pos++] = BITSET_CREATE_EMPTY_FILL(div - word_offset); 340 | bitset->buffer[pos] = BITSET_CREATE_LITERAL(rem); 341 | word_offset = div; 342 | } else { 343 | bitset->buffer[pos++] = BITSET_CREATE_FILL(div - word_offset, rem); 344 | bitset->buffer[pos] = 0; 345 | word_offset = div + 1; 346 | } 347 | } 348 | if (next_div - word_offset > BITSET_MAX_LENGTH) { 349 | fills = (next_div - word_offset) / BITSET_MAX_LENGTH; 350 | bitset_resize(bitset, bitset->length + fills); 351 | for (bitset_offset j = 0; j < fills; j++) { 352 | bitset->buffer[pos++] = fill; 353 | } 354 | word_offset += fills * BITSET_MAX_LENGTH; 355 | } 356 | div = next_div; 357 | rem = next_rem; 358 | } 359 | if (count > 1 && div == bits[i-2] / BITSET_LITERAL_LENGTH) { 360 | bitset->buffer[pos] |= BITSET_CREATE_LITERAL(rem); 361 | } else { 362 | if (div - word_offset > BITSET_MAX_LENGTH) { 363 | fills = (div - word_offset) / BITSET_MAX_LENGTH; 364 | bitset_resize(bitset, bitset->length + fills); 365 | for (bitset_offset j = 0; j < fills; j++) { 366 | bitset->buffer[pos++] = fill; 367 | } 368 | word_offset += fills * BITSET_MAX_LENGTH; 369 | } 370 | bitset->buffer[pos] = BITSET_CREATE_FILL(div - word_offset, rem); 371 | } 372 | return bitset; 373 | } 374 | 375 | bitset_iterator_t *bitset_iterator_new(const bitset_t *bitset) { 376 | bitset_iterator_t *iterator = bitset_malloc(sizeof(bitset_iterator_t)); 377 | if (!iterator) { 378 | bitset_oom(); 379 | } 380 | iterator->length = bitset_count(bitset); 381 | if (!iterator->length) { 382 | iterator->offsets = NULL; 383 | return iterator; 384 | } 385 | iterator->offsets = bitset_malloc(sizeof(bitset_offset) * iterator->length); 386 | if (!iterator->offsets) { 387 | bitset_oom(); 388 | } 389 | bitset_offset offset = 0; 390 | unsigned position; 391 | for (size_t j = 0, k = 0; j < bitset->length; j++) { 392 | if (BITSET_IS_FILL_WORD(bitset->buffer[j])) { 393 | offset += BITSET_GET_LENGTH(bitset->buffer[j]); 394 | position = BITSET_GET_POSITION(bitset->buffer[j]); 395 | if (!position) { 396 | continue; 397 | } 398 | iterator->offsets[k++] = BITSET_LITERAL_LENGTH * offset + position - 1; 399 | } else { 400 | for (size_t x = BITSET_LITERAL_LENGTH; x--; ) { 401 | if (bitset->buffer[j] & (1 << x)) { 402 | iterator->offsets[k++] = BITSET_LITERAL_LENGTH * offset 403 | + BITSET_LITERAL_LENGTH - x - 1; 404 | } 405 | } 406 | } 407 | offset++; 408 | } 409 | return iterator; 410 | } 411 | 412 | void bitset_iterator_free(bitset_iterator_t *iterator) { 413 | if (iterator->length) { 414 | bitset_malloc_free(iterator->offsets); 415 | } 416 | bitset_malloc_free(iterator); 417 | } 418 | 419 | -------------------------------------------------------------------------------- /lib/estimate.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "bitset/malloc.h" 6 | #include "bitset/estimate.h" 7 | 8 | bitset_linear_t *bitset_linear_new(size_t size) { 9 | bitset_linear_t *counter = bitset_malloc(sizeof(bitset_linear_t)); 10 | if (!counter) { 11 | bitset_oom(); 12 | } 13 | counter->count = 0; 14 | size = (size_t)(size / BITSET_LITERAL_LENGTH) + 1; 15 | size_t pow2; 16 | BITSET_NEXT_POW2(pow2, size); 17 | counter->size = pow2; 18 | counter->words = bitset_calloc(1, counter->size * sizeof(bitset_word)); 19 | if (!counter->words) { 20 | bitset_oom(); 21 | } 22 | return counter; 23 | } 24 | 25 | void bitset_linear_add(bitset_linear_t *counter, const bitset_t *bitset) { 26 | bitset_offset offset = 0; 27 | bitset_word word, mask, tmp; 28 | unsigned position; 29 | unsigned offset_mask = counter->size - 1; 30 | for (size_t i = 0; i < bitset->length; i++) { 31 | word = bitset->buffer[i]; 32 | if (BITSET_IS_FILL_WORD(word)) { 33 | offset += BITSET_GET_LENGTH(word); 34 | position = BITSET_GET_POSITION(word); 35 | if (!position) { 36 | continue; 37 | } 38 | mask = BITSET_CREATE_LITERAL(position - 1); 39 | if ((counter->words[offset & offset_mask] & mask) == 0) { 40 | counter->count++; 41 | counter->words[offset & offset_mask] |= mask; 42 | } 43 | } else { 44 | tmp = counter->words[offset & offset_mask]; 45 | counter->words[offset & offset_mask] |= word; 46 | word &= ~tmp; 47 | BITSET_POP_COUNT(counter->count, word); 48 | } 49 | offset++; 50 | } 51 | } 52 | 53 | unsigned bitset_linear_count(const bitset_linear_t *counter) { 54 | return counter->count; 55 | } 56 | 57 | void bitset_linear_free(bitset_linear_t *counter) { 58 | bitset_malloc_free(counter->words); 59 | bitset_malloc_free(counter); 60 | } 61 | 62 | bitset_countn_t *bitset_countn_new(unsigned n, size_t size) { 63 | bitset_countn_t *counter = bitset_malloc(sizeof(bitset_countn_t)); 64 | if (!counter) { 65 | bitset_oom(); 66 | } 67 | assert(n); 68 | counter->n = n; 69 | size = (size_t)(size / BITSET_LITERAL_LENGTH) + 1; 70 | size_t pow2; 71 | BITSET_NEXT_POW2(pow2, size); 72 | counter->size = pow2; 73 | counter->words = bitset_malloc(sizeof(bitset_word *) * (counter->n + 1)); 74 | if (!counter->words) { 75 | bitset_oom(); 76 | } 77 | //Create N+1 uncompressed bitsets 78 | for (size_t i = 0; i <= n; i++) { 79 | counter->words[i] = bitset_calloc(1, counter->size * sizeof(bitset_word)); 80 | if (!counter->words[i]) { 81 | bitset_oom(); 82 | } 83 | } 84 | return counter; 85 | } 86 | 87 | void bitset_countn_add(bitset_countn_t *counter, const bitset_t *bitset) { 88 | bitset_offset offset = 0; 89 | bitset_word word, tmp; 90 | unsigned position; 91 | unsigned offset_mask = counter->size - 1; 92 | for (size_t i = 0; i < bitset->length; i++) { 93 | word = bitset->buffer[i]; 94 | if (BITSET_IS_FILL_WORD(word)) { 95 | offset += BITSET_GET_LENGTH(word); 96 | position = BITSET_GET_POSITION(word); 97 | if (!position) { 98 | continue; 99 | } 100 | word = BITSET_CREATE_LITERAL(position - 1); 101 | } 102 | for (size_t n = 0; n <= counter->n; n++) { 103 | tmp = word & counter->words[n][offset & offset_mask]; 104 | counter->words[n][offset & offset_mask] |= word; 105 | word = tmp; 106 | } 107 | offset++; 108 | } 109 | } 110 | 111 | unsigned bitset_countn_count(const bitset_countn_t *counter) { 112 | unsigned count = 0, nth = counter->n - 1, last = counter->n; 113 | bitset_word word; 114 | //Find bits that occur in the Nth bitset, but not the N+1th bitset 115 | for (size_t offset = 0; offset < counter->size; offset++) { 116 | word = counter->words[nth][offset] & ~counter->words[last][offset]; 117 | if (word) { 118 | BITSET_POP_COUNT(count, word); 119 | } 120 | } 121 | return count; 122 | } 123 | 124 | unsigned *bitset_countn_count_all(const bitset_countn_t *counter) { 125 | unsigned *counts = bitset_calloc(1, sizeof(unsigned) * counter->n); 126 | if (!counts) { 127 | bitset_oom(); 128 | } 129 | bitset_word word; 130 | for (size_t offset = 0; offset < counter->size; offset++) { 131 | for (size_t n = 1; n <= counter->n; n++) { 132 | word = counter->words[n-1][offset] & ~counter->words[n][offset]; 133 | if (word) { 134 | BITSET_POP_COUNT(counts[n-1], word); 135 | } 136 | } 137 | } 138 | return counts; 139 | } 140 | 141 | unsigned *bitset_countn_count_mask(const bitset_countn_t *counter, const bitset_t *mask) { 142 | bitset_word *mask_words = bitset_calloc(1, counter->size * sizeof(bitset_word)); 143 | if (!mask_words) { 144 | bitset_oom(); 145 | } 146 | bitset_offset offset = 0; 147 | bitset_word word, mask_word; 148 | unsigned position; 149 | for (size_t i = 0; i < mask->length; i++) { 150 | mask_word = mask->buffer[i]; 151 | if (BITSET_IS_FILL_WORD(mask_word)) { 152 | offset += BITSET_GET_LENGTH(mask_word); 153 | if (offset >= counter->size) { 154 | offset %= counter->size; 155 | } 156 | position = BITSET_GET_POSITION(mask_word); 157 | if (!position) { 158 | continue; 159 | } 160 | mask_word = BITSET_CREATE_LITERAL(position - 1); 161 | } 162 | mask_words[offset] |= mask_word; 163 | offset++; 164 | if (offset >= counter->size) { 165 | offset -= counter->size; 166 | } 167 | } 168 | unsigned *counts = bitset_calloc(1, sizeof(unsigned) * counter->n); 169 | if (!counts) { 170 | bitset_oom(); 171 | } 172 | for (size_t offset = 0; offset < counter->size; offset++) { 173 | for (size_t n = 1; n <= counter->n; n++) { 174 | word = counter->words[n-1][offset] & ~counter->words[n][offset]; 175 | word &= mask_words[offset]; 176 | BITSET_POP_COUNT(counts[n-1], word); 177 | } 178 | } 179 | bitset_malloc_free(mask_words); 180 | return counts; 181 | } 182 | 183 | void bitset_countn_count_free(unsigned *counts) { 184 | bitset_malloc_free(counts); 185 | } 186 | 187 | void bitset_countn_free(bitset_countn_t *counter) { 188 | for (size_t i = 0; i <= counter->n; i++) { 189 | bitset_malloc_free(counter->words[i]); 190 | } 191 | bitset_malloc_free(counter->words); 192 | bitset_malloc_free(counter); 193 | } 194 | 195 | -------------------------------------------------------------------------------- /lib/operation.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "bitset/malloc.h" 5 | #include "bitset/operation.h" 6 | 7 | bitset_operation_t *bitset_operation_new(bitset_t *bitset) { 8 | bitset_operation_t *operation = bitset_malloc(sizeof(bitset_operation_t)); 9 | if (!operation) { 10 | bitset_oom(); 11 | } 12 | operation->length = 0; 13 | if (bitset) { 14 | bitset_operation_add(operation, bitset, BITSET_OR); 15 | } 16 | return operation; 17 | } 18 | 19 | void bitset_operation_free(bitset_operation_t *operation) { 20 | for (size_t i = 0; i < operation->length; i++) { 21 | if (operation->steps[i]->is_nested) { 22 | if (operation->steps[i]->is_operation) { 23 | bitset_operation_free(operation->steps[i]->data.nested); 24 | } else { 25 | bitset_malloc_free(operation->steps[i]->data.bitset.buffer); 26 | } 27 | } 28 | bitset_malloc_free(operation->steps[i]); 29 | } 30 | bitset_malloc_free(operation->steps); 31 | bitset_malloc_free(operation); 32 | } 33 | 34 | static inline bitset_operation_step_t *bitset_operation_add_step(bitset_operation_t *operation) { 35 | bitset_operation_step_t *step = bitset_malloc(sizeof(bitset_operation_step_t)); 36 | if (!step) { 37 | bitset_oom(); 38 | } 39 | if (operation->length % 2 == 0) { 40 | if (!operation->length) { 41 | operation->steps = bitset_malloc(sizeof(bitset_operation_step_t *) * 2); 42 | } else { 43 | operation->steps = bitset_realloc(operation->steps, sizeof(bitset_operation_step_t *) * operation->length * 2); 44 | } 45 | if (!operation->steps) { 46 | bitset_oom(); 47 | } 48 | } 49 | return operation->steps[operation->length++] = step; 50 | } 51 | 52 | void bitset_operation_add_buffer(bitset_operation_t *operation, 53 | bitset_word *buffer, size_t length, enum bitset_operation_type type) { 54 | if (!length) { 55 | if (type == BITSET_AND && operation->length) { 56 | for (size_t i = 0; i < operation->length; i++) { 57 | bitset_malloc_free(operation->steps[i]); 58 | } 59 | operation->length = 0; 60 | } 61 | return; 62 | } 63 | bitset_operation_step_t *step = bitset_operation_add_step(operation); 64 | step->is_nested = false; 65 | step->is_operation = false; 66 | step->data.bitset.buffer = buffer; 67 | step->data.bitset.length = length; 68 | step->type = type; 69 | } 70 | 71 | void bitset_operation_add(bitset_operation_t *operation, 72 | bitset_t *bitset, enum bitset_operation_type type) { 73 | bitset_operation_add_buffer(operation, bitset->buffer, bitset->length, type); 74 | } 75 | 76 | void bitset_operation_add_nested(bitset_operation_t *operation, bitset_operation_t *nested, 77 | enum bitset_operation_type type) { 78 | bitset_operation_step_t *step = bitset_operation_add_step(operation); 79 | step->is_nested = true; 80 | step->is_operation = true; 81 | step->data.nested = nested; 82 | step->type = type; 83 | } 84 | 85 | static inline bitset_hash_t *bitset_hash_new(size_t buckets) { 86 | bitset_hash_t *hash = bitset_malloc(sizeof(bitset_hash_t)); 87 | if (!hash) { 88 | bitset_oom(); 89 | } 90 | size_t size; 91 | BITSET_NEXT_POW2(size, buckets); 92 | hash->size = size; 93 | hash->count = 0; 94 | hash->buckets = bitset_calloc(1, sizeof(bitset_hash_bucket_t *) * hash->size); 95 | hash->buffer = bitset_malloc(sizeof(bitset_word) * hash->size); 96 | if (!hash->buckets || !hash->buffer) { 97 | bitset_oom(); 98 | } 99 | return hash; 100 | } 101 | 102 | static inline void bitset_hash_free(bitset_hash_t *hash) { 103 | bitset_hash_bucket_t *bucket, *tmp; 104 | for (size_t i = 0; i < hash->size; i++) { 105 | bucket = hash->buckets[i]; 106 | if (BITSET_IS_TAGGED_POINTER(bucket)) { 107 | continue; 108 | } 109 | while (bucket) { 110 | tmp = bucket; 111 | bucket = bucket->next; 112 | bitset_malloc_free(tmp); 113 | } 114 | } 115 | bitset_malloc_free(hash->buckets); 116 | bitset_malloc_free(hash->buffer); 117 | bitset_malloc_free(hash); 118 | } 119 | 120 | static inline bool bitset_hash_insert(bitset_hash_t *hash, bitset_offset offset, bitset_word word) { 121 | unsigned key = offset & (hash->size - 1); 122 | bitset_hash_bucket_t *insert, *bucket = hash->buckets[key]; 123 | bitset_offset off; 124 | if (BITSET_IS_TAGGED_POINTER(bucket)) { 125 | off = BITSET_UINT_FROM_POINTER(bucket); 126 | if (off == offset) { 127 | return false; 128 | } 129 | insert = bitset_malloc(sizeof(bitset_hash_bucket_t)); 130 | if (!insert) { 131 | bitset_oom(); 132 | } 133 | insert->offset = off; 134 | insert->word = (uintptr_t)hash->buffer[key]; 135 | bucket = hash->buckets[key] = insert; 136 | insert = bitset_malloc(sizeof(bitset_hash_bucket_t)); 137 | if (!insert) { 138 | bitset_oom(); 139 | } 140 | insert->offset = offset; 141 | insert->word = word; 142 | insert->next = NULL; 143 | bucket->next = insert; 144 | hash->count++; 145 | return true; 146 | } else if (!bucket) { 147 | #if SIZEOF_VOID_P != BITSET_WORD_BYTES 148 | hash->buckets[key] = (bitset_hash_bucket_t *) BITSET_UINT_IN_POINTER(offset); 149 | hash->buffer[key] = word; 150 | hash->count++; 151 | #else 152 | if (BITSET_UINT_CAN_TAG(offset)) { 153 | hash->buckets[key] = (bitset_hash_bucket_t *) BITSET_UINT_IN_POINTER(offset); 154 | hash->buffer[key] = word; 155 | hash->count++; 156 | } else { 157 | insert = bitset_malloc(sizeof(bitset_hash_bucket_t)); 158 | if (!insert) { 159 | bitset_oom(); 160 | } 161 | insert->offset = offset; 162 | insert->word = word; 163 | insert->next = NULL; 164 | hash->buckets[key] = insert; 165 | } 166 | #endif 167 | return true; 168 | } 169 | for (;;) { 170 | if (bucket->offset == offset) { 171 | return false; 172 | } 173 | if (bucket->next == NULL) { 174 | break; 175 | } 176 | bucket = bucket->next; 177 | } 178 | insert = bitset_malloc(sizeof(bitset_hash_bucket_t)); 179 | if (!insert) { 180 | bitset_oom(); 181 | } 182 | insert->offset = offset; 183 | insert->word = word; 184 | insert->next = NULL; 185 | bucket->next = insert; 186 | hash->count++; 187 | return true; 188 | } 189 | 190 | static inline bitset_word *bitset_hash_get(const bitset_hash_t *hash, bitset_offset offset) { 191 | unsigned key = offset & (hash->size - 1); 192 | bitset_hash_bucket_t *bucket = hash->buckets[key]; 193 | bitset_offset off; 194 | while (bucket) { 195 | if (BITSET_IS_TAGGED_POINTER(bucket)) { 196 | off = BITSET_UINT_FROM_POINTER(bucket); 197 | if (off != offset) { 198 | return NULL; 199 | } 200 | return &hash->buffer[key]; 201 | } 202 | if (bucket->offset == offset) { 203 | return &bucket->word; 204 | } 205 | bucket = bucket->next; 206 | } 207 | return NULL; 208 | } 209 | 210 | static inline bitset_hash_t *bitset_operation_iter(bitset_operation_t *operation) { 211 | bitset_offset word_offset, max = 0, b_max, length, and_offset; 212 | bitset_operation_step_t *step; 213 | bitset_word word = 0, *hashed, and_word; 214 | unsigned position, count = 0, k, j; 215 | int last_k, last_j; 216 | size_t size, start_at; 217 | bitset_hash_t *words, *and_words = NULL; 218 | bitset_t *tmp, *bitset, *and; 219 | 220 | //Recursively flatten nested operations 221 | for (size_t i = 0; i < operation->length; i++) { 222 | if (operation->steps[i]->is_operation) { 223 | tmp = bitset_operation_exec(operation->steps[i]->data.nested); 224 | bitset_operation_free(operation->steps[i]->data.nested); 225 | operation->steps[i]->data.bitset.buffer = tmp->buffer; 226 | operation->steps[i]->data.bitset.length = tmp->length; 227 | operation->steps[i]->is_operation = false; 228 | bitset_malloc_free(tmp); 229 | } 230 | count += operation->steps[i]->data.bitset.length; 231 | b_max = bitset_max(&operation->steps[i]->data.bitset); 232 | max = BITSET_MAX(max, b_max); 233 | } 234 | 235 | //Work out the number of hash buckets to allocate 236 | if (count <= 8) { 237 | size = 16; 238 | } else if (count <= 8388608) { 239 | size = count * 2; 240 | } else { 241 | size = max / BITSET_LITERAL_LENGTH + 2; 242 | while (count < max / 64) { 243 | size /= 2; 244 | max /= 64; 245 | } 246 | size = size <= 16 ? 16 : size > 16777216 ? 16777216 : size; 247 | } 248 | words = bitset_hash_new(size); 249 | start_at = 1; 250 | bitset = &operation->steps[0]->data.bitset; 251 | word_offset = 0; 252 | 253 | //Compute (0 OR (A AND B)) instead of the usual ((0 OR A) AND B) 254 | if (operation->length >= 2 && operation->steps[1]->type == BITSET_AND) { 255 | start_at = 2; 256 | and_offset = 0; 257 | and_word = 0; 258 | and = &operation->steps[1]->data.bitset; 259 | k = 0; 260 | j = 0; 261 | last_k = -1; 262 | last_j = -1; 263 | while (1) { 264 | if (last_j < (int)j && j < and->length) { 265 | if (BITSET_IS_FILL_WORD(and->buffer[j])) { 266 | and_offset += BITSET_GET_LENGTH(and->buffer[j]); 267 | position = BITSET_GET_POSITION(and->buffer[j]); 268 | if (!position) { 269 | j++; 270 | continue; 271 | } 272 | and_word = BITSET_CREATE_LITERAL(position - 1); 273 | } else { 274 | and_word = and->buffer[j]; 275 | } 276 | and_offset++; 277 | last_j = j; 278 | } 279 | if (last_k < (int)k && k < bitset->length) { 280 | if (BITSET_IS_FILL_WORD(bitset->buffer[k])) { 281 | length = BITSET_GET_LENGTH(bitset->buffer[k]); 282 | word_offset += length; 283 | position = BITSET_GET_POSITION(bitset->buffer[k]); 284 | if (!position) { 285 | k++; 286 | continue; 287 | } 288 | word = BITSET_CREATE_LITERAL(position - 1); 289 | } else { 290 | word = bitset->buffer[k]; 291 | } 292 | word_offset++; 293 | last_k = k; 294 | } 295 | if (and_offset < word_offset) { 296 | if (j++ >= and->length) { 297 | break; 298 | } 299 | } else if (word_offset < and_offset) { 300 | if (k++ >= bitset->length) { 301 | break; 302 | } 303 | } else { 304 | word &= and_word; 305 | if (word) { 306 | bitset_hash_insert(words, word_offset, word); 307 | } 308 | j++; 309 | k++; 310 | if (j >= and->length && k >= bitset->length) { 311 | break; 312 | } 313 | } 314 | } 315 | } else { 316 | //Populate the offset=>word hash (0 OR A) 317 | for (size_t i = 0; i < bitset->length; i++) { 318 | word = bitset->buffer[i]; 319 | if (BITSET_IS_FILL_WORD(word)) { 320 | length = BITSET_GET_LENGTH(word); 321 | word_offset += length; 322 | position = BITSET_GET_POSITION(word); 323 | if (!position) { 324 | continue; 325 | } 326 | word = BITSET_CREATE_LITERAL(position - 1); 327 | } 328 | word_offset++; 329 | bitset_hash_insert(words, word_offset, word); 330 | } 331 | } 332 | 333 | //Apply the remaining steps in the operation 334 | for (size_t i = start_at; i < operation->length; i++) { 335 | step = operation->steps[i]; 336 | bitset = &step->data.bitset; 337 | word_offset = 0; 338 | if (step->type == BITSET_AND) { 339 | and_words = bitset_hash_new(words->size); 340 | for (size_t j = 0; j < bitset->length; j++) { 341 | word = bitset->buffer[j]; 342 | if (BITSET_IS_FILL_WORD(word)) { 343 | length = BITSET_GET_LENGTH(word); 344 | word_offset += length; 345 | position = BITSET_GET_POSITION(word); 346 | if (!position) { 347 | continue; 348 | } 349 | word = BITSET_CREATE_LITERAL(position - 1); 350 | } 351 | word_offset++; 352 | hashed = bitset_hash_get(words, word_offset); 353 | if (hashed && *hashed) { 354 | word &= *hashed; 355 | if (word) { 356 | bitset_hash_insert(and_words, word_offset, word); 357 | } 358 | } 359 | } 360 | bitset_hash_free(words); 361 | words = and_words; 362 | } else { 363 | for (size_t j = 0; j < bitset->length; j++) { 364 | word = bitset->buffer[j]; 365 | if (BITSET_IS_FILL_WORD(word)) { 366 | length = BITSET_GET_LENGTH(word); 367 | word_offset += length; 368 | position = BITSET_GET_POSITION(word); 369 | if (!position) { 370 | continue; 371 | } 372 | word = BITSET_CREATE_LITERAL(position - 1); 373 | } 374 | word_offset++; 375 | hashed = bitset_hash_get(words, word_offset); 376 | if (hashed) { 377 | switch (step->type) { 378 | case BITSET_OR: *hashed |= word; break; 379 | case BITSET_ANDNOT: *hashed &= ~word; break; 380 | case BITSET_XOR: *hashed ^= word; break; 381 | default: break; 382 | } 383 | } else if (step->type != BITSET_ANDNOT) { 384 | bitset_hash_insert(words, word_offset, word); 385 | } 386 | } 387 | } 388 | } 389 | return words; 390 | } 391 | 392 | static int bitset_operation_quick_sort(const void *a, const void *b) { 393 | bitset_offset a_offset = *(bitset_offset *)a; 394 | bitset_offset b_offset = *(bitset_offset *)b; 395 | return a_offset < b_offset ? -1 : a_offset > b_offset; 396 | } 397 | 398 | static inline void bitset_operation_insertion_sort(bitset_offset *offsets, size_t count) { 399 | for (size_t i = 0, j; i < count; ++i) { 400 | for (j = i; j && offsets[j-1] > offsets[j]; j--) { 401 | bitset_offset tmp = offsets[j]; 402 | offsets[j] = offsets[j-1]; 403 | offsets[j-1] = tmp; 404 | } 405 | } 406 | } 407 | 408 | static inline unsigned char bitset_fls(bitset_word word) { 409 | static char table[64] = { 410 | 32, 31, 0, 16, 0, 30, 3, 0, 15, 0, 0, 0, 29, 10, 2, 0, 411 | 0, 0, 12, 14, 21, 0, 19, 0, 0, 28, 0, 25, 0, 9, 1, 0, 412 | 17, 0, 4, 0, 0, 0, 11, 0, 13, 22, 20, 0, 26, 0, 0, 18, 413 | 5, 0, 0, 23, 0, 27, 0, 6, 0, 24, 7, 0, 8, 0, 0, 0 414 | }; 415 | word = word | (word >> 1); 416 | word = word | (word >> 2); 417 | word = word | (word >> 4); 418 | word = word | (word >> 8); 419 | word = word | (word >> 16); 420 | word = (word << 3) - word; 421 | word = (word << 8) - word; 422 | word = (word << 8) - word; 423 | word = (word << 8) - word; 424 | return table[word >> 26] - 1; 425 | } 426 | 427 | bitset_t *bitset_operation_exec(bitset_operation_t *operation) { 428 | if (!operation->length) { 429 | return bitset_new(); 430 | } else if (operation->length == 1 && !operation->steps[0]->is_operation) { 431 | return bitset_copy(&operation->steps[0]->data.bitset); 432 | } 433 | bitset_hash_t *words = bitset_operation_iter(operation); 434 | bitset_hash_bucket_t *bucket; 435 | bitset_t *result = bitset_new(); 436 | bitset_offset word_offset = 0, fills, offset; 437 | bitset_word word, *hashed, fill = BITSET_CREATE_EMPTY_FILL(BITSET_MAX_LENGTH); 438 | if (!words->count) { 439 | bitset_hash_free(words); 440 | return result; 441 | } 442 | bitset_offset *offsets = bitset_malloc(sizeof(bitset_offset) * words->count); 443 | if (!offsets) { 444 | bitset_oom(); 445 | } 446 | for (size_t i = 0, j = 0; i < words->size; i++) { 447 | bucket = words->buckets[i]; 448 | if (BITSET_IS_TAGGED_POINTER(bucket)) { 449 | offsets[j++] = BITSET_UINT_FROM_POINTER(bucket); 450 | continue; 451 | } 452 | while (bucket) { 453 | offsets[j++] = bucket->offset; 454 | bucket = bucket->next; 455 | } 456 | } 457 | if (words->count < 64) { 458 | bitset_operation_insertion_sort(offsets, words->count); 459 | } else { 460 | qsort(offsets, words->count, sizeof(bitset_offset), bitset_operation_quick_sort); 461 | } 462 | for (size_t i = 0, pos = 0; i < words->count; i++) { 463 | offset = offsets[i]; 464 | hashed = bitset_hash_get(words, offset); 465 | word = *hashed; 466 | if (!word) continue; 467 | if (offset - word_offset == 1) { 468 | bitset_resize(result, result->length + 1); 469 | result->buffer[pos++] = word; 470 | } else { 471 | if (offset - word_offset > BITSET_MAX_LENGTH) { 472 | fills = (offset - word_offset) / BITSET_MAX_LENGTH; 473 | bitset_resize(result, result->length + fills); 474 | for (bitset_offset i = 0; i < fills; i++) { 475 | result->buffer[pos++] = fill; 476 | } 477 | word_offset += fills * BITSET_MAX_LENGTH; 478 | } 479 | if (BITSET_IS_POW2(word)) { 480 | bitset_resize(result, result->length + 1); 481 | result->buffer[pos++] = BITSET_CREATE_FILL(offset - word_offset - 1, 482 | bitset_fls(word)); 483 | } else { 484 | bitset_resize(result, result->length + 2); 485 | result->buffer[pos++] = BITSET_CREATE_EMPTY_FILL(offset - word_offset - 1); 486 | result->buffer[pos++] = word; 487 | } 488 | } 489 | word_offset = offset; 490 | } 491 | bitset_malloc_free(offsets); 492 | bitset_hash_free(words); 493 | return result; 494 | } 495 | 496 | bitset_offset bitset_operation_count(bitset_operation_t *operation) { 497 | bitset_offset count = 0; 498 | bitset_hash_t *words = bitset_operation_iter(operation); 499 | for (size_t i = 0; i < words->size; i++) { 500 | bitset_hash_bucket_t *bucket = words->buckets[i]; 501 | if (BITSET_IS_TAGGED_POINTER(bucket)) { 502 | bitset_word word = words->buffer[i]; 503 | BITSET_POP_COUNT(count, word); 504 | continue; 505 | } 506 | while (bucket) { 507 | BITSET_POP_COUNT(count, bucket->word); 508 | bucket = bucket->next; 509 | } 510 | } 511 | bitset_hash_free(words); 512 | return count; 513 | } 514 | 515 | -------------------------------------------------------------------------------- /lib/vector.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "bitset/malloc.h" 8 | #include "bitset/vector.h" 9 | 10 | bitset_vector_t *bitset_vector_new() { 11 | bitset_vector_t *vector = bitset_malloc(sizeof(bitset_vector_t)); 12 | if (!vector) { 13 | bitset_oom(); 14 | } 15 | vector->buffer = bitset_malloc(sizeof(char)); 16 | if (!vector->buffer) { 17 | bitset_oom(); 18 | } 19 | vector->tail_offset = 0; 20 | vector->size = 1; 21 | vector->length = 0; 22 | return vector; 23 | } 24 | 25 | void bitset_vector_free(bitset_vector_t *vector) { 26 | bitset_malloc_free(vector->buffer); 27 | bitset_malloc_free(vector); 28 | } 29 | 30 | bitset_vector_t *bitset_vector_copy(const bitset_vector_t *vector) { 31 | bitset_vector_t *copy = bitset_vector_new(); 32 | if (vector->length) { 33 | copy->buffer = bitset_realloc(copy->buffer, sizeof(char) * vector->length); 34 | if (!copy->buffer) { 35 | bitset_oom(); 36 | } 37 | memcpy(copy->buffer, vector->buffer, vector->length); 38 | copy->length = copy->size = vector->length; 39 | copy->tail_offset = vector->tail_offset; 40 | } 41 | return copy; 42 | } 43 | 44 | void bitset_vector_resize(bitset_vector_t *vector, size_t length) { 45 | size_t new_size = vector->size; 46 | while (new_size < length) { 47 | new_size *= 2; 48 | } 49 | if (new_size > vector->size) { 50 | vector->buffer = bitset_realloc(vector->buffer, new_size * sizeof(char)); 51 | if (!vector->buffer) { 52 | bitset_oom(); 53 | } 54 | vector->size = new_size; 55 | } 56 | vector->length = length; 57 | } 58 | 59 | char *bitset_vector_export(const bitset_vector_t *vector) { 60 | return vector->buffer; 61 | } 62 | 63 | size_t bitset_vector_length(const bitset_vector_t *vector) { 64 | return vector->length; 65 | } 66 | 67 | void bitset_vector_init(bitset_vector_t *vector) { 68 | char *buffer = vector->buffer; 69 | bitset_t bitset; 70 | vector->tail_offset = 0; 71 | while (buffer < vector->buffer + vector->length) { 72 | buffer = bitset_vector_advance(buffer, &bitset, &vector->tail_offset); 73 | } 74 | } 75 | 76 | bitset_vector_t *bitset_vector_import(const char *buffer, size_t length) { 77 | bitset_vector_t *vector = bitset_vector_new(); 78 | if (length) { 79 | bitset_vector_resize(vector, length); 80 | if (buffer) { 81 | memcpy(vector->buffer, buffer, length); 82 | bitset_vector_init(vector); 83 | } 84 | } 85 | return vector; 86 | } 87 | 88 | static inline size_t bitset_encoded_length_required_bytes(size_t length) { 89 | return (length >= (1 << 15)) * 2 + 2; 90 | } 91 | 92 | static inline void bitset_encoded_length_bytes(char *buffer, size_t length) { 93 | if (length < (1 << 15)) { 94 | buffer[0] = (unsigned char)(length >> 8); 95 | buffer[1] = (unsigned char)length; 96 | } else { 97 | buffer[0] = 0x80 | (unsigned char)(length >> 24); 98 | buffer[1] = (unsigned char)(length >> 16); 99 | buffer[2] = (unsigned char)(length >> 8); 100 | buffer[3] = (unsigned char)length; 101 | } 102 | } 103 | 104 | static inline size_t bitset_encoded_length_size(const char *buffer) { 105 | return ((buffer[0] & 0x80) != 0) * 2 + 2; 106 | } 107 | 108 | static inline size_t bitset_encoded_length(const char *buffer) { 109 | size_t length; 110 | if (buffer[0] & 0x80) { 111 | length = (((unsigned char)buffer[0] & 0x7F) << 24); 112 | length += ((unsigned char)buffer[1] << 16); 113 | length += ((unsigned char)buffer[2] << 8); 114 | length += (unsigned char)buffer[3]; 115 | } else { 116 | length = (((unsigned char)buffer[0] & 0x7F) << 8); 117 | length += (unsigned char)buffer[1]; 118 | } 119 | return length; 120 | } 121 | 122 | char *bitset_vector_advance(char *buffer, bitset_t *bitset, unsigned *offset) { 123 | *offset += bitset_encoded_length(buffer); 124 | buffer += bitset_encoded_length_size(buffer); 125 | bitset->length = bitset_encoded_length(buffer); 126 | buffer += bitset_encoded_length_size(buffer); 127 | bitset->buffer = (bitset_word *) buffer; 128 | return buffer + bitset->length * sizeof(bitset_word); 129 | } 130 | 131 | static inline char *bitset_vector_encode(bitset_vector_t *vector, const bitset_t *bitset, unsigned offset) { 132 | size_t length_bytes = bitset_encoded_length_required_bytes(bitset->length); 133 | size_t offset_bytes = bitset_encoded_length_required_bytes(offset); 134 | size_t current_length = vector->length; 135 | bitset_vector_resize(vector, vector->length + length_bytes + offset_bytes + bitset->length * sizeof(bitset_word)); 136 | char *buffer = vector->buffer + current_length; 137 | bitset_encoded_length_bytes(buffer, offset); 138 | buffer += offset_bytes; 139 | bitset_encoded_length_bytes(buffer, bitset->length); 140 | buffer += length_bytes; 141 | if (bitset->length) { 142 | memcpy(buffer, bitset->buffer, bitset->length * sizeof(bitset_word)); 143 | } 144 | return buffer + bitset->length * sizeof(bitset_word); 145 | } 146 | 147 | void bitset_vector_push(bitset_vector_t *vector, const bitset_t *bitset, unsigned offset) { 148 | if (vector->length && vector->tail_offset >= offset) { 149 | BITSET_FATAL("bitset vectors are append-only"); 150 | } 151 | bitset_vector_encode(vector, bitset, offset - vector->tail_offset); 152 | vector->tail_offset = offset; 153 | } 154 | 155 | void bitset_vector_concat(bitset_vector_t *vector, const bitset_vector_t *next, unsigned offset, unsigned start, unsigned end) { 156 | if (vector->length && vector->tail_offset >= offset) { 157 | BITSET_FATAL("bitset vectors are append-only"); 158 | } 159 | 160 | unsigned current_offset = 0; 161 | bitset_t bitset; 162 | 163 | char *buffer, *c_buffer = next->buffer, *c_start, *c_end = next->buffer + next->length; 164 | while (c_buffer < c_end) { 165 | c_buffer = bitset_vector_advance(c_buffer, &bitset, ¤t_offset); 166 | if (current_offset >= start && (!end || current_offset < end)) { 167 | c_start = c_buffer; 168 | 169 | //Copy the initial bitset from c 170 | buffer = bitset_vector_encode(vector, &bitset, offset + current_offset - vector->tail_offset); 171 | 172 | //Look for a slice end point 173 | if (end != BITSET_VECTOR_END && c_end > c_start) { 174 | do { 175 | c_end = c_buffer; 176 | if (c_end == next->buffer + next->length) { 177 | break; 178 | } 179 | c_buffer = bitset_vector_advance(c_buffer, &bitset, ¤t_offset); 180 | vector->tail_offset = current_offset + offset; 181 | } while (current_offset < end); 182 | } else { 183 | vector->tail_offset = next->tail_offset + offset; 184 | } 185 | 186 | //Concat the rest of the vector 187 | if (c_end > c_start) { 188 | uintptr_t buf_offset = buffer - vector->buffer; 189 | bitset_vector_resize(vector, vector->length + (c_end - c_start)); 190 | memcpy(vector->buffer + buf_offset, c_start, c_end - c_start); 191 | } 192 | 193 | break; 194 | } 195 | } 196 | } 197 | 198 | unsigned bitset_vector_bitsets(const bitset_vector_t *vector) { 199 | unsigned count = 0, offset; 200 | bitset_t *bitset; 201 | BITSET_VECTOR_FOREACH(vector, bitset, offset) { 202 | count++; 203 | } 204 | return count; 205 | } 206 | 207 | void bitset_vector_cardinality(const bitset_vector_t *vector, unsigned *raw, unsigned *unique) { 208 | unsigned offset; 209 | bitset_t *bitset; 210 | *raw = 0; 211 | BITSET_VECTOR_FOREACH(vector, bitset, offset) { 212 | *raw += bitset_count(bitset); 213 | } 214 | if (unique) { 215 | if (*raw) { 216 | bitset_linear_t *counter = bitset_linear_new(*raw * 100); 217 | BITSET_VECTOR_FOREACH(vector, bitset, offset) { 218 | bitset_linear_add(counter, bitset); 219 | } 220 | *unique = bitset_linear_count(counter); 221 | bitset_linear_free(counter); 222 | } else { 223 | *unique = 0; 224 | } 225 | } 226 | } 227 | 228 | bitset_t *bitset_vector_merge(const bitset_vector_t *vector) { 229 | unsigned offset; 230 | bitset_t *bitset; 231 | bitset_operation_t *operation = bitset_operation_new(NULL); 232 | BITSET_VECTOR_FOREACH(vector, bitset, offset) { 233 | bitset_operation_add(operation, bitset, BITSET_OR); 234 | } 235 | bitset = bitset_operation_exec(operation); 236 | bitset_operation_free(operation); 237 | return bitset; 238 | } 239 | 240 | static inline void bitset_vector_start_end(bitset_vector_t *vector, unsigned *start, unsigned *end) { 241 | if (!vector->length) { 242 | *start = 0; 243 | *end = 0; 244 | return; 245 | } 246 | bitset_t bitset; 247 | bitset_vector_advance(vector->buffer, &bitset, start); 248 | *end = vector->tail_offset; 249 | } 250 | 251 | bitset_vector_operation_t *bitset_vector_operation_new(bitset_vector_t *vector) { 252 | bitset_vector_operation_t *operation = bitset_malloc(sizeof(bitset_vector_operation_t)); 253 | if (!operation) { 254 | bitset_oom(); 255 | } 256 | operation->length = operation->max = 0; 257 | operation->min = UINT_MAX; 258 | if (vector) { 259 | bitset_vector_operation_add(operation, vector, BITSET_OR); 260 | } 261 | return operation; 262 | } 263 | 264 | void bitset_vector_operation_free(bitset_vector_operation_t *operation) { 265 | if (operation->length) { 266 | for (size_t i = 0; i < operation->length; i++) { 267 | if (operation->steps[i]->is_nested) { 268 | if (operation->steps[i]->is_operation) { 269 | bitset_vector_operation_free(operation->steps[i]->data.operation); 270 | } else { 271 | bitset_vector_free(operation->steps[i]->data.vector); 272 | } 273 | } 274 | bitset_malloc_free(operation->steps[i]); 275 | } 276 | bitset_malloc_free(operation->steps); 277 | } 278 | bitset_malloc_free(operation); 279 | } 280 | 281 | void bitset_vector_operation_free_operands(bitset_vector_operation_t *operation) { 282 | if (operation->length) { 283 | for (size_t i = 0; i < operation->length; i++) { 284 | if (operation->steps[i]->is_nested) { 285 | if (operation->steps[i]->is_operation) { 286 | bitset_vector_operation_free_operands(operation->steps[i]->data.operation); 287 | } 288 | } else { 289 | if (operation->steps[i]->data.vector) { 290 | bitset_vector_free(operation->steps[i]->data.vector); 291 | } 292 | operation->steps[i]->data.vector = NULL; 293 | } 294 | } 295 | } 296 | } 297 | 298 | static inline bitset_vector_operation_step_t * 299 | bitset_vector_operation_add_step(bitset_vector_operation_t *operation) { 300 | bitset_vector_operation_step_t *step = bitset_malloc(sizeof(bitset_vector_operation_step_t)); 301 | if (!step) { 302 | bitset_oom(); 303 | } 304 | if (operation->length % 2 == 0) { 305 | if (!operation->length) { 306 | operation->steps = bitset_malloc(sizeof(bitset_vector_operation_step_t *) * 2); 307 | } else { 308 | operation->steps = bitset_realloc(operation->steps, sizeof(bitset_vector_operation_step_t *) * operation->length * 2); 309 | } 310 | if (!operation->steps) { 311 | bitset_oom(); 312 | } 313 | } 314 | operation->steps[operation->length++] = step; 315 | return step; 316 | } 317 | 318 | void bitset_vector_operation_add(bitset_vector_operation_t *operation, 319 | bitset_vector_t *vector, enum bitset_operation_type type) { 320 | if (!vector->length) { 321 | return; 322 | } 323 | bitset_vector_operation_step_t *step = bitset_vector_operation_add_step(operation); 324 | step->is_nested = false; 325 | step->is_operation = false; 326 | step->data.vector = vector; 327 | step->type = type; 328 | unsigned start = 0, end = 0; 329 | bitset_vector_start_end(vector, &start, &end); 330 | operation->min = BITSET_MIN(operation->min, start); 331 | operation->max = BITSET_MAX(operation->max, end); 332 | } 333 | 334 | void bitset_vector_operation_add_nested(bitset_vector_operation_t *operation, 335 | bitset_vector_operation_t *nested, enum bitset_operation_type type) { 336 | bitset_vector_operation_step_t *step = bitset_vector_operation_add_step(operation); 337 | step->is_nested = true; 338 | step->is_operation = true; 339 | step->data.operation = nested; 340 | step->type = type; 341 | operation->min = BITSET_MIN(operation->min, nested->min); 342 | operation->max = BITSET_MAX(operation->max, nested->max); 343 | } 344 | 345 | void bitset_vector_operation_add_data(bitset_vector_operation_t *operation, 346 | void *data, enum bitset_operation_type type) { 347 | bitset_vector_operation_step_t *step = bitset_vector_operation_add_step(operation); 348 | step->is_nested = false; 349 | step->is_operation = false; 350 | step->data.vector = NULL; 351 | step->type = type; 352 | step->userdata = data; 353 | } 354 | 355 | void bitset_vector_operation_resolve_data(bitset_vector_operation_t *operation, 356 | bitset_vector_t *(*resolve_fn)(void *, void *), void *context) { 357 | unsigned start, end; 358 | if (operation->length) { 359 | for (size_t j = 0; j < operation->length; j++) { 360 | start = 0; 361 | end = 0; 362 | if (operation->steps[j]->is_operation) { 363 | bitset_vector_operation_resolve_data(operation->steps[j]->data.operation, resolve_fn, context); 364 | } else if (operation->steps[j]->userdata) { 365 | bitset_vector_t *vector = resolve_fn(operation->steps[j]->userdata, context); 366 | operation->steps[j]->data.vector = vector; 367 | if (vector && vector->length) { 368 | bitset_vector_start_end(vector, &start, &end); 369 | operation->min = BITSET_MIN(operation->min, start); 370 | operation->max = BITSET_MAX(operation->max, end); 371 | } 372 | } 373 | } 374 | } 375 | } 376 | 377 | void bitset_vector_operation_free_data(bitset_vector_operation_t *operation, void (*free_fn)(void *)) { 378 | if (operation->length) { 379 | for (size_t j = 0; j < operation->length; j++) { 380 | if (operation->steps[j]->is_operation) { 381 | bitset_vector_operation_free_data(operation->steps[j]->data.operation, free_fn); 382 | } else if (operation->steps[j]->userdata) { 383 | free_fn(operation->steps[j]->userdata); 384 | } 385 | } 386 | } 387 | } 388 | 389 | bitset_vector_t *bitset_vector_operation_exec(bitset_vector_operation_t *operation) { 390 | if (!operation->length) { 391 | return bitset_vector_new(); 392 | } else if (operation->length == 1 && !operation->steps[0]->is_operation) { 393 | return bitset_vector_copy(operation->steps[0]->data.vector); 394 | } 395 | 396 | bitset_vector_t *vector, *result; 397 | bitset_t *bitset_ptr, bitset; 398 | bitset_operation_t *nested; 399 | unsigned offset; 400 | char *buffer, *next, *bitset_buffer; 401 | size_t bitset_length, buckets, key, copy_length, offset_bytes; 402 | void **bucket, **and_bucket; 403 | enum bitset_operation_type type; 404 | 405 | //Recursively flatten nested operations 406 | for (size_t i = 0; i < operation->length; i++) { 407 | if (operation->steps[i]->is_operation) { 408 | vector = bitset_vector_operation_exec(operation->steps[i]->data.operation); 409 | bitset_vector_operation_free(operation->steps[i]->data.operation); 410 | operation->steps[i]->data.vector = vector; 411 | operation->steps[i]->is_operation = false; 412 | } 413 | } 414 | 415 | //Prepare the result vector 416 | result = bitset_vector_new(); 417 | 418 | //Prepare hash buckets 419 | buckets = operation->max - operation->min + 1; 420 | bucket = bitset_calloc(1, sizeof(void*) * buckets); 421 | if (!bucket) { 422 | bitset_oom(); 423 | } 424 | 425 | //OR the first vector 426 | vector = operation->steps[0]->data.vector; 427 | 428 | buffer = vector->buffer; 429 | offset = 0; 430 | while (buffer < vector->buffer + vector->length) { 431 | next = bitset_vector_advance(buffer, &bitset, &offset); 432 | assert(offset >= operation->min && offset <= operation->max); 433 | bucket[offset - operation->min] = buffer + bitset_encoded_length_size(buffer); 434 | buffer = next; 435 | } 436 | 437 | for (size_t i = 1; i < operation->length; i++) { 438 | 439 | type = operation->steps[i]->type; 440 | vector = operation->steps[i]->data.vector; 441 | 442 | if (type == BITSET_AND) { 443 | 444 | and_bucket = bitset_calloc(1, sizeof(void*) * buckets); 445 | if (!and_bucket) { 446 | bitset_oom(); 447 | } 448 | if (vector) { 449 | buffer = vector->buffer; 450 | offset = 0; 451 | while (buffer < vector->buffer + vector->length) { 452 | next = bitset_vector_advance(buffer, &bitset, &offset); 453 | assert(offset >= operation->min && offset <= operation->max); 454 | key = offset - operation->min; 455 | if (bucket[key]) { 456 | if (BITSET_IS_TAGGED_POINTER(bucket[key])) { 457 | nested = (bitset_operation_t *) BITSET_UNTAG_POINTER(bucket[key]); 458 | } else { 459 | bitset_buffer = bucket[key]; 460 | bitset_length = bitset_encoded_length(bitset_buffer); 461 | bitset_buffer += bitset_encoded_length_size(bitset_buffer); 462 | nested = bitset_operation_new(NULL); 463 | bitset_operation_add_buffer(nested, (bitset_word*)bitset_buffer, bitset_length, BITSET_OR); 464 | } 465 | bitset_operation_add_buffer(nested, bitset.buffer, bitset.length, BITSET_AND); 466 | and_bucket[key] = (void *) BITSET_TAG_POINTER(nested); 467 | } 468 | buffer = next; 469 | } 470 | } 471 | for (size_t j = 0; j < buckets; j++) { 472 | if (and_bucket[j] && BITSET_IS_TAGGED_POINTER(bucket[j])) { 473 | nested = (bitset_operation_t *) BITSET_UNTAG_POINTER(bucket[j]); 474 | bitset_operation_free(nested); 475 | } 476 | } 477 | bitset_malloc_free(bucket); 478 | bucket = and_bucket; 479 | 480 | } else { 481 | 482 | buffer = vector->buffer; 483 | offset = 0; 484 | while (buffer < vector->buffer + vector->length) { 485 | next = bitset_vector_advance(buffer, &bitset, &offset); 486 | assert(offset >= operation->min && offset <= operation->max); 487 | key = offset - operation->min; 488 | if (BITSET_IS_TAGGED_POINTER(bucket[key])) { 489 | nested = (bitset_operation_t *) BITSET_UNTAG_POINTER(bucket[key]); 490 | bitset_operation_add_buffer(nested, bitset.buffer, bitset.length, type); 491 | } else if (bucket[key]) { 492 | bitset_buffer = bucket[key]; 493 | bitset_length = bitset_encoded_length(bitset_buffer); 494 | bitset_buffer += bitset_encoded_length_size(bitset_buffer); 495 | nested = bitset_operation_new(NULL); 496 | bitset_operation_add_buffer(nested, (bitset_word*)bitset_buffer, bitset_length, BITSET_OR); 497 | bucket[key] = (void *) BITSET_TAG_POINTER(nested); 498 | bitset_operation_add_buffer(nested, bitset.buffer, bitset.length, type); 499 | } else { 500 | bucket[key] = buffer + bitset_encoded_length_size(buffer); 501 | } 502 | buffer = next; 503 | } 504 | } 505 | } 506 | 507 | //Prepare the result vector 508 | offset = 0; 509 | buffer = result->buffer; 510 | for (size_t i = 0; i < buckets; i++) { 511 | if (BITSET_IS_TAGGED_POINTER(bucket[i])) { 512 | nested = (bitset_operation_t *) BITSET_UNTAG_POINTER(bucket[i]); 513 | bitset_ptr = bitset_operation_exec(nested); 514 | if (bitset_ptr->length) { 515 | buffer = bitset_vector_encode(result, bitset_ptr, operation->min + i - offset); 516 | offset = operation->min + i; 517 | } 518 | bitset_free(bitset_ptr); 519 | bitset_operation_free(nested); 520 | } else if (bucket[i]) { 521 | offset_bytes = bitset_encoded_length_required_bytes(operation->min + i - offset); 522 | bitset_length = bitset_encoded_length(bucket[i]); 523 | copy_length = bitset_encoded_length_required_bytes(bitset_length) + bitset_length * sizeof(bitset_word); 524 | uintptr_t buf_offset = buffer - result->buffer; 525 | bitset_vector_resize(result, result->length + offset_bytes + copy_length); 526 | buffer = result->buffer + buf_offset; 527 | bitset_encoded_length_bytes(buffer, operation->min + i - offset); 528 | buffer += offset_bytes; 529 | memcpy(buffer, bucket[i], copy_length); 530 | buffer += copy_length; 531 | offset = operation->min + i; 532 | } 533 | } 534 | 535 | bitset_malloc_free(bucket); 536 | 537 | return result; 538 | } 539 | 540 | -------------------------------------------------------------------------------- /m4/ax_cc_maxopt.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_cc_maxopt.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CC_MAXOPT 8 | # 9 | # DESCRIPTION 10 | # 11 | # Try to turn on "good" C optimization flags for various compilers and 12 | # architectures, for some definition of "good". (In our case, good for 13 | # FFTW and hopefully for other scientific codes. Modify as needed.) 14 | # 15 | # The user can override the flags by setting the CFLAGS environment 16 | # variable. The user can also specify --enable-portable-binary in order to 17 | # disable any optimization flags that might result in a binary that only 18 | # runs on the host architecture. 19 | # 20 | # Note also that the flags assume that ANSI C aliasing rules are followed 21 | # by the code (e.g. for gcc's -fstrict-aliasing), and that floating-point 22 | # computations can be re-ordered as needed. 23 | # 24 | # Requires macros: AX_CHECK_COMPILE_FLAG, AX_COMPILER_VENDOR, 25 | # AX_GCC_ARCHFLAG, AX_GCC_X86_CPUID. 26 | # 27 | # LICENSE 28 | # 29 | # Copyright (c) 2008 Steven G. Johnson 30 | # Copyright (c) 2008 Matteo Frigo 31 | # 32 | # This program is free software: you can redistribute it and/or modify it 33 | # under the terms of the GNU General Public License as published by the 34 | # Free Software Foundation, either version 3 of the License, or (at your 35 | # option) any later version. 36 | # 37 | # This program is distributed in the hope that it will be useful, but 38 | # WITHOUT ANY WARRANTY; without even the implied warranty of 39 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 40 | # Public License for more details. 41 | # 42 | # You should have received a copy of the GNU General Public License along 43 | # with this program. If not, see . 44 | # 45 | # As a special exception, the respective Autoconf Macro's copyright owner 46 | # gives unlimited permission to copy, distribute and modify the configure 47 | # scripts that are the output of Autoconf when processing the Macro. You 48 | # need not follow the terms of the GNU General Public License when using 49 | # or distributing such scripts, even though portions of the text of the 50 | # Macro appear in them. The GNU General Public License (GPL) does govern 51 | # all other use of the material that constitutes the Autoconf Macro. 52 | # 53 | # This special exception to the GPL applies to versions of the Autoconf 54 | # Macro released by the Autoconf Archive. When you make and distribute a 55 | # modified version of the Autoconf Macro, you may extend this special 56 | # exception to the GPL to apply to your modified version as well. 57 | 58 | #serial 13 59 | 60 | AC_DEFUN([AX_CC_MAXOPT], 61 | [ 62 | AC_REQUIRE([AC_PROG_CC]) 63 | AC_REQUIRE([AX_COMPILER_VENDOR]) 64 | AC_REQUIRE([AC_CANONICAL_HOST]) 65 | 66 | AC_ARG_ENABLE(portable-binary, [AS_HELP_STRING([--enable-portable-binary], [disable compiler optimizations that would produce unportable binaries])], 67 | acx_maxopt_portable=$enableval, acx_maxopt_portable=no) 68 | 69 | # Try to determine "good" native compiler flags if none specified via CFLAGS 70 | if test "$ac_test_CFLAGS" != "set"; then 71 | CFLAGS="" 72 | case $ax_cv_c_compiler_vendor in 73 | dec) CFLAGS="-newc -w0 -O5 -ansi_alias -ansi_args -fp_reorder -tune host" 74 | if test "x$acx_maxopt_portable" = xno; then 75 | CFLAGS="$CFLAGS -arch host" 76 | fi;; 77 | 78 | sun) CFLAGS="-native -fast -xO5 -dalign" 79 | if test "x$acx_maxopt_portable" = xyes; then 80 | CFLAGS="$CFLAGS -xarch=generic" 81 | fi;; 82 | 83 | hp) CFLAGS="+Oall +Optrs_ansi +DSnative" 84 | if test "x$acx_maxopt_portable" = xyes; then 85 | CFLAGS="$CFLAGS +DAportable" 86 | fi;; 87 | 88 | ibm) if test "x$acx_maxopt_portable" = xno; then 89 | xlc_opt="-qarch=auto -qtune=auto" 90 | else 91 | xlc_opt="-qtune=auto" 92 | fi 93 | AX_CHECK_COMPILE_FLAG($xlc_opt, 94 | CFLAGS="-O3 -qansialias -w $xlc_opt", 95 | [CFLAGS="-O3 -qansialias -w" 96 | echo "******************************************************" 97 | echo "* You seem to have the IBM C compiler. It is *" 98 | echo "* recommended for best performance that you use: *" 99 | echo "* *" 100 | echo "* CFLAGS=-O3 -qarch=xxx -qtune=xxx -qansialias -w *" 101 | echo "* ^^^ ^^^ *" 102 | echo "* where xxx is pwr2, pwr3, 604, or whatever kind of *" 103 | echo "* CPU you have. (Set the CFLAGS environment var. *" 104 | echo "* and re-run configure.) For more info, man cc. *" 105 | echo "******************************************************"]) 106 | ;; 107 | 108 | intel) CFLAGS="-O3 -ansi_alias" 109 | if test "x$acx_maxopt_portable" = xno; then 110 | icc_archflag=unknown 111 | icc_flags="" 112 | case $host_cpu in 113 | i686*|x86_64*) 114 | # icc accepts gcc assembly syntax, so these should work: 115 | AX_GCC_X86_CPUID(0) 116 | AX_GCC_X86_CPUID(1) 117 | case $ax_cv_gcc_x86_cpuid_0 in # see AX_GCC_ARCHFLAG 118 | *:756e6547:*:*) # Intel 119 | case $ax_cv_gcc_x86_cpuid_1 in 120 | *6a?:*[[234]]:*:*|*6[[789b]]?:*:*:*) icc_flags="-xK";; 121 | *f3[[347]]:*:*:*|*f4[1347]:*:*:*) icc_flags="-xP -xN -xW -xK";; 122 | *f??:*:*:*) icc_flags="-xN -xW -xK";; 123 | esac ;; 124 | esac ;; 125 | esac 126 | if test "x$icc_flags" != x; then 127 | for flag in $icc_flags; do 128 | AX_CHECK_COMPILE_FLAG($flag, [icc_archflag=$flag; break]) 129 | done 130 | fi 131 | AC_MSG_CHECKING([for icc architecture flag]) 132 | AC_MSG_RESULT($icc_archflag) 133 | if test "x$icc_archflag" != xunknown; then 134 | CFLAGS="$CFLAGS $icc_archflag" 135 | fi 136 | fi 137 | ;; 138 | 139 | gnu) 140 | # default optimization flags for gcc on all systems 141 | CFLAGS="-O3 -fomit-frame-pointer" 142 | 143 | # -malign-double for x86 systems 144 | AX_CHECK_COMPILE_FLAG(-malign-double, CFLAGS="$CFLAGS -malign-double") 145 | 146 | # -fstrict-aliasing for gcc-2.95+ 147 | AX_CHECK_COMPILE_FLAG(-fstrict-aliasing, 148 | CFLAGS="$CFLAGS -fstrict-aliasing") 149 | 150 | # note that we enable "unsafe" fp optimization with other compilers, too 151 | AX_CHECK_COMPILE_FLAG(-ffast-math, CFLAGS="$CFLAGS -ffast-math") 152 | 153 | AX_GCC_ARCHFLAG($acx_maxopt_portable) 154 | ;; 155 | esac 156 | 157 | if test -z "$CFLAGS"; then 158 | echo "" 159 | echo "********************************************************" 160 | echo "* WARNING: Don't know the best CFLAGS for this system *" 161 | echo "* Use ./configure CFLAGS=... to specify your own flags *" 162 | echo "* (otherwise, a default of CFLAGS=-O3 will be used) *" 163 | echo "********************************************************" 164 | echo "" 165 | CFLAGS="-O3" 166 | fi 167 | 168 | AX_CHECK_COMPILE_FLAG($CFLAGS, [], [ 169 | echo "" 170 | echo "********************************************************" 171 | echo "* WARNING: The guessed CFLAGS don't seem to work with *" 172 | echo "* your compiler. *" 173 | echo "* Use ./configure CFLAGS=... to specify your own flags *" 174 | echo "********************************************************" 175 | echo "" 176 | CFLAGS="" 177 | ]) 178 | 179 | fi 180 | ]) 181 | -------------------------------------------------------------------------------- /m4/ax_check_compile_flag.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check whether the given FLAG works with the current language's compiler 12 | # or gives an error. (Warnings, however, are ignored) 13 | # 14 | # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on 15 | # success/failure. 16 | # 17 | # If EXTRA-FLAGS is defined, it is added to the current language's default 18 | # flags (e.g. CFLAGS) when the check is done. The check is thus made with 19 | # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to 20 | # force the compiler to issue an error when a bad flag is given. 21 | # 22 | # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this 23 | # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. 24 | # 25 | # LICENSE 26 | # 27 | # Copyright (c) 2008 Guido U. Draheim 28 | # Copyright (c) 2011 Maarten Bosmans 29 | # 30 | # This program is free software: you can redistribute it and/or modify it 31 | # under the terms of the GNU General Public License as published by the 32 | # Free Software Foundation, either version 3 of the License, or (at your 33 | # option) any later version. 34 | # 35 | # This program is distributed in the hope that it will be useful, but 36 | # WITHOUT ANY WARRANTY; without even the implied warranty of 37 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 38 | # Public License for more details. 39 | # 40 | # You should have received a copy of the GNU General Public License along 41 | # with this program. If not, see . 42 | # 43 | # As a special exception, the respective Autoconf Macro's copyright owner 44 | # gives unlimited permission to copy, distribute and modify the configure 45 | # scripts that are the output of Autoconf when processing the Macro. You 46 | # need not follow the terms of the GNU General Public License when using 47 | # or distributing such scripts, even though portions of the text of the 48 | # Macro appear in them. The GNU General Public License (GPL) does govern 49 | # all other use of the material that constitutes the Autoconf Macro. 50 | # 51 | # This special exception to the GPL applies to versions of the Autoconf 52 | # Macro released by the Autoconf Archive. When you make and distribute a 53 | # modified version of the Autoconf Macro, you may extend this special 54 | # exception to the GPL to apply to your modified version as well. 55 | 56 | #serial 2 57 | 58 | AC_DEFUN([AX_CHECK_COMPILE_FLAG], 59 | [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX 60 | AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl 61 | AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ 62 | ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS 63 | _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" 64 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], 65 | [AS_VAR_SET(CACHEVAR,[yes])], 66 | [AS_VAR_SET(CACHEVAR,[no])]) 67 | _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) 68 | AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], 69 | [m4_default([$2], :)], 70 | [m4_default([$3], :)]) 71 | AS_VAR_POPDEF([CACHEVAR])dnl 72 | ])dnl AX_CHECK_COMPILE_FLAGS 73 | -------------------------------------------------------------------------------- /m4/ax_compiler_vendor.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_COMPILER_VENDOR 8 | # 9 | # DESCRIPTION 10 | # 11 | # Determine the vendor of the C/C++ compiler, e.g., gnu, intel, ibm, sun, 12 | # hp, borland, comeau, dec, cray, kai, lcc, metrowerks, sgi, microsoft, 13 | # watcom, etc. The vendor is returned in the cache variable 14 | # $ax_cv_c_compiler_vendor for C and $ax_cv_cxx_compiler_vendor for C++. 15 | # 16 | # LICENSE 17 | # 18 | # Copyright (c) 2008 Steven G. Johnson 19 | # Copyright (c) 2008 Matteo Frigo 20 | # 21 | # This program is free software: you can redistribute it and/or modify it 22 | # under the terms of the GNU General Public License as published by the 23 | # Free Software Foundation, either version 3 of the License, or (at your 24 | # option) any later version. 25 | # 26 | # This program is distributed in the hope that it will be useful, but 27 | # WITHOUT ANY WARRANTY; without even the implied warranty of 28 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 29 | # Public License for more details. 30 | # 31 | # You should have received a copy of the GNU General Public License along 32 | # with this program. If not, see . 33 | # 34 | # As a special exception, the respective Autoconf Macro's copyright owner 35 | # gives unlimited permission to copy, distribute and modify the configure 36 | # scripts that are the output of Autoconf when processing the Macro. You 37 | # need not follow the terms of the GNU General Public License when using 38 | # or distributing such scripts, even though portions of the text of the 39 | # Macro appear in them. The GNU General Public License (GPL) does govern 40 | # all other use of the material that constitutes the Autoconf Macro. 41 | # 42 | # This special exception to the GPL applies to versions of the Autoconf 43 | # Macro released by the Autoconf Archive. When you make and distribute a 44 | # modified version of the Autoconf Macro, you may extend this special 45 | # exception to the GPL to apply to your modified version as well. 46 | 47 | #serial 11 48 | 49 | AC_DEFUN([AX_COMPILER_VENDOR], 50 | [AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, 51 | [# note: don't check for gcc first since some other compilers define __GNUC__ 52 | vendors="intel: __ICC,__ECC,__INTEL_COMPILER 53 | ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__ 54 | pathscale: __PATHCC__,__PATHSCALE__ 55 | clang: __clang__ 56 | gnu: __GNUC__ 57 | sun: __SUNPRO_C,__SUNPRO_CC 58 | hp: __HP_cc,__HP_aCC 59 | dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER 60 | borland: __BORLANDC__,__TURBOC__ 61 | comeau: __COMO__ 62 | cray: _CRAYC 63 | kai: __KCC 64 | lcc: __LCC__ 65 | sgi: __sgi,sgi 66 | microsoft: _MSC_VER 67 | metrowerks: __MWERKS__ 68 | watcom: __WATCOMC__ 69 | portland: __PGI 70 | unknown: UNKNOWN" 71 | for ventest in $vendors; do 72 | case $ventest in 73 | *:) vendor=$ventest; continue ;; 74 | *) vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")" ;; 75 | esac 76 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[ 77 | #if !($vencpp) 78 | thisisanerror; 79 | #endif 80 | ])], [break]) 81 | done 82 | ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=`echo $vendor | cut -d: -f1` 83 | ]) 84 | ]) 85 | -------------------------------------------------------------------------------- /m4/ax_gcc_archflag.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_gcc_archflag.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_GCC_ARCHFLAG([PORTABLE?], [ACTION-SUCCESS], [ACTION-FAILURE]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # This macro tries to guess the "native" arch corresponding to the target 12 | # architecture for use with gcc's -march=arch or -mtune=arch flags. If 13 | # found, the cache variable $ax_cv_gcc_archflag is set to this flag and 14 | # ACTION-SUCCESS is executed; otherwise $ax_cv_gcc_archflag is set to 15 | # "unknown" and ACTION-FAILURE is executed. The default ACTION-SUCCESS is 16 | # to add $ax_cv_gcc_archflag to the end of $CFLAGS. 17 | # 18 | # PORTABLE? should be either [yes] (default) or [no]. In the former case, 19 | # the flag is set to -mtune (or equivalent) so that the architecture is 20 | # only used for tuning, but the instruction set used is still portable. In 21 | # the latter case, the flag is set to -march (or equivalent) so that 22 | # architecture-specific instructions are enabled. 23 | # 24 | # The user can specify --with-gcc-arch= in order to override the 25 | # macro's choice of architecture, or --without-gcc-arch to disable this. 26 | # 27 | # When cross-compiling, or if $CC is not gcc, then ACTION-FAILURE is 28 | # called unless the user specified --with-gcc-arch manually. 29 | # 30 | # Requires macros: AX_CHECK_COMPILE_FLAG, AX_GCC_X86_CPUID 31 | # 32 | # (The main emphasis here is on recent CPUs, on the principle that doing 33 | # high-performance computing on old hardware is uncommon.) 34 | # 35 | # LICENSE 36 | # 37 | # Copyright (c) 2008 Steven G. Johnson 38 | # Copyright (c) 2008 Matteo Frigo 39 | # Copyright (c) 2012 Tsukasa Oi 40 | # 41 | # This program is free software: you can redistribute it and/or modify it 42 | # under the terms of the GNU General Public License as published by the 43 | # Free Software Foundation, either version 3 of the License, or (at your 44 | # option) any later version. 45 | # 46 | # This program is distributed in the hope that it will be useful, but 47 | # WITHOUT ANY WARRANTY; without even the implied warranty of 48 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 49 | # Public License for more details. 50 | # 51 | # You should have received a copy of the GNU General Public License along 52 | # with this program. If not, see . 53 | # 54 | # As a special exception, the respective Autoconf Macro's copyright owner 55 | # gives unlimited permission to copy, distribute and modify the configure 56 | # scripts that are the output of Autoconf when processing the Macro. You 57 | # need not follow the terms of the GNU General Public License when using 58 | # or distributing such scripts, even though portions of the text of the 59 | # Macro appear in them. The GNU General Public License (GPL) does govern 60 | # all other use of the material that constitutes the Autoconf Macro. 61 | # 62 | # This special exception to the GPL applies to versions of the Autoconf 63 | # Macro released by the Autoconf Archive. When you make and distribute a 64 | # modified version of the Autoconf Macro, you may extend this special 65 | # exception to the GPL to apply to your modified version as well. 66 | 67 | #serial 11 68 | 69 | AC_DEFUN([AX_GCC_ARCHFLAG], 70 | [AC_REQUIRE([AC_PROG_CC]) 71 | AC_REQUIRE([AC_CANONICAL_HOST]) 72 | 73 | AC_ARG_WITH(gcc-arch, [AS_HELP_STRING([--with-gcc-arch=], [use architecture for gcc -march/-mtune, instead of guessing])], 74 | ax_gcc_arch=$withval, ax_gcc_arch=yes) 75 | 76 | AC_MSG_CHECKING([for gcc architecture flag]) 77 | AC_MSG_RESULT([]) 78 | AC_CACHE_VAL(ax_cv_gcc_archflag, 79 | [ 80 | ax_cv_gcc_archflag="unknown" 81 | 82 | if test "$GCC" = yes; then 83 | 84 | if test "x$ax_gcc_arch" = xyes; then 85 | ax_gcc_arch="" 86 | if test "$cross_compiling" = no; then 87 | case $host_cpu in 88 | i[[3456]]86*|x86_64*) # use cpuid codes 89 | AX_GCC_X86_CPUID(0) 90 | AX_GCC_X86_CPUID(1) 91 | case $ax_cv_gcc_x86_cpuid_0 in 92 | *:756e6547:*:*) # Intel 93 | case $ax_cv_gcc_x86_cpuid_1 in 94 | *5[[48]]?:*:*:*) ax_gcc_arch="pentium-mmx pentium" ;; 95 | *5??:*:*:*) ax_gcc_arch=pentium ;; 96 | *0?6[[3456]]?:*:*:*) ax_gcc_arch="pentium2 pentiumpro" ;; 97 | *0?6a?:*[[01]]:*:*) ax_gcc_arch="pentium2 pentiumpro" ;; 98 | *0?6a?:*[[234]]:*:*) ax_gcc_arch="pentium3 pentiumpro" ;; 99 | *0?6[[9de]]?:*:*:*) ax_gcc_arch="pentium-m pentium3 pentiumpro" ;; 100 | *0?6[[78b]]?:*:*:*) ax_gcc_arch="pentium3 pentiumpro" ;; 101 | *0?6f?:*:*:*|*1?66?:*:*:*) ax_gcc_arch="core2 pentium-m pentium3 pentiumpro" ;; 102 | *1?6[[7d]]?:*:*:*) ax_gcc_arch="penryn core2 pentium-m pentium3 pentiumpro" ;; 103 | *1?6[[aef]]?:*:*:*|*2?6[[5cef]]?:*:*:*) ax_gcc_arch="corei7 core2 pentium-m pentium3 pentiumpro" ;; 104 | *1?6c?:*:*:*|*[[23]]?66?:*:*:*) ax_gcc_arch="atom core2 pentium-m pentium3 pentiumpro" ;; 105 | *2?6[[ad]]?:*:*:*) ax_gcc_arch="corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; 106 | *0?6??:*:*:*) ax_gcc_arch=pentiumpro ;; 107 | *6??:*:*:*) ax_gcc_arch="core2 pentiumpro" ;; 108 | ?000?f3[[347]]:*:*:*|?000?f4[1347]:*:*:*|?000?f6?:*:*:*) 109 | case $host_cpu in 110 | x86_64*) ax_gcc_arch="nocona pentium4 pentiumpro" ;; 111 | *) ax_gcc_arch="prescott pentium4 pentiumpro" ;; 112 | esac ;; 113 | ?000?f??:*:*:*) ax_gcc_arch="pentium4 pentiumpro";; 114 | esac ;; 115 | *:68747541:*:*) # AMD 116 | case $ax_cv_gcc_x86_cpuid_1 in 117 | *5[[67]]?:*:*:*) ax_gcc_arch=k6 ;; 118 | *5[[8d]]?:*:*:*) ax_gcc_arch="k6-2 k6" ;; 119 | *5[[9]]?:*:*:*) ax_gcc_arch="k6-3 k6" ;; 120 | *60?:*:*:*) ax_gcc_arch=k7 ;; 121 | *6[[12]]?:*:*:*) ax_gcc_arch="athlon k7" ;; 122 | *6[[34]]?:*:*:*) ax_gcc_arch="athlon-tbird k7" ;; 123 | *67?:*:*:*) ax_gcc_arch="athlon-4 athlon k7" ;; 124 | *6[[68a]]?:*:*:*) 125 | AX_GCC_X86_CPUID(0x80000006) # L2 cache size 126 | case $ax_cv_gcc_x86_cpuid_0x80000006 in 127 | *:*:*[[1-9a-f]]??????:*) # (L2 = ecx >> 16) >= 256 128 | ax_gcc_arch="athlon-xp athlon-4 athlon k7" ;; 129 | *) ax_gcc_arch="athlon-4 athlon k7" ;; 130 | esac ;; 131 | ?00??f[[4cef8b]]?:*:*:*) ax_gcc_arch="athlon64 k8" ;; 132 | ?00??f5?:*:*:*) ax_gcc_arch="opteron k8" ;; 133 | ?00??f7?:*:*:*) ax_gcc_arch="athlon-fx opteron k8" ;; 134 | ?00??f??:*:*:*) ax_gcc_arch="k8" ;; 135 | ?05??f??:*:*:*) ax_gcc_arch="btver1 amdfam10 k8" ;; 136 | ?06??f??:*:*:*) ax_gcc_arch="bdver1 amdfam10 k8" ;; 137 | *f??:*:*:*) ax_gcc_arch="amdfam10 k8" ;; 138 | esac ;; 139 | *:746e6543:*:*) # IDT 140 | case $ax_cv_gcc_x86_cpuid_1 in 141 | *54?:*:*:*) ax_gcc_arch=winchip-c6 ;; 142 | *58?:*:*:*) ax_gcc_arch=winchip2 ;; 143 | *6[[78]]?:*:*:*) ax_gcc_arch=c3 ;; 144 | *69?:*:*:*) ax_gcc_arch="c3-2 c3" ;; 145 | esac ;; 146 | esac 147 | if test x"$ax_gcc_arch" = x; then # fallback 148 | case $host_cpu in 149 | i586*) ax_gcc_arch=pentium ;; 150 | i686*) ax_gcc_arch=pentiumpro ;; 151 | esac 152 | fi 153 | ;; 154 | 155 | sparc*) 156 | AC_PATH_PROG([PRTDIAG], [prtdiag], [prtdiag], [$PATH:/usr/platform/`uname -i`/sbin/:/usr/platform/`uname -m`/sbin/]) 157 | cputype=`(((grep cpu /proc/cpuinfo | cut -d: -f2) ; ($PRTDIAG -v |grep -i sparc) ; grep -i cpu /var/run/dmesg.boot ) | head -n 1) 2> /dev/null` 158 | cputype=`echo "$cputype" | tr -d ' -' |tr $as_cr_LETTERS $as_cr_letters` 159 | case $cputype in 160 | *ultrasparciv*) ax_gcc_arch="ultrasparc4 ultrasparc3 ultrasparc v9" ;; 161 | *ultrasparciii*) ax_gcc_arch="ultrasparc3 ultrasparc v9" ;; 162 | *ultrasparc*) ax_gcc_arch="ultrasparc v9" ;; 163 | *supersparc*|*tms390z5[[05]]*) ax_gcc_arch="supersparc v8" ;; 164 | *hypersparc*|*rt62[[056]]*) ax_gcc_arch="hypersparc v8" ;; 165 | *cypress*) ax_gcc_arch=cypress ;; 166 | esac ;; 167 | 168 | alphaev5) ax_gcc_arch=ev5 ;; 169 | alphaev56) ax_gcc_arch=ev56 ;; 170 | alphapca56) ax_gcc_arch="pca56 ev56" ;; 171 | alphapca57) ax_gcc_arch="pca57 pca56 ev56" ;; 172 | alphaev6) ax_gcc_arch=ev6 ;; 173 | alphaev67) ax_gcc_arch=ev67 ;; 174 | alphaev68) ax_gcc_arch="ev68 ev67" ;; 175 | alphaev69) ax_gcc_arch="ev69 ev68 ev67" ;; 176 | alphaev7) ax_gcc_arch="ev7 ev69 ev68 ev67" ;; 177 | alphaev79) ax_gcc_arch="ev79 ev7 ev69 ev68 ev67" ;; 178 | 179 | powerpc*) 180 | cputype=`((grep cpu /proc/cpuinfo | head -n 1 | cut -d: -f2 | cut -d, -f1 | sed 's/ //g') ; /usr/bin/machine ; /bin/machine; grep CPU /var/run/dmesg.boot | head -n 1 | cut -d" " -f2) 2> /dev/null` 181 | cputype=`echo $cputype | sed -e 's/ppc//g;s/ *//g'` 182 | case $cputype in 183 | *750*) ax_gcc_arch="750 G3" ;; 184 | *740[[0-9]]*) ax_gcc_arch="$cputype 7400 G4" ;; 185 | *74[[4-5]][[0-9]]*) ax_gcc_arch="$cputype 7450 G4" ;; 186 | *74[[0-9]][[0-9]]*) ax_gcc_arch="$cputype G4" ;; 187 | *970*) ax_gcc_arch="970 G5 power4";; 188 | *POWER4*|*power4*|*gq*) ax_gcc_arch="power4 970";; 189 | *POWER5*|*power5*|*gr*|*gs*) ax_gcc_arch="power5 power4 970";; 190 | 603ev|8240) ax_gcc_arch="$cputype 603e 603";; 191 | *) ax_gcc_arch=$cputype ;; 192 | esac 193 | ax_gcc_arch="$ax_gcc_arch powerpc" 194 | ;; 195 | esac 196 | fi # not cross-compiling 197 | fi # guess arch 198 | 199 | if test "x$ax_gcc_arch" != x -a "x$ax_gcc_arch" != xno; then 200 | for arch in $ax_gcc_arch; do 201 | if test "x[]m4_default([$1],yes)" = xyes; then # if we require portable code 202 | flags="-mtune=$arch" 203 | # -mcpu=$arch and m$arch generate nonportable code on every arch except 204 | # x86. And some other arches (e.g. Alpha) don't accept -mtune. Grrr. 205 | case $host_cpu in i*86|x86_64*) flags="$flags -mcpu=$arch -m$arch";; esac 206 | else 207 | flags="-march=$arch -mcpu=$arch -m$arch" 208 | fi 209 | for flag in $flags; do 210 | AX_CHECK_COMPILE_FLAG($flag, [ax_cv_gcc_archflag=$flag; break]) 211 | done 212 | test "x$ax_cv_gcc_archflag" = xunknown || break 213 | done 214 | fi 215 | 216 | fi # $GCC=yes 217 | ]) 218 | AC_MSG_CHECKING([for gcc architecture flag]) 219 | AC_MSG_RESULT($ax_cv_gcc_archflag) 220 | if test "x$ax_cv_gcc_archflag" = xunknown; then 221 | m4_default([$3],:) 222 | else 223 | m4_default([$2], [CFLAGS="$CFLAGS $ax_cv_gcc_archflag"]) 224 | fi 225 | ]) 226 | -------------------------------------------------------------------------------- /m4/ax_gcc_x86_cpuid.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_gcc_x86_cpuid.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_GCC_X86_CPUID(OP) 8 | # 9 | # DESCRIPTION 10 | # 11 | # On Pentium and later x86 processors, with gcc or a compiler that has a 12 | # compatible syntax for inline assembly instructions, run a small program 13 | # that executes the cpuid instruction with input OP. This can be used to 14 | # detect the CPU type. 15 | # 16 | # On output, the values of the eax, ebx, ecx, and edx registers are stored 17 | # as hexadecimal strings as "eax:ebx:ecx:edx" in the cache variable 18 | # ax_cv_gcc_x86_cpuid_OP. 19 | # 20 | # If the cpuid instruction fails (because you are running a 21 | # cross-compiler, or because you are not using gcc, or because you are on 22 | # a processor that doesn't have this instruction), ax_cv_gcc_x86_cpuid_OP 23 | # is set to the string "unknown". 24 | # 25 | # This macro mainly exists to be used in AX_GCC_ARCHFLAG. 26 | # 27 | # LICENSE 28 | # 29 | # Copyright (c) 2008 Steven G. Johnson 30 | # Copyright (c) 2008 Matteo Frigo 31 | # 32 | # This program is free software: you can redistribute it and/or modify it 33 | # under the terms of the GNU General Public License as published by the 34 | # Free Software Foundation, either version 3 of the License, or (at your 35 | # option) any later version. 36 | # 37 | # This program is distributed in the hope that it will be useful, but 38 | # WITHOUT ANY WARRANTY; without even the implied warranty of 39 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 40 | # Public License for more details. 41 | # 42 | # You should have received a copy of the GNU General Public License along 43 | # with this program. If not, see . 44 | # 45 | # As a special exception, the respective Autoconf Macro's copyright owner 46 | # gives unlimited permission to copy, distribute and modify the configure 47 | # scripts that are the output of Autoconf when processing the Macro. You 48 | # need not follow the terms of the GNU General Public License when using 49 | # or distributing such scripts, even though portions of the text of the 50 | # Macro appear in them. The GNU General Public License (GPL) does govern 51 | # all other use of the material that constitutes the Autoconf Macro. 52 | # 53 | # This special exception to the GPL applies to versions of the Autoconf 54 | # Macro released by the Autoconf Archive. When you make and distribute a 55 | # modified version of the Autoconf Macro, you may extend this special 56 | # exception to the GPL to apply to your modified version as well. 57 | 58 | #serial 7 59 | 60 | AC_DEFUN([AX_GCC_X86_CPUID], 61 | [AC_REQUIRE([AC_PROG_CC]) 62 | AC_LANG_PUSH([C]) 63 | AC_CACHE_CHECK(for x86 cpuid $1 output, ax_cv_gcc_x86_cpuid_$1, 64 | [AC_RUN_IFELSE([AC_LANG_PROGRAM([#include ], [ 65 | int op = $1, eax, ebx, ecx, edx; 66 | FILE *f; 67 | __asm__("cpuid" 68 | : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) 69 | : "a" (op)); 70 | f = fopen("conftest_cpuid", "w"); if (!f) return 1; 71 | fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx); 72 | fclose(f); 73 | return 0; 74 | ])], 75 | [ax_cv_gcc_x86_cpuid_$1=`cat conftest_cpuid`; rm -f conftest_cpuid], 76 | [ax_cv_gcc_x86_cpuid_$1=unknown; rm -f conftest_cpuid], 77 | [ax_cv_gcc_x86_cpuid_$1=unknown])]) 78 | AC_LANG_POP([C]) 79 | ]) 80 | -------------------------------------------------------------------------------- /m4/jemalloc.m4: -------------------------------------------------------------------------------- 1 | dnl -------------------------------------------------------- -*- autoconf -*- 2 | dnl Licensed to the Apache Software Foundation (ASF) under one or more 3 | dnl contributor license agreements. See the NOTICE file distributed with 4 | dnl this work for additional information regarding copyright ownership. 5 | dnl The ASF licenses this file to You under the Apache License, Version 2.0 6 | dnl (the "License"); you may not use this file except in compliance with 7 | dnl the License. You may obtain a copy of the License at 8 | dnl 9 | dnl http://www.apache.org/licenses/LICENSE-2.0 10 | dnl 11 | dnl Unless required by applicable law or agreed to in writing, software 12 | dnl distributed under the License is distributed on an "AS IS" BASIS, 13 | dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | dnl See the License for the specific language governing permissions and 15 | dnl limitations under the License. 16 | 17 | dnl 18 | dnl jemalloc.m4: Trafficserver's jemalloc autoconf macros 19 | dnl modified to skip other TS_ helpers 20 | dnl 21 | 22 | AC_DEFUN([TS_CHECK_JEMALLOC], [ 23 | AC_ARG_WITH([jemalloc-prefix], 24 | [AS_HELP_STRING([--with-jemalloc-prefix=PREFIX],[Specify the jemalloc prefix [default=""]])], 25 | [ 26 | jemalloc_prefix="$withval" 27 | ],[ 28 | if test "`uname -s`" = "Darwin"; then 29 | jemalloc_prefix="je_" 30 | else 31 | jemalloc_prefix="" 32 | fi 33 | ] 34 | ) 35 | AC_DEFINE_UNQUOTED([prefix_jemalloc], [${jemalloc_prefix}], [jemalloc prefix]) 36 | 37 | enable_jemalloc=no 38 | AC_ARG_WITH([jemalloc], [AS_HELP_STRING([--with-jemalloc=DIR], [use a specific jemalloc library])], 39 | [ 40 | if test "$withval" != "no"; then 41 | if test "x${enable_tcmalloc}" = "xyes"; then 42 | AC_MSG_ERROR([Cannot compile with both jemalloc and tcmalloc]) 43 | fi 44 | enable_jemalloc=yes 45 | jemalloc_base_dir="$withval" 46 | case "$withval" in 47 | yes) 48 | jemalloc_base_dir="/usr" 49 | AC_MSG_CHECKING(checking for jemalloc includes standard directories) 50 | ;; 51 | *":"*) 52 | jemalloc_include="`echo $withval |sed -e 's/:.*$//'`" 53 | jemalloc_ldflags="`echo $withval |sed -e 's/^.*://'`" 54 | AC_MSG_CHECKING(checking for jemalloc includes in $jemalloc_include libs in $jemalloc_ldflags) 55 | ;; 56 | *) 57 | jemalloc_include="$withval/include" 58 | jemalloc_ldflags="$withval/lib" 59 | AC_MSG_CHECKING(checking for jemalloc includes in $withval) 60 | ;; 61 | esac 62 | fi 63 | ]) 64 | 65 | has_jemalloc=0 66 | if test "$enable_jemalloc" != "no"; then 67 | jemalloc_have_headers=0 68 | jemalloc_have_libs=0 69 | if test "$jemalloc_base_dir" != "/usr"; then 70 | CFLAGS="${CFLAGS} -I${jemalloc_include}" 71 | LDFLAGS="${LDFLAGS} -L${jemalloc_ldflags}" 72 | LIBTOOL_LINK_FLAGS="${LIBTOOL_LINK_FLAGS} -R${jemalloc_ldflags}" 73 | fi 74 | func="${jemalloc_prefix}malloc_stats_print" 75 | AC_CHECK_LIB(jemalloc, ${func}, [jemalloc_have_libs=1]) 76 | if test "$jemalloc_have_libs" != "0"; then 77 | AC_CHECK_HEADERS([jemalloc/jemalloc.h], [jemalloc_have_headers=1]) 78 | fi 79 | if test "$jemalloc_have_headers" != "0"; then 80 | has_jemalloc=1 81 | LIBS="${LIBS} -ljemalloc" 82 | AC_DEFINE(has_jemalloc, [1], [Link/compile against jemalloc]) 83 | else 84 | AC_MSG_ERROR([Couldn't find a jemalloc installation]) 85 | fi 86 | fi 87 | AC_SUBST(has_jemalloc) 88 | ]) 89 | -------------------------------------------------------------------------------- /m4/tcmalloc.m4: -------------------------------------------------------------------------------- 1 | dnl -------------------------------------------------------- -*- autoconf -*- 2 | dnl Licensed to the Apache Software Foundation (ASF) under one or more 3 | dnl contributor license agreements. See the NOTICE file distributed with 4 | dnl this work for additional information regarding copyright ownership. 5 | dnl The ASF licenses this file to You under the Apache License, Version 2.0 6 | dnl (the "License"); you may not use this file except in compliance with 7 | dnl the License. You may obtain a copy of the License at 8 | dnl 9 | dnl http://www.apache.org/licenses/LICENSE-2.0 10 | dnl 11 | dnl Unless required by applicable law or agreed to in writing, software 12 | dnl distributed under the License is distributed on an "AS IS" BASIS, 13 | dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | dnl See the License for the specific language governing permissions and 15 | dnl limitations under the License. 16 | 17 | dnl 18 | dnl tcmalloc.m4: Trafficserver's tcmalloc autoconf macros 19 | dnl modified to skip other TS_ helpers 20 | dnl 21 | 22 | dnl This is kinda fugly, but need a way to both specify a directory and which 23 | dnl of the many tcmalloc libraries to use ... 24 | AC_DEFUN([TS_CHECK_TCMALLOC], [ 25 | AC_ARG_WITH([tcmalloc-lib], 26 | [AS_HELP_STRING([--with-tcmalloc-lib],[specify the tcmalloc library to use [default=tcmalloc]])], 27 | [ 28 | with_tcmalloc_lib="$withval" 29 | ],[ 30 | with_tcmalloc_lib="tcmalloc" 31 | ] 32 | ) 33 | 34 | has_tcmalloc=0 35 | AC_ARG_WITH([tcmalloc], [AS_HELP_STRING([--with-tcmalloc=DIR], [use the tcmalloc library])], 36 | [ 37 | if test "$withval" != "no"; then 38 | if test "x${enable_jemalloc}" = "xyes"; then 39 | AC_MSG_ERROR([Cannot compile with both tcmalloc and jemalloc]) 40 | fi 41 | tcmalloc_have_lib=0 42 | if test "x$withval" != "xyes" && test "x$withval" != "x"; then 43 | tcmalloc_ldflags="$withval/lib" 44 | LDFLAGS="${LDFLAGS} -L${tcmalloc_ldflags}" 45 | LIBTOOL_LINK_FLAGS="${LIBTOOL_LINK_FLAGS} -rpath ${tcmalloc_ldflags}" 46 | fi 47 | AC_CHECK_LIB(${with_tcmalloc_lib}, tc_cfree, [tcmalloc_have_lib=1]) 48 | if test "$tcmalloc_have_lib" != "0"; then 49 | LIBS="${LIBS} -l${with_tcmalloc_lib}" 50 | has_tcmalloc=1 51 | AC_DEFINE(has_tcmalloc, [1], [Link/compile against tcmalloc]) 52 | else 53 | AC_MSG_ERROR([Couldn't find a tcmalloc installation]) 54 | fi 55 | fi 56 | ]) 57 | AC_SUBST(has_tcmalloc) 58 | ]) 59 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | TESTS = test 2 | 3 | check_PROGRAMS = $(TESTS) 4 | EXTRA_PROGRAMS = stress 5 | 6 | LDADD= $(top_builddir)/lib/libbitset.la 7 | AM_CPPFLAGS = -I$(top_srcdir)/include 8 | AM_CFLAGS= -std=c99 -Wall 9 | 10 | test_SOURCES = test.c 11 | stress = stress.c 12 | 13 | EXTRA_DIST = test.h 14 | -------------------------------------------------------------------------------- /test/stress.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "bitset/malloc.h" 5 | #include "bitset/vector.h" 6 | 7 | /** 8 | * Bundle a PRNG to get around dists with a tiny RAND_MAX. 9 | */ 10 | 11 | static unsigned bitset_rand_seed = 1; 12 | static inline unsigned bitset_rand() { 13 | bitset_rand_seed = bitset_rand_seed * 1103515245 + 12345; 14 | return bitset_rand_seed; 15 | } 16 | 17 | void stress_small(unsigned bits, unsigned max, unsigned count) { 18 | float start, end; 19 | 20 | bitset_t *b, *b2, *b3, *b4; 21 | bitset_operation_t *o; 22 | bitset_offset *offsets = bitset_malloc(sizeof(bitset_offset) * bits); 23 | 24 | start = (float) clock(); 25 | for (size_t j = 0; j < count; j++) { 26 | for (size_t j = 0; j < bits; j++) { 27 | offsets[j] = bitset_rand() % max; 28 | } 29 | b = bitset_new_bits(offsets, bits); 30 | for (size_t j = 0; j < bits; j++) { 31 | offsets[j] = bitset_rand() % max; 32 | } 33 | b2 = bitset_new_bits(offsets, bits); 34 | for (size_t j = 0; j < bits; j++) { 35 | offsets[j] = bitset_rand() % max; 36 | } 37 | b3 = bitset_new_bits(offsets, bits); 38 | o = bitset_operation_new(b); 39 | bitset_operation_add(o, b2, BITSET_AND); 40 | bitset_operation_add(o, b3, BITSET_OR); 41 | b4 = bitset_operation_exec(o); 42 | bitset_operation_free(o); 43 | bitset_free(b4); 44 | bitset_free(b); 45 | bitset_free(b2); 46 | bitset_free(b3); 47 | } 48 | end = ((float) clock() - start) / CLOCKS_PER_SEC; 49 | printf("Executed small ops in %.2fs\n", end); 50 | } 51 | 52 | void stress_vector(unsigned bitsets, unsigned bits, unsigned max) { 53 | float start, end, size = 0; 54 | size_t i; 55 | 56 | bitset_t **b = bitset_malloc(sizeof(bitset_t *) * bitsets); 57 | bitset_offset *offsets = bitset_malloc(sizeof(bitset_offset) * bits); 58 | bitset_vector_t *vector = bitset_vector_new(); 59 | 60 | //Create the bitsets 61 | start = (float) clock(); 62 | for (i = 0; i < bitsets; i++) { 63 | for (size_t j = 0; j < bits; j++) { 64 | offsets[j] = bitset_rand() % max; 65 | } 66 | b[i] = bitset_new_bits(offsets, bits); 67 | bitset_vector_push(vector, b[i], i); 68 | size += b[i]->length * sizeof(bitset_word); 69 | } 70 | end = ((float) clock() - start) / CLOCKS_PER_SEC; 71 | size /= 1024 * 1024; 72 | printf("Created %.2fMB in %.2fs (%.2fMB/s)\n", size, end, size/end); 73 | 74 | //Popcnt bitsets 75 | unsigned count = 0, ucount = 0; 76 | bitset_operation_t *o = bitset_operation_new(NULL); 77 | for (i = 0; i < bitsets; i++) { 78 | count += bitset_count(b[i]); 79 | bitset_operation_add(o, b[i], BITSET_OR); 80 | } 81 | ucount = bitset_operation_count(o); 82 | 83 | //Popcnt all bitsets 84 | unsigned raw, unique; 85 | start = (float) clock(); 86 | bitset_vector_cardinality(vector, &raw, &unique); 87 | end = ((float) clock() - start) / CLOCKS_PER_SEC; 88 | printf("Counted %u unique bits (%u expected) from " 89 | "%u (%u expected) bits using an iterator in %.2fs\n", unique, ucount, raw, count, end); 90 | for (i = 0; i < bitsets; i++) { 91 | bitset_free(b[i]); 92 | } 93 | bitset_vector_free(vector); 94 | bitset_operation_free(o); 95 | bitset_malloc_free(b); 96 | bitset_malloc_free(offsets); 97 | } 98 | 99 | void stress_exec(unsigned bitsets, unsigned bits, unsigned max) { 100 | float start, end, size = 0; 101 | 102 | bitset_t **b = bitset_malloc(sizeof(bitset_t *) * bitsets); 103 | bitset_offset *offsets = bitset_malloc(sizeof(bitset_offset) * bits); 104 | 105 | //Create the bitsets 106 | start = (float) clock(); 107 | for (size_t i = 0; i < bitsets; i++) { 108 | for (size_t j = 0; j < bits; j++) { 109 | offsets[j] = bitset_rand() % max; 110 | } 111 | b[i] = bitset_new_bits(offsets, bits); 112 | size += b[i]->length * sizeof(bitset_word); 113 | } 114 | end = ((float) clock() - start) / CLOCKS_PER_SEC; 115 | size /= 1024 * 1024; 116 | printf("Created %.2fMB in %.2fs (%.2fMB/s)\n", size, end, size/end); 117 | 118 | //Estimate count based on size 119 | start = (float) clock(); 120 | bitset_offset count = 0; 121 | for (size_t i = 0; i < bitsets; i++) { 122 | count += b[i]->length; 123 | } 124 | printf("Estimated bit count => " bitset_format "\n", count); 125 | end = ((float) clock() - start) / CLOCKS_PER_SEC; 126 | printf("Executed count estimate in %.2fs (%.2fMB/s)\n", end, size/end); 127 | 128 | //Pop count all bitsets 129 | start = (float) clock(); 130 | count = 0; 131 | for (size_t i = 0; i < bitsets; i++) { 132 | count += bitset_count(b[i]); 133 | } 134 | printf("Bit count => " bitset_format "\n", count); 135 | end = ((float) clock() - start) / CLOCKS_PER_SEC; 136 | printf("Executed pop count in %.2fs (%.2fMB/s)\n", end, size/end); 137 | 138 | //Bitwise OR + pop count 139 | start = (float) clock(); 140 | bitset_operation_t *op = bitset_operation_new(b[0]); 141 | for (size_t i = 1; i < bitsets; i++) { 142 | bitset_operation_add(op, b[i], BITSET_OR); 143 | } 144 | printf("Unique bit count => " bitset_format "\n", bitset_operation_count(op)); 145 | end = ((float) clock() - start) / CLOCKS_PER_SEC; 146 | printf("Executed bitwise OR + pop count operation in %.2fs (%.2fMB/s)\n", end, size/end); 147 | printf("Unique bit count => " bitset_format "\n", bitset_count(bitset_operation_exec(op))); 148 | end = ((float) clock() - start) / CLOCKS_PER_SEC; 149 | printf("Executed bitwise OR into temporary + pop count operation in %.2fs (%.2fMB/s)\n", end, size/end); 150 | bitset_operation_free(op); 151 | 152 | //Use linear counting 153 | start = (float) clock(); 154 | bitset_linear_t *e = bitset_linear_new(max); 155 | for (size_t i = 0; i < bitsets; i++) { 156 | bitset_linear_add(e, b[i]); 157 | } 158 | printf("Unique bit count => %u\n", bitset_linear_count(e)); 159 | end = ((float) clock() - start) / CLOCKS_PER_SEC; 160 | printf("Executed linear count in %.2fs (%.2fMB/s)\n", end, size/end); 161 | bitset_linear_free(e); 162 | 163 | for (size_t i = 0; i < bitsets; i++) { 164 | bitset_free(b[i]); 165 | } 166 | bitset_malloc_free(b); 167 | bitset_malloc_free(offsets); 168 | } 169 | 170 | int main(int argc, char **argv) { 171 | printf("Testing 100k small operations\n"); 172 | stress_small(10, 1000000, 100000); 173 | 174 | printf("\nCreating 100k bitsets with 10M total bits between 1->1M\n"); 175 | stress_exec(100000, 100, 1000000); 176 | 177 | printf("\nCreating 100k bitsets with 10M total bits between 1->10M\n"); 178 | stress_exec(100000, 100, 10000000); 179 | 180 | printf("\nStress testing vector with 100k bitsets and 10M bits\n"); 181 | stress_vector(100000, 100, 10000000); 182 | 183 | printf("\nCreating 1M bitsets with 100M total bits between 1->100M\n"); 184 | stress_exec(1000000, 100, 100000000); 185 | } 186 | 187 | -------------------------------------------------------------------------------- /test/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "test.h" 7 | 8 | #include "bitset/malloc.h" 9 | #include "bitset/vector.h" 10 | 11 | void bitset_dump(bitset_t *b) { 12 | printf("\x1B[33mDumping bitset of size %u\x1B[0m\n", (unsigned)b->length); 13 | for (size_t i = 0; i < b->length; i++) { 14 | printf("\x1B[36m%3zu.\x1B[0m %-8x\n", i, b->buffer[i]); 15 | } 16 | } 17 | 18 | #define TEST_DEFINE(pref, type, format) \ 19 | void test_##pref(char *title, type expected, type value) { \ 20 | if (value != expected) { \ 21 | printf("\x1B[31m%s\x1B[0m", title); \ 22 | printf(" expected '" format "', got '" format "'\n", expected, value); \ 23 | exit(1); \ 24 | } \ 25 | } 26 | 27 | TEST_DEFINE(int, int, "%d") 28 | TEST_DEFINE(ulong, unsigned long, "%lu") 29 | TEST_DEFINE(bool, bool, "%d") 30 | TEST_DEFINE(str, char *, "%s") 31 | TEST_DEFINE(hex, int, "%#x") 32 | 33 | bool test_bitset(char *title, bitset_t *b, unsigned length, uint32_t *expected) { 34 | bool mismatch = length != b->length; 35 | if (!mismatch) { 36 | for (size_t i = 0; i < length; i++) { 37 | if (b->buffer[i] != expected[i]) { 38 | mismatch = true; 39 | break; 40 | } 41 | } 42 | } 43 | if (mismatch) { 44 | size_t length_max = BITSET_MAX(b->length, length); 45 | printf("\x1B[31m%s\x1B[0m\n", title); 46 | for (size_t i = 0; i < length_max; i++) { 47 | printf(" \x1B[36m%3zu.\x1B[0m ", i); 48 | if (i < b->length) { 49 | printf("%-8x ", b->buffer[i]); 50 | } else { 51 | printf(" "); 52 | } 53 | if (i < length) { 54 | printf("\x1B[32m%-8x\x1B[0m", expected[i]); 55 | } 56 | putchar('\n'); 57 | } 58 | } 59 | return !mismatch; 60 | } 61 | 62 | int main(int argc, char **argv) { 63 | printf("Testing get\n"); 64 | test_suite_get(); 65 | printf("Testing set\n"); 66 | test_suite_set(); 67 | printf("Testing count\n"); 68 | test_suite_count(); 69 | printf("Testing operations\n"); 70 | test_suite_operation(); 71 | printf("Testing min / max\n"); 72 | test_suite_min(); 73 | test_suite_max(); 74 | printf("Testing vector\n"); 75 | test_suite_vector(); 76 | printf("Testing vector operations\n"); 77 | test_suite_vector_operation(); 78 | printf("Testing estimate algorithms\n"); 79 | test_suite_estimate(); 80 | printf("Testing stress\n"); 81 | test_suite_stress(); 82 | printf("OK\n"); 83 | } 84 | 85 | void test_suite_get() { 86 | bitset_t *b = bitset_new(); 87 | for (size_t i = 0; i < 32; i++) 88 | test_bool("Testing initial bits are unset\n", false, bitset_get(b, i)); 89 | bitset_free(b); 90 | 91 | uint32_t p1[] = { BITSET_CREATE_EMPTY_FILL(0), BITSET_CREATE_LITERAL(30) }; 92 | b = bitset_new_buffer((const char *)p1, 8); 93 | test_bool("Testing get in the first literal 1\n", true, bitset_get(b, 30)); 94 | test_bool("Testing get in the first literal 2\n", false, bitset_get(b, 31)); 95 | bitset_free(b); 96 | 97 | uint32_t p2[] = { BITSET_CREATE_EMPTY_FILL(0), BITSET_CREATE_LITERAL(0) }; 98 | b = bitset_new_buffer((const char *)p2, 8); 99 | test_bool("Testing get in the first literal 3\n", true, bitset_get(b, 0)); 100 | test_bool("Testing get in the first literal 4\n", false, bitset_get(b, 1)); 101 | bitset_free(b); 102 | 103 | uint32_t p3[] = { BITSET_CREATE_EMPTY_FILL(1), BITSET_CREATE_LITERAL(0) }; 104 | b = bitset_new_buffer((const char *)p3, 8); 105 | test_bool("Testing get in the first literal with offset 1\n", false, bitset_get(b, 1)); 106 | test_bool("Testing get in the first literal with offset 2\n", true, bitset_get(b, 31)); 107 | bitset_free(b); 108 | 109 | uint32_t p4[] = { 110 | BITSET_CREATE_EMPTY_FILL(1), BITSET_CREATE_EMPTY_FILL(1), BITSET_CREATE_LITERAL(0) 111 | }; 112 | b = bitset_new_buffer((const char *)p4, 12); 113 | test_bool("Testing get in the first literal with offset 4\n", false, bitset_get(b, 0)); 114 | test_bool("Testing get in the first literal with offset 5\n", false, bitset_get(b, 31)); 115 | test_bool("Testing get in the first literal with offset 6\n", true, bitset_get(b, 62)); 116 | bitset_free(b); 117 | 118 | uint32_t p5[] = { BITSET_CREATE_FILL(1, 0) }; 119 | b = bitset_new_buffer((const char *)p5, 4); 120 | test_bool("Testing get with position following a fill 1\n", false, bitset_get(b, 0)); 121 | test_bool("Testing get with position following a fill 2\n", true, bitset_get(b, 31)); 122 | test_bool("Testing get with position following a fill 3\n", false, bitset_get(b, 32)); 123 | bitset_free(b); 124 | 125 | BITSET_NEW(b2, 1, 10, 100); 126 | test_int("Testing BITSET_NEW macro 1\n", 3, bitset_count(b2)); 127 | test_bool("Testing BITSET_NEW macro 2\n", true, bitset_get(b2, 1)); 128 | test_bool("Testing BITSET_NEW macro 3\n", true, bitset_get(b2, 10)); 129 | test_bool("Testing BITSET_NEW macro 4\n", true, bitset_get(b2, 100)); 130 | bitset_free(b2); 131 | 132 | BITSET_NEW(b3, 300); 133 | test_int("Testing BITSET_NEW macro 5\n", 1, bitset_count(b3)); 134 | test_bool("Testing BITSET_NEW macro 6\n", true, bitset_get(b3, 300)); 135 | bitset_free(b3); 136 | 137 | BITSET_NEW(b4b, 4000000000); 138 | test_int("Testing BITSET_NEW macro 7\n", 1, bitset_count(b4b)); 139 | test_bool("Testing BITSET_NEW macro 8\n", true, bitset_get(b4b, 4000000000)); 140 | bitset_free(b4b); 141 | 142 | BITSET_NEW(b4, 100, 300, 302, 305, 1000); 143 | bitset_iterator_t *i = bitset_iterator_new(b4); 144 | unsigned o, iters = 0; 145 | BITSET_FOREACH(i, o) { 146 | test_bool("Checking bitset iterator", true, o==100 || o==300 || o==302 || o==305 || o==1000); 147 | iters++; 148 | } 149 | test_int("Checking bitset iterator 2\n", 5, iters); 150 | (void)o; 151 | bitset_iterator_free(i); 152 | bitset_free(b4); 153 | } 154 | 155 | void test_suite_count() { 156 | bitset_t *b = bitset_new(); 157 | test_ulong("Testing pop count of empty set\n", 0, bitset_count(b)); 158 | bitset_free(b); 159 | 160 | uint32_t p1[] = { BITSET_CREATE_EMPTY_FILL(0), BITSET_CREATE_LITERAL(0) }; 161 | b = bitset_new_buffer((const char *)p1, 8); 162 | test_ulong("Testing pop count of single literal 1\n", 1, bitset_count(b)); 163 | bitset_free(b); 164 | 165 | uint32_t p2[] = { BITSET_CREATE_EMPTY_FILL(0), 0x11111111 }; 166 | b = bitset_new_buffer((const char *)p2, 8); 167 | test_ulong("Testing pop count of single literal 2\n", 8, bitset_count(b)); 168 | bitset_free(b); 169 | 170 | uint32_t p3[] = { BITSET_CREATE_EMPTY_FILL(1) }; 171 | b = bitset_new_buffer((const char *)p3, 4); 172 | test_ulong("Testing pop count of single fill 1\n", 0, bitset_count(b)); 173 | bitset_free(b); 174 | 175 | uint32_t p8[] = { BITSET_CREATE_FILL(3, 4) }; 176 | b = bitset_new_buffer((const char *)p8, 4); 177 | test_ulong("Testing pop count of fill with position 1\n", 1, bitset_count(b)); 178 | bitset_free(b); 179 | } 180 | 181 | void test_suite_min() { 182 | bitset_t *b = bitset_new(); 183 | bitset_set_to(b, 1000, true); 184 | test_ulong("Test find first set 1", 1000, bitset_min(b)); 185 | bitset_set_to(b, 300, true); 186 | test_ulong("Test find first set 2", 300, bitset_min(b)); 187 | bitset_set_to(b, 299, true); 188 | test_ulong("Test find first set 3", 299, bitset_min(b)); 189 | bitset_set_to(b, 298, true); 190 | test_ulong("Test find first set 4", 298, bitset_min(b)); 191 | bitset_set_to(b, 290, true); 192 | test_ulong("Test find first set 5", 290, bitset_min(b)); 193 | bitset_set_to(b, 240, true); 194 | test_ulong("Test find first set 6", 240, bitset_min(b)); 195 | bitset_set_to(b, 12, true); 196 | test_ulong("Test find first set 7", 12, bitset_min(b)); 197 | bitset_set_to(b, 3, true); 198 | test_ulong("Test find first set 8", 3, bitset_min(b)); 199 | bitset_free(b); 200 | } 201 | 202 | void test_suite_max() { 203 | bitset_t *b = bitset_new(); 204 | bitset_set_to(b, 3, true); 205 | test_ulong("Test find last set 8", 3, bitset_max(b)); 206 | bitset_set_to(b, 12, true); 207 | test_ulong("Test find last set 7", 12, bitset_max(b)); 208 | bitset_set_to(b, 240, true); 209 | test_ulong("Test find last set 6", 240, bitset_max(b)); 210 | bitset_set_to(b, 290, true); 211 | test_ulong("Test find last set 5", 290, bitset_max(b)); 212 | bitset_set_to(b, 298, true); 213 | test_ulong("Test find last set 4", 298, bitset_max(b)); 214 | bitset_set_to(b, 299, true); 215 | test_ulong("Test find last set 3", 299, bitset_max(b)); 216 | bitset_set_to(b, 300, true); 217 | test_ulong("Test find last set 2", 300, bitset_max(b)); 218 | bitset_set_to(b, 1000, true); 219 | test_ulong("Test find last set 1", 1000, bitset_max(b)); 220 | bitset_free(b); 221 | } 222 | 223 | void test_suite_set() { 224 | bitset_t *b = bitset_new(); 225 | test_bool("Testing set on empty set 1\n", false, bitset_set_to(b, 0, true)); 226 | test_bool("Testing set on empty set 2\n", true, bitset_get(b, 0)); 227 | test_bool("Testing set on empty set 3\n", false, bitset_get(b, 1)); 228 | bitset_free(b); 229 | 230 | b = bitset_new(); 231 | test_bool("Testing unset on empty set 1\n", false, bitset_set_to(b, 100, false)); 232 | test_ulong("Testing unset on empty set doesn't create it\n", 0, b->length); 233 | bitset_free(b); 234 | 235 | b = bitset_new(); 236 | test_bool("Testing set on empty set 4\n", false, bitset_set_to(b, 31, true)); 237 | test_bool("Testing set on empty set 5\n", true, bitset_get(b, 31)); 238 | bitset_free(b); 239 | 240 | uint32_t p1[] = { BITSET_CREATE_EMPTY_FILL(1) }; 241 | b = bitset_new_buffer((const char *)p1, 4); 242 | test_bool("Testing append after fill 1\n", false, bitset_set_to(b, 93, true)); 243 | uint32_t e1[] = { BITSET_CREATE_EMPTY_FILL(1), BITSET_CREATE_FILL(2, 0) }; 244 | test_bitset("Testing append after fill 2", b, 2, e1); 245 | bitset_free(b); 246 | 247 | uint32_t p2[] = { BITSET_CREATE_FILL(1, 0) }; 248 | b = bitset_new_buffer((const char *)p2, 4); 249 | test_bool("Testing append after fill 3\n", false, bitset_set_to(b, 93, true)); 250 | uint32_t e2[] = { BITSET_CREATE_FILL(1, 0), BITSET_CREATE_FILL(1, 0) }; 251 | test_bitset("Testing append after fill 4", b, 2, e2); 252 | bitset_free(b); 253 | 254 | uint32_t p3[] = { BITSET_CREATE_EMPTY_FILL(1), 0 }; 255 | b = bitset_new_buffer((const char *)p3, 8); 256 | test_bool("Testing set in literal 1\n", false, bitset_set_to(b, 32, true)); 257 | test_bool("Testing set in literal 2\n", false, bitset_set_to(b, 38, true)); 258 | test_bool("Testing set in literal 3\n", false, bitset_set_to(b, 45, true)); 259 | test_bool("Testing set in literal 4\n", false, bitset_set_to(b, 55, true)); 260 | test_bool("Testing set in literal 5\n", false, bitset_set_to(b, 61, true)); 261 | uint32_t e3[] = { BITSET_CREATE_EMPTY_FILL(1), 0x20810041 }; 262 | test_bitset("Testing set in literal 6", b, 2, e3); 263 | test_bool("Testing set in literal 7\n", true, bitset_set_to(b, 61, false)); 264 | uint32_t e4[] = { BITSET_CREATE_EMPTY_FILL(1), 0x20810040 }; 265 | test_bitset("Testing set in literal 8", b, 2, e4); 266 | bitset_free(b); 267 | 268 | uint32_t p5[] = { BITSET_CREATE_FILL(1, 0) }; 269 | b = bitset_new_buffer((const char *)p5, 4); 270 | test_bool("Testing partition of fill 1\n", false, bitset_set_to(b, 32, true)); 271 | uint32_t e5[] = { BITSET_CREATE_EMPTY_FILL(1), BITSET_CREATE_LITERAL(0) | BITSET_CREATE_LITERAL(1) }; 272 | test_bitset("Testing partition of fill 2", b, 2, e5); 273 | bitset_free(b); 274 | 275 | uint32_t p6[] = { BITSET_CREATE_FILL(1, 0), BITSET_CREATE_FILL(1, 0) }; 276 | b = bitset_new_buffer((const char *)p6, 8); 277 | test_bool("Testing partition of fill 3\n", false, bitset_set_to(b, 32, true)); 278 | uint32_t e6[] = { BITSET_CREATE_EMPTY_FILL(1), BITSET_CREATE_LITERAL(0) | BITSET_CREATE_LITERAL(1), BITSET_CREATE_FILL(1, 0) }; 279 | test_bitset("Testing partition of fill 4", b, 3, e6); 280 | bitset_free(b); 281 | 282 | uint32_t p7[] = { BITSET_CREATE_EMPTY_FILL(1) }; 283 | b = bitset_new_buffer((const char *)p7, 4); 284 | test_bool("Testing partition of fill 5\n", false, bitset_set_to(b, 31, true)); 285 | uint32_t e7[] = { BITSET_CREATE_FILL(1, 0) }; 286 | test_bitset("Testing partition of fill 6", b, 1, e7); 287 | bitset_free(b); 288 | 289 | uint32_t p8[] = { BITSET_CREATE_FILL(1, 0), BITSET_CREATE_FILL(1, 2) }; 290 | b = bitset_new_buffer((const char *)p8, 8); 291 | test_bool("Testing partition of fill 7\n", false, bitset_set_to(b, 0, true)); 292 | uint32_t e8[] = { BITSET_CREATE_LITERAL(0), BITSET_CREATE_LITERAL(0), BITSET_CREATE_FILL(1, 2) }; 293 | test_bitset("Testing partition of fill 7", b, 3, e8); 294 | bitset_free(b); 295 | 296 | uint32_t p8b[] = { BITSET_CREATE_FILL(2, 0), BITSET_CREATE_FILL(1, 2) }; 297 | b = bitset_new_buffer((const char *)p8b, 8); 298 | test_bool("Testing partition of fill 7b\n", false, bitset_set_to(b, 32, true)); 299 | uint32_t e8b[] = { BITSET_CREATE_FILL(1, 1), BITSET_CREATE_LITERAL(0), BITSET_CREATE_FILL(1, 2) }; 300 | test_bitset("Testing partition of fill 7b - 3", b, 3, e8b); 301 | test_bool("Testing partition of fill 7b - 1\n", true, bitset_get(b, 32)); 302 | test_bool("Testing partition of fill 7b - 2\n", true, bitset_get(b, 62)); 303 | bitset_free(b); 304 | 305 | uint32_t p9[] = { BITSET_CREATE_FILL(3, 0), BITSET_CREATE_FILL(1, 2) }; 306 | b = bitset_new_buffer((const char *)p9, 8); 307 | test_bool("Testing partition of fill 8\n", false, bitset_set_to(b, 32, true)); 308 | uint32_t e9[] = { BITSET_CREATE_FILL(1, 1), BITSET_CREATE_FILL(1, 0), BITSET_CREATE_FILL(1, 2) }; 309 | test_bitset("Testing partition of fill 9", b, 3, e9); 310 | bitset_free(b); 311 | 312 | uint32_t p10[] = { BITSET_CREATE_EMPTY_FILL(1), BITSET_CREATE_FILL(1, 0) }; 313 | b = bitset_new_buffer((const char *)p10, 8); 314 | test_bool("Testing partition of fill 10\n", false, bitset_set_to(b, 1, true)); 315 | uint32_t e10[] = { BITSET_CREATE_LITERAL(1), BITSET_CREATE_FILL(1, 0) }; 316 | test_bitset("Testing partition of fill 11", b, 2, e10); 317 | bitset_free(b); 318 | 319 | uint32_t p11[] = { BITSET_CREATE_FILL(1, 0) }; 320 | b = bitset_new_buffer((const char *)p11, 4); 321 | test_bool("Testing setting position bit 1\n", true, bitset_set_to(b, 31, true)); 322 | test_bitset("Testing setting position bit 2", b, 1, p11); 323 | uint32_t e11[] = { BITSET_CREATE_EMPTY_FILL(1) }; 324 | test_bool("Testing setting position bit 3\n", true, bitset_set_to(b, 31, false)); 325 | test_bitset("Testing setting position bit 4", b, 1, e11); 326 | bitset_free(b); 327 | 328 | b = bitset_new(); 329 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 0, true)); 330 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 36, true)); 331 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 4, true)); 332 | test_bool("Testing random set/get 2\n", true, bitset_get(b, 0)); 333 | test_bool("Testing random set/get 2\n", true, bitset_get(b, 36)); 334 | test_bool("Testing random set/get 2\n", true, bitset_get(b, 4)); 335 | bitset_free(b); 336 | 337 | b = bitset_new(); 338 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 47, true)); 339 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 58, true)); 340 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 34, true)); 341 | test_bool("Testing random set/get 3\n", true, bitset_get(b, 47)); 342 | test_bool("Testing random set/get 4\n", true, bitset_get(b, 58)); 343 | test_bool("Testing random set/get 5\n", true, bitset_get(b, 34)); 344 | bitset_free(b); 345 | 346 | b = bitset_new(); 347 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 99, true)); 348 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 85, true)); 349 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 27, true)); 350 | test_bool("Testing random set/get 6\n", true, bitset_get(b, 99)); 351 | test_bool("Testing random set/get 7\n", true, bitset_get(b, 85)); 352 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 27)); 353 | bitset_free(b); 354 | 355 | b = bitset_new(); 356 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 62, true)); 357 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 29, true)); 358 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 26, true)); 359 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 65, true)); 360 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 54, true)); 361 | test_bool("Testing random set/get 6\n", true, bitset_get(b, 62)); 362 | test_bool("Testing random set/get 7\n", true, bitset_get(b, 29)); 363 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 26)); 364 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 65)); 365 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 54)); 366 | bitset_free(b); 367 | 368 | b = bitset_new(); 369 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 73, true)); 370 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 83, true)); 371 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 70, true)); 372 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 48, true)); 373 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 11, true)); 374 | test_bool("Testing random set/get 6\n", true, bitset_get(b, 73)); 375 | test_bool("Testing random set/get 7\n", true, bitset_get(b, 83)); 376 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 70)); 377 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 48)); 378 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 11)); 379 | bitset_free(b); 380 | 381 | b = bitset_new(); 382 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 10, true)); 383 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 20, true)); 384 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 96, true)); 385 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 52, true)); 386 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 32, true)); 387 | test_bool("Testing random set/get 6\n", true, bitset_get(b, 10)); 388 | test_bool("Testing random set/get 7\n", true, bitset_get(b, 20)); 389 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 96)); 390 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 52)); 391 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 32)); 392 | bitset_free(b); 393 | 394 | b = bitset_new(); 395 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 62, true)); 396 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 96, true)); 397 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 55, true)); 398 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 88, true)); 399 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 19, true)); 400 | test_bool("Testing random set/get 6\n", true, bitset_get(b, 62)); 401 | test_bool("Testing random set/get 7\n", true, bitset_get(b, 96)); 402 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 55)); 403 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 88)); 404 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 19)); 405 | bitset_free(b); 406 | 407 | b = bitset_new(); 408 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 73, true)); 409 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 93, true)); 410 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 14, true)); 411 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 51, true)); 412 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 41, true)); 413 | test_bool("Testing random set/get 6\n", true, bitset_get(b, 73)); 414 | test_bool("Testing random set/get 7\n", true, bitset_get(b, 93)); 415 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 14)); 416 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 51)); 417 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 41)); 418 | bitset_free(b); 419 | 420 | b = bitset_new(); 421 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 99, true)); 422 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 23, true)); 423 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 45, true)); 424 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 57, true)); 425 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 67, true)); 426 | test_bool("Testing random set/get 6\n", true, bitset_get(b, 99)); 427 | test_bool("Testing random set/get 7\n", true, bitset_get(b, 23)); 428 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 45)); 429 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 57)); 430 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 67)); 431 | bitset_free(b); 432 | 433 | b = bitset_new(); 434 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 71, true)); 435 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 74, true)); 436 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 94, true)); 437 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 19, true)); 438 | test_bool("Testing random set/get 6\n", true, bitset_get(b, 71)); 439 | test_bool("Testing random set/get 7\n", true, bitset_get(b, 74)); 440 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 94)); 441 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 19)); 442 | bitset_free(b); 443 | 444 | b = bitset_new(); 445 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 85, true)); 446 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 25, true)); 447 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 93, true)); 448 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 88, true)); 449 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 54, true)); 450 | test_bool("Testing random set/get 6\n", true, bitset_get(b, 85)); 451 | test_bool("Testing random set/get 7\n", true, bitset_get(b, 25)); 452 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 93)); 453 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 88)); 454 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 54)); 455 | bitset_free(b); 456 | 457 | b = bitset_new(); 458 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 94, true)); 459 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 47, true)); 460 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 79, true)); 461 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 67, true)); 462 | test_bool("Testing random set/get 1\n", false, bitset_set_to(b, 24, true)); 463 | test_bool("Testing random set/get 6\n", true, bitset_get(b, 94)); 464 | test_bool("Testing random set/get 7\n", true, bitset_get(b, 47)); 465 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 79)); 466 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 67)); 467 | test_bool("Testing random set/get 8\n", true, bitset_get(b, 24)); 468 | bitset_free(b); 469 | 470 | #ifdef BITSET_64BIT_OFFSETS 471 | b = bitset_new(b); 472 | bitset_set_to(b, 1, true); 473 | bitset_set_to(b, 1000000000000, true); 474 | test_bool("Testing set where a chain of fills is required 1\n", true, bitset_get(b, 1)); 475 | test_bool("Testing set where a chain of fills is required 2\n", true, bitset_get(b, 1000000000000)); 476 | test_ulong("Testing set where a chain of fills is required 3\n", 2, bitset_count(b)); 477 | bitset_free(b); 478 | #endif 479 | } 480 | 481 | void test_suite_stress() { 482 | bitset_t *b = bitset_new(); 483 | unsigned int max = 100000000, num = 1000; 484 | unsigned *bits = bitset_malloc(sizeof(unsigned) * num); 485 | srand(time(NULL)); 486 | for (size_t i = 0; i < num; i++) { 487 | bits[i] = rand() % max; 488 | bitset_set_to(b, bits[i], true); 489 | } 490 | for (size_t i = 0; i < num; i++) { 491 | test_bool("Checking stress test bits were set", true, bitset_get(b, bits[i])); 492 | } 493 | for (size_t i = 0; i < 86400; i++) { 494 | bitset_count(b); 495 | } 496 | bitset_malloc_free(bits); 497 | bitset_free(b); 498 | } 499 | 500 | void test_suite_operation() { 501 | bitset_operation_t *ops; 502 | bitset_t *b1, *b2, *b3, *b4; 503 | 504 | b1 = bitset_new(); 505 | b2 = bitset_new(); 506 | b3 = bitset_new(); 507 | bitset_set_to(b1, 100, true); 508 | //bitset_set_to(b1, 138, true); 509 | //bitset_set_to(b1, 169, true); 510 | bitset_set_to(b1, 200, true); 511 | bitset_set_to(b1, 300, true); 512 | bitset_set_to(b2, 100, true); 513 | bitset_set_to(b3, 300, true); 514 | bitset_set_to(b3, 400, true); 515 | ops = bitset_operation_new(b1); 516 | bitset_operation_add(ops, b2, BITSET_OR); 517 | bitset_operation_add(ops, b3, BITSET_OR); 518 | b4 = bitset_operation_exec(ops); 519 | test_int("Checking operation regression count 1\n", 4, bitset_count(b4)); 520 | test_bool("Checking operation regression 1\n", true, bitset_get(b4, 100)); 521 | test_bool("Checking operation regression 2\n", true, bitset_get(b4, 200)); 522 | test_bool("Checking operation regression 3\n", true, bitset_get(b4, 300)); 523 | test_bool("Checking opreation regression 4\n", true, bitset_get(b4, 400)); 524 | bitset_operation_free(ops); 525 | bitset_free(b1); 526 | bitset_free(b2); 527 | bitset_free(b3); 528 | bitset_free(b4); 529 | 530 | b1 = bitset_new(); 531 | b2 = bitset_new(); 532 | b3 = bitset_new(); 533 | bitset_set_to(b1, 2147483650, true); 534 | bitset_set_to(b1, 2147483760, true); 535 | bitset_set_to(b1, 3147483860, true); 536 | bitset_set_to(b2, 2147483760, true); 537 | bitset_set_to(b3, 300, true); 538 | bitset_set_to(b3, 3147483860, true); 539 | ops = bitset_operation_new(b1); 540 | bitset_operation_add(ops, b2, BITSET_OR); 541 | bitset_operation_add(ops, b3, BITSET_OR); 542 | b4 = bitset_operation_exec(ops); 543 | test_int("Checking operation regression count 2\n", 4, bitset_count(b4)); 544 | test_bool("Checking operation regression 5\n", true, bitset_get(b4, 2147483650)); 545 | test_bool("Checking operation regression 6\n", true, bitset_get(b4, 2147483760)); 546 | test_bool("Checking operation regression 7\n", true, bitset_get(b4, 300)); 547 | test_bool("Checking opreation regression 8\n", true, bitset_get(b4, 3147483860)); 548 | bitset_operation_free(ops); 549 | bitset_free(b1); 550 | bitset_free(b2); 551 | bitset_free(b3); 552 | bitset_free(b4); 553 | 554 | b1 = bitset_new(); 555 | b2 = bitset_new(); 556 | b3 = bitset_new(); 557 | bitset_set_to(b1, 100, true); 558 | bitset_set_to(b1, 200, true); 559 | bitset_set_to(b1, 199, true); 560 | bitset_set_to(b1, 300, true); 561 | bitset_set_to(b1, 10000, true); 562 | bitset_set_to(b2, 1, true); 563 | bitset_set_to(b2, 60, true); 564 | bitset_set_to(b2, 100, true); 565 | bitset_set_to(b2, 200, true); 566 | bitset_set_to(b2, 1000, true); 567 | bitset_set_to(b2, 2000, true); 568 | bitset_set_to(b2, 3000, true); 569 | bitset_set_to(b2, 10000, true); 570 | bitset_set_to(b3, 500, true); 571 | ops = bitset_operation_new(b1); 572 | bitset_operation_add(ops, b2, BITSET_AND); 573 | bitset_operation_add(ops, b3, BITSET_OR); 574 | b4 = bitset_operation_exec(ops); 575 | test_int("Checking operation regression count 3\n", 4, bitset_count(b4)); 576 | test_bool("Checking operation regression 5\n", true, bitset_get(b4, 100)); 577 | test_bool("Checking operation regression 6\n", true, bitset_get(b4, 200)); 578 | test_bool("Checking opreation regression 7\n", true, bitset_get(b4, 500)); 579 | test_bool("Checking operation regression 8\n", true, bitset_get(b4, 10000)); 580 | bitset_operation_free(ops); 581 | bitset_free(b1); 582 | bitset_free(b2); 583 | bitset_free(b3); 584 | bitset_free(b4); 585 | 586 | b1 = bitset_new(); 587 | b2 = bitset_new(); 588 | b3 = bitset_new(); 589 | bitset_set_to(b1, 100, true); 590 | bitset_set_to(b1, 200, true); 591 | bitset_set_to(b1, 199, true); 592 | bitset_set_to(b1, 300, true); 593 | bitset_set_to(b1, 10000, true); 594 | bitset_set_to(b2, 1, true); 595 | bitset_set_to(b2, 60, true); 596 | bitset_set_to(b2, 100, true); 597 | bitset_set_to(b2, 200, true); 598 | bitset_set_to(b2, 1000, true); 599 | bitset_set_to(b2, 2000, true); 600 | bitset_set_to(b2, 3000, true); 601 | bitset_set_to(b2, 10000, true); 602 | bitset_set_to(b3, 500, true); 603 | ops = bitset_operation_new(b2); 604 | bitset_operation_add(ops, b1, BITSET_AND); 605 | bitset_operation_add(ops, b3, BITSET_OR); 606 | b4 = bitset_operation_exec(ops); 607 | test_int("Checking operation regression count 4\n", 4, bitset_count(b4)); 608 | test_bool("Checking operation regression 6\n", true, bitset_get(b4, 100)); 609 | test_bool("Checking operation regression 7\n", true, bitset_get(b4, 200)); 610 | test_bool("Checking opreation regression 8\n", true, bitset_get(b4, 500)); 611 | test_bool("Checking operation regression 9\n", true, bitset_get(b4, 10000)); 612 | bitset_operation_free(ops); 613 | bitset_free(b1); 614 | bitset_free(b2); 615 | bitset_free(b3); 616 | bitset_free(b4); 617 | 618 | b1 = bitset_new(); 619 | bitset_set_to(b1, 10, true); 620 | b2 = bitset_new(); 621 | bitset_set_to(b2, 20, true); 622 | b3 = bitset_new(); 623 | bitset_set_to(b3, 12, true); 624 | ops = bitset_operation_new(b1); 625 | test_int("Checking initial operation length is one\n", 1, ops->length); 626 | test_bool("Checking primary bitset_t is added\n", true, bitset_get(&ops->steps[0]->data.bitset, 10)); 627 | bitset_operation_add(ops, b2, BITSET_OR); 628 | test_int("Checking op length increases\n", 2, ops->length); 629 | bitset_operation_add(ops, b3, BITSET_OR); 630 | test_int("Checking op length increases\n", 3, ops->length); 631 | test_bool("Checking bitset was added correctly\n", true, bitset_get(&ops->steps[1]->data.bitset, 20)); 632 | test_int("Checking op was added correctly\n", BITSET_OR, ops->steps[1]->type); 633 | test_bool("Checking bitset was added correctly\n", true, bitset_get(&ops->steps[2]->data.bitset, 12)); 634 | test_int("Checking op was added correctly\n", BITSET_OR, ops->steps[2]->type); 635 | test_ulong("Checking operation count 1\n", 3, bitset_operation_count(ops)); 636 | bitset_operation_free(ops); 637 | bitset_free(b1); 638 | bitset_free(b2); 639 | bitset_free(b3); 640 | 641 | b1 = bitset_new(); 642 | b2 = bitset_new(); 643 | b3 = bitset_new(); 644 | bitset_set_to(b1, 1000, true); 645 | bitset_set_to(b2, 100, true); 646 | bitset_set_to(b3, 20, true); 647 | ops = bitset_operation_new(b1); 648 | bitset_operation_add(ops, b2, BITSET_OR); 649 | bitset_operation_add(ops, b3, BITSET_OR); 650 | test_ulong("Checking operation count 2\n", 3, bitset_operation_count(ops)); 651 | bitset_operation_free(ops); 652 | bitset_free(b1); 653 | bitset_free(b2); 654 | bitset_free(b3); 655 | 656 | b1 = bitset_new(); 657 | b2 = bitset_new(); 658 | b3 = bitset_new(); 659 | bitset_set_to(b1, 102, true); 660 | bitset_set_to(b1, 10000, true); 661 | bitset_set_to(b2, 100, true); 662 | bitset_set_to(b3, 20, true); 663 | bitset_set_to(b3, 101, true); 664 | bitset_set_to(b3, 20000, true); 665 | ops = bitset_operation_new(b1); 666 | bitset_operation_add(ops, b2, BITSET_OR); 667 | bitset_operation_add(ops, b3, BITSET_OR); 668 | test_ulong("Checking operation count 3\n", 6, bitset_operation_count(ops)); 669 | bitset_operation_free(ops); 670 | bitset_free(b1); 671 | bitset_free(b2); 672 | bitset_free(b3); 673 | 674 | b1 = bitset_new(); 675 | b2 = bitset_new(); 676 | b3 = bitset_new(); 677 | bitset_set_to(b1, 101, true); 678 | bitset_set_to(b1, 8000, true); 679 | bitset_set_to(b2, 100, true); 680 | bitset_set_to(b3, 20, true); 681 | bitset_set_to(b3, 101, true); 682 | bitset_set_to(b3, 8001, true); 683 | ops = bitset_operation_new(b1); 684 | bitset_operation_add(ops, b2, BITSET_OR); 685 | bitset_operation_add(ops, b3, BITSET_OR); 686 | test_ulong("Checking operation count 4\n", 5, bitset_operation_count(ops)); 687 | bitset_operation_free(ops); 688 | bitset_free(b1); 689 | bitset_free(b2); 690 | bitset_free(b3); 691 | 692 | b1 = bitset_new(); 693 | b2 = bitset_new(); 694 | b3 = bitset_new(); 695 | bitset_set_to(b1, 101, true); 696 | bitset_set_to(b1, 102, true); 697 | bitset_set_to(b2, 1000, true); 698 | bitset_set_to(b3, 101, true); 699 | bitset_set_to(b3, 1000, true); 700 | ops = bitset_operation_new(b1); 701 | bitset_operation_add(ops, b2, BITSET_OR); 702 | bitset_operation_add(ops, b3, BITSET_AND); 703 | test_ulong("Checking operation count 5\n", 2, bitset_operation_count(ops)); 704 | bitset_operation_free(ops); 705 | bitset_free(b1); 706 | bitset_free(b2); 707 | bitset_free(b3); 708 | 709 | b1 = bitset_new(); 710 | b2 = bitset_new(); 711 | b3 = bitset_new(); 712 | bitset_set_to(b1, 1000, true); 713 | bitset_set_to(b2, 100, true); 714 | bitset_set_to(b2, 105, true); 715 | bitset_set_to(b2, 130, true); 716 | bitset_set_to(b3, 20, true); 717 | ops = bitset_operation_new(b1); 718 | bitset_operation_add(ops, b2, BITSET_OR); 719 | bitset_operation_add(ops, b3, BITSET_OR); 720 | b4 = bitset_operation_exec(ops); 721 | test_ulong("Checking operation exec 1\n", 5, bitset_count(b4)); 722 | test_bool("Checking operation exec get 1\n", true, bitset_get(b4, 1000)); 723 | test_bool("Checking operation exec get 2\n", true, bitset_get(b4, 100)); 724 | test_bool("Checking operation exec get 3\n", true, bitset_get(b4, 105)); 725 | test_bool("Checking operation exec get 4\n", true, bitset_get(b4, 130)); 726 | test_bool("Checking operation exec get 5\n", true, bitset_get(b4, 20)); 727 | bitset_operation_free(ops); 728 | bitset_free(b1); 729 | bitset_free(b2); 730 | bitset_free(b3); 731 | bitset_free(b4); 732 | 733 | b1 = bitset_new(); 734 | b2 = bitset_new(); 735 | b3 = bitset_new(); 736 | bitset_set_to(b1, 1000, true); 737 | bitset_set_to(b1, 1001, true); 738 | bitset_set_to(b1, 1100, true); 739 | bitset_set_to(b1, 3, true); 740 | bitset_set_to(b2, 1000, true); 741 | bitset_set_to(b2, 1101, true); 742 | bitset_set_to(b2, 3, true); 743 | bitset_set_to(b2, 130, true); 744 | bitset_set_to(b3, 1000, true); 745 | ops = bitset_operation_new(b1); 746 | bitset_operation_add(ops, b2, BITSET_AND); 747 | bitset_operation_add(ops, b3, BITSET_ANDNOT); 748 | b4 = bitset_operation_exec(ops); 749 | test_bool("Checking operation exec get 6\n", true, bitset_get(b4, 3)); 750 | test_bool("Checking operation exec get 7\n", false, bitset_get(b4, 1000)); 751 | test_bool("Checking operation exec get 8\n", false, bitset_get(b4, 130)); 752 | test_bool("Checking operation exec get 9\n", false, bitset_get(b4, 1001)); 753 | test_bool("Checking operation exec get 10\n", false, bitset_get(b4, 1100)); 754 | test_bool("Checking operation exec get 11\n", false, bitset_get(b4, 1101)); 755 | test_ulong("Checking operation exec 2\n", 1, bitset_count(b4)); 756 | bitset_operation_free(ops); 757 | bitset_free(b1); 758 | bitset_free(b2); 759 | bitset_free(b3); 760 | bitset_free(b4); 761 | 762 | b1 = bitset_new(); 763 | b2 = bitset_new(); 764 | b3 = bitset_new(); 765 | bitset_set_to(b1, 100, true); 766 | bitset_set_to(b1, 200, true); 767 | bitset_set_to(b1, 300, true); 768 | bitset_set_to(b2, 100, true); 769 | bitset_set_to(b3, 300, true); 770 | bitset_set_to(b3, 400, true); 771 | ops = bitset_operation_new(b1); 772 | bitset_operation_t *op2 = bitset_operation_new(b2); 773 | bitset_operation_add(op2, b3, BITSET_OR); 774 | bitset_operation_add_nested(ops, op2, BITSET_AND); 775 | b4 = bitset_operation_exec(ops); 776 | test_int("Checking nested operation count 1\n", 2, bitset_count(b4)); 777 | test_bool("Checking nested operation get 1\n", true, bitset_get(b4, 100)); 778 | test_bool("Checking nested operation get 2\n", true, bitset_get(b4, 300)); 779 | bitset_operation_free(ops); 780 | bitset_free(b1); 781 | bitset_free(b2); 782 | bitset_free(b3); 783 | bitset_free(b4); 784 | 785 | b1 = bitset_new(); 786 | b2 = bitset_new(); 787 | b3 = bitset_new(); 788 | bitset_set_to(b1, 100, true); 789 | bitset_set_to(b1, 200, true); 790 | bitset_set_to(b1, 300, true); 791 | bitset_set_to(b2, 100, true); 792 | bitset_set_to(b3, 300, true); 793 | bitset_set_to(b3, 400, true); 794 | ops = bitset_operation_new(b1); 795 | op2 = bitset_operation_new(b2); 796 | bitset_operation_add(op2, b3, BITSET_OR); 797 | bitset_operation_add_nested(ops, op2, BITSET_OR); 798 | b4 = bitset_operation_exec(ops); 799 | test_int("Checking nested operation count 2\n", 4, bitset_count(b4)); 800 | test_bool("Checking nested operation get 3\n", true, bitset_get(b4, 100)); 801 | test_bool("Checking nested operation get 4\n", true, bitset_get(b4, 200)); 802 | test_bool("Checking nested operation get 5\n", true, bitset_get(b4, 300)); 803 | test_bool("Checking nested operation get 6\n", true, bitset_get(b4, 400)); 804 | bitset_operation_free(ops); 805 | bitset_free(b1); 806 | bitset_free(b2); 807 | bitset_free(b3); 808 | bitset_free(b4); 809 | 810 | #ifdef BITSET_64BIT_OFFSETS 811 | b1 = bitset_new(); 812 | b2 = bitset_new(); 813 | bitset_set_to(b1, 1, true); 814 | bitset_set_to(b2, 10000000000, true); 815 | bitset_set_to(b2, 100000000000, true); 816 | ops = bitset_operation_new(b1); 817 | bitset_operation_add(ops, b2, BITSET_OR); 818 | b4 = bitset_operation_exec(ops); 819 | test_ulong("Checking operation exec 2\n", 3, bitset_count(b4)); 820 | test_bool("Checking operation exec get 12\n", true, bitset_get(b4, 1)); 821 | test_bool("Checking operation exec get 12\n", true, bitset_get(b4, 10000000000)); 822 | test_bool("Checking operation exec get 13\n", true, bitset_get(b4, 100000000000)); 823 | bitset_operation_free(ops); 824 | bitset_free(b1); 825 | bitset_free(b2); 826 | bitset_free(b4); 827 | #endif 828 | } 829 | 830 | void test_suite_vector() { 831 | 832 | bitset_vector_t *l, *l2, *l3; 833 | bitset_t *b; 834 | bitset_word *tmp; 835 | unsigned loop_count; 836 | unsigned offset, raw, unique; 837 | 838 | l = bitset_vector_new(); 839 | test_int("Checking vector length is zero initially\n", 0, bitset_vector_length(l)); 840 | test_int("Checking vector size is one initially\n", 1, l->size); 841 | test_int("Checking vector counts are initially zero\n", 0, bitset_vector_bitsets(l)); 842 | loop_count = 0; 843 | BITSET_VECTOR_FOREACH(l, b, offset) { 844 | loop_count++; 845 | } 846 | test_int("Checking an empty iterator is safe to use with foreach\n", 0, loop_count); 847 | bitset_vector_free(l); 848 | 849 | l = bitset_vector_new(); 850 | b = bitset_new(); 851 | bitset_vector_push(l, b, 0); 852 | test_int("Checking vector bitset count 1\n", 1, bitset_vector_bitsets(l)); 853 | test_int("Checking vector was resized properly 1\n", 4, l->size); 854 | test_int("Checking vector was resized properly 2\n", 4, l->length); 855 | test_int("Checking the offset is zero\n", 0, (unsigned char)l->buffer[0]); 856 | test_int("Checking the length is zero\n", 0, (unsigned char)l->buffer[1]); 857 | bitset_free(b); 858 | bitset_vector_free(l); 859 | 860 | l = bitset_vector_new(); 861 | b = bitset_new(); 862 | bitset_set_to(b, 10, true); 863 | bitset_vector_push(l, b, 3); 864 | test_int("Checking vector was resized properly 1\n", 8, l->size); 865 | test_int("Checking vector was resized properly 2\n", 8, l->length); 866 | tmp = b->buffer; 867 | b->buffer = (bitset_word *) (l->buffer + 4); 868 | test_bool("Checking bitset was added properly 1\n", true, bitset_get(b, 10)); 869 | test_bool("Checking bitset was added properly 2\n", false, bitset_get(b, 100)); 870 | b->buffer = tmp; 871 | bitset_free(b); 872 | 873 | 874 | b = bitset_new(); 875 | bitset_set_to(b, 100, true); 876 | bitset_set_to(b, 1000, true); 877 | bitset_vector_push(l, b, 10); 878 | test_int("Checking vector bitset count 2\n", 2, bitset_vector_bitsets(l)); 879 | test_int("Checking vector was resized properly 4\n", 32, l->size); 880 | test_int("Checking vector was resized properly 5\n", 20, l->length); 881 | tmp = b->buffer; 882 | b->buffer = (bitset_word *) (l->buffer + 12); 883 | test_bool("Checking bitset was added properly 3\n", true, bitset_get(b, 100)); 884 | test_bool("Checking bitset was added properly 4\n", true, bitset_get(b, 1000)); 885 | test_bool("Checking bitset was added properly 5\n", false, bitset_get(b, 10)); 886 | b->buffer = tmp; 887 | bitset_free(b); 888 | 889 | b = bitset_new(); 890 | bitset_set(b, 10000); 891 | bitset_set(b, 20000); 892 | l2 = bitset_vector_new(); 893 | bitset_vector_push(l2, b, 13600); 894 | bitset_free(b); 895 | loop_count = 0; 896 | BITSET_VECTOR_FOREACH(l2, b, offset) { 897 | loop_count++; 898 | test_bool("Checking vector medium offset 1\n", true, offset == 13600); 899 | test_bool("Checking vector medium offset 2\n", true, bitset_get(b, 10000)); 900 | test_bool("Checking vector medium offset 3\n", true, bitset_get(b, 20000)); 901 | test_int("Checking vector medium offset 4\n", 2, bitset_count(b)); 902 | } 903 | test_int("Checking it looped the right number of times a\n", 1, loop_count); 904 | bitset_vector_free(l2); 905 | 906 | loop_count = 0; 907 | BITSET_VECTOR_FOREACH(l, b, offset) { 908 | loop_count++; 909 | test_bool("Checking foreach works\n", true, offset == 3 || offset == 10); 910 | if (offset == 3) { 911 | test_int("Checking bitset count 1\n", 1, bitset_count(b)); 912 | test_bool("Checking bitset was added properly to iter 6\n", true, bitset_get(b, 10)); 913 | test_bool("Checking bitset was added properly to iter 7\n", false, bitset_get(b, 100)); 914 | } else if (offset == 10) { 915 | test_int("Checking bitset count 2\n", 2, bitset_count(b)); 916 | test_bool("Checking bitset was added properly to iter 8\n", false, bitset_get(b, 10)); 917 | test_bool("Checking bitset was added properly to iter 9\n", true, bitset_get(b, 100)); 918 | test_bool("Checking bitset was added properly to iter 10\n", true, bitset_get(b, 1000)); 919 | } 920 | } 921 | test_int("Checking it looped the right number of times\n", 2, loop_count); 922 | 923 | b = bitset_vector_merge(l); 924 | test_int("Checking vector merge 1\n", 3, bitset_count(b)); 925 | test_bool("Checking vector merge 2\n", true, bitset_get(b, 10)); 926 | test_bool("Checking vector merge 2\n", true, bitset_get(b, 100)); 927 | test_bool("Checking vector merge 2\n", true, bitset_get(b, 1000)); 928 | bitset_free(b); 929 | 930 | l3 = bitset_vector_new(); 931 | bitset_vector_concat(l3, l, 0, 3, 10); 932 | loop_count = 0; 933 | BITSET_VECTOR_FOREACH(l3, b, offset) { 934 | loop_count++; 935 | test_bool("Checking foreach works 2\n", true, offset == 3); 936 | } 937 | test_int("Checking it looped the right number of times 2\n", 1, loop_count); 938 | bitset_vector_free(l3); 939 | l3 = bitset_vector_new(); 940 | bitset_vector_concat(l3, l, 0, 4, 5); 941 | loop_count = 0; 942 | BITSET_VECTOR_FOREACH(l3, b, offset) { 943 | loop_count++; 944 | } 945 | test_int("Checking it looped the right number of times 3\n", 0, loop_count); 946 | bitset_vector_free(l3); 947 | 948 | l3 = bitset_vector_new(); 949 | bitset_vector_concat(l3, l, 0, BITSET_VECTOR_START, BITSET_VECTOR_END); 950 | bitset_vector_concat(l3, l, 11, BITSET_VECTOR_START, BITSET_VECTOR_END); 951 | bitset_vector_cardinality(l3, &raw, &unique); 952 | test_int("Checking vector bitset count 3\n", 4, bitset_vector_bitsets(l3)); 953 | test_int("Checking vector bitset count 4\n", 6, raw); 954 | test_int("Checking vector bitset count 5\n", 3, unique); 955 | loop_count = 0; 956 | BITSET_VECTOR_FOREACH(l3, b, offset) { 957 | loop_count++; 958 | test_bool("Checking foreach works 3\n", true, offset == 3 || 959 | offset == 10 || offset == 14 || offset == 21); 960 | } 961 | test_int("Checking it looped the right number of times 4\n", 4, loop_count); 962 | test_int("Checking tail offset\n", 21, l3->tail_offset); 963 | bitset_vector_free(l3); 964 | 965 | l3 = bitset_vector_new(); 966 | bitset_vector_concat(l3, l, 100000, BITSET_VECTOR_START, BITSET_VECTOR_END); 967 | bitset_vector_concat(l3, l, 200000, BITSET_VECTOR_START, BITSET_VECTOR_END); 968 | bitset_vector_cardinality(l3, &raw, &unique); 969 | test_int("Checking vector bitset count 3\n", 4, bitset_vector_bitsets(l3)); 970 | test_int("Checking vector bitset count 4\n", 6, raw); 971 | test_int("Checking vector bitset count 5\n", 3, unique); 972 | loop_count = 0; 973 | BITSET_VECTOR_FOREACH(l3, b, offset) { 974 | loop_count++; 975 | test_bool("Checking foreach works 3\n", true, offset == 100003 || 976 | offset == 100010 || offset == 200003 || offset == 200010); 977 | } 978 | test_int("Checking it looped the right number of times 4\n", 4, loop_count); 979 | test_int("Checking tail offset\n", 200010, l3->tail_offset); 980 | bitset_vector_free(l3); 981 | 982 | //Make a copy of the buffer 983 | char *buffer = bitset_malloc(sizeof(char) * l->length); 984 | memcpy(buffer, l->buffer, l->length); 985 | unsigned length = l->length; 986 | bitset_vector_free(l); 987 | 988 | //Check the copy is the same 989 | l = bitset_vector_import(buffer, length); 990 | test_int("Check size is copied\n", 32, l->size); 991 | test_int("Check length is copied\n", 20, l->length); 992 | test_int("Check tail_offset is copied\n", 10, l->tail_offset); 993 | bitset_vector_free(l); 994 | bitset_malloc_free(buffer); 995 | } 996 | 997 | void test_suite_vector_operation() { 998 | bitset_vector_operation_t *o1, *o2; 999 | bitset_vector_t *v1, *v2, *v3, *v4, *v5; 1000 | bitset_t *b1, *b2, *b3, *b4; 1001 | unsigned offset; 1002 | 1003 | b1 = bitset_new(); 1004 | bitset_set(b1, 100); 1005 | b2 = bitset_new(); 1006 | bitset_set(b2, 100); 1007 | b3 = bitset_new(); 1008 | bitset_set(b3, 100); 1009 | b4 = bitset_new(); 1010 | bitset_set(b4, 100); 1011 | v1 = bitset_vector_new(); 1012 | bitset_vector_push(v1, b1, 1); 1013 | bitset_vector_push(v1, b2, 2); 1014 | bitset_vector_push(v1, b3, 3); 1015 | bitset_vector_push(v1, b4, 4); 1016 | bitset_free(b1); 1017 | bitset_free(b2); 1018 | bitset_free(b3); 1019 | bitset_free(b4); 1020 | 1021 | b1 = bitset_new(); 1022 | bitset_set(b1, 200); 1023 | b2 = bitset_new(); 1024 | bitset_set(b2, 100); 1025 | bitset_set(b2, 200); 1026 | b3 = bitset_new(); 1027 | bitset_set(b3, 200); 1028 | b4 = bitset_new(); 1029 | bitset_set(b4, 200); 1030 | v2 = bitset_vector_new(); 1031 | bitset_vector_push(v2, b1, 2); 1032 | bitset_vector_push(v2, b2, 4); 1033 | bitset_vector_push(v2, b3, 6); 1034 | bitset_vector_push(v2, b4, 8); 1035 | bitset_free(b1); 1036 | bitset_free(b2); 1037 | bitset_free(b3); 1038 | bitset_free(b4); 1039 | 1040 | b1 = bitset_new(); 1041 | bitset_set(b1, 300); 1042 | b2 = bitset_new(); 1043 | bitset_set(b2, 100); 1044 | bitset_set(b2, 300); 1045 | b3 = bitset_new(); 1046 | bitset_set(b3, 300); 1047 | b4 = bitset_new(); 1048 | bitset_set(b4, 300); 1049 | v3 = bitset_vector_new(); 1050 | bitset_vector_push(v3, b1, 1); 1051 | bitset_vector_push(v3, b2, 2); 1052 | bitset_vector_push(v3, b3, 3); 1053 | bitset_vector_push(v3, b4, 4); 1054 | bitset_free(b1); 1055 | bitset_free(b2); 1056 | bitset_free(b3); 1057 | bitset_free(b4); 1058 | 1059 | b1 = bitset_new(); 1060 | bitset_set(b1, 400); 1061 | b2 = bitset_new(); 1062 | bitset_set(b2, 400); 1063 | b3 = bitset_new(); 1064 | bitset_set(b3, 400); 1065 | b4 = bitset_new(); 1066 | bitset_set(b4, 400); 1067 | v4 = bitset_vector_new(); 1068 | bitset_vector_push(v4, b1, 1); 1069 | bitset_vector_push(v4, b2, 2); 1070 | bitset_vector_push(v4, b3, 3); 1071 | bitset_vector_push(v4, b4, 4); 1072 | bitset_free(b1); 1073 | bitset_free(b2); 1074 | bitset_free(b3); 1075 | bitset_free(b4); 1076 | 1077 | //V1 AND (V2 | V3) OR V4 1078 | o1 = bitset_vector_operation_new(v1); 1079 | o2 = bitset_vector_operation_new(v2); 1080 | bitset_vector_operation_add(o2, v3, BITSET_OR); 1081 | bitset_vector_operation_add_nested(o1, o2, BITSET_AND); 1082 | bitset_vector_operation_add(o1, v4, BITSET_OR); 1083 | v5 = bitset_vector_operation_exec(o1); 1084 | bitset_vector_operation_free(o1); 1085 | 1086 | unsigned loop_count = 0; 1087 | BITSET_VECTOR_FOREACH(v5, b1, offset) { 1088 | loop_count++; 1089 | if (offset == 1) { 1090 | test_int("Check vector operation count 1\n", 1, bitset_count(b1)); 1091 | test_int("Check vector operation bitset 1\n", true, bitset_get(b1, 400)); 1092 | } else if (offset == 2) { 1093 | test_int("Check vector operation count 2\n", 2, bitset_count(b1)); 1094 | test_int("Check vector operation bitset 2\n", true, bitset_get(b1, 100)); 1095 | test_int("Check vector operation bitset 3\n", true, bitset_get(b1, 400)); 1096 | } else if (offset == 3) { 1097 | test_int("Check vector operation count 3\n", 1, bitset_count(b1)); 1098 | test_int("Check vector operation bitset 4\n", true, bitset_get(b1, 400)); 1099 | } else if (offset == 4) { 1100 | test_int("Check vector operation count 4\n", 2, bitset_count(b1)); 1101 | test_int("Check vector operation bitset 5\n", true, bitset_get(b1, 100)); 1102 | test_int("Check vector operation bitset 6\n", true, bitset_get(b1, 400)); 1103 | } else { 1104 | test_bool("", false, true); 1105 | } 1106 | } 1107 | test_int("Check vector operation looped right amount of times\n", 4, loop_count); 1108 | 1109 | bitset_vector_free(v1); 1110 | bitset_vector_free(v2); 1111 | bitset_vector_free(v3); 1112 | bitset_vector_free(v4); 1113 | bitset_vector_free(v5); 1114 | } 1115 | 1116 | void test_suite_estimate() { 1117 | BITSET_NEW(b1, 100); 1118 | BITSET_NEW(b2, 101); 1119 | BITSET_NEW(b3, 102); 1120 | BITSET_NEW(b4, 100, 101, 102); 1121 | bitset_linear_t *l = bitset_linear_new(102); 1122 | bitset_linear_add(l, b1); 1123 | bitset_linear_add(l, b2); 1124 | bitset_linear_add(l, b3); 1125 | bitset_linear_add(l, b4); 1126 | test_int("Test linear count\n", 3, bitset_linear_count(l)); 1127 | bitset_linear_free(l); 1128 | bitset_free(b1); 1129 | bitset_free(b2); 1130 | bitset_free(b3); 1131 | bitset_free(b4); 1132 | 1133 | BITSET_NEW(b5, 1, 2, 3, 40, 41, 42, 43, 51); 1134 | BITSET_NEW(b6, 1, 3, 41, 43); 1135 | BITSET_NEW(b7, 1); 1136 | bitset_countn_t *c = bitset_countn_new(1, 100); 1137 | bitset_countn_add(c, b5); 1138 | bitset_countn_add(c, b6); 1139 | bitset_countn_add(c, b7); 1140 | test_int("Test countn count where N=1\n", 4, bitset_countn_count(c)); 1141 | bitset_countn_free(c); 1142 | c = bitset_countn_new(2, 100); 1143 | bitset_countn_add(c, b5); 1144 | bitset_countn_add(c, b6); 1145 | bitset_countn_add(c, b7); 1146 | test_int("Test countn count where N=2\n", 3, bitset_countn_count(c)); 1147 | bitset_countn_free(c); 1148 | c = bitset_countn_new(3, 100); 1149 | bitset_countn_add(c, b5); 1150 | bitset_countn_add(c, b6); 1151 | bitset_countn_add(c, b7); 1152 | test_int("Test countn count where N=3\n", 1, bitset_countn_count(c)); 1153 | unsigned *all = bitset_countn_count_all(c); 1154 | test_int("Test countn count_all where N=1\n", 4, all[0]); 1155 | test_int("Test countn count_all where N=2\n", 3, all[1]); 1156 | test_int("Test countn count_all where N=3\n", 1, all[2]); 1157 | bitset_malloc_free(all); 1158 | 1159 | BITSET_NEW(mask, 2, 4, 5, 40, 41); 1160 | all = bitset_countn_count_mask(c, mask); 1161 | test_int("Test countn count_mask where N=1\n", 2, all[0]); 1162 | test_int("Test countn count_mask where N=2\n", 1, all[1]); 1163 | test_int("Test countn count_mask where N=3\n", 0, all[2]); 1164 | bitset_free(mask); 1165 | bitset_malloc_free(all); 1166 | 1167 | bitset_countn_free(c); 1168 | bitset_free(b5); 1169 | bitset_free(b6); 1170 | bitset_free(b7); 1171 | } 1172 | 1173 | -------------------------------------------------------------------------------- /test/test.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_H_ 2 | #define TEST_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include "bitset/bitset.h" 8 | 9 | void test_suite_macros(); 10 | void test_suite_get(); 11 | void test_suite_set(); 12 | void test_suite_stress(); 13 | void test_suite_count(); 14 | void test_suite_operation(); 15 | void test_suite_min(); 16 | void test_suite_max(); 17 | void test_suite_vector(); 18 | void test_suite_vector_operation(); 19 | void test_suite_estimate(); 20 | 21 | void test_bool(char *, bool, bool); 22 | void test_ulong(char *, unsigned long, unsigned long); 23 | void test_int(char *, int, int); 24 | bool test_bitset(char *, bitset_t *, unsigned, uint32_t *); 25 | void bitset_dump(bitset_t *); 26 | 27 | #endif 28 | --------------------------------------------------------------------------------