bits.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. // Bits/bytes manipulation tools
  2. //
  3. // Platform: ISO C++ 98/11
  4. // $Id$
  5. //
  6. // (c) __vic 2011
  7. #ifndef __VIC_BITS_H
  8. #define __VIC_BITS_H
  9. #include<__vic/defs.h>
  10. #include<__vic/stdint.h>
  11. #include<climits>
  12. #if defined(_MSC_VER) && !defined(__VIC_NO_BUILTINS)
  13. #include<intrin.h>
  14. #endif
  15. #if __cpp_static_assert
  16. #define __VIC_ASSERT_UINT(T) \
  17. static_assert(T(-1) > 0, "Unsigned type is required")
  18. #else
  19. #define __VIC_ASSERT_UINT(T) \
  20. typedef char assert_argument_is_unsigned[T(-1) > 0 : 1 : -1]
  21. #endif
  22. namespace __vic {
  23. //----------------------------------------------------------------------------
  24. // Returns low-order nibble (or tetrad, or half-byte) of the byte
  25. __VIC_CONSTEXPR_FUNC uint8_t lo_nibble(uint8_t b)
  26. {
  27. return b & 0x0F;
  28. }
  29. //----------------------------------------------------------------------------
  30. // Returns high-order nibble (or tetrad, or half-byte) of the byte
  31. __VIC_CONSTEXPR_FUNC uint8_t hi_nibble(uint8_t b)
  32. {
  33. return b >> 4;
  34. }
  35. //------------------------------------------------------------------------------
  36. // Returns value with all most significant bits are 1 (others - 0)
  37. // Parameter specifies the number of "ones"
  38. template<class T>
  39. inline T msb_ones(unsigned bits_num)
  40. {
  41. return ~T(0) << (sizeof(T) * CHAR_BIT - bits_num);
  42. }
  43. //------------------------------------------------------------------------------
  44. // Returns value with all least significant bits are 1 (others - 0)
  45. // Parameter specifies the number of "ones"
  46. template<class T>
  47. inline T lsb_ones(unsigned bits_num)
  48. {
  49. return ~(~T(0) << bits_num);
  50. }
  51. //------------------------------------------------------------------------------
  52. // Clears all but bits_num least significant bits
  53. template<class T>
  54. inline T get_lsbs(T v, unsigned bits_num)
  55. {
  56. return v & lsb_ones<T>(bits_num);
  57. }
  58. //----------------------------------------------------------------------------
  59. // Returns char code 0..255
  60. __VIC_CONSTEXPR_FUNC int ord(char ch)
  61. {
  62. return static_cast<unsigned char>(ch);
  63. }
  64. //----------------------------------------------------------------------------
  65. // Swap high-order nibble with low-order one
  66. __VIC_CONSTEXPR_FUNC uint8_t swapped_nibbles(uint8_t b)
  67. {
  68. return (b << 4) | (b >> 4);
  69. }
  70. //----------------------------------------------------------------------------
  71. //----------------------------------------------------------------------------
  72. // Counts 1-bits
  73. template<class UInt>
  74. __VIC_CONSTEXPR14 unsigned popcount_uint(UInt v)
  75. {
  76. __VIC_ASSERT_UINT(UInt);
  77. unsigned c = 0;
  78. for(; v; v >>= 1) c += v & 1;
  79. return c;
  80. }
  81. //----------------------------------------------------------------------------
  82. inline unsigned popcount(unsigned v)
  83. {
  84. #if defined(__GNUC__) && !defined(__VIC_NO_BUILTINS)
  85. return __builtin_popcount(v);
  86. #elif defined(_MSC_VER) && !defined(__VIC_NO_BUILTINS)
  87. return __popcnt(v);
  88. #else
  89. return popcount_uint(v);
  90. #endif
  91. }
  92. //----------------------------------------------------------------------------
  93. inline unsigned popcount(unsigned long v)
  94. {
  95. #if defined(__GNUC__) && !defined(__VIC_NO_BUILTINS)
  96. return __builtin_popcountl(v);
  97. #else
  98. return popcount_uint(v);
  99. #endif
  100. }
  101. //----------------------------------------------------------------------------
  102. #ifdef __VIC_LONGLONG
  103. inline unsigned popcount(unsigned __VIC_LONGLONG v)
  104. {
  105. #if defined(__GNUC__) && !defined(__VIC_NO_BUILTINS)
  106. return __builtin_popcountll(v);
  107. #elif defined(_MSC_VER) && !defined(__VIC_NO_BUILTINS)
  108. return static_cast<unsigned>(__popcnt64(v));
  109. #else
  110. return popcount_uint(v);
  111. #endif
  112. }
  113. #endif
  114. //----------------------------------------------------------------------------
  115. inline unsigned popcount(unsigned short v)
  116. {
  117. #if defined(__GNUC__) && !defined(__VIC_NO_BUILTINS)
  118. return __builtin_popcount(v);
  119. #else
  120. return popcount_uint(v);
  121. #endif
  122. }
  123. //----------------------------------------------------------------------------
  124. inline unsigned popcount(unsigned char v)
  125. {
  126. #if defined(__GNUC__) && !defined(__VIC_NO_BUILTINS)
  127. return __builtin_popcount(v);
  128. #else
  129. return popcount_uint(v);
  130. #endif
  131. }
  132. //----------------------------------------------------------------------------
  133. //----------------------------------------------------------------------------
  134. // Returns position of the most significant 1-bit
  135. // Precondition: v != 0
  136. template<class UInt>
  137. inline unsigned msb_position_uint(UInt v)
  138. {
  139. __VIC_ASSERT_UINT(UInt);
  140. unsigned c = 0;
  141. while(v >>= 1) c++;
  142. return c;
  143. }
  144. //----------------------------------------------------------------------------
  145. inline unsigned msb_position(unsigned v)
  146. {
  147. #if defined(__GNUC__) && !defined(__VIC_NO_BUILTINS)
  148. return sizeof(v) * CHAR_BIT - __builtin_clz(v) - 1U;
  149. #else
  150. return msb_position_uint(v);
  151. #endif
  152. }
  153. //----------------------------------------------------------------------------
  154. inline unsigned msb_position(unsigned long v)
  155. {
  156. #if defined(__GNUC__) && !defined(__VIC_NO_BUILTINS)
  157. return sizeof(v) * CHAR_BIT - __builtin_clzl(v) - 1U;
  158. #else
  159. return msb_position_uint(v);
  160. #endif
  161. }
  162. //----------------------------------------------------------------------------
  163. #ifdef __VIC_LONGLONG
  164. inline unsigned msb_position(unsigned __VIC_LONGLONG v)
  165. {
  166. #if defined(__GNUC__) && !defined(__VIC_NO_BUILTINS)
  167. return sizeof(v) * CHAR_BIT - __builtin_clzll(v) - 1U;
  168. #else
  169. return msb_position_uint(v);
  170. #endif
  171. }
  172. #endif
  173. //----------------------------------------------------------------------------
  174. inline unsigned msb_position(unsigned short v)
  175. {
  176. #if defined(__GNUC__) && !defined(__VIC_NO_BUILTINS)
  177. return msb_position(static_cast<unsigned>(v));
  178. #else
  179. return msb_position_uint(v);
  180. #endif
  181. }
  182. //----------------------------------------------------------------------------
  183. inline unsigned msb_position(unsigned char v)
  184. {
  185. #if defined(__GNUC__) && !defined(__VIC_NO_BUILTINS)
  186. return msb_position(static_cast<unsigned>(v));
  187. #else
  188. return msb_position_uint(v);
  189. #endif
  190. }
  191. //----------------------------------------------------------------------------
  192. //----------------------------------------------------------------------------
  193. template<class UInt>
  194. inline UInt rotl_uint(UInt v, int shift)
  195. {
  196. const int w = sizeof(UInt) * CHAR_BIT; // width in bits
  197. //return (v << shift) | (v >> (w - shift)); // UB if shift == 0
  198. return (v << shift) | (v >> ((w - shift) & (w - 1)));
  199. }
  200. //----------------------------------------------------------------------------
  201. template<class UInt>
  202. inline UInt rotr_uint(UInt v, int shift)
  203. {
  204. const int w = sizeof(UInt) * CHAR_BIT; // width in bits
  205. //return (v >> shift) | (v << (w - shift)); // UB if shift == 0
  206. return (v >> shift) | (v << ((w - shift) & (w - 1)));
  207. }
  208. //----------------------------------------------------------------------------
  209. inline unsigned rotl(unsigned v, int sh) { return rotl_uint(v, sh); }
  210. inline unsigned long rotl(unsigned long v, int sh) { return rotl_uint(v, sh); }
  211. inline unsigned short rotl(unsigned short v, int sh) { return rotl_uint(v, sh); }
  212. inline unsigned char rotl(unsigned char v, int sh) { return rotl_uint(v, sh); }
  213. //----------------------------------------------------------------------------
  214. inline unsigned rotr(unsigned v, int sh) { return rotr_uint(v, sh); }
  215. inline unsigned long rotr(unsigned long v, int sh) { return rotr_uint(v, sh); }
  216. inline unsigned short rotr(unsigned short v, int sh) { return rotr_uint(v, sh); }
  217. inline unsigned char rotr(unsigned char v, int sh) { return rotr_uint(v, sh); }
  218. //----------------------------------------------------------------------------
  219. #ifdef __VIC_LONGLONG
  220. inline unsigned __VIC_LONGLONG rotl(unsigned __VIC_LONGLONG v, int sh)
  221. {
  222. return rotl_uint(v, sh);
  223. }
  224. inline unsigned __VIC_LONGLONG rotr(unsigned __VIC_LONGLONG v, int sh)
  225. {
  226. return rotr_uint(v, sh);
  227. }
  228. #endif
  229. //----------------------------------------------------------------------------
  230. //----------------------------------------------------------------------------
  231. template<class UInt>
  232. inline bool ispow2(UInt n)
  233. {
  234. __VIC_ASSERT_UINT(UInt);
  235. return popcount(n) == 1;
  236. }
  237. //----------------------------------------------------------------------------
  238. template<class UInt>
  239. inline unsigned ceil_log2(UInt n)
  240. {
  241. __VIC_ASSERT_UINT(UInt);
  242. return n >> 1 ? msb_position(UInt(n - 1)) + 1 : 0;
  243. }
  244. //----------------------------------------------------------------------------
  245. template<class UInt>
  246. inline unsigned floor_log2(UInt n)
  247. {
  248. __VIC_ASSERT_UINT(UInt);
  249. return n ? msb_position(n) : 0;
  250. }
  251. //----------------------------------------------------------------------------
  252. // Returns the number x: ispow2(x) && x >= n
  253. template<class UInt>
  254. inline UInt ceil2(UInt n)
  255. {
  256. __VIC_ASSERT_UINT(UInt);
  257. if(n == 0 || n == 1) return 1;
  258. return UInt(1) << (msb_position(UInt(n - 1)) + 1);
  259. }
  260. //----------------------------------------------------------------------------
  261. // If n != 0 returns the number x: ispow2(x) && x <= n
  262. // Otherwise 0 is returned
  263. template<class UInt>
  264. inline UInt floor2(UInt n)
  265. {
  266. __VIC_ASSERT_UINT(UInt);
  267. return n ? UInt(1) << msb_position(n) : 0;
  268. }
  269. //----------------------------------------------------------------------------
  270. #undef __VIC_ASSERT_UINT
  271. } // namespace
  272. #endif // header guard