bitarray.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*
  2. Copyright (c) 2008 - 2025, Ilan Schnell; All Rights Reserved
  3. bitarray is published under the PSF license.
  4. Author: Ilan Schnell
  5. */
  6. #define BITARRAY_VERSION "3.7.2"
  7. #ifdef STDC_HEADERS
  8. # include <stddef.h>
  9. #else
  10. # ifdef HAVE_SYS_TYPES_H
  11. # include <sys/types.h> /* For size_t */
  12. # endif
  13. #endif
  14. /* Compatibility with Visual Studio 2013 and older which don't support
  15. the inline keyword in C (only in C++): use __inline instead.
  16. (copied from pythoncapi_compat.h) */
  17. #if (defined(_MSC_VER) && _MSC_VER < 1900 \
  18. && !defined(__cplusplus) && !defined(inline))
  19. #define inline __inline
  20. #endif
  21. #ifdef _MSC_VER
  22. #include <intrin.h> /* For _byteswap_uint64() */
  23. #endif
  24. /* --- definitions specific to Python --- */
  25. /* Py_UNREACHABLE was introduced in Python 3.7 */
  26. #ifndef Py_UNREACHABLE
  27. #define Py_UNREACHABLE() assert(0)
  28. #endif
  29. /* --- bitarrayobject --- */
  30. /* .ob_size is the buffer size (in bytes), not the number of elements.
  31. The number of elements (bits) is .nbits. */
  32. typedef struct {
  33. PyObject_VAR_HEAD
  34. char *ob_item; /* buffer */
  35. Py_ssize_t allocated; /* allocated buffer size (in bytes) */
  36. Py_ssize_t nbits; /* length of bitarray, i.e. elements */
  37. int endian; /* bit-endianness of bitarray */
  38. int ob_exports; /* how many buffer exports */
  39. PyObject *weakreflist; /* list of weak references */
  40. Py_buffer *buffer; /* used when importing a buffer */
  41. int readonly; /* buffer is readonly */
  42. } bitarrayobject;
  43. /* --- bit-endianness --- */
  44. #define ENDIAN_LITTLE 0
  45. #define ENDIAN_BIG 1
  46. #define IS_LE(self) ((self)->endian == ENDIAN_LITTLE)
  47. #define IS_BE(self) ((self)->endian == ENDIAN_BIG)
  48. /* endianness as string */
  49. #define ENDIAN_STR(endian) ((endian) == ENDIAN_LITTLE ? "little" : "big")
  50. /* number of pad bits */
  51. #define PADBITS(self) ((8 - (self)->nbits % 8) % 8)
  52. /* number of bytes necessary to store given nunmber of bits */
  53. #define BYTES(bits) (((bits) + 7) >> 3)
  54. /* we're not using bitmask_table here, as it is actually slower */
  55. #define BITMASK(self, i) (((char) 1) << ((self)->endian == ENDIAN_LITTLE ? \
  56. ((i) % 8) : (7 - (i) % 8)))
  57. /* buffer as uint64 array */
  58. #define WBUFF(self) ((uint64_t *) (self)->ob_item)
  59. /* assert that .nbits is in agreement with .ob_size */
  60. #define assert_nbits(self) assert(BYTES((self)->nbits) == Py_SIZE(self))
  61. /* assert byte index is in range */
  62. #define assert_byte_in_range(self, j) \
  63. assert(self->ob_item && 0 <= (j) && (j) < Py_SIZE(self))
  64. /* ------------ low level access to bits in bitarrayobject ------------- */
  65. static inline int
  66. getbit(bitarrayobject *self, Py_ssize_t i)
  67. {
  68. assert_nbits(self);
  69. assert(0 <= i && i < self->nbits);
  70. return self->ob_item[i >> 3] & BITMASK(self, i) ? 1 : 0;
  71. }
  72. static inline void
  73. setbit(bitarrayobject *self, Py_ssize_t i, int vi)
  74. {
  75. char *cp, mask;
  76. assert_nbits(self);
  77. assert(0 <= i && i < self->nbits);
  78. assert(self->readonly == 0);
  79. mask = BITMASK(self, i);
  80. cp = self->ob_item + (i >> 3);
  81. if (vi)
  82. *cp |= mask;
  83. else
  84. *cp &= ~mask;
  85. }
  86. static const char bitmask_table[2][8] = {
  87. {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}, /* little endian */
  88. {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}, /* big endian */
  89. };
  90. /* character with n leading ones is: ones_table[endian][n] */
  91. static const char ones_table[2][8] = {
  92. {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f}, /* little endian */
  93. {0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe}, /* big endian */
  94. };
  95. /* Return last byte in buffer with pad bits zeroed out.
  96. If the length of the bitarray is a multiple of 8 (which includes an empty
  97. bitarray), 0 is returned. */
  98. static inline char
  99. zlc(bitarrayobject *self) /* zlc = zeroed last char */
  100. {
  101. const int r = self->nbits % 8; /* index into mask table */
  102. if (r == 0)
  103. return 0;
  104. return self->ob_item[Py_SIZE(self) - 1] & ones_table[IS_BE(self)][r];
  105. }
  106. /* Return a uint64_t word representing the last (up to 63) remaining bits
  107. of the buffer. All missing bytes (to complete the word) and padbits are
  108. treated as zeros.
  109. If the length of the bitarray is a multiple of 64 (which also includes
  110. an empty bitarray), 0 is returned. */
  111. static inline uint64_t
  112. zlw(bitarrayobject *self) /* zlw = zeroed last word */
  113. {
  114. const size_t nbits = self->nbits;
  115. const size_t nw = (nbits / 64) * 8; /* bytes in complete words */
  116. const size_t nr = (nbits % 64) / 8; /* complete remaining bytes */
  117. uint64_t res = 0;
  118. assert(nw + nr == nbits / 8 && 8 * (nw + nr) + nbits % 8 == nbits);
  119. memcpy((char *) &res, self->ob_item + nw, nr);
  120. if (nbits % 8)
  121. *(((char *) &res) + nr) = zlc(self);
  122. return res;
  123. }
  124. /* unless buffer is readonly, zero out pad bits - self->nbits is unchanged */
  125. static inline void
  126. set_padbits(bitarrayobject *self)
  127. {
  128. if (self->readonly == 0) {
  129. int r = self->nbits % 8; /* index into mask table */
  130. if (r)
  131. self->ob_item[Py_SIZE(self) - 1] &= ones_table[IS_BE(self)][r];
  132. }
  133. }
  134. /* population count - number of 1's in uint64 */
  135. static inline int
  136. popcnt_64(uint64_t x)
  137. {
  138. #if (defined(__clang__) || defined(__GNUC__))
  139. return __builtin_popcountll(x);
  140. #else
  141. /* https://en.wikipedia.org/wiki/Hamming_weight popcount64c */
  142. const uint64_t m1 = 0x5555555555555555;
  143. const uint64_t m2 = 0x3333333333333333;
  144. const uint64_t m4 = 0x0f0f0f0f0f0f0f0f;
  145. const uint64_t h01 = 0x0101010101010101;
  146. x -= (x >> 1) & m1;
  147. x = (x & m2) + ((x >> 2) & m2);
  148. x = (x + (x >> 4)) & m4;
  149. return (x * h01) >> 56;
  150. #endif
  151. }
  152. static inline int
  153. parity_64(uint64_t x)
  154. {
  155. #if (defined(__clang__) || defined(__GNUC__))
  156. return __builtin_parityll(x);
  157. #else
  158. int i;
  159. for (i = 32; i > 0; i /= 2)
  160. x ^= x >> i;
  161. return x & 1;
  162. #endif
  163. }
  164. static inline uint64_t
  165. builtin_bswap64(uint64_t word)
  166. {
  167. #if (defined(__clang__) || \
  168. (defined(__GNUC__) \
  169. && ((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))))
  170. /* __builtin_bswap64() is available since GCC 4.3 */
  171. # define HAVE_BUILTIN_BSWAP64 1
  172. return __builtin_bswap64(word);
  173. #elif defined(_MSC_VER)
  174. # define HAVE_BUILTIN_BSWAP64 1
  175. return _byteswap_uint64(word);
  176. #else
  177. # define HAVE_BUILTIN_BSWAP64 0
  178. Py_UNREACHABLE();
  179. #endif
  180. }
  181. /* reverse order of first n bytes of p */
  182. static inline void
  183. swap_bytes(char *p, Py_ssize_t n)
  184. {
  185. Py_ssize_t i, j;
  186. for (i = 0, j = n - 1; i < j; i++, j--) {
  187. char t = p[i];
  188. p[i] = p[j];
  189. p[j] = t;
  190. }
  191. }
  192. /* write 256 characters into table for given kernel operation */
  193. static inline void
  194. setup_table(char *table, char kop)
  195. {
  196. int k;
  197. for (k = 0; k < 256; k++) {
  198. char t = 0, j;
  199. for (j = 0; j < 8; j++) {
  200. if (k & 1 << j) {
  201. /* j are the indices of active bits in k (little endian) */
  202. switch (kop) {
  203. case 'a': t += j; break; /* add active indices */
  204. case 'A': t += 7 - j; break; /* 'a' for big endian */
  205. case 's': t += j * j; /* add squares of active indices */
  206. break;
  207. case 'S': t += (7-j) * (7-j); /* 's' for big endian */
  208. break;
  209. case 'x': t ^= j; break; /* xor active indices */
  210. case 'X': t ^= 7 - j; break; /* 'x' for big endian */
  211. case 'c': t++; break; /* bit count */
  212. case 'p': t ^= 1; break; /* parity */
  213. case 'r': t |= 128 >> j; break; /* reverse bits */
  214. default: Py_UNREACHABLE();
  215. }
  216. }
  217. }
  218. table[k] = t;
  219. }
  220. }
  221. /* Return distance [0..3] to next aligned pointer.
  222. While on modern compilers uint64_t pointers may be misaligned, it may
  223. cause problems on older ones. Moreover, it may lead to slowdown (even
  224. on modern compilers). */
  225. static inline int
  226. to_aligned(void *p)
  227. {
  228. int r = ((uintptr_t) p) % 4;
  229. return (4 - r) % 4;
  230. }
  231. /* population count of n words starting from at uint64_t pointer w */
  232. static inline Py_ssize_t
  233. popcnt_words(uint64_t *w, Py_ssize_t n)
  234. {
  235. Py_ssize_t cnt = 0;
  236. assert(n >= 0 && ((uintptr_t) w) % 4 == 0);
  237. while (n--)
  238. cnt += popcnt_64(*w++);
  239. return cnt;
  240. }
  241. /* Adjust slice parameters such that step is always positive.
  242. This produces simpler loops over elements when their order is irrelevant.
  243. Moreover, for step = -1, we can now use set_span() in set_range() and
  244. count_span() in count_range().
  245. */
  246. static inline void
  247. adjust_step_positive(Py_ssize_t slicelength,
  248. Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
  249. {
  250. if (*step < 0) {
  251. *stop = *start + 1;
  252. *start = *stop + *step * (slicelength - 1) - 1;
  253. *step = -(*step);
  254. }
  255. assert(*start >= 0 && *stop >= 0 && *step > 0 && slicelength >= 0);
  256. /* slicelength == 0 implies stop <= start */
  257. assert(slicelength != 0 || *stop <= *start);
  258. /* step == 1 and slicelength != 0 implies stop - start == slicelength */
  259. assert(*step != 1 || slicelength == 0 || *stop - *start == slicelength);
  260. }
  261. /* convert Python object to C int and set value at address -
  262. return 1 on success, 0 on failure (and set exception) */
  263. static inline int
  264. conv_pybit(PyObject *value, int *vi)
  265. {
  266. Py_ssize_t n;
  267. n = PyNumber_AsSsize_t(value, NULL);
  268. if (n == -1 && PyErr_Occurred())
  269. return 0;
  270. if (n >> 1) {
  271. PyErr_Format(PyExc_ValueError, "bit must be 0 or 1, got %zd", n);
  272. return 0;
  273. }
  274. *vi = (int) n;
  275. return 1;
  276. }
  277. /* Return 0 if bitarrays have equal length and bit-endianness.
  278. Otherwise, set exception and return -1. */
  279. static inline int
  280. ensure_eq_size_endian(bitarrayobject *a, bitarrayobject *b)
  281. {
  282. if (a->nbits != b->nbits) {
  283. PyErr_SetString(PyExc_ValueError,
  284. "bitarrays of equal length expected");
  285. return -1;
  286. }
  287. if (a->endian != b->endian) {
  288. PyErr_SetString(PyExc_ValueError,
  289. "bitarrays of equal bit-endianness expected");
  290. return -1;
  291. }
  292. return 0;
  293. }
  294. /* Equivalent to: import bitarray; return getattr(bitarray, name) */
  295. static inline PyObject *
  296. bitarray_module_attr(char *name)
  297. {
  298. PyObject *bitarray_module, *result;
  299. bitarray_module = PyImport_ImportModule("bitarray");
  300. if (bitarray_module == NULL)
  301. return NULL;
  302. result = PyObject_GetAttrString(bitarray_module, name);
  303. Py_DECREF(bitarray_module);
  304. return result;
  305. }