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