1 /* The MIT License
2 
3    Copyright (C) 2015, 2018 Genome Research Ltd.
4 
5    Permission is hereby granted, free of charge, to any person obtaining
6    a copy of this software and associated documentation files (the
7    "Software"), to deal in the Software without restriction, including
8    without limitation the rights to use, copy, modify, merge, publish,
9    distribute, sublicense, and/or sell copies of the Software, and to
10    permit persons to whom the Software is furnished to do so, subject to
11    the following conditions:
12 
13    The above copyright notice and this permission notice shall be
14    included in all copies or substantial portions of the Software.
15 
16    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20    BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23    SOFTWARE.
24 */
25 module htslib.kbitset;
26 
27 import core.stdc.config;
28 import core.stdc.limits;
29 import core.stdc.stdlib;
30 import core.stdc.string;
31 
32 @system:
33 nothrow:
34 @nogc:
35 
36 extern (C):
37 
38 /* Example of using kbitset_t, which represents a subset of {0,..., N-1},
39    where N is the size specified in kbs_init().
40 
41 	kbitset_t *bset = kbs_init(100);
42 	kbs_insert(bset, 5);
43 	kbs_insert(bset, 68);
44 	kbs_delete(bset, 37);
45 	// ...
46 
47 	if (kbs_exists(bset, 68)) printf("68 present\n");
48 
49 	kbitset_iter_t itr;
50 	int i;
51 	kbs_start(&itr);
52 	while ((i = kbs_next(bset, &itr)) >= 0)
53 		printf("%d present\n", i);
54 
55 	kbs_destroy(bset);
56 
57    Example of declaring a kbitset_t-using function in a header file, so that
58    only source files that actually use process() need to include <kbitset.h>:
59 
60 	struct kbitset_t;
61 	void process(struct kbitset_t *bset);
62 */
63 
64 enum KBS_ELTBITS = CHAR_BIT * c_ulong.sizeof;
65 
66 extern (D) auto KBS_ELT(T)(auto ref T i)
67 {
68     return i / KBS_ELTBITS;
69 }
70 
71 extern (D) auto KBS_MASK(T)(auto ref T i)
72 {
73     return 1U << (i % KBS_ELTBITS);
74 }
75 
76 struct kbitset_t
77 {
78     size_t n;
79     size_t n_max;
80     c_ulong[1] b;
81 }
82 
83 pragma(inline, true):
84 /// (For internal use only.) Returns a mask (like 00011111) showing
85 /// which bits are in use in the last slot (for the given ni) set.
86 c_ulong kbs_last_mask (size_t ni)
87 {
88 	uint mask = KBS_MASK(ni) - 1;
89 	return mask? mask : ~0UL;
90 }
91 
92 /// Initialise a bit set capable of holding ni integers, 0 <= i < ni.
93 /// The set returned is empty if fill == 0, or all of [0,ni) otherwise.
94 
95 /// b[n] is always non-zero (a fact used by kbs_next()).
96 kbitset_t* kbs_init2 (size_t ni, int fill)
97 {
98 	size_t n = (ni + KBS_ELTBITS-1) / KBS_ELTBITS;
99 	kbitset_t *bs =
100 		cast(kbitset_t *) malloc(kbitset_t.sizeof + n * uint.sizeof);
101 	if (bs == null) return null;
102 	bs.n = bs.n_max = n;
103 	memset(cast(void*)bs.b, fill? ~0 : 0, n * uint.sizeof);
104 	// b[n] is always non-zero (a fact used by kbs_next()).
105 	bs.b[n] = kbs_last_mask(ni);
106 	if (fill) bs.b[n-1] &= bs.b[n];
107 	return bs;
108 }
109 
110 /// Initialise an empty bit set capable of holding ni integers, 0 <= i < ni.
111 kbitset_t* kbs_init (size_t ni)
112 {
113 	return kbs_init2(ni, 0);
114 }
115 
116 /// Resize an existing bit set to be capable of holding ni_new integers.
117 /// Elements in [ni_old,ni_new) are added to the set if fill != 0.
118 
119 /// Need to clear excess bits when fill!=0 or n_new<n; always is simpler.
120 int kbs_resize2 (kbitset_t** bsp, size_t ni_new, int fill)
121 {
122 	kbitset_t *bs = *bsp;
123 	size_t n = bs? bs.n : 0;
124 	size_t n_new = (ni_new + KBS_ELTBITS-1) / KBS_ELTBITS;
125 	if (bs == null || n_new > bs.n_max) {
126 		bs = cast(kbitset_t *)
127 			realloc(*bsp, kbitset_t.sizeof + n_new * uint.sizeof);
128 		if (bs == null) return -1;
129 
130 		bs.n_max = n_new;
131 		*bsp = bs;
132 	}
133 
134 	bs.n = n_new;
135 	if (n_new >= n)
136 		memset(&bs.b[n], fill? ~0 : 0, (n_new - n) * uint.sizeof);
137 	bs.b[n_new] = kbs_last_mask(ni_new);
138 	// Need to clear excess bits when fill!=0 or n_new<n; always is simpler.
139 	bs.b[n_new-1] &= bs.b[n_new];
140 	return 0;
141 }
142 /// Resize an existing bit set to be capable of holding ni_new integers.
143 /// Returns negative on error.
144 int kbs_resize (kbitset_t** bsp, size_t ni_new)
145 {
146 	return kbs_resize2(bsp, ni_new, 0);
147 }
148 /// Destroy a bit set.
149 void kbs_destroy (kbitset_t* bs)
150 {
151 	free(bs);
152 }
153 
154 /// Reset the bit set to empty.
155 void kbs_clear (kbitset_t* bs)
156 {
157 	memset(cast(void*)bs.b, 0, bs.n * uint.sizeof);
158 }
159 
160 /// Reset the bit set to all of [0,ni).
161 void kbs_insert_all (kbitset_t* bs)
162 {
163 	memset(cast(void*)bs.b, ~0, bs.n * uint.sizeof);
164 	bs.b[bs.n-1] &= bs.b[bs.n];
165 }
166 
167 /// Insert an element into the bit set.
168 void kbs_insert (kbitset_t* bs, int i)
169 {
170 	bs.b[KBS_ELT(i)] |= KBS_MASK(i);
171 }
172 
173 /// Remove an element from the bit set.
174 void kbs_delete (kbitset_t* bs, int i)
175 {
176 	bs.b[KBS_ELT(i)] &= ~KBS_MASK(i);
177 }
178 
179 /// Test whether the bit set contains the element.
180 int kbs_exists (const(kbitset_t)* bs, int i)
181 {
182 	return (bs.b[KBS_ELT(i)] & KBS_MASK(i)) != 0;
183 }
184 
185 struct kbitset_iter_t
186 {
187     c_ulong mask;
188     size_t elt;
189     int i;
190 }
191 
192 /// Initialise or reset a bit set iterator.
193 void kbs_start (kbitset_iter_t* itr)
194 {
195 	itr.mask = 1;
196 	itr.elt = 0;
197 	itr.i = 0;
198 }
199 
200 /// Return the next element contained in the bit set, or -1 if there are no more.
201 int kbs_next (const(kbitset_t)* bs, kbitset_iter_t* itr)
202 {
203 	size_t b = bs.b[itr.elt];
204 
205 	for (;;) {
206 		if (itr.mask == 0) {
207 			while ((b = bs.b[++itr.elt]) == 0) itr.i += KBS_ELTBITS;
208 			if (itr.elt == bs.n) return -1;
209 			itr.mask = 1;
210 		}
211 
212 		if (b & itr.mask) break;
213 
214 		itr.i++;
215 		itr.mask <<= 1;
216 	}
217 
218 	itr.mask <<= 1;
219 	return itr.i++;
220 }
221