-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbitset.h
162 lines (142 loc) · 4.56 KB
/
bitset.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/**
* @file bitset.h
* @author Samuel Stolarik (xstola03@fit.vutbr.cz), FIT
*
* @brief IJC-DU1, part A
* header file containing macros and inline functions
* needed for operations on bitsets
*
* Known issue: bitset_set() on index 0 causes a compiler warning (0 > unsigned value)
* @date 2022-03-01
*
*/
#ifndef _BITSET_H
#define _BITSET_H
#include <stdlib.h>
#include <limits.h> // used for CHAR_BIT
#include <assert.h> //used for static_assert
#include <stdbool.h>
#include "error.h"
#define BITS_IN_LONG ((sizeof(unsigned long) * CHAR_BIT))
#define _MAX_LSHIFT (BITS_IN_LONG - 1)
typedef unsigned long int * bitset_t;
typedef unsigned long int bitset_index_t;
/**
* @brief create a bitset called name with size size + 1, to store the size
* the first index will store the size of the bitfield
* initializes the bitfield with zeroes and stores size in the 0th index
*/
#define bitset_create(name, size)\
static_assert((size) > 0, "Can not create bitset with size less than zero");\
unsigned long int name[((size) / BITS_IN_LONG) + (((size) % BITS_IN_LONG) ? 1 : 0) + 1] = {[0] = (size), 0};\
/**
* @brief create a dynamicaly allocated bitset
* called name with size size + 1, to store the size
* initializes the bitfield with zeroes and stores size in the 0th index
*/
#define bitset_alloc(name, size)\
assert((size) < ULONG_MAX);\
bitset_t name = calloc((((size) / BITS_IN_LONG) + (((size) % BITS_IN_LONG) ? 1 : 0) + 1), sizeof(unsigned long));\
name[0] = (size);\
#ifndef USE_INLINE
/**
* @brief free bitset created with bitset_alloc
*
*/
#define bitset_free(name)\
free(name)
/**
* @brief return size of the bitset "name"
*
*/
#define bitset_size(name)\
(name)[0]
/**
* @brief sets bit on index "index" to either 1 or 0
* depending on what "expr" evaluates to
*
* first it checks if index is valid (not out of bitset)
* in case of error, only frees "name" and than calls error_exit()
*/
#define bitset_setbit(name, index, expr)\
if ((index) > (bitset_size((name)))) {bitset_free((name)); error_exit("bitset_getbit: Index %lu mimo rozsah 0..%lu", (unsigned long)(index), (unsigned long)(BITS_IN_LONG * bitset_size(name)));}\
else if (expr) (name)[(index) / BITS_IN_LONG + 1] |= 1ul << (_MAX_LSHIFT - (index) % BITS_IN_LONG);\
else (name)[(index) / BITS_IN_LONG + 1] &= ~(1ul << (_MAX_LSHIFT - (index) % BITS_IN_LONG))
/**
* @brief returns value bit in "name" on "index"
*
* first it checks if index is valid (not out of bitset)
* in case of error, only frees "name" and than calls error_exit()
*/
#define bitset_getbit(name, index)\
(((index) > bitset_size((name))) ?\
(bitset_free((name)), error_exit("bitset_getbit: Index %lu mimo rozsah 0..%lu", (unsigned long)(index), (unsigned long)(BITS_IN_LONG * bitset_size(name))),0):\
(((name)[(index)/BITS_IN_LONG +1] & 1ul << (_MAX_LSHIFT - ((index) % BITS_IN_LONG))) ? 1 : 0))
#else //USE_INLINE
/**
* @brief free memmory allocated by bitset_alloc pointed to by "name"
*
* @param name
*/
extern inline void bitset_free(bitset_t name)
{
free(name);
}
/**
* @brief returns size of bitset
*
* @param name
* @return bitset_index_t
*/
extern inline bitset_index_t bitset_size(bitset_t name)
{
return name[0];
}
/**
* @brief sets bit at index "index" depending on what "expr evaluates to"
*
* @param name
* @param index
* @param expr
*/
extern inline void bitset_setbit(bitset_t name, bitset_index_t index, bool expr)
{
bitset_index_t index_real = (index) / BITS_IN_LONG + 1;
unsigned int index_offset = _MAX_LSHIFT - (index) % BITS_IN_LONG;
if (index > bitset_size(name))
{
bitset_free(name);
error_exit("bitset_getbit: Index %lu mimo rozsah 0..%lu", (unsigned long)(index), (unsigned long)(BITS_IN_LONG * bitset_size(name)));
}
if (expr)
{
name[index_real] |= 1ul << index_offset;
}
else
{
name[index_real] &= ~(1ul << (index_offset - 1));
}
return;
}
/**
* @brief returns bool value depending of value of bit on index "index"
*
* @param name
* @param index
* @return true
* @return false
*/
extern inline bool bitset_getbit(bitset_t name, bitset_index_t index)
{
if (index > bitset_size(name))
{
free(name);
error_exit("bitset_getbit: Index %lu mimo rozsah 0..%lu", (unsigned long)(index), (unsigned long)(BITS_IN_LONG * bitset_size(name)));
}
else
{
return (name[(index)/BITS_IN_LONG +1] & 1ul << (_MAX_LSHIFT - (index % BITS_IN_LONG))) ? true : false;
}
}
#endif //USE_INLINE
#endif //_BITSET_H\ No newline at end of file