├── AUTHORS ├── .gitignore ├── examples ├── Makefile ├── example.cpp └── example.c ├── .travis.yml ├── dev ├── Makefile ├── bitlock_try_test.c ├── bit_array_generate.c ├── bitlock_test.c └── bit_array_test.c ├── Makefile ├── bar.h ├── LICENSE ├── bit_macros.h ├── bit_array.h └── README.md /AUTHORS: -------------------------------------------------------------------------------- 1 | Isaac Turner (@noporpoise) 2 | Diego Caro (@diegocaro) 3 | Sergey Philippov (@duhovny) 4 | Chris J. Kiick (@ckiick) 5 | Daniel McDonald (@wasade) 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dev/bartest 2 | dev/bit_array_generate 3 | dev/bit_array_test 4 | dev/bitlock_test 5 | dev/bitlock_try_test 6 | dev/core 7 | examples/example_c 8 | examples/example_cpp 9 | *.dump 10 | *.a 11 | *.o 12 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | ifndef CC 2 | CC = gcc 3 | endif 4 | 5 | CFLAGS = -Wall -Wextra -I.. -L.. 6 | 7 | all: example_cpp example_c 8 | 9 | example_cpp: example.cpp ../libbitarr.a 10 | $(CXX) $(CFLAGS) -o example_cpp example.cpp -lbitarr 11 | 12 | example_c: example.c ../libbitarr.a 13 | $(CC) $(CFLAGS) -Wc++-compat -o example_c example.c -lbitarr 14 | 15 | test: example_c example_cpp 16 | ./example_c 17 | ./example_cpp 18 | 19 | clean: 20 | rm -rf example_cpp example_c *.o *.dSYM *.greg 21 | 22 | .PHONY: all clean test 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Control file for continuous integration testing at http://travis-ci.org/ 2 | 3 | language: c 4 | compiler: 5 | - clang 6 | - gcc 7 | os: 8 | - linux 9 | - osx 10 | 11 | sudo: false 12 | 13 | install: make all 14 | script: make test 15 | 16 | # Gitter notifications 17 | notifications: 18 | webhooks: 19 | urls: 20 | - https://webhooks.gitter.im/e/6945dcbee7845a3c8966 21 | on_success: change # options: [always|never|change] default: always 22 | on_failure: always # options: [always|never|change] default: always 23 | on_start: false # default: false 24 | -------------------------------------------------------------------------------- /examples/example.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | examples/example.cpp 3 | project: bit array C library 4 | url: https://github.com/noporpoise/BitArray/ 5 | maintainer: Isaac Turner 6 | license: Public Domain, no warranty 7 | date: Sep 2014 8 | */ 9 | 10 | #include 11 | #include "bit_array.h" 12 | 13 | int main(int argc, char* argv[]) 14 | { 15 | using namespace std; 16 | 17 | if(argc > 1) 18 | { 19 | cout << " Unused args '" << argv[1] << "..'\n"; 20 | cout << "Usage: " << argv[0] << "\n"; 21 | return -1; 22 | } 23 | 24 | BIT_ARRAY *bitarr = bit_array_create(10); 25 | bit_array_print(bitarr, stdout); 26 | cout << "\n"; 27 | 28 | bit_array_set_bits(bitarr, 3, 1,2,5); 29 | bit_array_print(bitarr, stdout); 30 | cout << "\n"; 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /examples/example.c: -------------------------------------------------------------------------------- 1 | /* 2 | examples/example.c 3 | project: bit array C library 4 | url: https://github.com/noporpoise/BitArray/ 5 | maintainer: Isaac Turner 6 | license: Public Domain, no warranty 7 | date: Sep 2014 8 | */ 9 | 10 | #include 11 | #include 12 | #include "bit_array.h" 13 | 14 | int main(int argc, char* argv[]) 15 | { 16 | if(argc > 1) 17 | { 18 | printf("Unused args '%s..'\n", argv[1]); 19 | printf("Usage: ./%s\n", argv[0]); 20 | return EXIT_FAILURE; 21 | } 22 | 23 | BIT_ARRAY *bitarr = bit_array_create(10); 24 | bit_array_print(bitarr, stdout); 25 | fputc('\n', stdout); 26 | 27 | bit_array_set_bits(bitarr, 3, 1,2,5); 28 | bit_array_print(bitarr, stdout); 29 | fputc('\n', stdout); 30 | 31 | return EXIT_SUCCESS; 32 | } 33 | -------------------------------------------------------------------------------- /dev/Makefile: -------------------------------------------------------------------------------- 1 | ifndef CC 2 | CC = gcc 3 | endif 4 | 5 | ifdef DEBUG 6 | OPT = -DDEBUG=1 --debug -g 7 | else 8 | OPT = -O3 9 | endif 10 | 11 | CFLAGS = -Wall -Wextra -Wc++-compat 12 | 13 | all: bit_array_test bitlock_test bitlock_try_test bit_array_generate 14 | 15 | bit_array_test: bit_array_test.c ../bar.h ../libbitarr.a 16 | $(CC) $(OPT) $(CFLAGS) -I.. -L.. -o bit_array_test bit_array_test.c -lbitarr 17 | 18 | bitlock_test: bitlock_test.c ../bit_macros.h 19 | $(CC) $(OPT) $(CFLAGS) -I.. -o bitlock_test bitlock_test.c -lpthread 20 | 21 | bitlock_try_test: bitlock_try_test.c ../bit_macros.h 22 | $(CC) $(OPT) $(CFLAGS) -I.. -o bitlock_try_test bitlock_try_test.c -lpthread 23 | 24 | bit_array_generate: 25 | $(CC) $(OPT) $(CFLAGS) -o bit_array_generate bit_array_generate.c 26 | 27 | 28 | ../libbitarr.a: 29 | cd .. && make 30 | 31 | test: bit_array_test bitlock_test 32 | ./bit_array_test && ./bitlock_test 33 | 34 | clean: 35 | rm -rf bit_array_test bitlock_test bit_array_generate 36 | rm -rf bitarr_example.dump *.o *.dSYM *.greg 37 | 38 | .PHONY: all clean test 39 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC ?= gcc 2 | 3 | PLATFORM := $(shell uname) 4 | COMPILER := $(shell ($(CC) -v 2>&1) | tr A-Z a-z ) 5 | 6 | ifdef DEBUG 7 | OPT = -O0 -DDEBUG=1 --debug -g -ggdb 8 | else 9 | ifneq (,$(findstring gcc,$(COMPILER))) 10 | OPT = -O4 11 | TGTFLAGS = -fwhole-program 12 | else 13 | OPT = -O3 14 | endif 15 | endif 16 | 17 | CFLAGS = -Wall -Wextra -Wc++-compat -I. $(OPT) 18 | OBJFLAGS = -fPIC 19 | 20 | all: libbitarr.a dev examples 21 | 22 | bit_array.o: bit_array.c bit_array.h bit_macros.h 23 | 24 | libbitarr.a: bit_array.o 25 | ar -csru libbitarr.a bit_array.o 26 | 27 | %.o: %.c %.h 28 | $(CC) $(CFLAGS) $(OBJFLAGS) -c $< -o $@ 29 | 30 | dev: libbitarr.a bit_macros.h 31 | cd dev && $(MAKE) 32 | 33 | examples: libbitarr.a 34 | cd examples && $(MAKE) 35 | 36 | test: libbitarr.a 37 | cd dev && $(MAKE) test 38 | cd examples && $(MAKE) test 39 | 40 | clean: 41 | rm -rf libbitarr.a *.o *.dSYM *.greg 42 | cd dev && $(MAKE) clean 43 | cd examples && $(MAKE) clean 44 | 45 | # Comment this line out to keep .o files 46 | .INTERMEDIATE: $(OBJS) 47 | .PHONY: all clean test examples dev 48 | -------------------------------------------------------------------------------- /dev/bitlock_try_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | dev/bitlock_try_test.c 3 | project: bit array C library 4 | url: https://github.com/noporpoise/BitArray/ 5 | maintainer: Isaac Turner 6 | license: Public Domain, no warranty 7 | date: Sep 2014 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "bit_macros.h" 18 | 19 | // Use the bitlock_try_acquire() macro to visit each number exactly once 20 | 21 | typedef struct { 22 | pthread_t th; 23 | size_t id, result; 24 | uint8_t *locks; 25 | } TestThread; 26 | 27 | #define NWORKERS 10 28 | #define LIMIT 10000 29 | 30 | void* worker(void *ptr) 31 | { 32 | TestThread *wrkr = (TestThread*)ptr; 33 | size_t i, locked; 34 | for(i = 0; i < LIMIT; i++) { 35 | bitlock_try_acquire(wrkr->locks, i, &locked); 36 | wrkr->result += locked*i; 37 | if((i&0xff) == 0xff) { usleep(50); sched_yield(); } 38 | } 39 | return NULL; 40 | } 41 | 42 | // sum of 0 up to num (inclusive) 43 | #define cumm_sum(num) ((num)*(((num)+1)/2)+(((num)&1) ? 0 : (num)/2)) 44 | 45 | int main(int argc, char **argv) 46 | { 47 | (void)argc; (void)argv; 48 | 49 | size_t i; int rc; 50 | uint8_t *locks = (uint8_t*)calloc((LIMIT+7)/8, sizeof(uint8_t)); 51 | TestThread *workers = (TestThread*)calloc(NWORKERS, sizeof(TestThread)); 52 | 53 | // Create threads 54 | for(i = 0; i < NWORKERS; i++) { 55 | workers[i] = (TestThread){.id = i, .result = 0, .locks = locks}; 56 | rc = pthread_create(&workers[i].th, NULL, worker, &workers[i]); 57 | if(rc) { fprintf(stderr, "pthread error: %s\n", strerror(rc)); exit(-1); } 58 | } 59 | 60 | // Wait for threads to finish 61 | for(i = 0; i < NWORKERS; i++) { 62 | rc = pthread_join(workers[i].th, NULL); 63 | if(rc) { fprintf(stderr, "pthread error: %s\n", strerror(rc)); exit(-1); } 64 | } 65 | 66 | size_t sum = 0, expsum = cumm_sum(LIMIT-1); 67 | for(i = 0; i < NWORKERS; i++) sum += workers[i].result; 68 | 69 | bool pass = (sum == expsum); 70 | 71 | for(i = 0; i < sizeof(locks) && locks[i] == 0xff; i++) {} 72 | if(i < sizeof(locks)) { 73 | printf("locks not all ones!\n"); 74 | pass = false; 75 | } 76 | 77 | printf("sum: %zu exp: %zu\n", sum, expsum); 78 | printf("%s.\n\n", pass ? "Pass" : "Fail"); 79 | 80 | free(workers); 81 | free(locks); 82 | 83 | return pass ? EXIT_SUCCESS : EXIT_FAILURE; 84 | } 85 | -------------------------------------------------------------------------------- /dev/bit_array_generate.c: -------------------------------------------------------------------------------- 1 | /* 2 | dev/bit_array_generate.c 3 | project: bit array C library 4 | url: https://github.com/noporpoise/BitArray/ 5 | author: Isaac Turner 6 | license: Public Domain, no warranty 7 | date: Dec 2013 8 | */ 9 | 10 | 11 | // 64 bit words 12 | // Array length can be zero 13 | // Unused top bits must be zero 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include // memset 20 | #include 21 | 22 | uint8_t reverse(uint8_t b) 23 | { 24 | uint8_t r = 0; 25 | int i; 26 | 27 | for(i = 0; i < 8; i++) 28 | { 29 | r <<= 1; 30 | r |= b & 0x1; 31 | b >>= 1; 32 | } 33 | 34 | return r; 35 | } 36 | 37 | // Print table of bytes -> byte reverse 38 | void generate_reverse() 39 | { 40 | int i; 41 | printf("static const word_t reverse_table[256] = \n{\n "); 42 | for(i = 0; i < 256; i++) 43 | { 44 | if(i % 8 == 0 && i > 0) 45 | printf("\n "); 46 | 47 | printf(" 0x%02X%c", reverse(i), i == 255 ? '\n' : ','); 48 | } 49 | printf("};\n\n"); 50 | } 51 | 52 | uint16_t morton(uint8_t b) 53 | { 54 | uint16_t r = 0; 55 | int i; 56 | for(i = 0; i < 8; i++) 57 | { 58 | r |= (b & 0x1) << (2*i); 59 | b >>= 1; 60 | } 61 | return r; 62 | } 63 | 64 | // a is either 0 or 1, and is how much to shift by 65 | void generate_morton(char a) 66 | { 67 | int i; 68 | printf("static const word_t morton_table%c[256] = \n{\n ", a ? '1' : '0'); 69 | for(i = 0; i < 256; i++) 70 | { 71 | if(i % 8 == 0 && i > 0) 72 | printf("\n "); 73 | 74 | uint16_t m = morton(i); 75 | 76 | if(a) 77 | m <<= 1; 78 | 79 | printf(" 0x%04X%c", m, i == 255 ? '\n' : ','); 80 | } 81 | printf("};\n\n"); 82 | } 83 | 84 | unsigned int next_permutation(unsigned int v) 85 | { 86 | unsigned int t = v | (v - 1); // t gets v's least significant 0 bits set to 1 87 | // Next set to 1 the most significant bit to change, 88 | // set to 0 the least significant ones, and add the necessary 1 bits. 89 | //return (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(v) + 1)); 90 | return (t+1) | (((~t & (t+1)) - 1) >> (__builtin_ctz(v) + 1)); 91 | } 92 | 93 | long factorial(int k) 94 | { 95 | long r = k; 96 | for(k--; k > 1; k--) 97 | { 98 | r *= k; 99 | } 100 | return r; 101 | } 102 | 103 | void generate_shuffle() 104 | { 105 | int i; 106 | 107 | printf("static const uint8_t shuffle_permutations[9] = {1"); 108 | 109 | for(i = 1; i < 8; i++) 110 | { 111 | // nCk = n! / ((n-k)!k!) 112 | long combinations = factorial(8) / (factorial(8-i)*factorial(i)); 113 | printf(", %li", combinations); 114 | } 115 | 116 | printf(", 1};\n"); 117 | 118 | printf("static const uint8_t shuffle[9][70] = {\n"); 119 | 120 | for(i = 0; i <= 8; i++) 121 | { 122 | printf(" // %i bits set\n", i); 123 | unsigned char init = i == 0 ? 0 : (0x1 << i) - 1; 124 | 125 | printf(" {0x%02X", (int)init); 126 | 127 | unsigned int c = next_permutation(init); 128 | int num; 129 | 130 | for(num = 1; num < 70; c = next_permutation(c), num++) 131 | { 132 | printf(num % 10 == 0 ? ",\n " : ", "); 133 | printf("0x%02X", c <= 255 ? (int)c : 0); 134 | } 135 | 136 | printf(i < 8 ? "},\n" : "}\n};\n\n"); 137 | } 138 | } 139 | 140 | int main() 141 | { 142 | printf("// byte reverse look up table\n"); 143 | generate_reverse(); 144 | printf("// Morton table for interleaving bytes\n"); 145 | generate_morton(0); 146 | printf("// Morton table for interleaving bytes, shifted left 1 bit\n"); 147 | generate_morton(1); 148 | printf("// Tables for shuffling\n"); 149 | generate_shuffle(); 150 | return 1; 151 | } 152 | -------------------------------------------------------------------------------- /dev/bitlock_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | dev/bitlock_test.c 3 | project: bit array C library 4 | url: https://github.com/noporpoise/BitArray/ 5 | maintainer: Isaac Turner 6 | license: Public Domain, no warranty 7 | date: Aug 2014 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "bit_macros.h" 18 | 19 | typedef struct { 20 | pthread_t th; 21 | size_t id, result; 22 | } TestThread; 23 | 24 | // Do a million loops 25 | #define NUM_LOOPS 10000 26 | char *locks, *data; 27 | pthread_mutex_t *mutexes; 28 | 29 | void* worker_bitlock(void *ptr) 30 | { 31 | TestThread *wrkr = (TestThread*)ptr; 32 | size_t i; 33 | for(i = 0; i < NUM_LOOPS; i++) { 34 | bitlock_yield_acquire(locks, i); 35 | wrkr->result += i + *(volatile char *)&data[i]; 36 | data[i] = wrkr->id; 37 | usleep(5); 38 | bitlock_release(locks, i); 39 | usleep(5); 40 | } 41 | 42 | return NULL; 43 | } 44 | 45 | void* worker_bitlock_spin(void *ptr) 46 | { 47 | TestThread *wrkr = (TestThread*)ptr; 48 | size_t i; 49 | for(i = 0; i < NUM_LOOPS; i++) { 50 | bitlock_acquire(locks, i); 51 | wrkr->result += i + *(volatile char *)&data[i]; 52 | data[i] = wrkr->id; 53 | usleep(5); 54 | bitlock_release(locks, i); 55 | usleep(5); 56 | } 57 | 58 | return NULL; 59 | } 60 | 61 | void* worker_mutex(void *ptr) 62 | { 63 | TestThread *wrkr = (TestThread*)ptr; 64 | size_t i; 65 | for(i = 0; i < NUM_LOOPS; i++) { 66 | pthread_mutex_lock(&mutexes[0]); 67 | wrkr->result += i + *(volatile char *)&data[i]; 68 | data[i] = wrkr->id; 69 | usleep(5); 70 | pthread_mutex_unlock(&mutexes[0]); 71 | usleep(5); 72 | } 73 | 74 | return NULL; 75 | } 76 | 77 | void* worker_mutexes(void *ptr) 78 | { 79 | TestThread *wrkr = (TestThread*)ptr; 80 | size_t i; 81 | for(i = 0; i < NUM_LOOPS; i++) { 82 | pthread_mutex_lock(&mutexes[i]); 83 | wrkr->result += i + *(volatile char *)&data[i]; 84 | data[i] = wrkr->id; 85 | usleep(5); 86 | pthread_mutex_unlock(&mutexes[i]); 87 | usleep(5); 88 | } 89 | 90 | return NULL; 91 | } 92 | 93 | // sum of 0 up to num (inclusive) 94 | #define cumm_sum(num) ((num)*(((num)+1)/2)+(((num)&1) ? 0 : (num)/2)) 95 | 96 | int main(int argc, char **argv) 97 | { 98 | char *method = "Bitlocks"; 99 | void* (*func)(void*) = worker_bitlock; 100 | 101 | if(argc == 2 && strcmp(argv[1],"bits") == 0) {} 102 | else if(argc == 2 && strcmp(argv[1],"mutex") == 0) { 103 | method = "Mutex"; 104 | func = worker_mutex; 105 | } 106 | else if(argc == 2 && strcmp(argv[1],"mutexes") == 0) { 107 | method = "Mutexes"; 108 | func = worker_mutexes; 109 | } 110 | else if(argc == 2 && strcmp(argv[1],"spin") == 0) { 111 | method = "Bitlocks-Spin"; 112 | func = worker_bitlock_spin; 113 | } 114 | else if(argc != 1) { 115 | fprintf(stderr, "usage: ./bitlock_test \n"); 116 | exit(-1); 117 | } 118 | 119 | printf("\nTesting %s\n\n", method); 120 | 121 | int rc; 122 | size_t i, num_threads = 30; 123 | TestThread workers[num_threads]; 124 | 125 | locks = (char*)calloc(1, (NUM_LOOPS+7)/8); 126 | data = (char*)calloc(1, NUM_LOOPS); 127 | mutexes = (pthread_mutex_t*)calloc(NUM_LOOPS, sizeof(pthread_mutex_t)); 128 | 129 | for(i = 0; i < NUM_LOOPS; i++) 130 | pthread_mutex_init(&mutexes[i], NULL); 131 | 132 | // for(i = 0; i < num_threads; i++) 133 | // printf("cummulative sum %zu: %zu\n", i, cumm_sum(i)); 134 | 135 | // Create threads 136 | for(i = 0; i < num_threads; i++) { 137 | workers[i] = (TestThread){.id = i+1, .result = 0}; 138 | rc = pthread_create(&workers[i].th, NULL, func, &workers[i]); 139 | if(rc) { fprintf(stderr, "pthread error: %s\n", strerror(rc)); exit(-1); } 140 | } 141 | 142 | // Wait for threads to finish 143 | for(i = 0; i < num_threads; i++) { 144 | rc = pthread_join(workers[i].th, NULL); 145 | if(rc) { fprintf(stderr, "pthread error: %s\n", strerror(rc)); exit(-1); } 146 | } 147 | 148 | for(i = 0; i < NUM_LOOPS; i++) 149 | pthread_mutex_destroy(&mutexes[i]); 150 | 151 | size_t sum = 0, expsum = 0; 152 | for(i = 0; i < NUM_LOOPS; i++) sum += data[i]; 153 | for(i = 0; i < num_threads; i++) sum += workers[i].result; 154 | 155 | // for(i = 0; i < num_threads; i++) printf("got: %zu %zu\n", i, workers[i].result); 156 | 157 | // 0 1 2 3 4 5 158 | // 0 1 3 6 10 159 | expsum = cumm_sum(NUM_LOOPS-1)*num_threads + cumm_sum(num_threads)*NUM_LOOPS; 160 | // expsum = cumm_sum(NUM_LOOPS-1) * num_threads; 161 | 162 | bool pass = (sum == expsum); 163 | 164 | for(i = 0; i < sizeof(locks) && locks[i] == 0; i++) {} 165 | if(i < sizeof(locks)) { 166 | printf("locks not zeroed!\n"); 167 | pass = false; 168 | } 169 | 170 | printf("sum: %zu exp: %zu\n", sum, expsum); 171 | printf("%s.\n\n", pass ? "Pass" : "Fail"); 172 | 173 | free(mutexes); 174 | free(data); 175 | free(locks); 176 | 177 | return pass ? EXIT_SUCCESS : EXIT_FAILURE; 178 | } 179 | -------------------------------------------------------------------------------- /bar.h: -------------------------------------------------------------------------------- 1 | /* 2 | bar.h 3 | project: bit array C library 4 | url: https://github.com/noporpoise/BitArray/ 5 | maintainer: Isaac Turner 6 | license: Public Domain, no warranty 7 | date: Sept 2014 8 | */ 9 | 10 | // shorten the names of some of the bit_array functions to be more 11 | // like the str* function names. The prefix "bar" is used to represent 12 | // bit_array and is analogous to "str". 13 | 14 | #ifndef BAR_HEADER_SEEN 15 | #define BAR_HEADER_SEEN 16 | 17 | #include "bit_array.h" 18 | 19 | #define bar BIT_ARRAY 20 | 21 | #define barcreate bit_array_create 22 | #define bardestroy bit_array_free 23 | #define baralloc bit_array_alloc 24 | #define barfree bit_array_dealloc 25 | #define barlen bit_array_length 26 | 27 | #define barsize bit_array_resize 28 | #define barcap bit_array_ensure_size 29 | 30 | // These five are MACROs 31 | #define barget bit_array_get 32 | #define barset bit_array_set 33 | #define barclr bit_array_clear 34 | #define barflip bit_array_toggle 35 | #define barmake bit_array_assign 36 | 37 | /* Functions instead of macros bars* => s for safe */ 38 | #define barsget bit_array_get_bit 39 | #define barsset bit_array_set_bit 40 | #define barsclr bit_array_clear_bit 41 | #define barsflip bit_array_toggle_bit 42 | #define barsmake bit_array_assign_bit 43 | 44 | /* "resize" functions barr*: automatically enlarge array if needed */ 45 | #define barrget bit_array_rget 46 | #define barrset bit_array_rset 47 | #define barrclr bit_array_rclear 48 | #define barrflip bit_array_rtoggle 49 | #define barrmake bit_array_rassign 50 | 51 | #define barsetn bit_array_set_bits 52 | #define barclrn bit_array_clear_bits 53 | #define barflipn bit_array_toggle_bits 54 | 55 | #define barsetr bit_array_set_region 56 | #define barclrr bit_array_clear_region 57 | #define barflipr bit_array_toggle_region 58 | 59 | #define barfill bit_array_set_all 60 | #define barzero bit_array_clear_all 61 | #define bartogl bit_array_toggle_all 62 | 63 | /* gw "get word" */ 64 | #define bargw64 bit_array_get_word64 65 | #define bargw32 bit_array_get_word32 66 | #define bargw16 bit_array_get_word16 67 | #define bargw8 bit_array_get_word8 68 | #define bargwn bit_array_get_wordn 69 | 70 | /* sw "set word" */ 71 | #define barsw64 bit_array_set_word64 72 | #define barsw32 bit_array_set_word32 73 | #define barsw16 bit_array_set_word16 74 | #define barswn bit_array_set_wordn 75 | 76 | #define barncpy bit_array_copy 77 | #define barcpy bit_array_copy_all 78 | #define bardup bit_array_clone 79 | 80 | #define barpopc bit_array_num_bits_set 81 | #define barzeros bit_array_num_bits_cleared 82 | #define bardist bit_array_hamming_distance 83 | #define barparity bit_array_parity 84 | 85 | #define barfns bit_array_find_next_set_bit 86 | #define barfps bit_array_find_prev_set_bit 87 | #define barffs bit_array_find_first_set_bit 88 | #define barfls bit_array_find_last_set_bit 89 | 90 | #define barfnz bit_array_find_next_clear_bit 91 | #define barfpz bit_array_find_prev_clear_bit 92 | #define barffz bit_array_find_first_clear_bit 93 | #define barflz bit_array_find_last_clear_bit 94 | 95 | #define barsort bit_array_sort_bits 96 | #define barsortr bit_array_sort_bits_rev 97 | 98 | #define barand bit_array_and 99 | #define baror bit_array_or 100 | #define barxor bit_array_xor 101 | #define barnot bit_array_not 102 | 103 | #define barcmp bit_array_cmp 104 | #define barcmpbe bit_array_cmp_big_endian 105 | #define barcmpw bit_array_cmp_words 106 | #define barcmp64 bit_array_cmp_uint64 107 | 108 | #define barshr bit_array_shift_right 109 | #define barshl bit_array_shift_left 110 | #define bareshl bit_array_shift_left_extend 111 | 112 | #define barcycr bit_array_cycle_right 113 | #define barcycl bit_array_cycle_left 114 | 115 | #define barmix bit_array_interleave 116 | 117 | #define barrev bit_array_reverse 118 | #define barrevr bit_array_reverse_region 119 | 120 | #define bar2num bit_array_as_num 121 | 122 | /* Add/sub/mult/div a bit array with: */ 123 | /* _i unsigned integer, _si shifted integer, _sb shifted bitarray */ 124 | #define baraddi bit_array_add_uint64 125 | #define baraddsi bit_array_add_word 126 | #define baraddsb bit_array_add_words 127 | #define barsubi bit_array_sub_uint64 128 | #define barsubsi bit_array_sub_word 129 | #define barsubsb bit_array_sub_words 130 | #define barmuli bit_array_mul_uint64 131 | #define bardivi bit_array_div_uint64 132 | 133 | /* arguments are both bit arrays */ 134 | #define baradd bit_array_add 135 | #define barsub bit_array_subtract 136 | #define barmul bit_array_multiply 137 | #define bardiv bit_array_divide 138 | 139 | #define barsave bit_array_save 140 | #define barload bit_array_load 141 | 142 | #define barhash bit_array_hash 143 | 144 | #define barrand bit_array_random 145 | #define barshfl bit_array_shuffle 146 | #define barperm bit_array_next_permutation 147 | 148 | #endif /* BAR_HEADER_SEEN */ 149 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Statement of Purpose 2 | -------------------- 3 | 4 | The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). 5 | 6 | Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. 7 | 8 | For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 9 | 10 | ----------------------- 11 | 12 | 1. *Copyright and Related Rights.* A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: 13 | 14 | - the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; 15 | - moral rights retained by the original author(s) and/or performer(s); 16 | - publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; 17 | - rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; 18 | - rights protecting the extraction, dissemination, use and reuse of data in a Work; 19 | - database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and 20 | - other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 21 | 22 | 2. *Waiver.* To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 23 | 24 | 3. *Public License Fallback.* Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 25 | 26 | 4. *Limitations and Disclaimers.* 27 | 28 | - No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. 29 | - Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. 30 | - Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. 31 | - Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. 32 | -------------------------------------------------------------------------------- /bit_macros.h: -------------------------------------------------------------------------------- 1 | /* 2 | bit_macros.h 3 | project: bit array C library 4 | url: https://github.com/noporpoise/BitArray/ 5 | author: Isaac Turner 6 | license: Public Domain, no warranty 7 | date: Dec 2013 8 | */ 9 | 10 | #ifndef BITSET_H_ 11 | #define BITSET_H_ 12 | 13 | #include 14 | #include 15 | 16 | // trailing_zeros is number of least significant zeros 17 | // leading_zeros is number of most significant zeros 18 | #if defined(_WIN32) 19 | #define trailing_zeros(x) ({ __typeof(x) _r; _BitScanReverse64(&_r, x); _r; }) 20 | #define leading_zeros(x) ({ __typeof(x) _r; _BitScanForward64(&_r, x); _r; }) 21 | #else 22 | #define trailing_zeros(x) ((x) ? (__typeof(x))__builtin_ctzll(x) : (__typeof(x))sizeof(x)*8) 23 | #define leading_zeros(x) ((x) ? (__typeof(x))__builtin_clzll(x) : (__typeof(x))sizeof(x)*8) 24 | #endif 25 | 26 | // Get index of top set bit. If x is 0 return nbits 27 | #define top_set_bit(x) ((x) ? sizeof(x)*8-leading_zeros(x)-1 : sizeof(x)*8) 28 | 29 | #define roundup_bits2bytes(bits) (((bits)+7)/8) 30 | #define roundup_bits2words32(bits) (((bits)+31)/32) 31 | #define roundup_bits2words64(bits) (((bits)+63)/64) 32 | 33 | // Round a number up to the nearest number that is a power of two 34 | #define roundup2pow(x) (1UL << (64 - leading_zeros(x))) 35 | 36 | #define rot32(x,r) (((x)<<(r)) | ((x)>>(32-(r)))) 37 | #define rot64(x,r) (((x)<<(r)) | ((x)>>(64-(r)))) 38 | 39 | // need to check for length == 0, undefined behaviour if uint64_t >> 64 etc 40 | #define bitmask(nbits,type) ((nbits) ? ~(type)0 >> (sizeof(type)*8-(nbits)): (type)0) 41 | #define bitmask32(nbits) bitmask(nbits,uint32_t) 42 | #define bitmask64(nbits) bitmask(nbits,uint64_t) 43 | 44 | // A possibly faster way to combine two words with a mask 45 | //#define bitmask_merge(a,b,abits) ((a & abits) | (b & ~abits)) 46 | #define bitmask_merge(a,b,abits) (b ^ ((a ^ b) & abits)) 47 | 48 | // Swap lowest four bits. A nibble is 4 bits (i.e. half a byte) 49 | #define rev_nibble(x) ((((x)&1)<<3)|(((x)&2)<<1)|(((x)&4)>>1)|(((x)&8)>>3)) 50 | 51 | // 52 | // Bit array (bitset) 53 | // 54 | // bitsetX_wrd(): get word for a given position 55 | // bitsetX_idx(): get index within word for a given position 56 | #define _VOLPTR(x) ((volatile __typeof(x) *)(&(x))) 57 | #define _VOLVALUE(x) (*_VOLPTR(x)) 58 | 59 | #define _TYPESHIFT(arr,word,shift) \ 60 | ((__typeof(*(arr)))((__typeof(*(arr)))(word) << (shift))) 61 | 62 | #define bitsetX_wrd(wrdbits,pos) ((pos) / (wrdbits)) 63 | #define bitsetX_idx(wrdbits,pos) ((pos) % (wrdbits)) 64 | 65 | #define bitset32_wrd(pos) ((pos) >> 5) 66 | #define bitset32_idx(pos) ((pos) & 31) 67 | 68 | #define bitset64_wrd(pos) ((pos) >> 6) 69 | #define bitset64_idx(pos) ((pos) & 63) 70 | 71 | // 72 | // Bit functions on arrays 73 | // 74 | #define bitset2_get(arr,wrd,idx) (((arr)[wrd] >> (idx)) & 0x1) 75 | #define bitset2_set(arr,wrd,idx) ((arr)[wrd] |= _TYPESHIFT(arr,1,idx)) 76 | #define bitset2_del(arr,wrd,idx) ((arr)[wrd] &=~ _TYPESHIFT(arr,1,idx)) 77 | #define bitset2_tgl(arr,wrd,idx) ((arr)[wrd] ^= _TYPESHIFT(arr,1,idx)) 78 | #define bitset2_or(arr,wrd,idx,bit) ((arr)[wrd] |= _TYPESHIFT(arr,bit,idx)) 79 | #define bitset2_xor(arr,wrd,idx,bit) ((arr)[wrd] = ~((arr)[wrd] ^ (~_TYPESHIFT(arr,bit,idx)))) 80 | #define bitset2_and(arr,wrd,idx,bit) ((arr)[wrd] &= (_TYPESHIFT(arr,bit,idx) | ~_TYPESHIFT(arr,1,idx))) 81 | #define bitset2_cpy(arr,wrd,idx,bit) ((arr)[wrd] = ((arr)[wrd] &~ _TYPESHIFT(arr,1,idx)) | _TYPESHIFT(arr,bit,idx)) 82 | 83 | // 84 | // Thread safe versions 85 | // 86 | // They return the value of the bit (0 or 1) before it was updated 87 | #define bitset2_get_mt(arr,wrd,idx) bitset2_get(_VOLPTR(*(arr)),wrd,idx) 88 | #define bitset2_set_mt(arr,wrd,idx) ((__sync_fetch_and_or (_VOLPTR((arr)[wrd]), _TYPESHIFT(arr,1,idx)) >> (idx))&1) 89 | #define bitset2_del_mt(arr,wrd,idx) ((__sync_fetch_and_and(_VOLPTR((arr)[wrd]), ~_TYPESHIFT(arr,1,idx)) >> (idx))&1) 90 | #define bitset2_tgl_mt(arr,wrd,idx) ((__sync_fetch_and_xor(_VOLPTR((arr)[wrd]), _TYPESHIFT(arr,1,idx)) >> (idx))&1) 91 | #define bitset2_or_mt(arr,wrd,idx,bit) ((__sync_fetch_and_or (_VOLPTR((arr)[wrd]), _TYPESHIFT(arr,bit,idx)) >> (idx))&1) 92 | #define bitset2_xor_mt(arr,wrd,idx,bit) ((__sync_fetch_and_xor(_VOLPTR((arr)[wrd]), _TYPESHIFT(arr,bit,idx)) >> (idx))&1) 93 | #define bitset2_and_mt(arr,wrd,idx,bit) ((__sync_fetch_and_and(_VOLPTR((arr)[wrd]), (_TYPESHIFT(arr,bit,idx) | ~_TYPESHIFT(arr,1,idx))) >> (idx))&1) 94 | #define bitset2_cpy_mt(arr,wrd,idx,bit) ((bit) ? bitset2_set_mt(arr,wrd,idx) : bitset2_del_mt(arr,wrd,idx)) 95 | 96 | // 97 | // Auto detect size of type from pointer 98 | // 99 | #define bitset_wrd(arr,pos) bitsetX_wrd(sizeof(*(arr))*8,pos) 100 | #define bitset_idx(arr,pos) bitsetX_idx(sizeof(*(arr))*8,pos) 101 | #define bitset_op(func,arr,pos) func(arr, bitset_wrd(arr,pos), bitset_idx(arr,pos)) 102 | #define bitset_op2(func,arr,pos,bit) func(arr, bitset_wrd(arr,pos), bitset_idx(arr,pos), bit) 103 | 104 | // Auto-detect type size: bit functions 105 | #define bitset_get(arr,pos) bitset_op(bitset2_get, arr, pos) 106 | #define bitset_set(arr,pos) bitset_op(bitset2_set, arr, pos) 107 | #define bitset_del(arr,pos) bitset_op(bitset2_del, arr, pos) 108 | #define bitset_tgl(arr,pos) bitset_op(bitset2_tgl, arr, pos) 109 | #define bitset_or(arr,pos,bit) bitset_op2(bitset2_or, arr, pos, bit) 110 | #define bitset_xor(arr,pos,bit) bitset_op2(bitset2_xor, arr, pos, bit) 111 | #define bitset_and(arr,pos,bit) bitset_op2(bitset2_and, arr, pos, bit) 112 | #define bitset_cpy(arr,pos,bit) bitset_op2(bitset2_cpy, arr, pos, bit) 113 | 114 | // Auto-detect type size: thread safe bit functions 115 | // They return the value of the bit (0 or 1) before it was updated 116 | #define bitset_get_mt(arr,pos) bitset_op(bitset2_get_mt, arr, pos) 117 | #define bitset_set_mt(arr,pos) bitset_op(bitset2_set_mt, arr, pos) 118 | #define bitset_del_mt(arr,pos) bitset_op(bitset2_del_mt, arr, pos) 119 | #define bitset_tgl_mt(arr,pos) bitset_op(bitset2_tgl_mt, arr, pos) 120 | #define bitset_or_mt(arr,pos,bit) bitset_op2(bitset2_or_mt, arr, pos, bit) 121 | #define bitset_xor_mt(arr,pos,bit) bitset_op2(bitset2_xor_mt, arr, pos, bit) 122 | #define bitset_and_mt(arr,pos,bit) bitset_op2(bitset2_and_mt, arr, pos, bit) 123 | #define bitset_cpy_mt(arr,pos,bit) bitset_op2(bitset2_cpy_mt, arr, pos, bit) 124 | 125 | // Clearing a word does not return a meaningful value 126 | #define bitset_clear_word(arr,pos) ((arr)[bitset_wrd(arr,pos)] = 0) 127 | #define bitset_clear_word_mt(arr,pos) (_VOLVALUE((arr)[bitset_wrd(arr,pos)]) = 0) 128 | 129 | // 130 | // Compact bit array of spin locks 131 | // These are most effecient when arr is of type: volatile char* 132 | // 133 | // Acquire a lock 134 | #define bitlock_acquire_block(arr,pos,wait,abandon) do { \ 135 | size_t _w = bitset_wrd(arr,pos); \ 136 | __typeof(*(arr)) _o, _n, _b = _TYPESHIFT(arr, 1, bitset_idx(arr,pos)); \ 137 | do { \ 138 | while((_o = _VOLVALUE((arr)[_w])) & _b) { wait } \ 139 | abandon \ 140 | _n = _o | _b; \ 141 | } while(!__sync_bool_compare_and_swap(_VOLPTR((arr)[_w]), _o, _n)); \ 142 | __sync_synchronize(); /* Must not move commands to before acquiring lock */ \ 143 | } while(0) 144 | 145 | // Undefined behaviour if you do not already hold the lock 146 | #define bitlock_release(arr,pos) do { \ 147 | size_t _w = bitset_wrd(arr,pos); \ 148 | __typeof(*(arr)) _mask = ~_TYPESHIFT(arr, 1, bitset_idx(arr,pos)); \ 149 | __sync_synchronize(); /* Must get the lock before releasing it */ \ 150 | __sync_and_and_fetch(_VOLPTR((arr)[_w]), _mask); \ 151 | } while(0) 152 | 153 | #define bitlock_acquire(arr,pos) bitlock_acquire_block(arr,pos,{},{}) 154 | 155 | // calls yield if cannot acquire the lock 156 | #define bitlock_yield_acquire(arr,pos) bitlock_acquire_block(arr,pos,sched_yield();,{}) 157 | 158 | // Block until we get the lock or someone else does 159 | // sets the memory pointed to by retptr to 1 if we got the lock, 0 otherwise 160 | #define bitlock_try_acquire(arr,pos,retptr) do { \ 161 | *(retptr) = 1; /* default to success, set to zero if locked */ \ 162 | bitlock_acquire_block(arr,pos,{*(retptr)=0;break;},if(!*(retptr)){break;}); \ 163 | } while(0) 164 | 165 | /* 166 | * Byteswapping 167 | */ 168 | 169 | /* clang uses these to check for features */ 170 | #ifndef __has_feature 171 | #define __has_feature(x) 0 172 | #endif 173 | 174 | #ifndef __has_builtin 175 | #define __has_builtin(x) 0 176 | #endif 177 | 178 | /* GCC versions < 4.3 do not have __builtin_bswapX() */ 179 | #if ( defined(__clang__) && !__has_builtin(__builtin_bswap64) ) || \ 180 | ( !defined(__clang__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && \ 181 | ( (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)) ) 182 | #define byteswap64(x) ( (((uint64_t)(x) << 56)) | \ 183 | (((uint64_t)(x) << 40) & 0xff000000000000ULL) | \ 184 | (((uint64_t)(x) << 24) & 0xff0000000000ULL) | \ 185 | (((uint64_t)(x) << 8) & 0xff00000000ULL) | \ 186 | (((uint64_t)(x) >> 8) & 0xff000000ULL) | \ 187 | (((uint64_t)(x) >> 24) & 0xff0000ULL) | \ 188 | (((uint64_t)(x) >> 40) & 0xff00ULL) | \ 189 | (((uint64_t)(x) >> 56)) ) 190 | 191 | #define byteswap32(x) ( (((uint32_t)(x) << 24)) | \ 192 | (((uint32_t)(x) << 8) & 0xff0000U) | \ 193 | (((uint32_t)(x) >> 8) & 0xff00U) | \ 194 | (((uint32_t)(x) >> 24)) ) 195 | 196 | /* uint16_t type might be bigger than 2 bytes, so need to mask */ 197 | #define byteswap16(x) ( (((uint16_t)(x) & 0xff) << 8) | \ 198 | (((uint16_t)(x) >> 8) & 0xff) ) 199 | #else 200 | #define byteswap64(x) __builtin_bswap64(x) 201 | #define byteswap32(x) __builtin_bswap64(x) 202 | #define byteswap16(x) __builtin_bswap64(x) 203 | #endif 204 | 205 | #endif /* BITLOCK_H_ */ 206 | -------------------------------------------------------------------------------- /bit_array.h: -------------------------------------------------------------------------------- 1 | /* 2 | bit_array.h 3 | project: bit array C library 4 | url: https://github.com/noporpoise/BitArray/ 5 | maintainer: Isaac Turner 6 | license: Public Domain, no warranty 7 | date: Sep 2014 8 | */ 9 | 10 | #ifndef BIT_ARRAY_HEADER_SEEN 11 | #define BIT_ARRAY_HEADER_SEEN 12 | 13 | #include 14 | #include 15 | 16 | #include "bit_macros.h" 17 | 18 | typedef struct BIT_ARRAY BIT_ARRAY; 19 | 20 | // 64 bit words 21 | typedef uint64_t word_t, word_addr_t, bit_index_t; 22 | typedef uint8_t word_offset_t; // Offset within a 64 bit word 23 | 24 | #define BIT_INDEX_MIN 0 25 | #define BIT_INDEX_MAX (~(bit_index_t)0) 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | // 32 | // Structs 33 | // 34 | 35 | struct BIT_ARRAY 36 | { 37 | word_t* words; 38 | bit_index_t num_of_bits; 39 | // Number of words used -- this is just round_up(num_of_bits / 64) 40 | // if num_of_bits == 0, this is 0 41 | word_addr_t num_of_words; 42 | // For more efficient allocation we use realloc only to double size -- 43 | // not for adding every word. Initial size is INIT_CAPACITY_WORDS. 44 | word_addr_t capacity_in_words; 45 | }; 46 | 47 | // 48 | // Basics: Constructor, destructor, get length, resize 49 | // 50 | 51 | // Constructor - create a new bit array of length nbits 52 | BIT_ARRAY* bit_array_create(bit_index_t nbits); 53 | 54 | // Destructor - free the memory used for a bit array 55 | void bit_array_free(BIT_ARRAY* bitarray); 56 | 57 | // Allocate using existing struct 58 | BIT_ARRAY* bit_array_alloc(BIT_ARRAY* bitarr, bit_index_t nbits); 59 | void bit_array_dealloc(BIT_ARRAY* bitarr); 60 | 61 | // Get length of bit array 62 | bit_index_t bit_array_length(const BIT_ARRAY* bit_arr); 63 | 64 | // Change the size of a bit array. Enlarging an array will add zeros 65 | // to the end of it. Returns 1 on success, 0 on failure (e.g. not enough memory) 66 | char bit_array_resize(BIT_ARRAY* bitarr, bit_index_t new_num_of_bits); 67 | 68 | // If bitarr length < num_bits, resizes to num_bits 69 | char bit_array_ensure_size(BIT_ARRAY* bitarr, bit_index_t ensure_num_of_bits); 70 | 71 | // Same as above but exit with an error message if out of memory 72 | void bit_array_resize_critical(BIT_ARRAY* bitarr, bit_index_t num_of_bits); 73 | void bit_array_ensure_size_critical(BIT_ARRAY* bitarr, bit_index_t num_of_bits); 74 | 75 | 76 | // 77 | // Macros 78 | // 79 | 80 | // 81 | // Get, set, clear, assign and toggle individual bits 82 | // Macros for fast access -- beware: no bounds checking 83 | // 84 | 85 | #define bit_array_get(arr,i) bitset_get((arr)->words, i) 86 | #define bit_array_set(arr,i) bitset_set((arr)->words, i) 87 | #define bit_array_clear(arr,i) bitset_del((arr)->words, i) 88 | #define bit_array_toggle(arr,i) bitset_tgl((arr)->words, i) 89 | // c must be 0 or 1 90 | #define bit_array_assign(arr,i,c) bitset_cpy((arr)->words,i,c) 91 | 92 | #define bit_array_len(arr) ((arr)->num_of_bits) 93 | 94 | // 95 | // Get, set, clear, assign and toggle individual bits 96 | // "Safe": use assert() to check bounds 97 | // 98 | 99 | // Get the value of a bit (returns 0 or 1) 100 | char bit_array_get_bit(const BIT_ARRAY* bitarr, bit_index_t b); 101 | void bit_array_set_bit(BIT_ARRAY* bitarr, bit_index_t b); 102 | void bit_array_clear_bit(BIT_ARRAY* bitarr, bit_index_t b); 103 | void bit_array_toggle_bit(BIT_ARRAY* bitarr, bit_index_t b); 104 | // If char c != 0, set bit; otherwise clear bit 105 | void bit_array_assign_bit(BIT_ARRAY* bitarr, bit_index_t b, char c); 106 | 107 | // 108 | // "Resizing": enlarge array if needed 109 | // 110 | 111 | char bit_array_rget(BIT_ARRAY* bitarr, bit_index_t b); 112 | void bit_array_rset(BIT_ARRAY* bitarr, bit_index_t b); 113 | void bit_array_rclear(BIT_ARRAY* bitarr, bit_index_t b); 114 | void bit_array_rtoggle(BIT_ARRAY* bitarr, bit_index_t b); 115 | void bit_array_rassign(BIT_ARRAY* bitarr, bit_index_t b, char c); 116 | 117 | // 118 | // Get, set, clear and toggle several bits at once 119 | // 120 | 121 | // Get the offsets of the set bits (for offsets start<=offset hamming distance 2 (XOR is 10010) 203 | bit_index_t bit_array_hamming_distance(const BIT_ARRAY* arr1, 204 | const BIT_ARRAY* arr2); 205 | 206 | // Parity - returns 1 if odd number of bits set, 0 if even 207 | char bit_array_parity(const BIT_ARRAY* bitarr); 208 | 209 | // 210 | // Find indices of set/clear bits 211 | // 212 | 213 | // Find the index of the next bit that is set, at or after `offset` 214 | // Returns 1 if a bit is set, otherwise 0 215 | // Index of next set bit is stored in the integer pointed to by result 216 | // If no next bit is set result is not changed 217 | char bit_array_find_next_set_bit(const BIT_ARRAY* bitarr, bit_index_t offset, 218 | bit_index_t* result); 219 | 220 | // Find the index of the next bit that is NOT set, at or after `offset` 221 | // Returns 1 if a bit is NOT set, otherwise 0 222 | // Index of next zero bit is stored in the integer pointed to by `result` 223 | // If no next bit is zero, value at `result` is not changed 224 | char bit_array_find_next_clear_bit(const BIT_ARRAY* bitarr, bit_index_t offset, 225 | bit_index_t* result); 226 | 227 | // Find the index of the previous bit that is set, before offset. 228 | // Returns 1 if a bit is set, otherwise 0 229 | // Index of previous set bit is stored in the integer pointed to by `result` 230 | // If no previous bit is set result is not changed 231 | char bit_array_find_prev_set_bit(const BIT_ARRAY* bitarr, bit_index_t offset, 232 | bit_index_t* result); 233 | 234 | // Find the index of the previous bit that is NOT set, before offset. 235 | // Returns 1 if a bit is clear, otherwise 0 236 | // Index of previous zero bit is stored in the integer pointed to by `result` 237 | // If no previous bit is zero result is not changed 238 | char bit_array_find_prev_clear_bit(const BIT_ARRAY* bitarr, bit_index_t offset, 239 | bit_index_t* result); 240 | 241 | // Find the index of the first bit that is set. 242 | // Returns 1 if a bit is set, otherwise 0 243 | // Index of first set bit is stored in the integer pointed to by `result` 244 | // If no bit is set result is not changed 245 | char bit_array_find_first_set_bit(const BIT_ARRAY* bitarr, bit_index_t* result); 246 | 247 | // Find the index of the first bit that is NOT set. 248 | // Returns 1 if a bit is clear, otherwise 0 249 | // Index of first zero bit is stored in the integer pointed to by `result` 250 | // If no bit is zero result is not changed 251 | char bit_array_find_first_clear_bit(const BIT_ARRAY* bitarr, bit_index_t* result); 252 | 253 | // Find the index of the last bit that is set. 254 | // Returns 1 if a bit is set, otherwise 0 255 | // Index of last set bit is stored in the integer pointed to by `result` 256 | // If no bit is set result is not changed 257 | char bit_array_find_last_set_bit(const BIT_ARRAY* bitarr, bit_index_t* result); 258 | 259 | // Find the index of the last bit that is NOT set. 260 | // Returns 1 if a bit is clear, otherwise 0 261 | // Index of last zero bit is stored in the integer pointed to by `result` 262 | // If no bit is zero result is not changed 263 | char bit_array_find_last_clear_bit(const BIT_ARRAY* bitarr, bit_index_t* result); 264 | 265 | 266 | // 267 | // Sorting 268 | // 269 | 270 | // Put all the 0s before all the 1s 271 | void bit_array_sort_bits(BIT_ARRAY* bitarr); 272 | 273 | // Put all the 1s before all the 0s 274 | void bit_array_sort_bits_rev(BIT_ARRAY* bitarr); 275 | 276 | 277 | // 278 | // String and printing methods 279 | // 280 | 281 | // Construct a BIT_ARRAY from a string. 282 | void bit_array_from_str(BIT_ARRAY* bitarr, const char* bitstr); 283 | 284 | // Construct a BIT_ARRAY from a substring with given on and off characters. 285 | void bit_array_from_substr(BIT_ARRAY* bitarr, bit_index_t offset, 286 | const char* str, size_t len, 287 | const char *on, const char *off, char left_to_right); 288 | 289 | // Takes a char array to write to. `str` must be bitarr->num_of_bits+1 in 290 | // length. Terminates string with '\0' 291 | char* bit_array_to_str(const BIT_ARRAY* bitarr, char* str); 292 | char* bit_array_to_str_rev(const BIT_ARRAY* bitarr, char* str); 293 | 294 | // Get a string representations for a given region, using given on/off 295 | // characters. 296 | // Note: does not null-terminate 297 | void bit_array_to_substr(const BIT_ARRAY* bitarr, 298 | bit_index_t start, bit_index_t length, 299 | char* str, char on, char off, char left_to_right); 300 | 301 | // Print this array to a file stream. Prints '0's and '1'. Doesn't print 302 | // newline. 303 | void bit_array_print(const BIT_ARRAY* bitarr, FILE* fout); 304 | 305 | // Print a string representations for a given region, using given on/off 306 | // characters. Reverse prints from highest to lowest -- this is useful for 307 | // printing binary numbers 308 | void bit_array_print_substr(const BIT_ARRAY* bitarr, 309 | bit_index_t start, bit_index_t length, 310 | FILE* fout, char on, char off, char left_to_right); 311 | 312 | // 313 | // Decimal 314 | // 315 | 316 | // Get bit array as decimal str (e.g. 0b1101 -> "13") 317 | size_t bit_array_to_decimal(const BIT_ARRAY *bitarr, char *str, size_t len); 318 | 319 | // Return number of characters used 320 | size_t bit_array_from_decimal(BIT_ARRAY *bitarr, const char* decimal); 321 | 322 | // 323 | // Hexidecimal 324 | // 325 | 326 | // Loads array from hex string 327 | // Returns the number of bits loaded (will be chars rounded up to multiple of 8) 328 | // (0 on failure) 329 | bit_index_t bit_array_from_hex(BIT_ARRAY* bitarr, bit_index_t offset, 330 | const char* str, size_t len); 331 | 332 | // Returns number of characters written 333 | size_t bit_array_to_hex(const BIT_ARRAY* bitarr, 334 | bit_index_t start, bit_index_t length, 335 | char* str, char uppercase); 336 | 337 | // Print bit array as hex 338 | size_t bit_array_print_hex(const BIT_ARRAY* bitarr, 339 | bit_index_t start, bit_index_t length, 340 | FILE* fout, char uppercase); 341 | 342 | // 343 | // Clone and copy 344 | // 345 | 346 | // Copy a BIT_ARRAY struct and the data it holds - returns pointer to new object 347 | #define bit_array_dup bit_array_clone 348 | BIT_ARRAY* bit_array_clone(const BIT_ARRAY* bitarr); 349 | 350 | // Copy bits from one array to another 351 | // Note: use MACRO bit_array_copy 352 | // Destination and source can be the same bit_array and 353 | // src/dst regions can overlap 354 | void bit_array_copy(BIT_ARRAY* dst, bit_index_t dstindx, 355 | const BIT_ARRAY* src, bit_index_t srcindx, 356 | bit_index_t length); 357 | 358 | // copy all of src to dst. dst is resized to match src. 359 | void bit_array_copy_all(BIT_ARRAY* dst, const BIT_ARRAY* src); 360 | 361 | // 362 | // Logic operators 363 | // 364 | 365 | // BIT_ARRAYs can all be different or the same object 366 | // dest array will be resized if it is too short 367 | // 368 | void bit_array_and(BIT_ARRAY* dest, const BIT_ARRAY* src1, const BIT_ARRAY* src2); 369 | void bit_array_or (BIT_ARRAY* dest, const BIT_ARRAY* src1, const BIT_ARRAY* src2); 370 | void bit_array_xor(BIT_ARRAY* dest, const BIT_ARRAY* src1, const BIT_ARRAY* src2); 371 | void bit_array_not(BIT_ARRAY* dest, const BIT_ARRAY* src); 372 | 373 | // 374 | // Comparisons 375 | // 376 | 377 | // Note: (bit_array_cmp(a,b) == 0) <=> (bit_array_cmp_big_endian(a,b) == 0) 378 | 379 | // comparison functions return: 380 | // 1 iff bitarr1 > bitarr2 381 | // 0 iff bitarr1 == bitarr2 382 | // -1 iff bitarr1 < bitarr2 383 | 384 | // Compare two bit arrays by value stored, with index 0 being the Least 385 | // Significant Bit (LSB). Arrays do not have to be the same length. 386 | // Example: ..0101 (5) > ...0011 (3) [index 0 is LSB at right hand side] 387 | int bit_array_cmp(const BIT_ARRAY* bitarr1, const BIT_ARRAY* bitarr2); 388 | 389 | // Compare two bit arrays by value stored, with index 0 being the Most 390 | // Significant Bit (MSB). Arrays do not have to be the same length. 391 | // Example: 10.. > 01.. [index 0 is MSB at left hand side] 392 | int bit_array_cmp_big_endian(const BIT_ARRAY* bitarr1, const BIT_ARRAY* bitarr2); 393 | 394 | // compare bitarr with (bitarr2 << pos) 395 | int bit_array_cmp_words(const BIT_ARRAY *bitarr, 396 | bit_index_t pos, const BIT_ARRAY *bitarr2); 397 | 398 | // 399 | // Shift, interleave, reverse 400 | // 401 | 402 | // Shift array left/right. If fill is zero, filled with 0, otherwise 1 403 | void bit_array_shift_right(BIT_ARRAY* bitarr, bit_index_t shift_dist, char fill); 404 | void bit_array_shift_left (BIT_ARRAY* bitarr, bit_index_t shift_dist, char fill); 405 | 406 | // shift left without losing any bits. Resizes bitarr. 407 | void bit_array_shift_left_extend(BIT_ARRAY* bitarr, bit_index_t shift_dist, 408 | char fill); 409 | 410 | // Cyclic shift 411 | void bit_array_cycle_right(BIT_ARRAY* bitarr, bit_index_t dist); 412 | void bit_array_cycle_left (BIT_ARRAY* bitarr, bit_index_t dist); 413 | 414 | // Interleave 415 | // dst cannot point to the same bit array as src1 or src2 416 | // src1, src2 may point to the same bit array 417 | // abcd 1234 -> a1b2c3d4 418 | // 0011 0000 -> 00001010 419 | // 1111 0000 -> 10101010 420 | // 0101 1010 -> 01100110 421 | // Extends dst if it is too short, but does not shrink it if it is too long 422 | // if dst is longer than length(src1)+length(src2), the end bits are not altered 423 | void bit_array_interleave(BIT_ARRAY* dst, 424 | const BIT_ARRAY* src1, 425 | const BIT_ARRAY* src2); 426 | 427 | // Reverse the whole array or part of it 428 | void bit_array_reverse(BIT_ARRAY* bitarr); 429 | void bit_array_reverse_region(BIT_ARRAY* bitarr, bit_index_t start, bit_index_t len); 430 | 431 | // 432 | // Numeric 433 | // 434 | 435 | // Returns 1 on sucess, 0 if value in array is too big 436 | char bit_array_as_num(const BIT_ARRAY* bitarr, uint64_t* result); 437 | 438 | // 1 iff bitarr > value 439 | // 0 iff bitarr == value 440 | // -1 iff bitarr < value 441 | int bit_array_cmp_uint64(const BIT_ARRAY* bitarr, uint64_t value); 442 | 443 | // 444 | // Arithmetic 445 | // 446 | 447 | // bitarr will be extended if needed 448 | void bit_array_add_uint64(BIT_ARRAY* bitarr, uint64_t value); 449 | 450 | // Add `add` to `bitarr` at `pos` -- same as: 451 | // bitarr + (add << pos) 452 | // where pos can be bigger than the length of the array (bitarr will be resized) 453 | void bit_array_add_word(BIT_ARRAY *bitarr, bit_index_t pos, uint64_t add); 454 | 455 | // Add `add` to `bitarr` at `pos` 456 | void bit_array_add_words(BIT_ARRAY *bitarr, bit_index_t pos, const BIT_ARRAY *add); 457 | 458 | // If value is greater than bitarr, bitarr is not changed and 0 is returned 459 | // Returns 1 on success, 0 if value > bitarr 460 | char bit_array_sub_uint64(BIT_ARRAY* bitarr, uint64_t value); 461 | 462 | // minus `minus` from `bitarr` at `pos` -- same as: 463 | // bitarr + (minus << pos) 464 | // Returns 1 on success, 0 if value > bitarr 465 | char bit_array_sub_word(BIT_ARRAY *bitarr, bit_index_t pos, word_t minus); 466 | 467 | // minus `minus` from `bitarr` at `pos` 468 | // Returns 1 on success, 0 if value > bitarr 469 | char bit_array_sub_words(BIT_ARRAY* bitarr, bit_index_t pos, BIT_ARRAY* minus); 470 | 471 | // Multiply by some value 472 | void bit_array_mul_uint64(BIT_ARRAY *bitarr, uint64_t multiplier); 473 | 474 | // bitarr = round_down(bitarr / divisor) 475 | // rem = bitarr % divisor 476 | void bit_array_div_uint64(BIT_ARRAY *bitarr, uint64_t divisor, uint64_t *rem); 477 | 478 | // 479 | // Arithmetic between arrays 480 | // 481 | 482 | // dst = src1 + src2 483 | // src1, src2 and dst can all be the same BIT_ARRAY 484 | // If dst is shorter than either of src1, src2, it is enlarged 485 | void bit_array_add(BIT_ARRAY* dst, const BIT_ARRAY* src1, const BIT_ARRAY* src2); 486 | 487 | // dst = src1 - src2 488 | // src1, src2 and dst can all be the same BIT_ARRAY 489 | // If dst is shorter than src1, it will be extended to be as long as src1 490 | // src1 must be greater than or equal to src2 (src1 >= src2) 491 | void bit_array_subtract(BIT_ARRAY* dst, 492 | const BIT_ARRAY* src1, const BIT_ARRAY* src2); 493 | 494 | // dst = src1 * src2 495 | // Pointers cannot all point to the same BIT_ARRAY 496 | void bit_array_multiply(BIT_ARRAY *dst, BIT_ARRAY *src1, BIT_ARRAY *src2); 497 | 498 | // Results in: 499 | // quotient = dividend / divisor 500 | // dividend = dividend % divisor 501 | // (dividend is used to return the remainder) 502 | void bit_array_divide(BIT_ARRAY *dividend, BIT_ARRAY *quotient, BIT_ARRAY *divisor); 503 | 504 | // 505 | // Read/Write bit_array to a file 506 | // 507 | // File format is [8 bytes: for number of elements in array][data] 508 | // Number of bytes of data is: (int)((num_of_bits + 7) / 8) 509 | // 510 | 511 | // Saves bit array to a file 512 | // returns the number of bytes written 513 | bit_index_t bit_array_save(const BIT_ARRAY* bitarr, FILE* f); 514 | 515 | // Reads bit array from a file. bitarr is resized and filled. 516 | // Returns 1 on success, 0 on failure 517 | char bit_array_load(BIT_ARRAY* bitarr, FILE* f); 518 | 519 | 520 | // 521 | // Hash function 522 | // 523 | 524 | // Pass seed as 0 on first call, pass previous hash value if rehashing due 525 | // to a collision 526 | // Using bob jenkins hash lookup3 527 | uint64_t bit_array_hash(const BIT_ARRAY* bitarr, uint64_t seed); 528 | 529 | // 530 | // Randomness 531 | // 532 | 533 | // Set bits randomly with probability prob : 0 <= prob <= 1 534 | void bit_array_random(BIT_ARRAY* bitarr, float prob); 535 | 536 | // Shuffle the bits in an array randomly 537 | void bit_array_shuffle(BIT_ARRAY* bitarr); 538 | 539 | // Get the next permutation of an array with a fixed size and given number of 540 | // bits set. Also known as next lexicographic permutation. 541 | // Given a bit array find the next lexicographic orginisation of the bits 542 | // Number of possible combinations given by (size choose bits_set) i.e. nCk 543 | // 00011 -> 00101 -> 00110 -> 01001 -> 01010 -> 544 | // 01100 -> 10001 -> 10010 -> 10100 -> 11000 -> 00011 (back to start) 545 | void bit_array_next_permutation(BIT_ARRAY* bitarr); 546 | 547 | // 548 | // Generally useful functions 549 | // 550 | 551 | // Generalised 'binary to string' function 552 | // Adds bits to the string in order of lsb to msb 553 | // e.g. 0b11010 (26 in decimal) would come out as "01011" 554 | char* bit_array_word2str(const void *ptr, size_t num_of_bits, char *str); 555 | 556 | // Same as above but in reverse 557 | char* bit_array_word2str_rev(const void *ptr, size_t num_of_bits, char *str); 558 | 559 | #ifdef __cplusplus 560 | } 561 | #endif 562 | 563 | #endif 564 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **C code for bit arrays** 2 | ========================= 3 | 4 | https://github.com/noporpoise/BitArray/ 5 | License: Public Domain, no warranty 6 | Isaac Turner 7 | 8 | [![Build Status](https://travis-ci.org/noporpoise/BitArray.png?branch=master)](https://travis-ci.org/noporpoise/BitArray) 9 | 10 | About 11 | ===== 12 | 13 | Bit arrays are arrays of bits (values zero or one). This is a convenient and 14 | efficient implementation for C/C++. Arrays can be enlarged or shrunk as needed. 15 | 16 | Bit arrays are initialised to zero when created or extended. All operations 17 | have their bounds checked - an "Out of bounds" error is printed if you try to 18 | access a bit with index >= length. Arrays of length 0 are permitted. Indices 19 | must be >= 0. 20 | 21 | Please get in touch if you have suggestions / requests / bugs. 22 | 23 | Adapted from: http://stackoverflow.com/a/2633584/431087 24 | 25 | Build 26 | ===== 27 | 28 | To build the library: 29 | 30 | make 31 | 32 | To build and run the test code: 33 | 34 | make test 35 | 36 | Using bit_array in your code 37 | ============================ 38 | 39 | You are welcome to bundle bit_array with your own code. Add to the top of your code: 40 | 41 | #include "bit_array.h" 42 | 43 | Add to your compiler arguments: 44 | 45 | BIT_ARR_PATH=path/to/bit_array/ 46 | gcc ... -I$(BIT_ARR_PATH) -L$(BIT_ARR_PATH) -lbitarr 47 | 48 | Shorter function names are provided in `bar.h`, which can be included instead of 49 | `bit_array.h`: 50 | 51 | #include "bar.h" 52 | 53 | Thread safety 54 | ------------- 55 | 56 | You cannot safely access the same BitArray in multiple threads at once. Use a 57 | lock to protect BitArray objects. The same methods can be safely called in 58 | separate threads as long as they are not accessing the same BitArray struct. 59 | 60 | Basics 61 | ------ 62 | 63 | Constructor - create a new bit array of length nbits 64 | 65 | BIT_ARRAY* bit_array_create(bit_index_t nbits) 66 | 67 | Destructor - free the memory used for a bit array 68 | 69 | void bit_array_free(BIT_ARRAY* bitarray) 70 | 71 | Alternatively, allocate / free using an existing struct 72 | 73 | BIT_ARRAY* bit_array_alloc(BIT_ARRAY* bitarr, bit_index_t nbits) 74 | void bit_array_dealloc(BIT_ARRAY* bitarr) 75 | 76 | Get length of bit array 77 | 78 | bit_index_t bit_array_length(const BIT_ARRAY* bit_arr) 79 | 80 | Change the size of a bit array. Enlarging an array will add zeros to 81 | the end of it. Returns 1 on success, 0 on failure (e.g. not enough memory) 82 | 83 | char bit_array_resize(BIT_ARRAY* bitarr, bit_index_t new_num_of_bits) 84 | 85 | Set/Get bits 86 | ------------ 87 | 88 | Get the value of a bit (returns 0 or 1) 89 | 90 | char bit_array_get_bit(const BIT_ARRAY* bitarr, bit_index_t b) 91 | 92 | Set a bit (to 1) at position `b` 93 | 94 | void bit_array_set_bit(BIT_ARRAY* bitarr, bit_index_t b) 95 | 96 | Clear a bit (to 0) at position `b` 97 | 98 | void bit_array_clear_bit(BIT_ARRAY* bitarr, bit_index_t b) 99 | 100 | Toggle a bit. If bit is 0 change to 1; if bit is 1 change to 0. Also known as 101 | a complement function. 102 | 103 | void bit_array_toggle_bit(BIT_ARRAY* bitarr, bit_index_t b) 104 | 105 | Assign a value to a bit. If `c != 0` then set bit; otherwise clear bit. 106 | 107 | void bit_array_assign_bit(BIT_ARRAY* bitarr, bit_index_t b, char c) 108 | 109 | Fast MACROs 110 | ----------- 111 | 112 | You can also use the following which are implemented as MACROs without bounds 113 | checking: 114 | 115 | bit_array_get(BIT_ARRAY *arr, bit_index_t i) 116 | bit_array_set(BIT_ARRAY *arr, bit_index_t i) 117 | bit_array_clear(BIT_ARRAY *arr, bit_index_t i) 118 | bit_array_toggle(BIT_ARRAY *arr, bit_index_t i) 119 | bit_array_assign(BIT_ARRAY *arr, bit_index_t i, char c) 120 | 121 | Get a word_t with the bottom `nbits` set to 1, the rest to 0: 122 | 123 | word_t BIT_MASK(int nbits) 124 | 125 | Combine two words with a mask `((a & abits) | (b & ~abits))`: 126 | 127 | word_t BIT_MASK_MERGE(word_t a, word_t b, int abits) 128 | 129 | Set, clear and toggle several bits 130 | ---------------------------------- 131 | 132 | Note: variable args are of type unsigned int 133 | 134 | Set multiple bits at once. 135 | 136 | void bit_array_set_bits(BIT_ARRAY* bitarr, size_t n, ...) 137 | 138 | // e.g. set bits 1,20,31: 139 | bit_array_set_bits(bitarr, 3, 1,20,31); 140 | 141 | Clear multiple bits at once. 142 | 143 | void bit_array_clear_bits(BIT_ARRAY* bitarr, size_t n, ...) 144 | 145 | // e.g. clear bits 1,20,31: 146 | bit_array_clear_bits(bitarr, 3, 1,20,31); 147 | 148 | Toggle multiple bits at once 149 | 150 | void bit_array_toggle_bits(BIT_ARRAY* bitarr, size_t n, ...) 151 | 152 | // e.g. toggle bits 1,20,31: 153 | bit_array_toggle_bits(bitarr, 3, 1,20,31); 154 | 155 | Set, clear and toggle a region 156 | ------------------------------ 157 | 158 | Clear all the bits in the region `start` to `start+length-1` inclusive 159 | 160 | void bit_array_clear_region(BIT_ARRAY* bitarr, 161 | bit_index_t start, bit_index_t length) 162 | 163 | Set all the bits in the region `start` to `start+length-1` inclusive 164 | 165 | void bit_array_set_region(BIT_ARRAY* bitarr, 166 | bit_index_t start, bit_index_t length) 167 | 168 | Toggle all the bits in the region `start` to `start+length-1` inclusive 169 | 170 | void bit_array_toggle_region(BIT_ARRAY* bitarr, 171 | bit_index_t start, bit_index_t length) 172 | 173 | Set, clear and toggle all bits 174 | ------------------------------ 175 | 176 | Set all bits in this array to 0 177 | 178 | void bit_array_clear_all(BIT_ARRAY* bitarr) 179 | 180 | Set all bits in this array to 1 181 | 182 | void bit_array_set_all(BIT_ARRAY* bitarr) 183 | 184 | Set all 1 bits to 0, and all 0 bits to 1 (i.e. flip all the bits) 185 | 186 | void bit_array_toggle_all(BIT_ARRAY* bitarr) 187 | 188 | Get / set a word 189 | ---------------- 190 | 191 | Get a word of a given size. First bit is in the least significant bit position. 192 | Index `start` must be within the range of the bit array (0 <= x < length) 193 | 194 | uint64_t bit_array_get_word64(const BIT_ARRAY* bitarr, bit_index_t start) 195 | uint32_t bit_array_get_word32(const BIT_ARRAY* bitarr, bit_index_t start) 196 | uint16_t bit_array_get_word16(const BIT_ARRAY* bitarr, bit_index_t start) 197 | uint8_t bit_array_get_word8 (const BIT_ARRAY* bitarr, bit_index_t start) 198 | uint64_t bit_array_get_wordn (const BIT_ARRAY* bitarr, bit_index_t start, int n) 199 | 200 | Set 64 bits at once from a particular start position 201 | 202 | void bit_array_set_word64(BIT_ARRAY* bitarr, bit_index_t start, uint64_t word) 203 | void bit_array_set_word32(BIT_ARRAY* bitarr, bit_index_t start, uint32_t word) 204 | void bit_array_set_word16(BIT_ARRAY* bitarr, bit_index_t start, uint16_t word) 205 | void bit_array_set_word8 (BIT_ARRAY* bitarr, bit_index_t start, uint8_t word) 206 | void bit_array_set_wordn (BIT_ARRAY* bitarr, bit_index_t start, uint64_t word, int n) 207 | 208 | Count bits set 209 | -------------- 210 | 211 | Get the number of bits set (hamming weight) 212 | 213 | bit_index_t bit_array_num_bits_set(const BIT_ARRAY* bitarr) 214 | 215 | Get the number of bits set in on array and not the other. This is equivalent 216 | to hamming weight of the XOR of the two arrays. 217 | e.g. 10101 vs 00111 => hamming distance 2 (XOR is 10010) 218 | 219 | bit_index_t bit_array_hamming_distance(const BIT_ARRAY* arr1, 220 | const BIT_ARRAY* arr2) 221 | 222 | Get the number of bits not set (`length - hamming weight`) 223 | 224 | bit_index_t bit_array_num_bits_cleared(const BIT_ARRAY* bitarr) 225 | 226 | Find the index of the first bit that is set. 227 | Returns 1 if a bit is set, otherwise 0. 228 | Index of first set bit is stored in the integer pointed to by `result`. 229 | If no bits are set, value at `result` is not changed and zero is returned. 230 | 231 | char bit_array_find_first_set_bit(const BIT_ARRAY* bitarr, bit_index_t* result) 232 | 233 | Find the index of the first bit that is clear. 234 | Returns 1 if a bit is clear, otherwise 0. 235 | Index of first clear bit is stored in the integer pointed to by `result`. 236 | If no bits are clear, zero is returned. 237 | 238 | char bit_array_find_first_clear_bit(const BIT_ARRAY* bitarr, bit_index_t* result) 239 | 240 | Find the index of the last bit that is set. 241 | Returns 1 if a bit is set, otherwise 0. 242 | Index of last set bit is stored in the integer pointed to by `result`. 243 | If no bits are set, value at `result` is not changed and zero is returned. 244 | 245 | char bit_array_find_last_set_bit(const BIT_ARRAY* bitarr, bit_index_t* result) 246 | 247 | Find the index of the last bit that is NOT set. 248 | Returns 1 if a bit is zero, otherwise 0. 249 | Index of last zero bit is stored in the integer pointed to by `result`. 250 | If no bits are zero, value at `result` is not changed and zero is returned. 251 | 252 | char bit_array_find_last_clear_bit(const BIT_ARRAY* bitarr, bit_index_t* result) 253 | 254 | Find the index of the next bit that is set, at or after `offset`. 255 | Returns 1 if a bit is set, otherwise 0. 256 | Index of next set bit is stored in the integer pointed to by `result`. 257 | If no next bit is set, value at `result` is not changed and 0 is returned. 258 | 259 | char bit_array_find_next_set_bit(const BIT_ARRAY* bitarr, bit_index_t offset, 260 | bit_index_t* result) 261 | 262 | Find the index of the next bit that is clear, at or after `offset`. 263 | Returns 1 if a bit is clear, otherwise 0. 264 | Index of next clear bit is stored in the integer pointed to by `result`. 265 | If no next bit is clear, 0 is returned. 266 | 267 | char bit_array_find_next_clear_bit(const BIT_ARRAY* bitarr, bit_index_t offset, 268 | bit_index_t* result) 269 | 270 | Find the index of the previous bit that is set, before `offset`. 271 | Note: 'before' does not include `offset`. 272 | Returns 1 if a bit is set, otherwise 0 273 | Index of previous set bit is stored in the integer pointed to by `result` 274 | If no previous bit is set, value at `result` is not changed 275 | 276 | char bit_array_find_prev_set_bit(const BIT_ARRAY* bitarr, bit_index_t offset, 277 | bit_index_t* result) 278 | 279 | Find the index of the previous bit that is NOT set, before `offset`. 280 | Note: 'before' does not include `offset`. 281 | Returns 1 if a bit is clear, otherwise 0 282 | Index of previous zero bit is stored in the integer pointed to by `result` 283 | If no previous bit is zero, value at `result` is not changed 284 | 285 | char bit_array_find_prev_clear_bit(const BIT_ARRAY* bitarr, bit_index_t offset, 286 | bit_index_t* result) 287 | 288 | Parity / Permutation 289 | -------------------- 290 | 291 | Get parity: returns 1 if odd number of bits set, 0 if even. 292 | 293 | char bit_array_parity(const BIT_ARRAY* bitarr) 294 | 295 | Get the next permutation of an array with a fixed size and given number of 296 | bits set. Also known as next lexicographic permutation. 297 | Given a bit array find the next lexicographic orginisation of the bits 298 | Number of possible combinations given by `size choose bits_set` where `bits_set` 299 | is the result of `bit_array_num_bits_set(bitarr)`. Example: 300 | 00011 -> 00101 -> 00110 -> 01001 -> 01010 -> 301 | 01100 -> 10001 -> 10010 -> 10100 -> 11000 -> 00011 (back to start) 302 | 303 | void bit_array_next_permutation(BIT_ARRAY* bitarr) 304 | 305 | Sorting 306 | ------- 307 | 308 | Put all the 0s before all the 1s 309 | 310 | void bit_array_sort_bits(BIT_ARRAY* bitarr) 311 | 312 | Put all the 1s before all the 0s 313 | 314 | void bit_array_sort_bits_rev(BIT_ARRAY* bitarr) 315 | 316 | 317 | String and printing functions 318 | ----------------------------- 319 | 320 | To convert to/from string representations of an array, '1' and '0' are used by 321 | default as on and off. 322 | 323 | Create a bit array from a string of '0's and '1's e.g. "01001010110". 324 | 325 | void bit_array_from_str(BIT_ARRAY* bitarr, const char* bitstr) 326 | 327 | Construct a BIT_ARRAY from a substring with given on and off characters. 328 | `left_to_right` determines the order in which bits are printed. 329 | Terminates string with '\0'. 330 | 331 | void bit_array_from_substr(BIT_ARRAY* bitarr, bit_index_t offset, 332 | const char* str, size_t len, 333 | const char *on, const char *off, char left_to_right) 334 | 335 | To string method. Takes a char array to write to. 336 | `str` must be bitarr->num_of_bits+1 in length. 337 | Terminates string with '\0'. 338 | 339 | char* bit_array_to_str(const BIT_ARRAY* bitarr, char* str) 340 | 341 | To construct a string in reverse (highest bit on the left, lowest on the right) 342 | 343 | bit_array_to_str_rev(const BIT_ARRAY* bitarr, char* str) 344 | 345 | Get a string representations for a given region, using given on/off characters. 346 | `left_to_right` determines the order in which bits are printed. 347 | Note: does not null-terminate. 348 | 349 | void bit_array_to_substr(const BIT_ARRAY* bitarr, 350 | bit_index_t start, bit_index_t length, 351 | char* str, char on, char off, char left_to_right) 352 | 353 | Print this array to a file stream. Prints '0's and '1'. Doesn't print newline. 354 | 355 | void bit_array_print(const BIT_ARRAY* bitarr, FILE* fout) 356 | 357 | Print a string representations for a given region, using given on/off characters. 358 | `left_to_right` determines the order in which bits are printed. 359 | 360 | void bit_array_print_substr(const BIT_ARRAY* bitarr, 361 | bit_index_t start, bit_index_t length, 362 | FILE* fout, char on, char off, char left_to_right) 363 | 364 | Decimal 365 | ------- 366 | 367 | Get bit array as decimal str e.g. 0b1101 -> "13". 368 | `len` is the length of str char array. `bit_array_to_decimal()` write at most 369 | `len-1` chars to `str`. Returns the number of characters that would have been 370 | written to str -- return is the same as strlen(str) upon success. 371 | 372 | size_t bit_array_to_decimal(const BIT_ARRAY *bitarr, char *str, size_t len) 373 | 374 | Example usage: 375 | 376 | char str[10]; 377 | size_t len = bit_array_to_decimal(arr, str, 10); 378 | 379 | if(len > 9) 380 | { 381 | // str wasn't big enough 382 | } 383 | 384 | Get bit array from decimal str (e.g. "13" -> 0b1101). 385 | Returns number of characters used 386 | 387 | size_t bit_array_from_decimal(BIT_ARRAY *bitarr, const char* decimal) 388 | 389 | Example usage: 390 | 391 | char *str = "1234"; 392 | BIT_ARRAY *bitarr = bit_array_create(0); 393 | 394 | size_t len = bit_array_from_decimal(bitarr, str); 395 | 396 | if(len < strlen(str)) 397 | { 398 | // Parsing ended prematurely (non-numeric characters encountered) 399 | } 400 | 401 | 402 | Hexidecimal 403 | ----------- 404 | 405 | Loads array from hex string 406 | Returns the number of bits loaded (will be chars rounded up to multiple of 8) 407 | (0 on failure) 408 | 409 | bit_index_t bit_array_from_hex(BIT_ARRAY* bitarr, bit_index_t offset, 410 | const char* str, size_t len) 411 | 412 | Returns number of characters written 413 | 414 | size_t bit_array_to_hex(const BIT_ARRAY* bitarr, 415 | bit_index_t start, bit_index_t length, 416 | char* str, char uppercase) 417 | 418 | Print bit array as hex 419 | 420 | size_t bit_array_print_hex(const BIT_ARRAY* bitarr, 421 | bit_index_t start, bit_index_t length, 422 | FILE* fout, char uppercase) 423 | 424 | Clone/copy 425 | ---------- 426 | 427 | Copy a BIT_ARRAY struct and the data it holds - returns pointer to new object 428 | 429 | BIT_ARRAY* bit_array_clone(const BIT_ARRAY* bitarr) 430 | 431 | Copy bits from one array to another. 432 | Destination and source can be the same bit_array and src/dst regions can overlap 433 | 434 | void bit_array_copy(BIT_ARRAY* dst, bit_index_t dstindx, 435 | const BIT_ARRAY* src, bit_index_t srcindx, 436 | bit_index_t length) 437 | 438 | Logic operators and shifts 439 | -------------------------- 440 | 441 | Destination and source bit arrays must be of the same length, however they may 442 | point to the same object 443 | 444 | void bit_array_and(BIT_ARRAY* dest, const BIT_ARRAY* src1, const BIT_ARRAY* src2) 445 | void bit_array_or(BIT_ARRAY* dest, const BIT_ARRAY* src1, const BIT_ARRAY* src2) 446 | void bit_array_xor(BIT_ARRAY* dest, const BIT_ARRAY* src1, const BIT_ARRAY* src2) 447 | void bit_array_not(BIT_ARRAY* dest, const BIT_ARRAY* src) 448 | 449 | Shift array left/right with a given `fill` (0 or 1) 450 | 451 | void bit_array_shift_right(BIT_ARRAY* bitarr, bit_index_t shift_dist, char fill) 452 | void bit_array_shift_left(BIT_ARRAY* bitarr, bit_index_t shift_dist, char fill) 453 | 454 | To shift and add digits instead of losing data, use the extend left shift 455 | function: 456 | 457 | void bit_array_shift_left_extend(BIT_ARRAY* bitarr, bit_index_t shift_dist, char fill) 458 | 459 | Circular or cycle shifts. Bits wrap around once shifted off the end 460 | 461 | void bit_array_cycle_right(BIT_ARRAY* bitarr, bit_index_t dist) 462 | void bit_array_cycle_left(BIT_ARRAY* bitarr, bit_index_t dist) 463 | 464 | Interleave bits 465 | --------------- 466 | Copy bits from two arrays into another, alternating between taking a bit from each. 467 | In other words, two arrays a,b,c,d and 1,2,3,4 -> a,1,b,2,c,3,d,4. Examples: 468 | * 0011 0000 -> 00001010 469 | * 1111 0000 -> 10101010 470 | * 0101 1010 -> 01100110 471 | 472 | `dst` cannot point to the same bit array as `src1` or `src2`. However `src1` and 473 | `src2` may point to the same bit array. 474 | 475 | void bit_array_interleave(BIT_ARRAY* dst, const BIT_ARRAY* src1, const BIT_ARRAY* src2) 476 | 477 | Reverse 478 | ------- 479 | 480 | Reverse the whole array or part of it. 481 | 482 | void bit_array_reverse(BIT_ARRAY* bitarr) 483 | void bit_array_reverse_region(BIT_ARRAY* bitarr, 484 | bit_index_t start, bit_index_t length) 485 | 486 | Comparing 487 | --------- 488 | 489 | Comparison functions return: 490 | * > 0 iff bitarr1 > bitarr2 491 | * 0 iff bitarr1 == bitarr2 492 | * < 0 iff bitarr1 < bitarr2 493 | 494 | Compare two bit arrays by value stored, with index 0 being the Least 495 | Significant Bit (LSB). 496 | 497 | Arrays do not have to be the same length. 498 | Example: ..0101 (5) > ...0011 (3) [index 0 is LSB at right hand side]. 499 | 500 | int bit_array_cmp(const BIT_ARRAY* bitarr1, const BIT_ARRAY* bitarr2) 501 | 502 | Compare two bit arrays by value stored, with index 0 being the Most Significant 503 | Bit (MSB). Sorts on length if all zeros: (0,0) < (0,0,0) 504 | 505 | Arrays do not have to be the same length. 506 | Example: 10.. > 01.. [index 0 is MSB at left hand side] 507 | 508 | int bit_array_cmp_big_endian(const BIT_ARRAY* bitarr1, const BIT_ARRAY* bitarr2) 509 | 510 | Compare `bitarr` with `(bitarr2 << pos)`. Does not use array length, only value 511 | stored. 512 | 513 | int bit_array_cmp_words(const BIT_ARRAY *bitarr, 514 | bit_index_t pos, const BIT_ARRAY *bitarr2) 515 | 516 | Compare value stored against an unsigned long (treats `bitarr` as large unsigned 517 | integer type): 518 | 519 | int bit_array_compare_num(BIT_ARRAY* bitarr, unsigned long value) 520 | 521 | Arithmetic 522 | ---------- 523 | 524 | Bit arrays can be interpretted as arbitrarily large unsigned integers. To do this 525 | the bit at index 0 is treated as the least significant bit. BitArrays provide 526 | functions for arithmetic between a BitArray & a long, and between BitArrays. 527 | 528 | Get the value of this number in an unsigned long. 529 | Returns 1 on sucess, 0 if value in array is too big. 530 | 531 | char bit_array_as_num(BIT_ARRAY* bitarr, unsigned long* result) 532 | 533 | (Note: see also `bit_array_compare_num(BIT_ARRAY*, unsigned long)`) 534 | 535 | Add to an array. `bitarr` will be extended if needed. 536 | 537 | void bit_array_add_uint64(BIT_ARRAY* bitarr, unsigned long value) 538 | 539 | Add `add` to `bitarr` at `pos` -- same as: 540 | bitarr + (add << pos) 541 | where pos can be bigger than the length of the array (bitarr will be resized) 542 | 543 | void bit_array_add_word(BIT_ARRAY *bitarr, bit_index_t pos, uint64_t add) 544 | 545 | Add `add << pos` to `bitarr` 546 | 547 | void bit_array_add_words(BIT_ARRAY *bitarr, bit_index_t pos, BIT_ARRAY *add) 548 | 549 | Subtract from an array. If `value` is greater than `bitarr`, `bitarr` is not 550 | changed and `0` is returned. Returns `1` on success, `0` if `value > bitarr` 551 | 552 | char bit_array_sub_uint64(BIT_ARRAY* bitarr, unsigned long value) 553 | 554 | Minus `minus << pos` from `bitarr` 555 | 556 | char bit_array_sub_words(BIT_ARRAY* bitarr, bit_index_t pos, 557 | BIT_ARRAY* minus) 558 | 559 | Multiply by some value 560 | 561 | void bit_array_mul_uint64(BIT_ARRAY *bitarr, uint64_t multiplier) 562 | 563 | Add two bit arrays together and store the result. `src1` and `src2` do not have 564 | to be the same length. `src1`, `src2` and `dst` can all be the same or different 565 | `BIT_ARRAY`s. If `dst` is shorter than either of `src1` or `src2`, it is enlarged 566 | to be as long as the longest. 567 | 568 | void bit_array_add(BIT_ARRAY* dst, const BIT_ARRAY* src1, const BIT_ARRAY* src2) 569 | 570 | Subtract on BIT_ARRAY from another. `src1`, `src2` and `dst` can all be the same 571 | or different `BIT_ARRAY`s. If dst is shorter than src1, it will be extended to 572 | be as long as `src1`. `src1` must be greater than or equal to `src2` (`src1 >= src2`). 573 | 574 | void bit_array_subtract(BIT_ARRAY* dst, const BIT_ARRAY* src1, const BIT_ARRAY* src2) 575 | 576 | dst = src1 * src2 577 | Pointers cannot all point to the same BIT_ARRAY 578 | 579 | void bit_array_multiply(BIT_ARRAY *dst, BIT_ARRAY *src1, BIT_ARRAY *src2) 580 | 581 | Divide a BitArray by a BitArray; returns: 582 | * `quotient = dividend / divisor` 583 | * `dividend = dividend % divisor` 584 | 585 | Dividend is used to return the remainder. 586 | 587 | void bit_array_divide(BIT_ARRAY *dividend, BIT_ARRAY *quotient, 588 | BIT_ARRAY *divisor) 589 | 590 | 591 | Read/Write bit_array to a file 592 | ------------------------------ 593 | 594 | File format is [8 bytes: for number of elements in array][data]. 595 | Number of bytes of data is: `(int)((num_of_bits + 7) / 8)` -- i.e. 596 | `roundup(num_of_bits/8)` 597 | 598 | Saves bit array to a file. Returns the number of bytes written 599 | 600 | bit_index_t bit_array_save(const BIT_ARRAY* bitarr, FILE* f) 601 | 602 | Reads bit array from a file. `bitarr` is resized and filled with data from the file. 603 | Returns 1 on success, 0 on failure. 604 | 605 | char bit_array_load(BIT_ARRAY* bitarr, FILE* f) 606 | 607 | 608 | Hash Value 609 | ---------- 610 | 611 | Get a hash value for this array. Pass `seed` as `0` on first call, pass previous 612 | hash value if rehashing due to a collision. Uses Bob Jenkins hash lookup3 function 613 | (http://burtleburtle.net/bob/hash/index.html) 614 | 615 | uint64_t bit_array_hash(const BIT_ARRAY* bitarr, uint64_t seed) 616 | 617 | Randomness 618 | ---------- 619 | 620 | Set bits randomly with probability prob (where `0 <= prob <= 1`) 621 | 622 | void bit_array_random(BIT_ARRAY* bitarr, float prob) 623 | 624 | Shuffle the bits in an array randomly 625 | 626 | void bit_array_shuffle(BIT_ARRAY* bitarr) 627 | 628 | // e.g. If you want exactly 9 random bits set in an array, use: 629 | bit_array_set_region(arr, 0, 9); // set the first 9 bits 630 | bit_array_shuffle(arr); // shuffle the array 631 | 632 | Useful functions 633 | ---------------- 634 | 635 | The file `bit_macros.h` contains many useful macros for bit arrays. Simple bit 636 | array functions can be implemented with this file alone. 637 | 638 | Generalised 'binary to string' function. 639 | Adds bits to the string in order of lsb to msb 640 | e.g. 0b11010 (26 in decimal) would come out as "01011" 641 | 642 | char* bit_array_word2str(const void *ptr, size_t num_of_bits, char *str); 643 | 644 | // Same as above but in reverse 645 | char* bit_array_word2str_rev(const void *ptr, size_t num_of_bits, char *str); 646 | 647 | For those who hate all that typing: the file "bar.h" contains macros to 648 | supply short "bar*" names for the most used bit array operations. 649 | This is meant to be similar to the "str*" function names for string 650 | manipulation. 651 | 652 | Constants 653 | --------- 654 | 655 | `BIT_INDEX_MIN` and `BIT_INDEX_MAX` define the min and max values of datatype 656 | `bit_index_t`. These are defined as `0` and `2^63 - 1`. 657 | 658 | Contributing 659 | ============ 660 | 661 | Please feel free to submit issues and pull requests. I appreciate bug reports. 662 | 663 | Methods are named: 664 | * `_name()` indicates only used internally 665 | * `bit_array_name()` exported as is 666 | 667 | Testing on different platforms is especially appreciated. I only have access 668 | to Mac OS X and Linux. 669 | 670 | License 671 | ======= 672 | 673 | This software is in the *Public Domain*. That means you can do whatever you like 674 | with it. That includes being used in proprietary products without attribution or 675 | restrictions. There are no warranties and there may be bugs. 676 | 677 | Formally we are using CC0 - a Creative Commons license to place this work in the 678 | public domain. A copy of CC0 is in the LICENSE file. 679 | 680 | "CC0 is a public domain dedication from Creative Commons. A work released 681 | under CC0 is dedicated to the public domain to the fullest extent permitted 682 | by law. If that is not possible for any reason, CC0 also provides a lax, 683 | permissive license as a fallback. Both public domain works and the lax 684 | license provided by CC0 are compatible with the GNU GPL." 685 | - http://www.gnu.org/licenses/license-list.html#CC0 686 | 687 | Development 688 | =========== 689 | 690 | To do: 691 | * search function: `int bit_array_search(const BIT_ARRAY *arr, const BIT_ARRAY *query);` 692 | * windows support 693 | * 32 bit support 694 | * faster multiply / divide? (i.e. Karatsuba) 695 | -------------------------------------------------------------------------------- /dev/bit_array_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | dev/bit_array_test.c 3 | project: bit array C library 4 | url: https://github.com/noporpoise/BitArray/ 5 | maintainer: Isaac Turner 6 | license: Public Domain, no warranty 7 | date: Sep 2014 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include // needed for rand() 16 | #include // need for getpid() for getting setting rand number 17 | #include "bit_array.h" 18 | 19 | // Constants 20 | const char test_filename[] = "bitarr_example.dump"; 21 | 22 | #define MAX(x,y) ((x) >= (y) ? (x) : (y)) 23 | #define MIN(x,y) ((x) <= (y) ? (x) : (y)) 24 | 25 | #define RAND(x) (((x) * (long)rand())/RAND_MAX) 26 | 27 | // 28 | // Tests 29 | // 30 | const char *suite_name; 31 | char suite_pass; 32 | int suites_run = 0, suites_failed = 0, suites_empty = 0; 33 | int tests_in_suite = 0, tests_run = 0, tests_failed = 0; 34 | 35 | #define QUOTE(str) #str 36 | #define ASSERT(x) {tests_run++; tests_in_suite++; if(!(x)) \ 37 | { fprintf(stderr, "failed assert [%s:%i] %s\n", __FILE__, __LINE__, QUOTE(x)); \ 38 | suite_pass = 0; tests_failed++; }} 39 | 40 | void SUITE_START(const char *name) 41 | { 42 | suite_pass = 1; 43 | suite_name = name; 44 | suites_run++; 45 | tests_in_suite = 0; 46 | } 47 | 48 | void SUITE_END() 49 | { 50 | printf("Testing %s ", suite_name); 51 | size_t suite_i; 52 | for(suite_i = strlen(suite_name); suite_i < 80-8-5; suite_i++) printf("."); 53 | printf("%s\n", suite_pass ? " pass" : " fail"); 54 | if(!suite_pass) suites_failed++; 55 | if(!tests_in_suite) suites_empty++; 56 | } 57 | 58 | // 59 | // Utility functions 60 | // 61 | 62 | #define die(fmt,...) do { \ 63 | fprintf(stderr, "[%s:%i] Error: %s() "fmt"\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__); \ 64 | exit(EXIT_FAILURE); \ 65 | } while(0); 66 | 67 | void reverse_str(char *str) 68 | { 69 | size_t s, len = strlen(str); 70 | for(s = 0; s < len / 2; s++) 71 | { 72 | char tmp = str[s]; 73 | str[s] = str[len-s-1]; 74 | str[len-s-1] = tmp; 75 | } 76 | } 77 | 78 | word_t word_from_str(char *str) 79 | { 80 | word_t w = 0; 81 | int i; 82 | for(i = 0; i < 64 && str[i] != '\0'; i++) 83 | { 84 | w <<= 1; 85 | if(str[i] == '1') 86 | { 87 | w |= 1; 88 | } 89 | } 90 | return w; 91 | } 92 | 93 | // 94 | // Testing per function 95 | // 96 | 97 | void _test_copy(BIT_ARRAY *arr2, bit_index_t to, 98 | BIT_ARRAY *arr1, bit_index_t from, 99 | bit_index_t len) 100 | { 101 | char *str1 = (char*)malloc((bit_array_length(arr1)+1) * sizeof(char)); 102 | char *corr = (char*)malloc((bit_array_length(arr2)+to+len+1) * sizeof(char)); 103 | 104 | bit_array_to_str(arr1, str1); 105 | bit_array_to_str(arr2, corr); 106 | size_t arr2_len = strlen(corr); 107 | 108 | memmove(corr+to, str1+from, len * sizeof(char)); 109 | 110 | if(to+len > arr2_len) 111 | { 112 | corr[to+len] = '\0'; 113 | } 114 | 115 | // do copy 116 | bit_array_copy(arr2, to, arr1, from, len); 117 | 118 | char *str2 = (char*)malloc((bit_array_length(arr2)+1) * sizeof(char)); 119 | bit_array_to_str(arr2, str2); 120 | 121 | // compare 122 | ASSERT(strcmp(str2, corr) == 0); 123 | 124 | if(strcmp(str2, corr) != 0) 125 | { 126 | // debug output 127 | printf("str1: %s\n", str1); 128 | printf("str2: %s\n", str2); 129 | printf("corr: %s\n", corr); 130 | } 131 | 132 | free(str1); 133 | free(str2); 134 | free(corr); 135 | } 136 | 137 | void test_copy() 138 | { 139 | SUITE_START("copy"); 140 | 141 | BIT_ARRAY *arr = bit_array_create(200); 142 | bit_array_set_region(arr, 0, 20); 143 | 144 | _test_copy(arr, 30, arr, 0, 15); 145 | _test_copy(arr, 50, arr, 0, 50); 146 | _test_copy(arr, 100, arr, 0, 100); 147 | 148 | bit_index_t len = bit_array_length(arr); 149 | int shift = 3; 150 | 151 | bit_array_resize(arr, len + shift); 152 | _test_copy(arr, shift, arr, 0, len); 153 | _test_copy(arr, 0, arr, shift, len); 154 | 155 | bit_array_free(arr); 156 | 157 | SUITE_END(); 158 | } 159 | 160 | // Fetch bits start..end from arr into setbits, then check that the return 161 | // result is correct. `setbits` must be at least (end-start) elements long 162 | void _get_bits(const BIT_ARRAY *arr, bit_index_t start, bit_index_t end, 163 | bit_index_t *setbits) 164 | { 165 | bit_index_t i, j, n = bit_array_get_bits(arr, start, end, setbits); 166 | for(i = start, j = 0; i < end; i++) { 167 | if(bit_array_get(arr,i)) { 168 | ASSERT(setbits[j] == i); 169 | j++; 170 | } 171 | } 172 | ASSERT(j == n); 173 | } 174 | 175 | // Test function bit_array_get_bits(arr,start,end,indices) 176 | void test_get_bits() 177 | { 178 | bit_index_t *setbits = (bit_index_t *) calloc(200, sizeof(*setbits)); 179 | BIT_ARRAY *arr = bit_array_create(200); 180 | bit_array_random(arr, 0.5f); 181 | _get_bits(arr, 0, 0, setbits); 182 | _get_bits(arr, 0, 200, setbits); 183 | _get_bits(arr, 200, 200, setbits); 184 | _get_bits(arr, 50, 150, setbits); 185 | free(setbits); 186 | bit_array_free(arr); 187 | SUITE_END(); 188 | } 189 | 190 | void test_arithmetic() 191 | { 192 | printf("== testing arithmetic ==\n"); 193 | 194 | char tmp[101]; 195 | 196 | BIT_ARRAY* arr1 = bit_array_create(100); 197 | BIT_ARRAY* arr2 = bit_array_create(100); 198 | 199 | int i = 0; 200 | for(i = 0; i < 99; i+=3) 201 | { 202 | bit_array_set_bit(arr1, i); 203 | bit_array_set_bit(arr2, i); 204 | bit_array_set_bit(arr2, i+1); 205 | } 206 | 207 | printf("Init:\n"); 208 | printf("arr1: %s\n", bit_array_to_str(arr1, tmp)); 209 | printf("arr2: %s\n", bit_array_to_str(arr2, tmp)); 210 | 211 | printf("Increment: arr1++\n"); 212 | bit_array_add_uint64(arr1, 1); 213 | printf("arr1: %s\n", bit_array_to_str(arr1, tmp)); 214 | 215 | printf("Decrement: arr1--\n"); 216 | bit_array_sub_uint64(arr1, 1); 217 | printf("arr1: %s\n", bit_array_to_str(arr1, tmp)); 218 | 219 | printf("Sum: arr1 = arr1 + arr2\n"); 220 | bit_array_add(arr1, arr1, arr2); 221 | printf("arr1: %s\n", bit_array_to_str(arr1, tmp)); 222 | 223 | printf("Difference: arr1 = arr1 - arr2\n"); 224 | bit_array_subtract(arr1, arr1, arr2); 225 | printf("arr1: %s\n", bit_array_to_str(arr1, tmp)); 226 | 227 | printf("Difference: arr1 = arr1 - arr1\n"); 228 | bit_array_subtract(arr1, arr1, arr1); 229 | printf("arr1: %s\n", bit_array_to_str(arr1, tmp)); 230 | 231 | printf("Sum: arr1 = arr1 + arr2\n"); 232 | bit_array_add(arr1, arr1, arr2); 233 | printf("arr1: %s\n", bit_array_to_str(arr1, tmp)); 234 | 235 | printf("Sum: arr1 = arr1 + arr2\n"); 236 | bit_array_add(arr1, arr1, arr2); 237 | printf("arr1: %s\n", bit_array_to_str(arr1, tmp)); 238 | 239 | bit_array_free(arr1); 240 | bit_array_free(arr2); 241 | 242 | printf("== End of testing arithmetic ==\n\n"); 243 | } 244 | 245 | void _check_first_last_bit_set(BIT_ARRAY* arr, char not_zero, 246 | bit_index_t first, bit_index_t last) 247 | { 248 | bit_index_t first_bit = 0, last_bit = 0; 249 | 250 | char bit_set0 = bit_array_find_first_set_bit(arr, &first_bit); 251 | char bit_set1 = bit_array_find_last_set_bit(arr, &last_bit); 252 | 253 | ASSERT(not_zero == bit_set0); 254 | ASSERT(not_zero == bit_set1); 255 | 256 | if(not_zero) 257 | { 258 | ASSERT(first_bit == first); 259 | ASSERT(last_bit == last); 260 | } 261 | else 262 | { 263 | ASSERT(first_bit == 0); 264 | ASSERT(last_bit == 0); 265 | } 266 | } 267 | 268 | 269 | void test_first_last_bit_set() 270 | { 271 | SUITE_START("first/last bit set"); 272 | 273 | BIT_ARRAY *arr = bit_array_create(100); 274 | _check_first_last_bit_set(arr, 0, 0, 0); 275 | 276 | bit_array_set_bits(arr, 6, 0, 5, 24, 64, 80, 99); 277 | _check_first_last_bit_set(arr, 1, 0, 99); 278 | 279 | bit_array_clear_bits(arr, 2, 0, 99); 280 | _check_first_last_bit_set(arr, 1, 5, 80); 281 | 282 | bit_array_clear_bits(arr, 2, 5, 80); 283 | _check_first_last_bit_set(arr, 1, 24, 64); 284 | 285 | bit_array_clear_bits(arr, 2, 24, 64); 286 | _check_first_last_bit_set(arr, 0, 0, 0); 287 | 288 | bit_array_set_bit(arr, 0); 289 | _check_first_last_bit_set(arr, 1, 0, 0); 290 | 291 | const int len = 9; 292 | bit_index_t set[] = {0, 1, 31, 62, 63, 64, 65, 98, 99}; 293 | int i; 294 | 295 | for(i = 0; i < len; i++) 296 | { 297 | bit_index_t pos = set[i]; 298 | bit_array_clear_all(arr); 299 | bit_array_set_bit(arr, pos); 300 | _check_first_last_bit_set(arr, 1, pos, pos); 301 | } 302 | 303 | bit_array_free(arr); 304 | 305 | SUITE_END(); 306 | } 307 | 308 | // Check finding set/clear bits return the same results 309 | bit_index_t _test_find_next_bit(BIT_ARRAY *arr, bit_index_t offset, 310 | bit_index_t *result) 311 | { 312 | bit_index_t pos1 = 0, pos2 = 0; 313 | char found1, found2; 314 | found1 = bit_array_find_next_set_bit(arr, offset, &pos1); 315 | bit_array_toggle_all(arr); 316 | found2 = bit_array_find_next_clear_bit(arr, offset, &pos2); 317 | bit_array_toggle_all(arr); 318 | 319 | // printf("next (%i,%zu) vs (%i,%zu)\n", (int)found1, (size_t)pos1, 320 | // (int)found2, (size_t)pos2); 321 | ASSERT(found1 == found2); 322 | ASSERT(pos1 == pos2); 323 | *result = pos1; 324 | return found1; 325 | } 326 | 327 | // Check finding set/clear bits return the same results 328 | bit_index_t _test_find_prev_bit(BIT_ARRAY *arr, bit_index_t offset, 329 | bit_index_t *result) 330 | { 331 | bit_index_t pos1 = 0, pos2 = 0; 332 | char found1, found2; 333 | found1 = bit_array_find_prev_set_bit(arr, offset, &pos1); 334 | bit_array_toggle_all(arr); 335 | found2 = bit_array_find_prev_clear_bit(arr, offset, &pos2); 336 | bit_array_toggle_all(arr); 337 | 338 | // printf("prev (%i,%zu) vs (%i,%zu)\n", (int)found1, (size_t)pos1, 339 | // (int)found2, (size_t)pos2); 340 | ASSERT(found1 == found2); 341 | ASSERT(pos1 == pos2); 342 | *result = pos1; 343 | return found1; 344 | } 345 | 346 | void test_next_prev_bit_set() 347 | { 348 | SUITE_START("next/prev bit set"); 349 | 350 | BIT_ARRAY *arr = bit_array_create(100); 351 | bit_index_t pos = 0; 352 | char found; 353 | 354 | // Simple test 355 | // Nothing set 356 | found = _test_find_next_bit(arr, 0, &pos); 357 | ASSERT(!found && pos == 0); 358 | found = _test_find_next_bit(arr, 50, &pos); 359 | ASSERT(!found && pos == 0); 360 | found = _test_find_next_bit(arr, 99, &pos); 361 | ASSERT(!found && pos == 0); 362 | found = _test_find_prev_bit(arr, 0, &pos); 363 | ASSERT(!found && pos == 0); 364 | found = _test_find_prev_bit(arr, 50, &pos); 365 | ASSERT(!found && pos == 0); 366 | found = _test_find_prev_bit(arr, 100, &pos); 367 | ASSERT(!found && pos == 0); 368 | 369 | bit_array_set_bit(arr, 0); 370 | found = _test_find_prev_bit(arr, 0, &pos); 371 | ASSERT(!found && pos == 0); 372 | found = _test_find_next_bit(arr, 0, &pos); 373 | ASSERT(found && pos == 0); 374 | 375 | bit_array_set_bit(arr, 99); 376 | found = _test_find_prev_bit(arr, 99, &pos); 377 | ASSERT(found && pos == 0); 378 | found = _test_find_next_bit(arr, 99, &pos); 379 | ASSERT(found && pos == 99); 380 | 381 | bit_array_set_bits(arr, 3, 10, 20, 64); 382 | found = _test_find_prev_bit(arr, 99, &pos); 383 | ASSERT(found && pos == 64); 384 | found = _test_find_prev_bit(arr, 64, &pos); 385 | ASSERT(found && pos == 20); 386 | found = _test_find_next_bit(arr, 1, &pos); 387 | ASSERT(found && pos == 10); 388 | found = _test_find_next_bit(arr, 11, &pos); 389 | ASSERT(found && pos == 20); 390 | 391 | // Automated test 392 | bit_index_t indices[] = {0, 1, 2, 5, 24, 50, 51, 64, 80, 99}; 393 | size_t i, n, num_idx = sizeof(indices)/sizeof(indices[0]); 394 | 395 | // Loop over setting diff numbers of bits - check next_bit_set 396 | for(n = 0; n <= num_idx; n++) { 397 | bit_array_clear_all(arr); 398 | for(i = 0; i < n; i++) bit_array_set_bit(arr, indices[i]); 399 | 400 | for(i = 0; i < n; i++) { 401 | found = _test_find_next_bit(arr, indices[i], &pos); 402 | ASSERT(found == 1); 403 | ASSERT(pos == indices[i]); 404 | 405 | // Check from bit after index if in range 406 | if(indices[i]+1 < arr->num_of_bits) { 407 | found = _test_find_next_bit(arr, indices[i]+1, &pos); 408 | if(i+1 < n) { 409 | ASSERT(found == 1); 410 | ASSERT(pos == indices[i+1]); 411 | } else { 412 | ASSERT(found == 0); 413 | } 414 | } 415 | } 416 | } 417 | 418 | // Loop over setting diff numbers of bits - check prev_bit_set 419 | for(n = 0; n <= num_idx; n++) { 420 | bit_array_clear_all(arr); 421 | for(i = 0; i < n; i++) bit_array_set_bit(arr, indices[num_idx-i-1]); 422 | 423 | for(i = 0; i < n; i++) { 424 | found = _test_find_prev_bit(arr, indices[num_idx-i-1], &pos); 425 | if(i+1 < n) { 426 | ASSERT(found == 1); 427 | ASSERT(pos == indices[num_idx-i-2]); 428 | } else { 429 | ASSERT(found == 0); 430 | } 431 | } 432 | } 433 | 434 | bit_array_free(arr); 435 | 436 | SUITE_END(); 437 | } 438 | 439 | void test_parity() 440 | { 441 | SUITE_START("parity"); 442 | 443 | BIT_ARRAY* arr = bit_array_create(100); 444 | 445 | ASSERT(bit_array_parity(arr) == 0); 446 | 447 | bit_array_set_bits(arr, 6, 0, 5, 24, 64, 80, 99); 448 | ASSERT(bit_array_parity(arr) == 0); 449 | 450 | bit_array_clear_bit(arr, 24); 451 | ASSERT(bit_array_parity(arr) == 1); 452 | 453 | bit_array_clear_bit(arr, 99); 454 | ASSERT(bit_array_parity(arr) == 0); 455 | 456 | bit_array_clear_bit(arr, 0); 457 | ASSERT(bit_array_parity(arr) == 1); 458 | 459 | bit_array_free(arr); 460 | 461 | SUITE_END(); 462 | } 463 | 464 | void _test_interleave(BIT_ARRAY* result, BIT_ARRAY *arr1, BIT_ARRAY *arr2) 465 | { 466 | bit_array_interleave(result, arr1, arr2); 467 | 468 | size_t result_len = bit_array_length(result); 469 | char *result_str = (char*)malloc((result_len+1) * sizeof(char)); 470 | bit_array_to_str(result, result_str); 471 | 472 | size_t len1 = bit_array_length(arr1); 473 | size_t len2 = bit_array_length(arr2); 474 | 475 | char *correct = (char*)malloc(result_len+1); 476 | memset(correct, '0', sizeof(char) * result_len); 477 | correct[result_len] = '\0'; 478 | 479 | size_t i, j = 0; 480 | size_t len = MAX(len1,len2); 481 | for(i = 0; i < len; i++) 482 | { 483 | if(i < len1) 484 | correct[j++] = bit_array_get_bit(arr1, i) ? '1' : '0'; 485 | 486 | if(i < len2) 487 | correct[j++] = bit_array_get_bit(arr2, i) ? '1' : '0'; 488 | } 489 | 490 | ASSERT(strcmp(correct, result_str) == 0); 491 | 492 | if(strcmp(correct, result_str) != 0) 493 | { 494 | // debug output 495 | printf("corr: %s\n", correct); 496 | printf("got : %s\n", result_str); 497 | } 498 | 499 | free(correct); 500 | free(result_str); 501 | } 502 | 503 | void test_interleave() 504 | { 505 | SUITE_START("interleave"); 506 | 507 | BIT_ARRAY* arr1 = bit_array_create(10); 508 | BIT_ARRAY* arr2 = bit_array_create(10); 509 | BIT_ARRAY* result = bit_array_create(0); 510 | 511 | bit_array_set_all(arr1); 512 | _test_interleave(result, arr1, arr2); 513 | 514 | bit_array_clear_all(arr1); 515 | bit_array_set_all(arr2); 516 | bit_array_resize(result, 25); 517 | _test_interleave(result, arr1, arr2); 518 | 519 | bit_array_set_all(arr1); 520 | bit_array_set_all(arr2); 521 | _test_interleave(result, arr1, arr2); 522 | 523 | bit_array_clear_all(arr1); 524 | bit_array_clear_all(arr2); 525 | _test_interleave(result, arr1, arr2); 526 | 527 | bit_array_resize(arr1, 100); 528 | bit_array_resize(arr2, 100); 529 | bit_array_clear_all(arr1); 530 | bit_array_set_all(arr2); 531 | _test_interleave(result, arr1, arr2); 532 | 533 | bit_array_free(arr1); 534 | bit_array_free(arr2); 535 | bit_array_free(result); 536 | 537 | SUITE_END(); 538 | } 539 | 540 | int cmp_strings(const char *str1, const char *str2, char rev) 541 | { 542 | size_t len1 = strlen(str1); 543 | size_t len2 = strlen(str2); 544 | size_t max_len = MAX(len1, len2); 545 | 546 | if(rev) 547 | { 548 | size_t i; 549 | for(i = 0; i < max_len; i++) 550 | { 551 | char a = (i < len1 ? str1[i] : '0'); 552 | char b = (i < len2 ? str2[i] : '0'); 553 | 554 | if(a != b) 555 | { 556 | return a > b ? 1 : -1; 557 | } 558 | } 559 | } 560 | else 561 | { 562 | size_t i; 563 | for(i = max_len; i > 0; i--) 564 | { 565 | char a = (i < len1 ? str1[i] : '0'); 566 | char b = (i < len2 ? str2[i] : '0'); 567 | 568 | if(a != b) 569 | { 570 | return str1[i] > str2[i] ? 1 : -1; 571 | } 572 | else if(i == 0) 573 | { 574 | break; 575 | } 576 | } 577 | } 578 | 579 | return len1 > len2 ? 1 : (len1 < len2 ? -1 : 0); 580 | } 581 | 582 | void _test_cmp(const char *str1, const char *str2, char rev) 583 | { 584 | // Get correct answer 585 | int cmp_correct = cmp_strings(str1, str2, rev); 586 | 587 | BIT_ARRAY* arr1 = bit_array_create(0); 588 | BIT_ARRAY* arr2 = bit_array_create(0); 589 | 590 | bit_array_from_str(arr1, str1); 591 | bit_array_from_str(arr2, str2); 592 | 593 | int cmp1, cmp2; 594 | 595 | if(rev) 596 | { 597 | cmp1 = bit_array_cmp_big_endian(arr1, arr2); 598 | cmp2 = bit_array_cmp_big_endian(arr2, arr1); 599 | } 600 | else 601 | { 602 | cmp1 = bit_array_cmp(arr1, arr2); 603 | cmp2 = bit_array_cmp(arr2, arr1); 604 | } 605 | 606 | cmp1 = (cmp1 < 0 ? -1 : (cmp1 > 0 ? 1 : 0)); 607 | ASSERT(cmp1 == cmp_correct); 608 | 609 | cmp2 = (cmp2 < 0 ? -1 : (cmp2 > 0 ? 1 : 0)); 610 | ASSERT(cmp2 == -cmp_correct); 611 | 612 | bit_array_free(arr1); 613 | bit_array_free(arr2); 614 | } 615 | 616 | void _test_cmps(char rev) 617 | { 618 | // Remember right hand side is msb 619 | _test_cmp("011010100", "001101010", rev); 620 | _test_cmp("0", "00", rev); 621 | _test_cmp("", "", rev); 622 | _test_cmp("100000", "10", rev); 623 | _test_cmp("11000000000000000000000000000000000000000000010000000000000000" 624 | "00000000000000000000000000000000001000000000000000000000000000" 625 | "00000000000000000000000100000000000000000000000000000000000000" 626 | "000000000000100000", "1000000000000000000000000000000000000000" 627 | "00000001000000000000000000000000000000000000000000000000001000" 628 | "00000000000000000000000000000000000000000000000100000000000000" 629 | "00000000000000000000000000000000000010000000000000000000000000" 630 | "0000000000000000000000000100000", 1); 631 | 632 | /* 633 | // Some random tests 634 | size_t i, j; 635 | char str1[1000], str2[1000]; 636 | 637 | for(i = 0; i < 20; i++) 638 | { 639 | size_t len1 = RAND(600); 640 | size_t len2 = RAND(600); 641 | 642 | for(j = 0; j < len1; j++) 643 | { 644 | str1[j] = rand() > RAND_MAX / 2 ? '1' : '0'; 645 | } 646 | str1[len1] = '\0'; 647 | 648 | for(j = 0; j < len2; j++) 649 | { 650 | str2[j] = rand() > RAND_MAX / 2 ? '1' : '0'; 651 | } 652 | str2[len2] = '\0'; 653 | 654 | _test_cmp(str1, str2, rev); 655 | }*/ 656 | } 657 | 658 | void test_compare() 659 | { 660 | SUITE_START("compare"); 661 | 662 | _test_cmps(0); 663 | 664 | SUITE_END(); 665 | } 666 | 667 | void test_compare2() 668 | { 669 | SUITE_START("compare (rev endian)"); 670 | 671 | _test_cmps(1); 672 | 673 | SUITE_END(); 674 | } 675 | 676 | /* 677 | void test_hash() 678 | { 679 | 680 | printf("== Testing hash ==\n"); 681 | 682 | BIT_ARRAY* arr = bit_array_create(0); 683 | char str[200]; 684 | 685 | printf("arr: %s\n", bit_array_to_str(arr, str)); 686 | printf("hash: %lu\n", (unsigned long)bit_array_hash(arr, 0)); 687 | printf("--\n"); 688 | 689 | bit_array_resize(arr, 10); 690 | printf("arr: %s\n", bit_array_to_str(arr, str)); 691 | printf("hash: %lu\n", (unsigned long)bit_array_hash(arr, 0)); 692 | printf("--\n"); 693 | 694 | bit_array_set_bits(arr, 3, 5,7,9); 695 | printf("arr: %s\n", bit_array_to_str(arr, str)); 696 | printf("hash: %lu\n", (unsigned long)bit_array_hash(arr, 0)); 697 | printf("--\n"); 698 | 699 | bit_array_resize(arr, 80); 700 | printf("arr: %s\n", bit_array_to_str(arr, str)); 701 | printf("hash: %lu\n", (unsigned long)bit_array_hash(arr, 0)); 702 | printf("--\n"); 703 | 704 | bit_array_set_bits(arr, 3, 50,57,59); 705 | printf("arr: %s\n", bit_array_to_str(arr, str)); 706 | printf("hash: %lu\n", (unsigned long)bit_array_hash(arr, 0)); 707 | printf("--\n"); 708 | 709 | bit_array_resize(arr, 1000); 710 | printf("len: %lu\n", (unsigned long)bit_array_length(arr)); 711 | printf("hash: %lu\n", (unsigned long)bit_array_hash(arr, 0)); 712 | printf("--\n"); 713 | 714 | bit_array_free(arr); 715 | 716 | printf("== End of testing hash ==\n\n"); 717 | } 718 | */ 719 | 720 | void _test_reverse(int len) 721 | { 722 | char str[1000], str2[1000]; 723 | 724 | BIT_ARRAY* arr = bit_array_create(len); 725 | 726 | bit_array_random(arr, 0.5f); 727 | 728 | bit_array_to_str(arr, str); 729 | reverse_str(str); 730 | 731 | bit_array_reverse(arr); 732 | bit_array_to_str(arr, str2); 733 | 734 | ASSERT(strcmp(str, str2) == 0); 735 | 736 | if(strcmp(str, str2) != 0) 737 | { 738 | // debug output 739 | printf("strrev: %s\n", str); 740 | printf("arrrev: %s\n", str2); 741 | } 742 | 743 | bit_array_free(arr); 744 | } 745 | 746 | void test_reverse() 747 | { 748 | SUITE_START("reverse"); 749 | 750 | _test_reverse(0); 751 | _test_reverse(10); 752 | _test_reverse(63); 753 | _test_reverse(64); 754 | _test_reverse(65); 755 | _test_reverse(100); 756 | _test_reverse(128); 757 | _test_reverse(506); 758 | 759 | SUITE_END(); 760 | } 761 | 762 | void _test_toggle_region(BIT_ARRAY *arr, size_t start, size_t region_len) 763 | { 764 | bit_index_t len = bit_array_length(arr); 765 | char *str1 = (char*)malloc((len+1) * sizeof(char)); 766 | bit_array_to_str(arr, str1); 767 | 768 | // Toggle string 769 | size_t i; 770 | for(i = start; i < start+region_len; i++) 771 | { 772 | str1[i] = (str1[i] == '1' ? '0' : '1'); 773 | } 774 | 775 | // Toggle array 776 | char *str2 = (char*)malloc((len+1) * sizeof(char)); 777 | bit_array_toggle_region(arr, start, region_len); 778 | bit_array_to_str(arr, str2); 779 | 780 | ASSERT(strcmp(str1, str2) == 0); 781 | 782 | free(str1); 783 | free(str2); 784 | } 785 | 786 | void test_toggle() 787 | { 788 | SUITE_START("toggle"); 789 | 790 | BIT_ARRAY* arr = bit_array_create(0); 791 | _test_toggle_region(arr, 0, 0); 792 | 793 | bit_array_resize(arr, 10); 794 | bit_array_set_bits(arr, 4, 2,3,6,9); 795 | _test_toggle_region(arr, 3, 6); 796 | _test_toggle_region(arr, 0, 10); 797 | 798 | bit_array_resize(arr, 80); 799 | bit_array_set_bits(arr, 8, 0,20,50,62,64,70,75,79); 800 | _test_toggle_region(arr, 25, 50); 801 | 802 | bit_array_resize(arr, 100); 803 | bit_array_clear_all(arr); 804 | _test_toggle_region(arr, 0, 100); 805 | _test_toggle_region(arr, 0, 0); 806 | _test_toggle_region(arr, 1, 1); 807 | _test_toggle_region(arr, 3, 1); 808 | _test_toggle_region(arr, 20, 80); 809 | _test_toggle_region(arr, 0, 64); 810 | _test_toggle_region(arr, 64, 36); 811 | 812 | int i; 813 | for(i = 0; i < 1000; i += 50) 814 | { 815 | bit_array_resize(arr, i); 816 | bit_array_random(arr, 0.5f); 817 | _test_toggle_region(arr, i / 2, i - i / 2); 818 | } 819 | 820 | bit_array_free(arr); 821 | 822 | SUITE_END(); 823 | } 824 | 825 | void _test_random_and_shuffle() 826 | { 827 | int i, j, k, maxi_sum = 0; 828 | BIT_ARRAY *arr = bit_array_create(0); 829 | 830 | int max_len = 500; 831 | int num_hits = 50; 832 | int num_repetitions = 50; 833 | float prob = 0.5f; 834 | 835 | int *counts = (int*)malloc(max_len*sizeof(int)); 836 | int *hist = (int*)malloc((num_hits+1)*sizeof(int)); 837 | 838 | for(k = 0; k < num_repetitions; k++) 839 | { 840 | int len = RAND(max_len-5)+5; 841 | ASSERT(len <= max_len); 842 | 843 | bit_array_resize(arr, len); 844 | bit_array_random(arr, prob); 845 | 846 | bit_index_t bitset = bit_array_num_bits_set(arr); 847 | 848 | memset(counts, 0, len*sizeof(int)); 849 | memset(hist, 0, (num_hits+1)*sizeof(int)); 850 | 851 | for(i = 0; i < num_hits; i++) 852 | { 853 | bit_array_shuffle(arr); 854 | 855 | for(j = 0; j < len; j++) 856 | if(bit_array_get_bit(arr, j)) 857 | counts[j]++; 858 | } 859 | 860 | ASSERT(bitset == bit_array_num_bits_set(arr)); 861 | 862 | // Get the most common number of times to be hit 863 | for(i = 0; i < len; i++) { 864 | hist[counts[i]]++; 865 | } 866 | 867 | int maxi = 0; 868 | for(i = 1; i <= num_hits; i++) { 869 | if(hist[i] > hist[maxi]) { 870 | maxi = i; 871 | } 872 | } 873 | 874 | maxi_sum += maxi; 875 | } 876 | 877 | double average = (double)maxi_sum / num_repetitions; 878 | double expected = num_hits * (double)prob; 879 | ASSERT(average >= expected-10 && average <= expected+10); 880 | 881 | free(hist); 882 | free(counts); 883 | bit_array_free(arr); 884 | } 885 | 886 | void test_random_and_shuffle() 887 | { 888 | SUITE_START("random and shuffle"); 889 | 890 | int i; 891 | for(i = 0; i < 100; i++) 892 | _test_random_and_shuffle(); 893 | 894 | SUITE_END(); 895 | } 896 | 897 | /* 898 | // used in test_random 899 | void _print_random_arr(BIT_ARRAY* arr, float *rates, int num_rates, char *tmp) 900 | { 901 | int i, j; 902 | 903 | for(i = 0; i < num_rates; i++) 904 | { 905 | float rate = rates[i]; 906 | 907 | printf("Random %f\n", rate); 908 | 909 | // 4 repetitions 910 | for(j = 0; j < 4; j++) 911 | { 912 | bit_array_random(arr, rate); 913 | printf("arr: %s [%i]\n", bit_array_to_str(arr, tmp), 914 | (int)bit_array_num_bits_set(arr)); 915 | } 916 | } 917 | } 918 | 919 | void test_random() 920 | { 921 | printf("== Testing random ==\n"); 922 | 923 | BIT_ARRAY* arr = bit_array_create(0); 924 | char str[200]; 925 | 926 | const int num_rates = 4; 927 | float rates[] = {0.0, 0.1, 0.5, 1.0}; 928 | 929 | printf("Initialise length 0; random\n"); 930 | bit_array_random(arr, 0.1); 931 | printf("arr: %s [%i]\n", bit_array_to_str(arr, str), 932 | (int)bit_array_num_bits_set(arr)); 933 | 934 | printf("resize length 10; set bits 2,3,6,9\n"); 935 | bit_array_resize(arr, 10); 936 | bit_array_set_bits(arr, 4, 2,3,6,9); 937 | printf("arr: %s [%i]\n", bit_array_to_str(arr, str), 938 | (int)bit_array_num_bits_set(arr)); 939 | 940 | _print_random_arr(arr, rates, num_rates, str); 941 | 942 | printf("resize length 80; clear all\n"); 943 | bit_array_resize(arr, 80); 944 | bit_array_clear_all(arr); 945 | 946 | _print_random_arr(arr, rates, num_rates, str); 947 | 948 | bit_array_free(arr); 949 | 950 | printf("== End of testing random ==\n\n"); 951 | } 952 | */ 953 | 954 | void _test_cycle(BIT_ARRAY *arr, size_t dist, char left) 955 | { 956 | BIT_ARRAY *clone = bit_array_clone(arr); 957 | 958 | size_t len = bit_array_length(arr); 959 | 960 | if(len > 0) 961 | dist = dist % len; 962 | 963 | char *str1 = (char*)malloc((len+1) * sizeof(char)); 964 | char *str2 = (char*)malloc((len+1) * sizeof(char)); 965 | str1[len] = '\0'; 966 | str2[len] = '\0'; 967 | 968 | // cycle in str 969 | if(left) 970 | { 971 | // shift away from index zero 972 | if(len > 0) 973 | { 974 | bit_array_to_substr(arr, 0, len-dist, str1, '1', '0', 0); 975 | bit_array_to_substr(arr, len-dist, dist, str1+len-dist, '1', '0', 0); 976 | } 977 | 978 | bit_array_cycle_left(arr, dist); 979 | } 980 | else 981 | { 982 | // shift towards index zero 983 | if(len > 0) 984 | { 985 | bit_array_to_substr(arr, dist, len-dist, str1+dist, '1', '0', 0); 986 | bit_array_to_substr(arr, 0, dist, str1, '1', '0', 0); 987 | } 988 | 989 | bit_array_cycle_right(arr, dist); 990 | } 991 | 992 | bit_array_to_substr(arr, 0, len, str2, '1', '0', 0); 993 | 994 | // printf("arr : %s\n", str2); 995 | // printf("str : %s\n", str1); 996 | 997 | // Assert that string shifting is the same as bit array shifting 998 | ASSERT(strcmp(str1, str2) == 0); 999 | 1000 | free(str1); 1001 | free(str2); 1002 | 1003 | // Now test if we cycle back it is identical to its clone 1004 | if(left) 1005 | { 1006 | bit_array_cycle_right(arr, dist); 1007 | } 1008 | else 1009 | { 1010 | bit_array_cycle_left(arr, dist); 1011 | } 1012 | 1013 | ASSERT(bit_array_cmp(arr, clone) == 0); 1014 | 1015 | bit_array_free(clone); 1016 | } 1017 | 1018 | // Test cyclic shift / circular shift 1019 | void test_cycle() 1020 | { 1021 | SUITE_START("cycle"); 1022 | 1023 | BIT_ARRAY* arr = bit_array_create(0); 1024 | 1025 | _test_cycle(arr, 3, 1); 1026 | _test_cycle(arr, 0, 0); 1027 | 1028 | bit_array_resize(arr, 10); 1029 | bit_array_set_bits(arr, 4, 2,3,6,9); 1030 | 1031 | _test_cycle(arr, 3, 1); 1032 | _test_cycle(arr, 0, 0); 1033 | _test_cycle(arr, 3, 1); 1034 | _test_cycle(arr, 0, 0); 1035 | _test_cycle(arr, 25, 1); 1036 | _test_cycle(arr, 25, 0); 1037 | 1038 | bit_array_resize(arr, 80); 1039 | bit_array_set_bits(arr, 8, 10, 12, 28, 32, 39, 63, 64, 79); 1040 | 1041 | _test_cycle(arr, 65, 1); 1042 | _test_cycle(arr, 65, 0); 1043 | 1044 | // Set even bits 1045 | int i; 1046 | bit_array_clear_all(arr); 1047 | for(i = 0; i < 80; i += 2) 1048 | { 1049 | bit_array_set_bit(arr, i); 1050 | } 1051 | 1052 | bit_array_cycle_left(arr, 1); 1053 | bit_array_cycle_right(arr, 1); 1054 | 1055 | _test_cycle(arr, 1, 1); 1056 | _test_cycle(arr, 1, 0); 1057 | _test_cycle(arr, 1, 0); 1058 | _test_cycle(arr, 1, 1); 1059 | 1060 | // Random arrays 1061 | for(i = 0; i < 10; i++) 1062 | { 1063 | size_t len = RAND(1000UL); 1064 | size_t dist = RAND(1000UL); 1065 | char left = rand() > RAND_MAX / 2 ? 1 : 0; 1066 | 1067 | bit_array_resize(arr, len); 1068 | bit_array_random(arr, 0.5f); 1069 | _test_cycle(arr, dist, left); 1070 | } 1071 | 1072 | bit_array_resize(arr, 5); 1073 | bit_array_clear_all(arr); 1074 | bit_array_set_bit(arr, 1); 1075 | 1076 | bit_array_free(arr); 1077 | 1078 | SUITE_END(); 1079 | } 1080 | 1081 | void _test_shift(BIT_ARRAY *arr, size_t dist, char left, char fill) 1082 | { 1083 | size_t len = bit_array_length(arr); 1084 | 1085 | // printf("dist: %i; len: %i; %s; fill: %i\n", 1086 | // (int)dist, (int)len, left ? "left" : "right", fill); 1087 | 1088 | char *str1 = (char*)malloc((len+1) * sizeof(char)); 1089 | char *str2 = (char*)malloc((len+1) * sizeof(char)); 1090 | memset(str1, fill ? '1' : '0', len); 1091 | str1[len] = '\0'; 1092 | str2[len] = '\0'; 1093 | 1094 | bit_array_to_substr(arr, 0, len, str2, '1', '0', 0); 1095 | // printf("orig: %s\n", str2); 1096 | 1097 | // cycle in str 1098 | if(left) 1099 | { 1100 | // left is away from index zero 1101 | if(dist < len) 1102 | { 1103 | // printf("0-%i -> %i\n", (int)(len-dist), (int)dist); 1104 | // printf("str : %s\n", str1); 1105 | bit_array_to_substr(arr, 0, len-dist, str1, '1', '0', 0); 1106 | // printf("str : %s\n", str1); 1107 | } 1108 | 1109 | bit_array_shift_left(arr, dist, fill); 1110 | } 1111 | else 1112 | { 1113 | if(dist < len) 1114 | { 1115 | bit_array_to_substr(arr, dist, len-dist, str1+dist, '1', '0', 0); 1116 | } 1117 | 1118 | bit_array_shift_right(arr, dist, fill); 1119 | } 1120 | 1121 | bit_array_to_substr(arr, 0, len, str2, '1', '0', 0); 1122 | 1123 | // printf("arr : %s\n", str2); 1124 | // printf("str : %s\n", str1); 1125 | 1126 | ASSERT(strcmp(str1, str2) == 0); 1127 | 1128 | free(str1); 1129 | free(str2); 1130 | } 1131 | 1132 | // Test shift 1133 | void test_shift() 1134 | { 1135 | SUITE_START("shift"); 1136 | 1137 | BIT_ARRAY* arr = bit_array_create(0); 1138 | 1139 | const char left = 1; 1140 | const char right = 0; 1141 | const char fill_zero = 0; 1142 | const char fill_ones = 1; 1143 | 1144 | _test_shift(arr, 3, left, fill_ones); 1145 | _test_shift(arr, 0, right, fill_ones); 1146 | 1147 | bit_array_resize(arr, 10); 1148 | bit_array_set_bits(arr, 4, 2,3,6,9); 1149 | 1150 | _test_shift(arr, 3, left, fill_zero); 1151 | _test_shift(arr, 0, left, fill_zero); 1152 | _test_shift(arr, 3, right, fill_ones); 1153 | _test_shift(arr, 0, right, fill_ones); 1154 | _test_shift(arr, 25, left, fill_zero); 1155 | _test_shift(arr, 25, right, fill_zero); 1156 | 1157 | bit_array_resize(arr, 80); 1158 | bit_array_set_bits(arr, 8, 10, 12, 28, 32, 39, 63, 64, 79); 1159 | _test_shift(arr, 65, right, fill_zero); 1160 | _test_shift(arr, 65, left, fill_zero); 1161 | 1162 | // Set even bits 1163 | bit_array_clear_all(arr); 1164 | 1165 | int i; 1166 | for(i = 0; i < 80; i += 2) 1167 | { 1168 | bit_array_set_bit(arr, i); 1169 | } 1170 | 1171 | _test_shift(arr, 1, left, fill_ones); 1172 | _test_shift(arr, 1, right, fill_ones); 1173 | 1174 | bit_array_free(arr); 1175 | 1176 | SUITE_END(); 1177 | } 1178 | 1179 | void _test_hamming(BIT_ARRAY *arr1, BIT_ARRAY *arr2) 1180 | { 1181 | bit_index_t bits_set1 = 0, bits_set2 = 0, dist = 0; 1182 | 1183 | bit_index_t len1 = bit_array_length(arr1); 1184 | bit_index_t len2 = bit_array_length(arr2); 1185 | 1186 | bit_index_t i, max = MAX(len1, len2); 1187 | for(i = 0; i < max; i++) 1188 | { 1189 | char a = i < len1 ? bit_array_get_bit(arr1, i) : 0; 1190 | char b = i < len2 ? bit_array_get_bit(arr2, i) : 0; 1191 | 1192 | if(a) 1193 | bits_set1++; 1194 | 1195 | if(b) 1196 | bits_set2++; 1197 | 1198 | if(a != b) 1199 | dist++; 1200 | } 1201 | 1202 | ASSERT(bits_set1 == bit_array_num_bits_set(arr1)); 1203 | ASSERT(bits_set2 == bit_array_num_bits_set(arr2)); 1204 | ASSERT(dist == bit_array_hamming_distance(arr1, arr2)); 1205 | } 1206 | 1207 | void test_hamming_weight() 1208 | { 1209 | SUITE_START("hamming weight"); 1210 | 1211 | BIT_ARRAY* arr1 = bit_array_create(0); 1212 | BIT_ARRAY* arr2 = bit_array_create(0); 1213 | 1214 | _test_hamming(arr1, arr2); 1215 | _test_hamming(arr2, arr1); 1216 | 1217 | bit_array_resize(arr1, 10); 1218 | _test_hamming(arr1, arr2); 1219 | _test_hamming(arr2, arr1); 1220 | 1221 | bit_array_set_bits(arr1, 3, 0, 2, 7); 1222 | _test_hamming(arr1, arr2); 1223 | _test_hamming(arr2, arr1); 1224 | 1225 | bit_array_resize(arr2, 10); 1226 | _test_hamming(arr1, arr2); 1227 | _test_hamming(arr2, arr1); 1228 | 1229 | bit_array_set_bits(arr2, 3, 0, 2, 7); 1230 | _test_hamming(arr1, arr2); 1231 | _test_hamming(arr2, arr1); 1232 | 1233 | bit_array_resize(arr1, 80); 1234 | bit_array_clear_bit(arr1, 2); 1235 | bit_array_set_region(arr1, 50, 20); 1236 | _test_hamming(arr1, arr2); 1237 | _test_hamming(arr2, arr1); 1238 | 1239 | // random 1240 | int i; 1241 | for(i = 0; i < 10; i++) 1242 | { 1243 | size_t len1 = RAND(1000UL); 1244 | size_t len2 = RAND(1000UL); 1245 | bit_array_resize(arr1, len1); 1246 | bit_array_resize(arr2, len2); 1247 | bit_array_random(arr1, 0.5f); 1248 | bit_array_random(arr2, 0.5f); 1249 | _test_hamming(arr1, arr2); 1250 | _test_hamming(arr2, arr1); 1251 | } 1252 | 1253 | bit_array_free(arr1); 1254 | bit_array_free(arr2); 1255 | 1256 | SUITE_END(); 1257 | } 1258 | 1259 | // Saves arr1 to file, then reloads it into arr2 and compares them 1260 | void _test_save_load(BIT_ARRAY *arr1, BIT_ARRAY *arr2) 1261 | { 1262 | FILE *f = fopen(test_filename, "w"); 1263 | 1264 | if(f == NULL) 1265 | { 1266 | die("Couldn't open file to write: '%s'", test_filename); 1267 | } 1268 | 1269 | bit_array_save(arr1, f); 1270 | fclose(f); 1271 | 1272 | f = fopen(test_filename, "r"); 1273 | 1274 | if(f == NULL) 1275 | { 1276 | die("Couldn't open file to read: '%s'", test_filename); 1277 | } 1278 | 1279 | if(!bit_array_load(arr2, f)) 1280 | { 1281 | die("Load returned warning [file: %s]", test_filename); 1282 | } 1283 | 1284 | fclose(f); 1285 | 1286 | ASSERT(bit_array_cmp(arr1, arr2) == 0); 1287 | 1288 | if(bit_array_cmp(arr1, arr2) != 0 && bit_array_length(arr1) < 500) 1289 | { 1290 | // debug output 1291 | bit_index_t len = MAX(bit_array_length(arr1), bit_array_length(arr2)); 1292 | char *tmp = (char*)malloc((len+1) * sizeof(char)); 1293 | 1294 | printf("out: %s\n", bit_array_to_str(arr1, tmp)); 1295 | printf("in : %s\n", bit_array_to_str(arr2, tmp)); 1296 | 1297 | free(tmp); 1298 | } 1299 | } 1300 | 1301 | void test_save_load() 1302 | { 1303 | SUITE_START("load and save"); 1304 | 1305 | BIT_ARRAY* arr1 = bit_array_create(0); 1306 | BIT_ARRAY* arr2 = bit_array_create(0); 1307 | 1308 | // Empty array 1309 | _test_save_load(arr1, arr2); 1310 | 1311 | // Ten 0s 1312 | bit_array_resize(arr1, 10); 1313 | _test_save_load(arr1, arr2); 1314 | 1315 | // Thousand 1s: 1316 | bit_array_resize(arr1, 1000); 1317 | bit_array_set_all(arr1); 1318 | _test_save_load(arr1, arr2); 1319 | 1320 | // 1100111010 1321 | bit_array_resize(arr1, 10); 1322 | bit_array_clear_bits(arr1, 4, 2,3,7,9); 1323 | _test_save_load(arr1, arr2); 1324 | 1325 | // 100 x random lengths and bits 1326 | int i; 1327 | for(i = 0; i < 10; i++) 1328 | { 1329 | bit_array_resize(arr1, RAND(5000UL)); 1330 | bit_array_random(arr1, 0.5f); 1331 | _test_save_load(arr1, arr2); 1332 | } 1333 | 1334 | bit_array_free(arr1); 1335 | bit_array_free(arr2); 1336 | 1337 | SUITE_END(); 1338 | } 1339 | 1340 | // 1341 | // Aggregate testing 1342 | // 1343 | /* 1344 | void test_zero_length_arrays() 1345 | { 1346 | printf("== Testing zero length arrays ==\n"); 1347 | 1348 | BIT_ARRAY* arr1 = bit_array_create(0); 1349 | BIT_ARRAY* arr2 = bit_array_create(10); 1350 | 1351 | char tmp[101]; 1352 | 1353 | printf("Initial arr1[length:0] arr2[length:10]\n"); 1354 | printf("arr1: %s\n", bit_array_to_str(arr1, tmp)); 1355 | printf("arr2: %s\n", bit_array_to_str(arr2, tmp)); 1356 | 1357 | printf("--\nResize arr2 to 0\n"); 1358 | bit_array_resize(arr2, 0); 1359 | printf("arr1: %s\n", bit_array_to_str(arr1, tmp)); 1360 | printf("arr2: %s\n", bit_array_to_str(arr2, tmp)); 1361 | 1362 | printf("--\nAnd (arr1, arr2)\n"); 1363 | bit_array_and(arr1, arr1, arr2); 1364 | printf("arr1: %s\n", bit_array_to_str(arr1, tmp)); 1365 | printf("arr2: %s\n", bit_array_to_str(arr2, tmp)); 1366 | 1367 | printf("--\nNot (arr1)\n"); 1368 | printf("arr1: %s\n", bit_array_to_str(arr1, tmp)); 1369 | 1370 | printf("--\nAnd (arr1, arr2)\n"); 1371 | bit_array_and(arr1, arr1, arr2); 1372 | printf("arr1: %s\n", bit_array_to_str(arr1, tmp)); 1373 | printf("arr2: %s\n", bit_array_to_str(arr2, tmp)); 1374 | 1375 | bit_array_free(arr1); 1376 | bit_array_free(arr2); 1377 | 1378 | printf("== End of testing zero length arrays ==\n\n"); 1379 | } 1380 | 1381 | void test_multiple_actions() 1382 | { 1383 | printf("== testing all functions ==\n"); 1384 | 1385 | printf("Create bit array 100 bits long\n"); 1386 | 1387 | BIT_ARRAY* bitarr = bit_array_create(100); 1388 | bit_array_print(bitarr, stdout); 1389 | printf("\n"); 1390 | 1391 | printf("Set bit 2\n"); 1392 | bit_array_set_bit(bitarr, 2); 1393 | bit_array_print(bitarr, stdout); 1394 | printf("\n"); 1395 | 1396 | printf("Set bit 5\n"); 1397 | bit_array_set_bit(bitarr, 5); 1398 | bit_array_print(bitarr, stdout); 1399 | printf("\n"); 1400 | 1401 | printf("Set bit 99\n"); 1402 | bit_array_set_bit(bitarr, 99); 1403 | bit_array_print(bitarr, stdout); 1404 | printf("\n"); 1405 | 1406 | printf("Set bit 0\n"); 1407 | bit_array_set_bit(bitarr, 0); 1408 | bit_array_print(bitarr, stdout); 1409 | printf("\n"); 1410 | 1411 | // Test clone 1412 | printf("Clone\n"); 1413 | BIT_ARRAY* clone = bit_array_clone(bitarr); 1414 | bit_array_print(bitarr, stdout); 1415 | printf("\n"); 1416 | 1417 | printf(" Clear bit 0\n"); 1418 | bit_array_clear_bit(clone, 0); 1419 | bit_array_print(bitarr, stdout); 1420 | printf("\n"); 1421 | 1422 | printf(" Set bit 21\n"); 1423 | bit_array_set_bit(clone, 21); 1424 | bit_array_print(bitarr, stdout); 1425 | printf("\n"); 1426 | 1427 | printf(" Set bit 63\n"); 1428 | bit_array_set_bit(clone, 63); 1429 | bit_array_print(bitarr, stdout); 1430 | printf("\n"); 1431 | 1432 | printf(" End of clone\n"); 1433 | bit_array_free(clone); 1434 | 1435 | // End of clone 1436 | 1437 | printf("Fill with zeros\n"); 1438 | bit_array_clear_all(bitarr); 1439 | bit_array_print(bitarr, stdout); 1440 | printf("\n"); 1441 | 1442 | printf("Fill with ones\n"); 1443 | bit_array_set_all(bitarr); 1444 | bit_array_print(bitarr, stdout); 1445 | printf("\n"); 1446 | 1447 | printf("Clear bit 1\n"); 1448 | bit_array_clear_bit(bitarr, 1); 1449 | bit_array_print(bitarr, stdout); 1450 | printf("\n"); 1451 | 1452 | printf("Clear bits 0-39\n"); 1453 | bit_array_clear_region(bitarr, 0, 40); 1454 | bit_array_print(bitarr, stdout); 1455 | printf("\n"); 1456 | 1457 | bit_index_t first_set_bit; 1458 | if(bit_array_find_first_set_bit(bitarr, &first_set_bit)) 1459 | { 1460 | printf("first set bit: %i\n", (int)first_set_bit); 1461 | } 1462 | 1463 | printf("Set bits 1-1\n"); 1464 | bit_array_set_region(bitarr, 1, 1); 1465 | bit_array_print(bitarr, stdout); 1466 | printf("\n"); 1467 | 1468 | printf("Set bits (3,0)\n"); 1469 | bit_array_set_region(bitarr, 3, 0); 1470 | bit_array_print(bitarr, stdout); 1471 | printf("\n"); 1472 | 1473 | printf("Clear bits 50-59\n"); 1474 | bit_array_clear_region(bitarr, 50, 10); 1475 | bit_array_print(bitarr, stdout); 1476 | printf("\n"); 1477 | 1478 | printf("Negate\n"); 1479 | bit_array_not(bitarr, bitarr); 1480 | bit_array_print(bitarr, stdout); 1481 | printf("\n"); 1482 | 1483 | printf("Sort bits\n"); 1484 | bit_array_sort_bits(bitarr); 1485 | bit_array_print(bitarr, stdout); 1486 | printf("\n"); 1487 | 1488 | printf("Clear bits 1-51\n"); 1489 | bit_array_clear_region(bitarr, 1, 51); 1490 | bit_array_print(bitarr, stdout); 1491 | printf("\n"); 1492 | 1493 | if(bit_array_find_first_set_bit(bitarr, &first_set_bit)) 1494 | { 1495 | printf("first set bit: %i\n", (int)first_set_bit); 1496 | } 1497 | 1498 | printf("Set bits 1-51\n"); 1499 | bit_array_set_region(bitarr, 1, 51); 1500 | bit_array_print(bitarr, stdout); 1501 | printf("\n"); 1502 | 1503 | if(bit_array_find_first_set_bit(bitarr, &first_set_bit)) 1504 | { 1505 | printf("first set bit: %i\n", (int)first_set_bit); 1506 | } 1507 | 1508 | printf("Clear bit 98\n"); 1509 | bit_array_clear_bit(bitarr, 98); 1510 | bit_array_print(bitarr, stdout); 1511 | printf("\n"); 1512 | 1513 | printf("Clear bit 99\n"); 1514 | bit_array_clear_bit(bitarr, 99); 1515 | bit_array_print(bitarr, stdout); 1516 | printf("\n"); 1517 | 1518 | printf("Resize to 40 bits\n"); 1519 | bit_array_resize(bitarr, 40); 1520 | bit_array_print(bitarr, stdout); 1521 | printf("\n"); 1522 | 1523 | printf("Resize to 100 bits\n"); 1524 | bit_array_resize(bitarr, 100); 1525 | bit_array_print(bitarr, stdout); 1526 | printf("\n"); 1527 | 1528 | printf("Fill with ones\n"); 1529 | bit_array_set_all(bitarr); 1530 | bit_array_print(bitarr, stdout); 1531 | printf("\n"); 1532 | 1533 | printf("Resize to 64 bits\n"); 1534 | bit_array_resize(bitarr, 64); 1535 | bit_array_print(bitarr, stdout); 1536 | printf("\n"); 1537 | 1538 | printf("Resize to 100 bits\n"); 1539 | bit_array_resize(bitarr, 100); 1540 | bit_array_print(bitarr, stdout); 1541 | printf("\n"); 1542 | 1543 | printf("Set clear 0,10,55:\n"); 1544 | bit_array_clear_bits(bitarr, 3, 0, 10, 55); 1545 | printf("Set bits 67,69,70:\n"); 1546 | bit_array_set_bits(bitarr, 3, 67, 69, 70); 1547 | bit_array_print(bitarr, stdout); 1548 | printf("\n"); 1549 | 1550 | printf("Bits set: %i\n", (int)bit_array_num_bits_set(bitarr)); 1551 | 1552 | printf("Shift left 10 bits\n"); 1553 | bit_array_shift_left(bitarr, 10, 0); 1554 | bit_array_print(bitarr, stdout); 1555 | printf("\n"); 1556 | 1557 | printf("Shift right 10 bits [fill with 1s]\n"); 1558 | bit_array_shift_right(bitarr, 10, 1); 1559 | bit_array_print(bitarr, stdout); 1560 | printf("\n"); 1561 | 1562 | printf("Shift left 10 bits [fill with 1s]\n"); 1563 | bit_array_shift_left(bitarr, 10, 1); 1564 | bit_array_print(bitarr, stdout); 1565 | printf("\n"); 1566 | 1567 | // Test cycle bits 1568 | 1569 | printf("Cycle right 10 bits\n"); 1570 | bit_array_cycle_right(bitarr, 10); 1571 | bit_array_print(bitarr, stdout); 1572 | printf("\n"); 1573 | 1574 | printf("Cycle right 80 bits\n"); 1575 | bit_array_cycle_right(bitarr, 80); 1576 | bit_array_print(bitarr, stdout); 1577 | printf("\n"); 1578 | 1579 | bit_array_free(bitarr); 1580 | 1581 | printf("\nNew bit array:\n"); 1582 | bitarr = bit_array_create(210); // = ~3.28 words 1583 | bit_array_set_region(bitarr, 0, 100); 1584 | bit_array_set_bits(bitarr, 5, 200, 202, 204, 206, 208); 1585 | bit_array_print(bitarr, stdout); 1586 | printf("\n"); 1587 | 1588 | printf("Cycle right 80 bits\n"); 1589 | bit_array_cycle_right(bitarr, 80); 1590 | bit_array_print(bitarr, stdout); 1591 | printf("\n"); 1592 | 1593 | // Test reverse 1594 | 1595 | printf("Reverse region [10,90]:\n"); 1596 | bit_array_reverse_region(bitarr, 10, 90); 1597 | bit_array_print(bitarr, stdout); 1598 | printf("\n"); 1599 | 1600 | printf("Reverse region [10,90]:\n"); 1601 | bit_array_reverse_region(bitarr, 10, 90); 1602 | bit_array_print(bitarr, stdout); 1603 | printf("\n"); 1604 | 1605 | printf("Reverse region [90,10]:\n"); 1606 | bit_array_reverse_region(bitarr, 90, 10); 1607 | bit_array_print(bitarr, stdout); 1608 | printf("\n"); 1609 | 1610 | printf("Reverse region [90,10]:\n"); 1611 | bit_array_reverse_region(bitarr, 90, 10); 1612 | bit_array_print(bitarr, stdout); 1613 | printf("\n"); 1614 | 1615 | // Test write/read file 1616 | FILE* f; 1617 | 1618 | printf("Saving bitarray in %s\n", test_filename); 1619 | f = fopen(test_filename, "w"); 1620 | bit_array_save(bitarr, f); 1621 | fclose(f); 1622 | 1623 | bit_array_print(bitarr, stdout); 1624 | printf("\n"); 1625 | 1626 | // Deconstruct bit array 1627 | bit_array_free(bitarr); 1628 | 1629 | printf("Loading bitarray in %s\n", test_filename); 1630 | f = fopen(test_filename, "r"); 1631 | bit_array_load(bitarr, f); 1632 | fclose(f); 1633 | 1634 | bit_array_print(bitarr, stdout); 1635 | printf("\n"); 1636 | 1637 | // Deconstruct bit array 1638 | bit_array_free(bitarr); 1639 | 1640 | printf("== End of testing all functions ==\n\n"); 1641 | } 1642 | */ 1643 | 1644 | void _test_string_functions(BIT_ARRAY *arr) 1645 | { 1646 | size_t len = bit_array_length(arr); 1647 | 1648 | char *str = (char*)malloc((len+1) * sizeof(char)); 1649 | BIT_ARRAY *arr2 = bit_array_create(0); 1650 | 1651 | // to/from string 1652 | bit_array_to_str(arr, str); 1653 | bit_array_from_str(arr2, str); 1654 | 1655 | // compare 1656 | ASSERT(bit_array_cmp(arr, arr2) == 0); 1657 | 1658 | bit_array_resize(arr2, 0); 1659 | 1660 | // to/from substring 1661 | size_t len1 = len / 2; 1662 | size_t len2 = len - len1; 1663 | bit_array_to_substr(arr, 0, len1, str, '1', '0', 1); 1664 | bit_array_to_substr(arr, len1, len2, str+len1, '1', '0', 1); 1665 | bit_array_from_substr(arr2, 0, str, len1, "1", "0", 1); 1666 | bit_array_from_substr(arr2, len1, str+len1, len2, "1", "0", 1); 1667 | 1668 | // compare 1669 | ASSERT(bit_array_cmp(arr, arr2) == 0); 1670 | 1671 | free(str); 1672 | bit_array_free(arr2); 1673 | } 1674 | 1675 | // bit_array_from_str(), bit_array_from_substr() 1676 | // bit_array_to_str(), bit_array_to_substr() 1677 | // bit_array_print(), bit_array_print_substr() 1678 | void test_string_functions() 1679 | { 1680 | SUITE_START("string functions"); 1681 | 1682 | BIT_ARRAY *arr = bit_array_create(10); 1683 | bit_array_set_bits(arr, 3, 1,5,7); 1684 | _test_string_functions(arr); 1685 | 1686 | int i; 1687 | for(i = 0; i < 10; i++) 1688 | { 1689 | bit_array_resize(arr, RAND(500UL)); 1690 | bit_array_random(arr, 0.5f); 1691 | _test_string_functions(arr); 1692 | } 1693 | 1694 | bit_array_free(arr); 1695 | 1696 | SUITE_END(); 1697 | } 1698 | 1699 | // Convert string of hex to bit array and back, then compare 1700 | void _test_hex_functions(BIT_ARRAY *arr, const char* hex, int offset, char upper, 1701 | const char* correct) 1702 | { 1703 | char tmp_buf[1000]; 1704 | char *tmp = tmp_buf; 1705 | 1706 | if(hex[0] == '0' && hex[1] == 'x') 1707 | { 1708 | tmp_buf[0] = '0'; 1709 | tmp_buf[1] = 'x'; 1710 | tmp = tmp_buf + 2; 1711 | } 1712 | 1713 | // Reset BIT_ARRAY by resizing to zero 1714 | bit_array_resize(arr, 0); 1715 | bit_array_from_hex(arr, offset, hex, strlen(hex)); 1716 | bit_array_to_hex(arr, offset, bit_array_length(arr)-offset, tmp, upper); 1717 | 1718 | ASSERT(strcmp(tmp_buf, correct) == 0); 1719 | 1720 | if(strcmp(tmp_buf, correct) != 0) 1721 | { 1722 | printf("in : %s\n", hex); 1723 | printf("out: %s\n", tmp_buf); 1724 | printf("cor: %s\n\n", correct); 1725 | } 1726 | } 1727 | 1728 | // bit_array_from_hex(), bit_array_to_hex(), bit_array_print_hex() 1729 | void test_hex_functions() 1730 | { 1731 | SUITE_START("hex functions"); 1732 | 1733 | BIT_ARRAY *arr = bit_array_create(0); 1734 | 1735 | // lowercase then uppercase 1736 | _test_hex_functions(arr, "123456789ABcDeF0", 0, 0, "123456789abcdef0"); 1737 | _test_hex_functions(arr, "123456789ABcDeF0", 0, 1, "123456789ABCDEF0"); 1738 | 1739 | _test_hex_functions(arr, "0x123456789ABcDeF0", 0, 0, "0x123456789abcdef0"); 1740 | _test_hex_functions(arr, "0x123456789ABcDeF0", 0, 1, "0x123456789ABCDEF0"); 1741 | 1742 | _test_hex_functions(arr, "0x123456789Agadsfasdf", 0, 0, "0x123456789a"); 1743 | 1744 | _test_hex_functions(arr, "0x123456789ABcDeF0", 1, 0, "0x123456789abcdef0"); 1745 | _test_hex_functions(arr, "0x123456789ABcDeF0", 40, 0, "0x123456789abcdef0"); 1746 | 1747 | bit_array_free(arr); 1748 | 1749 | SUITE_END(); 1750 | } 1751 | 1752 | void _next_permutation_str(char *str, size_t len) 1753 | { 1754 | if(len == 0) 1755 | return; 1756 | 1757 | size_t i, j; 1758 | 1759 | for(i = 1; i < len; i++) 1760 | { 1761 | if(str[i-1] == '1' && str[i] == '0') 1762 | { 1763 | str[i-1] = '0'; 1764 | str[i] = '1'; 1765 | break; 1766 | } 1767 | } 1768 | 1769 | // Set 0..i (inclusive) to 0 1770 | int bits_set = 0; 1771 | 1772 | for(j = 0; j < i; j++) 1773 | { 1774 | if(str[j] == '1') 1775 | { 1776 | bits_set++; 1777 | } 1778 | } 1779 | 1780 | memset(str, '1', bits_set); 1781 | memset(str+bits_set, '0', i - bits_set); 1782 | } 1783 | 1784 | void test_next_permutation() 1785 | { 1786 | SUITE_START("next permutation"); 1787 | 1788 | BIT_ARRAY *arr = bit_array_create(0); 1789 | char tmp[2000], correct[2000]; 1790 | size_t len; 1791 | 1792 | #define TMPN 12 1793 | size_t lens[TMPN] = {0, 1, 2, 2, 2, 5, 5, 10, 101, 302, 512, 600}; 1794 | size_t bset[TMPN] = {0, 1, 0, 1, 2, 0, 1, 1, 1, 2, 2, 0}; 1795 | 1796 | int i, j; 1797 | for(i = 0; i < TMPN; i++) 1798 | { 1799 | len = lens[i]; 1800 | 1801 | bit_array_resize(arr, lens[i]); 1802 | bit_array_clear_all(arr); 1803 | bit_array_set_region(arr, 0, bset[i]); 1804 | 1805 | for(j = 0; j < 100; j++) 1806 | { 1807 | bit_array_to_str(arr, correct); 1808 | _next_permutation_str(correct, len); 1809 | bit_array_next_permutation(arr); 1810 | bit_array_to_str(arr, tmp); 1811 | ASSERT(strcmp(tmp, correct) == 0); 1812 | } 1813 | } 1814 | 1815 | bit_array_free(arr); 1816 | 1817 | SUITE_END(); 1818 | } 1819 | 1820 | void _test_num_cmp(BIT_ARRAY *arr, uint64_t value, uint64_t num) 1821 | { 1822 | int cmp1, cmp2; 1823 | 1824 | cmp1 = bit_array_cmp_uint64(arr, num); 1825 | cmp1 = cmp1 > 0 ? 1 : (cmp1 < 0 ? -1 : 0); 1826 | cmp2 = value > num ? 1 : (value < num ? -1 : 0); 1827 | 1828 | ASSERT(cmp1 == cmp2); 1829 | } 1830 | 1831 | void _test_as_num_cmp_num(uint64_t value) 1832 | { 1833 | BIT_ARRAY *arr = bit_array_create(0); 1834 | 1835 | bit_array_add_uint64(arr, value); 1836 | 1837 | // as_num returns 1 on success 1838 | uint64_t num = 0; 1839 | ASSERT(bit_array_as_num(arr, &num) == 1); 1840 | ASSERT(value == num); 1841 | 1842 | _test_num_cmp(arr, value, value-1); 1843 | _test_num_cmp(arr, value, value); 1844 | _test_num_cmp(arr, value, value+1); 1845 | 1846 | bit_array_free(arr); 1847 | } 1848 | 1849 | // Test bit_array_as_num(), bit_array_cmp_uint64() 1850 | void test_as_num_cmp_num() 1851 | { 1852 | SUITE_START("as_num and num_cmp"); 1853 | 1854 | _test_as_num_cmp_num(0); 1855 | _test_as_num_cmp_num(10); 1856 | _test_as_num_cmp_num(100000000); 1857 | _test_as_num_cmp_num(ULONG_MAX); 1858 | 1859 | int i; 1860 | for(i = 0; i < 10; i++) 1861 | { 1862 | _test_as_num_cmp_num(rand()); 1863 | } 1864 | 1865 | SUITE_END(); 1866 | } 1867 | 1868 | void _test_add_single_word_small(unsigned long init, unsigned long add, int offset) 1869 | { 1870 | BIT_ARRAY *arr1 = bit_array_create(0); 1871 | BIT_ARRAY *arr2 = bit_array_create(0); 1872 | 1873 | uint64_t a, b, result; 1874 | 1875 | bit_array_add_uint64(arr1, init); 1876 | bit_array_as_num(arr1, &a); 1877 | 1878 | bit_array_add_uint64(arr2, add); 1879 | if(offset > 0) 1880 | { 1881 | bit_array_resize(arr2, bit_array_length(arr2)+offset); 1882 | bit_array_shift_left(arr2, offset, 0); 1883 | } 1884 | 1885 | bit_array_as_num(arr2, &b); 1886 | 1887 | if(b != add << offset) 1888 | { 1889 | fprintf(stderr, "Warning: b != add << offset\n"); 1890 | } 1891 | 1892 | bit_array_add_word(arr1, offset, add); 1893 | bit_array_as_num(arr1, &result); 1894 | 1895 | ASSERT(a + b == result); 1896 | 1897 | // printf(" %lu + %lu = %lu [%s]\n", 1898 | // (unsigned long)a, (unsigned long)b, (unsigned long)result, 1899 | // (a + b == result ? "Pass" : "Fail")); 1900 | 1901 | bit_array_free(arr1); 1902 | bit_array_free(arr2); 1903 | } 1904 | 1905 | void test_add_single_word() 1906 | { 1907 | SUITE_START("add single word"); 1908 | 1909 | _test_add_single_word_small(0, 3, 0); 1910 | _test_add_single_word_small(0, 3, 1); 1911 | _test_add_single_word_small(3, 3, 0); 1912 | _test_add_single_word_small(3, 3, 1); 1913 | _test_add_single_word_small(0, 0, 3); 1914 | 1915 | // 0111010 [58] 1916 | // + 1010000 [5 << 4] 1917 | _test_add_single_word_small(58, 5, 4); 1918 | 1919 | _test_add_single_word_small(ULONG_MAX-(1<<4), 1, 4); 1920 | 1921 | SUITE_END(); 1922 | } 1923 | 1924 | void _test_minus_single_word() 1925 | { 1926 | uint64_t word = rand(); 1927 | // char tmp[1000]; 1928 | 1929 | int shift = RAND(1000); 1930 | // int shift = 5; 1931 | shift = MAX(shift, 5); 1932 | 1933 | BIT_ARRAY *arr = bit_array_create(0); 1934 | 1935 | // Add word twice, shift left (i.e. * 2^shift) 1936 | bit_array_add_uint64(arr, word); 1937 | bit_array_add_uint64(arr, word); 1938 | bit_array_resize(arr, bit_array_length(arr)+shift); 1939 | bit_array_shift_left(arr, shift, 0); 1940 | 1941 | // Subtract word shifted left (i.e. word * 2^shift) 1942 | ASSERT(bit_array_sub_word(arr, shift, word) == 1); 1943 | 1944 | // Shift to the right again (should now be equal to word again) 1945 | bit_array_shift_right(arr, shift, 0); 1946 | 1947 | BIT_ARRAY *arr2 = bit_array_create(0); 1948 | bit_array_add_uint64(arr2, word); 1949 | 1950 | ASSERT(bit_array_cmp_words(arr, 0, arr2) == 0); 1951 | 1952 | // Shift to the left and compare with word << shift 1953 | bit_array_shift_left(arr, shift, 0); 1954 | ASSERT(bit_array_cmp_words(arr, shift, arr2) == 0); 1955 | 1956 | bit_array_free(arr); 1957 | bit_array_free(arr2); 1958 | } 1959 | 1960 | void test_minus_single_word() 1961 | { 1962 | SUITE_START("minus single word"); 1963 | 1964 | int i; 1965 | for(i = 0; i < 100; i++) 1966 | { 1967 | _test_minus_single_word(); 1968 | } 1969 | 1970 | SUITE_END(); 1971 | } 1972 | 1973 | 1974 | void _test_add_words() 1975 | { 1976 | BIT_ARRAY *arr1 = bit_array_create(RAND(10)); 1977 | BIT_ARRAY *arr2 = bit_array_create(RAND(10)); 1978 | 1979 | bit_array_random(arr1, 0.5f); 1980 | bit_array_random(arr2, 0.5f); 1981 | 1982 | int shift1 = RAND(10); 1983 | int shift2 = RAND(10); 1984 | 1985 | BIT_ARRAY *shifted_sum = bit_array_create(0); 1986 | 1987 | bit_array_add_words(shifted_sum, shift1, arr1); 1988 | bit_array_add_words(shifted_sum, shift2, arr2); 1989 | 1990 | bit_array_resize(arr1, bit_array_length(arr1)+shift1); 1991 | bit_array_shift_left(arr1, shift1, 0); 1992 | bit_array_resize(arr2, bit_array_length(arr2)+shift2); 1993 | bit_array_shift_left(arr2, shift2, 0); 1994 | bit_array_add(arr1, arr1, arr2); // arr1 = arr1 + arr2 1995 | 1996 | ASSERT(bit_array_cmp_words(arr1, 0, shifted_sum) == 0); 1997 | 1998 | bit_array_free(arr1); 1999 | bit_array_free(arr2); 2000 | bit_array_free(shifted_sum); 2001 | } 2002 | 2003 | void test_add_words() 2004 | { 2005 | SUITE_START("add multiple words"); 2006 | 2007 | int i; 2008 | for(i = 0; i < 20; i++) 2009 | _test_add_words(); 2010 | 2011 | SUITE_END(); 2012 | } 2013 | 2014 | void _test_minus_words() 2015 | { 2016 | // Check that: A< 0 && bit_array_get_bit(accum, shift2)) shift2--; 2027 | bit_array_set_bit(accum, shift2); 2028 | 2029 | bit_array_sub_words(accum, shift1, arr); 2030 | 2031 | ASSERT(bit_array_get_bit(accum, shift2)); 2032 | bit_array_clear_bit(accum, shift2); 2033 | ASSERT(bit_array_cmp_uint64(accum, 0) == 0); 2034 | 2035 | bit_array_free(accum); 2036 | bit_array_free(arr); 2037 | } 2038 | 2039 | void test_minus_words() 2040 | { 2041 | SUITE_START("minus multiple words"); 2042 | 2043 | int i; 2044 | for(i = 0; i < 1000; i++) 2045 | _test_minus_words(); 2046 | 2047 | // Check minus word of length 0 2048 | BIT_ARRAY *arr1 = bit_array_create(RAND(100)); 2049 | bit_array_random(arr1, 0.5f); 2050 | BIT_ARRAY *arr2 = bit_array_clone(arr1); 2051 | BIT_ARRAY *zero = bit_array_create(0); 2052 | 2053 | for(i = 0; i < 100; i++) 2054 | { 2055 | bit_array_sub_words(arr1, 0, zero); 2056 | bit_array_sub_words(arr1, RAND(bit_array_length(arr1)), zero); 2057 | } 2058 | 2059 | ASSERT(bit_array_cmp(arr1, arr2) == 0); 2060 | bit_array_free(arr1); 2061 | bit_array_free(arr2); 2062 | bit_array_free(zero); 2063 | 2064 | SUITE_END(); 2065 | } 2066 | 2067 | void _test_multiply_small(uint64_t a, uint64_t b) 2068 | { 2069 | BIT_ARRAY *arr = bit_array_create(0); 2070 | uint64_t product; 2071 | 2072 | bit_array_add_uint64(arr, a); 2073 | bit_array_mul_uint64(arr, b); 2074 | bit_array_as_num(arr, &product); 2075 | 2076 | ASSERT(a * b == product); 2077 | 2078 | if(a * b != product) 2079 | { 2080 | // debug output 2081 | printf("%lu * %lu = %lu [expected: %lu]\n", (unsigned long)a, 2082 | (unsigned long)b, (unsigned long)product, (unsigned long)(a * b)); 2083 | } 2084 | 2085 | bit_array_free(arr); 2086 | } 2087 | 2088 | void test_multiply() 2089 | { 2090 | SUITE_START("small multiply"); 2091 | 2092 | _test_multiply_small(2, 4); 2093 | _test_multiply_small(4, 2); 2094 | _test_multiply_small(3, 6); 2095 | _test_multiply_small(9, 256); 2096 | _test_multiply_small(10, 100); 2097 | _test_multiply_small(0, 0); 2098 | _test_multiply_small(10, 0); 2099 | _test_multiply_small(0, 10); 2100 | 2101 | SUITE_END(); 2102 | } 2103 | 2104 | void _test_small_product(uint64_t a, uint64_t b, char expect_overflow) 2105 | { 2106 | BIT_ARRAY *arr1 = bit_array_create(0); 2107 | BIT_ARRAY *arr2 = bit_array_create(0); 2108 | 2109 | int i; 2110 | for(i = 0; i < 2; i++) 2111 | { 2112 | bit_array_resize(arr1, 0); 2113 | bit_array_resize(arr2, 0); 2114 | bit_array_add_uint64(arr1, a); 2115 | bit_array_add_uint64(arr2, b); 2116 | 2117 | BIT_ARRAY *result = (i == 0 ? arr1 : arr2); 2118 | 2119 | bit_array_multiply(result, arr1, arr2); 2120 | 2121 | // printf(" = %s\n", bit_array_to_str(result, tmp)); 2122 | 2123 | uint64_t c; 2124 | char overflowed = !bit_array_as_num(result, &c); 2125 | 2126 | ASSERT(expect_overflow == overflowed); 2127 | 2128 | if(!expect_overflow) 2129 | { 2130 | ASSERT(a*b == c); 2131 | } 2132 | 2133 | if(expect_overflow != overflowed || (!expect_overflow && a*b != c)) 2134 | { 2135 | // debug output 2136 | printf("expect: %lu * %lu = %lu [overflow: %s]\n", 2137 | (unsigned long)a, (unsigned long)b, (unsigned long)(a*b), 2138 | expect_overflow ? "yes" : "no"); 2139 | printf("got: %lu [overflow: %s]\n", (unsigned long)c, 2140 | overflowed ? "yes" : "no"); 2141 | } 2142 | } 2143 | 2144 | bit_array_free(arr1); 2145 | bit_array_free(arr2); 2146 | } 2147 | 2148 | void test_small_products() 2149 | { 2150 | SUITE_START("product with small numbers"); 2151 | 2152 | _test_small_product(1, 1, 0); 2153 | _test_small_product(0, 1, 0); 2154 | _test_small_product(0, 0, 0); 2155 | _test_small_product(2, 2, 0); 2156 | _test_small_product(3, 9, 0); 2157 | _test_small_product(3, 90000, 0); 2158 | _test_small_product(300000, 90000, 0); 2159 | _test_small_product(123456789123132, 9876543212351234, 1); 2160 | 2161 | SUITE_END(); 2162 | } 2163 | 2164 | void _test_div(uint64_t nom, uint64_t denom) 2165 | { 2166 | BIT_ARRAY *nom_arr = bit_array_create(0); 2167 | bit_array_add_uint64(nom_arr, nom); 2168 | 2169 | uint64_t quotient, rem; 2170 | 2171 | bit_array_div_uint64(nom_arr, denom, &rem); 2172 | bit_array_as_num(nom_arr, "ient); 2173 | 2174 | ASSERT(quotient * denom + rem == nom); 2175 | 2176 | if(quotient * denom + rem != nom) 2177 | { 2178 | // Debug output 2179 | printf("%lu = %lu * %lu + %lu [%s]\n", 2180 | (unsigned long)nom, (unsigned long)quotient, 2181 | (unsigned long)denom, (unsigned long)rem, 2182 | (quotient * denom + rem == nom ? "Pass" : "Fail")); 2183 | } 2184 | 2185 | bit_array_free(nom_arr); 2186 | } 2187 | 2188 | void test_div() 2189 | { 2190 | SUITE_START("bit_array_div"); 2191 | 2192 | _test_div(10, 2); 2193 | _test_div(100, 100); 2194 | _test_div(0, 100); 2195 | _test_div(12, 3); 2196 | _test_div(13, 7); 2197 | _test_div(12, 9); 2198 | _test_div(64, 8); 2199 | _test_div(9, 9); 2200 | _test_div(10000000, 13); 2201 | 2202 | SUITE_END(); 2203 | } 2204 | 2205 | void _test_to_from_decimal(char *str) 2206 | { 2207 | size_t len = strlen(str); 2208 | char new_str[len+1]; 2209 | BIT_ARRAY *bitarr = bit_array_create(0); 2210 | 2211 | bit_array_from_decimal(bitarr, str); 2212 | bit_array_to_decimal(bitarr, new_str, len+1); 2213 | 2214 | ASSERT(atoi(str) == atoi(new_str)); 2215 | 2216 | if(atoi(str) != atoi(new_str)) 2217 | { 2218 | // debug output 2219 | printf("%s -> %s\n", str, new_str); 2220 | } 2221 | 2222 | bit_array_free(bitarr); 2223 | } 2224 | 2225 | void test_to_from_decimal() 2226 | { 2227 | SUITE_START("to/from decimal"); 2228 | 2229 | _test_to_from_decimal("1"); 2230 | _test_to_from_decimal("0"); 2231 | _test_to_from_decimal("1234"); 2232 | _test_to_from_decimal("5678"); 2233 | _test_to_from_decimal("012"); 2234 | 2235 | SUITE_END(); 2236 | } 2237 | 2238 | void _test_product_divide() 2239 | { 2240 | // Rand number between 0-255 inclusive 2241 | int num_digits; 2242 | 2243 | do 2244 | { 2245 | num_digits = rand() & 255; 2246 | } while(num_digits == 0); 2247 | 2248 | // Set 2249 | BIT_ARRAY *arr = bit_array_create(num_digits); 2250 | BIT_ARRAY *divisor = bit_array_create(num_digits); 2251 | 2252 | while(bit_array_num_bits_set(divisor) == 0) 2253 | { 2254 | do 2255 | { 2256 | bit_array_random(arr, (float)((double)rand() / RAND_MAX)); 2257 | } while(bit_array_num_bits_set(arr) == 0); 2258 | 2259 | do 2260 | { 2261 | bit_array_random(divisor, (float)((double)rand() / RAND_MAX)); 2262 | } while(bit_array_num_bits_set(divisor) == 0); 2263 | 2264 | while(bit_array_cmp(arr, divisor) < 0) 2265 | { 2266 | bit_array_shift_right(divisor, 1, 0); 2267 | } 2268 | 2269 | if(bit_array_cmp_uint64(divisor, 1) > 0 && rand() < RAND_MAX / 2) 2270 | { 2271 | bit_array_shift_right(divisor, 1, 0); 2272 | } 2273 | } 2274 | 2275 | // Copy 2276 | BIT_ARRAY *tmp = bit_array_clone(arr); 2277 | BIT_ARRAY *quotient = bit_array_create(0); 2278 | 2279 | // Divide 2280 | bit_array_divide(tmp, quotient, divisor); 2281 | 2282 | // Multiply and add 2283 | bit_array_multiply(quotient, quotient, divisor); 2284 | bit_array_add(tmp, tmp, quotient); 2285 | 2286 | // Compare 2287 | ASSERT(bit_array_cmp_words(tmp, 0, arr) == 0); 2288 | // int cmp = bit_array_cmp_words(tmp, 0, arr); 2289 | // printf("product & divide: [%s]\n\n", cmp == 0 ? "Pass" : "Fail"); 2290 | 2291 | bit_array_free(tmp); 2292 | bit_array_free(quotient); 2293 | 2294 | bit_array_free(arr); 2295 | bit_array_free(divisor); 2296 | } 2297 | 2298 | void test_product_divide() 2299 | { 2300 | SUITE_START("product and divide"); 2301 | 2302 | int i; 2303 | for(i = 0; i < 10; i++) 2304 | { 2305 | _test_product_divide(); 2306 | } 2307 | 2308 | SUITE_END(); 2309 | } 2310 | 2311 | void _test_add_and_minus_multiple_words() 2312 | { 2313 | // Rand number between 0-511 inclusive 2314 | int num_digits; 2315 | 2316 | do 2317 | { 2318 | num_digits = rand() & 0x1ff; 2319 | } while(num_digits == 0); 2320 | 2321 | // Set 2322 | BIT_ARRAY *big = bit_array_create(num_digits); 2323 | BIT_ARRAY *small = bit_array_create(num_digits); 2324 | 2325 | int offset = RAND(num_digits-1); 2326 | 2327 | while(bit_array_num_bits_set(small) == 0) 2328 | { 2329 | do 2330 | { 2331 | bit_array_random(big, (float)((double)rand() / RAND_MAX)); 2332 | } while(bit_array_num_bits_set(big) == 0); 2333 | 2334 | do 2335 | { 2336 | bit_array_random(small, (float)((double)rand() / RAND_MAX)); 2337 | } while(bit_array_num_bits_set(small) == 0); 2338 | 2339 | while(bit_array_cmp_words(big, offset, small) < 0) 2340 | { 2341 | bit_array_shift_right(small, 1, 0); 2342 | } 2343 | } 2344 | 2345 | // Copy 2346 | // tmp = big 2347 | BIT_ARRAY *tmp = bit_array_clone(big); 2348 | 2349 | // tmp -= small 2350 | bit_array_sub_words(tmp, offset, small); 2351 | 2352 | // tmp += small 2353 | bit_array_add_words(tmp, offset, small); 2354 | 2355 | // Compare tmp and big 2356 | ASSERT(bit_array_cmp_words(tmp, 0, big) == 0); 2357 | // int cmp = bit_array_cmp_words(tmp, 0, big); 2358 | // printf(" add/minus words: [%s]\n\n", cmp == 0 ? "Pass" : "Fail"); 2359 | 2360 | bit_array_free(tmp); 2361 | bit_array_free(big); 2362 | bit_array_free(small); 2363 | } 2364 | 2365 | void test_add_and_minus_multiple_words() 2366 | { 2367 | SUITE_START("add/minus multiple words"); 2368 | 2369 | int i; 2370 | for(i = 0; i < 10; i++) 2371 | { 2372 | _test_add_and_minus_multiple_words(); 2373 | } 2374 | 2375 | SUITE_END(); 2376 | } 2377 | 2378 | void _test_add_and_minus_single_word() 2379 | { 2380 | // Rand number between 0-511 inclusive 2381 | int num_digits; 2382 | 2383 | do 2384 | { 2385 | num_digits = rand() & 0x1ff; 2386 | } while(num_digits == 0); 2387 | 2388 | // Set 2389 | BIT_ARRAY *arr = bit_array_create(num_digits); 2390 | 2391 | int offset = RAND(num_digits+2); 2392 | 2393 | do 2394 | { 2395 | bit_array_random(arr, (float)((double)rand() / RAND_MAX)); 2396 | } while(bit_array_num_bits_set(arr) == 0); 2397 | 2398 | word_t word = rand(); 2399 | 2400 | // Copy 2401 | // tmp = arr 2402 | BIT_ARRAY *tmp = bit_array_clone(arr); 2403 | 2404 | // tmp += word 2405 | bit_array_add_word(tmp, offset, word); 2406 | 2407 | // tmp -= word 2408 | bit_array_sub_word(tmp, offset, word); 2409 | 2410 | // Compare tmp and arr 2411 | ASSERT(bit_array_cmp_words(tmp, 0, arr) == 0); 2412 | 2413 | bit_array_free(tmp); 2414 | bit_array_free(arr); 2415 | } 2416 | 2417 | void test_add_and_minus_single_word() 2418 | { 2419 | SUITE_START("add/minus single word"); 2420 | 2421 | int i; 2422 | for(i = 0; i < 10; i++) 2423 | { 2424 | _test_add_and_minus_single_word(); 2425 | } 2426 | 2427 | SUITE_END(); 2428 | } 2429 | 2430 | void test_get_set_bytes() 2431 | { 2432 | SUITE_START("get/set byte"); 2433 | 2434 | #define NBYTES 8 2435 | uint8_t bytes[NBYTES] = {0x55,0x31,0x5A,0x12,0x02,0x31,0xC3,0x1E}; 2436 | size_t s, i; 2437 | 2438 | BIT_ARRAY *arr = bit_array_create(NBYTES*8); 2439 | 2440 | // Set bytes using different offsets 2441 | for(s = 0; s < 8; s++) { 2442 | bit_array_clear_all(arr); 2443 | for(i = 0; i < NBYTES-1; i++) { 2444 | bit_array_set_word8(arr, i*8+s, bytes[i]); 2445 | ASSERT(bit_array_get_word8(arr, i*8+s) == bytes[i]); 2446 | } 2447 | // Setting bytes doesn't extend the array - check last byte with masking 2448 | i = NBYTES-1; 2449 | bit_array_set_word8(arr, i*8+s, bytes[i]); 2450 | ASSERT(bit_array_get_word8(arr, i*8+s) == (bytes[i] & (0xff>>s))); 2451 | 2452 | // Check bits 2453 | for(i = 0; i < s; i++) ASSERT(bit_array_get(arr, i) == 0); 2454 | for(i = s; i < NBYTES*8; i++) 2455 | ASSERT(bit_array_get(arr, i) == bitset_get(bytes, i-s)); 2456 | } 2457 | 2458 | bit_array_free(arr); 2459 | #undef NBYTES 2460 | 2461 | SUITE_END(); 2462 | } 2463 | 2464 | // test new features of bitarr library. 2465 | // - resize from 0 2466 | // - get/set/clear/toggle/assign auto-resize 2467 | // - copy auto-resize 2468 | // - copy_all function (with auto-resize) 2469 | // - extended shift left 2470 | // - find clear bit 2471 | // exercise short names. (some of them anyway) 2472 | #include "bar.h" 2473 | 2474 | void test_bar_wrapper() 2475 | { 2476 | SUITE_START("testing bar wrapper"); 2477 | 2478 | bar bars[7]; 2479 | bar foo; 2480 | int i, j; 2481 | uint64_t res, w; 2482 | bit_index_t tb, rv, k; // test bit. 2483 | 2484 | // make sure this works, too. 2485 | w = 0x00000FFFFFFFFF00; 2486 | rv = leading_zeros(w); 2487 | // printf("clz=%d\n", rv); 2488 | ASSERT(rv == 20); 2489 | rv = trailing_zeros(w); 2490 | ASSERT(rv == 8); 2491 | rv = __builtin_ctzll(w); 2492 | ASSERT(rv == 8); 2493 | rv = __builtin_clzll(w); 2494 | ASSERT(rv == 20); 2495 | w = 0xFFFFFFFFFFFFFFFF; 2496 | w >>= 5; 2497 | rv = __builtin_clzll(w); 2498 | ASSERT(rv == 5); 2499 | 2500 | // initialize to zeros. 2501 | memset((void *)bars, 0, sizeof(bars)); 2502 | memset((void *)&foo, 0, sizeof(bar)); 2503 | 2504 | // test resize from nothing. 2505 | ASSERT(barlen(&foo) == 0); 2506 | rv = bit_array_resize(&foo, 23); 2507 | ASSERT(rv == 1); 2508 | ASSERT(barlen(&foo) == 23); 2509 | barfree(&foo); 2510 | ASSERT(barlen(&foo) == 0); 2511 | 2512 | // Auto-resizing array turned off, so these tests fail 2513 | 2514 | // run through get/set/clear/toggle/assign. 2515 | // start with 0, increase size each time. 2516 | 2517 | tb = 7; 2518 | ASSERT(barlen(&foo) == 0); 2519 | rv = barrget(&foo, tb); 2520 | ASSERT(rv == 0); 2521 | ASSERT(barlen(&foo) >= tb); 2522 | tb *= 4; 2523 | barrset(&foo, tb); 2524 | ASSERT(barlen(&foo) >= tb); 2525 | ASSERT(barrget(&foo, tb) == 1); 2526 | tb *= 4; 2527 | barrclr(&foo, tb); 2528 | ASSERT(barlen(&foo) >= tb); 2529 | ASSERT(barrget(&foo, tb) == 0); 2530 | tb *= 4; 2531 | barrflip(&foo, tb); 2532 | ASSERT(barlen(&foo) >= tb); 2533 | ASSERT(barrget(&foo, tb) == 1); 2534 | tb *= 4; 2535 | barrmake(&foo, tb, 1); 2536 | ASSERT(barlen(&foo) >= tb); 2537 | ASSERT(barrget(&foo, tb) == 1); 2538 | tb *= 4; 2539 | 2540 | for (i = 1; i < 5; i++) { 2541 | barcpy(&(bars[i]), &foo); 2542 | ASSERT(barlen(&(bars[i])) == barlen(&foo)); 2543 | rv = barlen(&(bars[i])); 2544 | rv += 57; 2545 | barrset(&(bars[i]), rv); 2546 | ASSERT(barlen(&(bars[i])) >= rv); 2547 | barcpy(&foo, &(bars[i])); 2548 | ASSERT(barlen(&foo) >= rv); 2549 | } 2550 | 2551 | for (i = 1; i < 5; i++) { 2552 | barfree(&(bars[i])); 2553 | } 2554 | 2555 | barfree(&foo); 2556 | ASSERT(barlen(&foo) == 0); 2557 | 2558 | barrset(&foo, 100); 2559 | barfill(&foo); 2560 | rv = barffz(&foo, &res); 2561 | ASSERT(rv == 0); 2562 | 2563 | barrclr(&foo, 50); 2564 | rv = barffz(&foo, &res); 2565 | ASSERT(rv == 1); 2566 | ASSERT(res == 50); 2567 | barclr(&foo, 77); 2568 | rv = barfnz(&foo, res+1, &res); 2569 | ASSERT(rv == 1); 2570 | ASSERT(res == 77); 2571 | 2572 | barfree(&foo); 2573 | ASSERT(barlen(&foo) == 0); 2574 | 2575 | barrset(&foo, 1); 2576 | barrset(&foo, 3); 2577 | barrset(&foo, 15); 2578 | ASSERT(barlen(&foo) >= 15); 2579 | 2580 | j = 9; 2581 | k = barlen(&foo); 2582 | for (i = 0; i < 10; i++) { 2583 | bareshl(&foo, j, 0); 2584 | k += j; 2585 | j *= 2; 2586 | } 2587 | ASSERT(barlen(&foo) >= k); 2588 | 2589 | barfree(&foo); 2590 | 2591 | SUITE_END(); 2592 | } 2593 | 2594 | int main(int argc, char* argv[]) 2595 | { 2596 | if(argc != 1) 2597 | { 2598 | printf(" Unused args '%s..'\n", argv[1]); 2599 | printf("Usage: ./bit_array_test\n"); 2600 | exit(EXIT_FAILURE); 2601 | } 2602 | 2603 | // Initialise random number generator 2604 | srand((unsigned int)time(NULL) + getpid()); 2605 | 2606 | printf(" Test bit_array C library:\n\n"); 2607 | 2608 | // Test functions 2609 | test_copy(); 2610 | test_get_set_bytes(); 2611 | 2612 | test_get_bits(); 2613 | test_parity(); 2614 | test_interleave(); 2615 | test_reverse(); 2616 | test_toggle(); 2617 | test_cycle(); 2618 | test_shift(); 2619 | 2620 | test_compare(); 2621 | test_compare2(); 2622 | test_first_last_bit_set(); 2623 | test_next_prev_bit_set(); 2624 | test_hamming_weight(); 2625 | test_save_load(); 2626 | 2627 | test_hex_functions(); 2628 | test_string_functions(); 2629 | test_to_from_decimal(); 2630 | 2631 | test_as_num_cmp_num(); 2632 | 2633 | test_add_single_word(); 2634 | test_minus_single_word(); 2635 | 2636 | test_add_words(); 2637 | test_minus_words(); 2638 | 2639 | test_add_and_minus_single_word(); 2640 | test_add_and_minus_multiple_words(); 2641 | 2642 | test_multiply(); 2643 | test_div(); 2644 | test_small_products(); 2645 | test_product_divide(); 2646 | 2647 | test_bar_wrapper(); 2648 | 2649 | // slooow 2650 | test_next_permutation(); 2651 | test_random_and_shuffle(); 2652 | 2653 | // Tests that need re-writing 2654 | // test_hash(); 2655 | 2656 | // To do 2657 | // test_crc(); 2658 | // test_multiple_actions(); 2659 | // test_zero_length_arrays(); 2660 | // test_arithmetic(); 2661 | 2662 | printf("\n"); 2663 | printf(" %i / %i suites failed\n", suites_failed, suites_run); 2664 | printf(" %i / %i suites empty\n", suites_empty, suites_run); 2665 | printf(" %i / %i tests failed\n", tests_failed, tests_run); 2666 | 2667 | printf("\n THE END.\n"); 2668 | 2669 | return tests_failed ? EXIT_FAILURE : EXIT_SUCCESS; 2670 | } 2671 | --------------------------------------------------------------------------------