cb_bitopt.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. /*
  2. * SPDX-License-Identifier: Apache-2.0
  3. *
  4. * Change Logs:
  5. * Date Author Notes
  6. * 2022-03-16 tyx first implementation
  7. */
  8. #ifndef CB_BITOPT_H_
  9. #define CB_BITOPT_H_
  10. #include "cb_def.h"
  11. #include <stdint.h>
  12. #ifdef __cplusplus
  13. extern "C" {
  14. #endif
  15. cb_inline void *cb_setbit(void *addr, unsigned int n)
  16. {
  17. cb_uint8_t *ptr = (cb_uint8_t *)addr;
  18. ptr[n / 8] |= 0x1 << n % 8;
  19. return addr;
  20. }
  21. cb_inline void *cb_clearbit(void *addr, unsigned int n)
  22. {
  23. cb_uint8_t *ptr = (cb_uint8_t *)addr;
  24. ptr[n / 8] &= ~(0x1 << n % 8);
  25. return addr;
  26. }
  27. cb_inline int cb_testbit(void *addr, unsigned int n)
  28. {
  29. cb_uint8_t *ptr = (cb_uint8_t *)addr;
  30. return !!(ptr[n / 8] & (0x1 << n % 8));
  31. }
  32. /**
  33. * @brief Find First bit Set in word(From LSB to MSB).
  34. * BIT counts from 0 and ranges from [0-31].
  35. * When the input value is 0x1, the return value is 0
  36. * When the input value is 0x2, the return value is 1
  37. * When the input value is 0x80000000, the return value is 31
  38. * When the input value is 0, the return value is also 0
  39. */
  40. cb_inline int cb_ffs32(cb_uint32_t x)
  41. {
  42. int r = 0;
  43. if (x)
  44. {
  45. if (!(x & 0xFFFFU))
  46. {
  47. x >>= 16;
  48. r += 16;
  49. }
  50. if (!(x & 0xFFU))
  51. {
  52. x >>= 8;
  53. r += 8;
  54. }
  55. if (!(x & 0xFU))
  56. {
  57. x >>= 4;
  58. r += 4;
  59. }
  60. if (!(x & 0x3U))
  61. {
  62. x >>= 2;
  63. r += 2;
  64. }
  65. if (!(x & 0x1U))
  66. {
  67. x >>= 1;
  68. r += 1;
  69. }
  70. }
  71. return r;
  72. }
  73. /**
  74. * @brief Find First bit Set in word(From LSB to MSB).
  75. * BIT counts from 0 and ranges from [0-63].
  76. * When the input value is 0x1, the return value is 0
  77. * When the input value is 0x2, the return value is 1
  78. * When the input value is 0x8000000000000000, the return value is 63
  79. * When the input value is 0, the return value is also 0
  80. */
  81. cb_inline int cb_ffs64(cb_uint64_t x)
  82. {
  83. int r = 0;
  84. if (x)
  85. {
  86. if (!(x & 0xFFFFFFFFULL))
  87. {
  88. x >>= 32;
  89. r += 32;
  90. }
  91. if (!(x & 0xFFFFULL))
  92. {
  93. x >>= 16;
  94. r += 16;
  95. }
  96. if (!(x & 0xFFULL))
  97. {
  98. x >>= 8;
  99. r += 8;
  100. }
  101. if (!(x & 0xFULL))
  102. {
  103. x >>= 4;
  104. r += 4;
  105. }
  106. if (!(x & 0x3ULL))
  107. {
  108. x >>= 2;
  109. r += 2;
  110. }
  111. if (!(x & 0x1ULL))
  112. {
  113. x >>= 1;
  114. r += 1;
  115. }
  116. }
  117. return r;
  118. }
  119. /**
  120. * @brief Find First bit Set in word(From LSB to MSB).
  121. * If the value of *addr is 0, the return value is meaningless
  122. */
  123. cb_inline int cb_ffs(unsigned long x)
  124. {
  125. return cb_ffs64(x);
  126. }
  127. /**
  128. * @brief Find First zero in word(From LSB to MSB).
  129. * BIT counts from 0 and ranges from [0-31].
  130. * When the input value is 0x0, the return value is 0
  131. * When the input value is 0x1, the return value is 1
  132. * When the input value is 0x2, the return value is 0
  133. * When the input value is 0x000000FF, the return value is 8
  134. * When the input value is 0xFFFFFFFF, the return value is also 0
  135. */
  136. cb_inline int cb_ffz32(cb_uint32_t x)
  137. {
  138. return cb_ffs32(~x);
  139. }
  140. /**
  141. * @brief Find First zero in word(From LSB to MSB).
  142. * BIT counts from 0 and ranges from [0-63].
  143. * When the input value is 0x0, the return value is 0
  144. * When the input value is 0x1, the return value is 1
  145. * When the input value is 0x2, the return value is 0
  146. * When the input value is 0x00000000FFFFFFFF, the return value is 32
  147. * When the input value is 0xFFFFFFFFFFFFFFFF, the return value is also 0
  148. */
  149. cb_inline int cb_ffz64(cb_uint64_t x)
  150. {
  151. return cb_ffs64(~x);
  152. }
  153. /**
  154. * @brief Find First zero in word(From LSB to MSB).
  155. * If *addr is the maximum machine word length, the return value is meaningless
  156. */
  157. cb_inline int cb_ffz(unsigned long x)
  158. {
  159. cb_uint64_t mask = (~0x0ULL) ^ (~0x0UL);
  160. return cb_ffz64(mask | x);
  161. }
  162. /**
  163. * @brief Count Leading Zeroes.
  164. * The value ranges from 0 to 32
  165. * When the input value is 0x0, the return value is 32
  166. * When the input value is 0x1, the return value is 31
  167. * When the input value is 0x2, the return value is 30
  168. * When the input value is 0xF0, the return value is 24
  169. * When the input value is 0xFFFFFFFF, the return value is 0
  170. */
  171. cb_inline int cb_clz32(cb_uint32_t x)
  172. {
  173. int r = 0;
  174. if (x)
  175. {
  176. if (!(x & 0xFFFF0000U))
  177. {
  178. x <<= 16;
  179. r += 16;
  180. }
  181. if (!(x & 0xFF000000U))
  182. {
  183. x <<= 8;
  184. r += 8;
  185. }
  186. if (!(x & 0xF0000000U))
  187. {
  188. x <<= 4;
  189. r += 4;
  190. }
  191. if (!(x & 0xC0000000U))
  192. {
  193. x <<= 2;
  194. r += 2;
  195. }
  196. if (!(x & 0x80000000U))
  197. {
  198. x <<= 1;
  199. r += 1;
  200. }
  201. }
  202. else
  203. {
  204. r = 32;
  205. }
  206. return r;
  207. }
  208. /**
  209. * @brief Count Leading Zeroes.
  210. * The value ranges from 0 to 64
  211. * When the input value is 0x0, the return value is 64
  212. * When the input value is 0x1, the return value is 63
  213. * When the input value is 0x2, the return value is 62
  214. * When the input value is 0xF0, the return value is 56
  215. * When the input value is 0x00000000FFFFFFFF, the return value is 32
  216. * When the input value is 0xFFFFFFFFFFFFFFFF, the return value is 0
  217. */
  218. cb_inline int cb_clz64(cb_uint64_t x)
  219. {
  220. int r = 0;
  221. if (x)
  222. {
  223. if (!(x & 0xFFFFFFFF00000000ULL))
  224. {
  225. x <<= 32;
  226. r += 32;
  227. }
  228. if (!(x & 0xFFFF000000000000ULL))
  229. {
  230. x <<= 16;
  231. r += 16;
  232. }
  233. if (!(x & 0xFF00000000000000ULL))
  234. {
  235. x <<= 8;
  236. r += 8;
  237. }
  238. if (!(x & 0xF000000000000000ULL))
  239. {
  240. x <<= 4;
  241. r += 4;
  242. }
  243. if (!(x & 0xC000000000000000ULL))
  244. {
  245. x <<= 2;
  246. r += 2;
  247. }
  248. if (!(x & 0x8000000000000000ULL))
  249. {
  250. x <<= 1;
  251. r += 1;
  252. }
  253. }
  254. else
  255. {
  256. r = 64;
  257. }
  258. return r;
  259. }
  260. /**
  261. * @brief Count Leading Zeroes.
  262. */
  263. cb_inline int cb_clz(unsigned long x)
  264. {
  265. cb_uint64_t t = x;
  266. cb_uint64_t mask = ~0x0ULL;
  267. mask = mask << (sizeof(cb_uint64_t) * 8U - CB_BITS_LONG);
  268. mask = ~mask;
  269. t = t << (sizeof(cb_uint64_t) * 8U - CB_BITS_LONG);
  270. t |= mask;
  271. return cb_clz64(t);
  272. }
  273. /**
  274. * @brief Find Last bit set
  275. * The value ranges from 0 to 32
  276. * When the input value is 0x0, the return value is 0
  277. * When the input value is 0x1, the return value is 1
  278. * When the input value is 0xF0, the return value is 8
  279. * When the input value is 0x80000000, the return value is 32
  280. * When the input value is 0x80000001, the return value is 32
  281. */
  282. cb_inline int cb_fls32(cb_uint32_t x)
  283. {
  284. return 32 - cb_clz32(x);
  285. }
  286. /**
  287. * @brief Find Last bit set
  288. * The value ranges from 0 to 64
  289. * When the input value is 0x0, the return value is 0
  290. * When the input value is 0x1, the return value is 1
  291. * When the input value is 0xF0, the return value is 8
  292. * When the input value is 0x80000000, the return value is 32
  293. * When the input value is 0x8000000000000000, the return value is 64
  294. * When the input value is 0x8000000000000001, the return value is 64
  295. */
  296. cb_inline int cb_fls64(cb_uint64_t x)
  297. {
  298. return 64 - cb_clz64(x);
  299. }
  300. /**
  301. * @brief Find Last bit set
  302. */
  303. cb_inline int cb_fls(unsigned long x)
  304. {
  305. return CB_BITS_LONG - cb_clz(x);
  306. }
  307. /**
  308. * @brief Count Trailing Zeroes
  309. * The value ranges from 0 to 32
  310. * When the input value is 0x0, the return value is 32
  311. * When the input value is 0x2, the return value is 1
  312. * When the input value is 0x80000000, the return value is 31
  313. * When the input value is 0xFFFFFFFF, the return value is 0
  314. */
  315. cb_inline int cb_ctz32(cb_uint32_t x)
  316. {
  317. int r;
  318. if (x != 0)
  319. {
  320. r = cb_ffs32(x);
  321. }
  322. else
  323. {
  324. r = 32;
  325. }
  326. return r;
  327. }
  328. /**
  329. * @brief Count Trailing Zeroes
  330. * The value ranges from 0 to 64
  331. * When the input value is 0x0, the return value is 64
  332. * When the input value is 0x2, the return value is 1
  333. * When the input value is 0x3, the return value is 0
  334. * When the input value is 0x80000000, the return value is 31
  335. * When the input value is 0xFFFFFFFFFFFFFFFF, the return value is 0
  336. */
  337. cb_inline int cb_ctz64(cb_uint64_t x)
  338. {
  339. int r;
  340. if (x != 0)
  341. {
  342. r = cb_ffs64(x);
  343. }
  344. else
  345. {
  346. r = 64;
  347. }
  348. return r;
  349. }
  350. /**
  351. * @brief Count Trailing Zeroes
  352. */
  353. cb_inline int cb_ctz(unsigned long x)
  354. {
  355. int r;
  356. if (x != 0)
  357. {
  358. r = cb_ffs(x);
  359. }
  360. else
  361. {
  362. r = CB_BITS_LONG;
  363. }
  364. return r;
  365. }
  366. /**
  367. * @brief Finds the location of the first set from a section of memory
  368. */
  369. cb_inline unsigned long cb_find_next_bit(const unsigned long* addr,
  370. unsigned long size, unsigned long offset)
  371. {
  372. unsigned long res = size;
  373. unsigned long unalign_size, value = 0;
  374. unsigned long pos = offset;
  375. if (offset < size)
  376. {
  377. pos = offset;
  378. addr += offset / CB_BITS_LONG;
  379. unalign_size = offset % CB_BITS_LONG;
  380. // Head alignment processing
  381. value = (*addr++) >> unalign_size;
  382. offset += CB_BITS_LONG - unalign_size;
  383. if (offset > size)
  384. {
  385. offset = size;
  386. }
  387. // find
  388. while (value == 0 && offset < size)
  389. {
  390. value = *addr++;
  391. pos = offset;
  392. offset += CB_BITS_LONG;
  393. }
  394. // Tail alignment processing
  395. if (offset > size)
  396. {
  397. value = value & (~0x0UL >> (offset - size));
  398. }
  399. if (value != 0)
  400. {
  401. res = pos + cb_ffs(value);
  402. }
  403. }
  404. return res;
  405. }
  406. cb_inline unsigned long cb_find_first_bit(const unsigned long* addr,
  407. unsigned long size)
  408. {
  409. return cb_find_next_bit(addr, size, 0);
  410. }
  411. #define cb_for_each_set_bit(bit, addr, size) \
  412. for ((bit) = cb_find_first_bit(addr, size); (bit) < (size); \
  413. (bit) = cb_find_next_bit(addr, size, (bit) + 1))
  414. #ifdef __cplusplus
  415. }
  416. #endif
  417. #endif /* CB_BITOPT_H_ */