bits.hpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #ifndef SIMPLE_COMPRESS_BITS_HPP
  2. #define SIMPLE_COMPRESS_BITS_HPP
  3. #include <type_traits> // std::enable_if_t std::is_integral_v std::is_same_v std::make_unsigned_t std::underlying_type_t std::is_unsigned_v std::is_enum_v std::is_enum_v
  4. #include <cstddef> // std::size_t
  5. #include <limits> // std::numeric_limits
  6. #include <iterator> // std::iterator_traits
  7. #include <algorithm> // std::min
  8. #include <string> // std::string
  9. #include "simple/support/type_traits.hpp" // support::remove_cvref_t
  10. namespace simple::compress
  11. {
  12. template <typename T,
  13. std::enable_if_t<std::is_integral_v<T>>* = nullptr>
  14. constexpr std::size_t bit_count(const T&) noexcept
  15. {
  16. if constexpr (std::is_same_v<T,bool>)
  17. return 1;
  18. else
  19. return std::numeric_limits<std::make_unsigned_t<T>>::digits;
  20. }
  21. template <typename T,
  22. std::enable_if_t<std::is_enum_v<T>>* = nullptr>
  23. constexpr std::size_t bit_count(const T& x) noexcept
  24. { return bit_count(static_cast<std::underlying_type_t<T>>(x)); }
  25. template <typename T,
  26. std::enable_if_t<std::is_integral_v<T>>* = nullptr>
  27. constexpr std::size_t bit_offset(const T&) noexcept
  28. {
  29. if constexpr (std::is_same_v<T,bool>)
  30. return std::numeric_limits<unsigned>::digits - 1;
  31. else
  32. return 0;
  33. }
  34. template <typename T,
  35. std::enable_if_t<std::is_enum_v<T>>* = nullptr>
  36. constexpr std::size_t bit_offset(const T& x) noexcept
  37. { return bit_offset(static_cast<std::underlying_type_t<T>>(x)); }
  38. template <typename T,
  39. std::enable_if_t<std::is_integral_v<T>>* = nullptr>
  40. constexpr auto get_bits(const T& t) noexcept
  41. {
  42. if constexpr (std::is_same_v<T,bool>)
  43. return static_cast<unsigned>(t);
  44. else
  45. return static_cast<std::make_unsigned_t<T>>(t);
  46. }
  47. template <typename T,
  48. std::enable_if_t<std::is_enum_v<T>>* = nullptr>
  49. constexpr auto get_bits(const T& t) noexcept
  50. { return get_bits(static_cast<std::underlying_type_t<T>>(t)); }
  51. template <typename It>
  52. struct bit_iterator
  53. {
  54. It iterator;
  55. std::size_t bit_index;
  56. };
  57. template <typename I> bit_iterator(I,std::size_t) -> bit_iterator<I>;
  58. // TODO: It end
  59. template <typename T, typename It>
  60. bit_iterator<It> read_bits(bit_iterator<It> it, T& to)
  61. {
  62. auto count = bit_count(to);
  63. auto type_offset = bit_offset(to);
  64. auto bits = decltype(get_bits(to)){};
  65. constexpr auto type_width = std::numeric_limits<decltype(bits)>::digits;
  66. constexpr auto read_width = std::numeric_limits<std::underlying_type_t<typename std::iterator_traits<support::remove_cvref_t<It>>::value_type>>::digits;
  67. if constexpr (type_width >= read_width)
  68. {
  69. constexpr auto type_shift = type_width - read_width;
  70. auto value = static_cast<decltype(bits)>(*it.iterator);
  71. std::size_t i = 0;
  72. while(i != count)
  73. {
  74. bits |= value
  75. << (type_shift + it.bit_index)
  76. >> (i + type_offset)
  77. ;
  78. using std::min;
  79. auto read = min(count - i, read_width - it.bit_index);
  80. i += read;
  81. it.bit_index += read;
  82. if(it.bit_index == read_width)
  83. {
  84. ++it.iterator;
  85. value = static_cast<decltype(bits)>(*it.iterator);
  86. it.bit_index = 0;
  87. }
  88. }
  89. auto tail = type_width - count - type_offset;
  90. bits = bits >> tail << tail;
  91. }
  92. else
  93. {
  94. // TODO:
  95. static_assert(type_width < read_width, "not implemented");
  96. }
  97. if constexpr (std::is_enum_v<T>)
  98. to = static_cast<T>(bits);
  99. else
  100. to = bits;
  101. return it;
  102. }
  103. // TODO: It end
  104. template <typename T, typename It>
  105. bit_iterator<It> read_bits(It it, T& to)
  106. {
  107. return read_bits(bit_iterator{it,0}, to);
  108. }
  109. template <typename T = unsigned, std::enable_if_t<std::is_unsigned_v<T>>* = nullptr>
  110. struct bits
  111. {
  112. T value{};
  113. std::size_t count{};
  114. using value_type = T;
  115. static constexpr std::size_t capacity = std::numeric_limits<value_type>::digits;
  116. constexpr bool full() const noexcept { return count == capacity; }
  117. constexpr bool empty() const noexcept { return count == 0; }
  118. constexpr void insert(bool bit) noexcept
  119. {
  120. assert(not full());
  121. ++count;
  122. value >>= 1;
  123. value |= value_type{bit} << (capacity - 1);
  124. }
  125. constexpr bits& operator=(const T& x) noexcept
  126. {
  127. // TODO: assert x has no junk outside of count
  128. value = x;
  129. return *this;
  130. }
  131. constexpr bool operator==(const bits& other) const noexcept
  132. { return value == other.value && count == other.count; }
  133. constexpr bool operator!=(const bits& other) const noexcept
  134. { return not ((*this) == other); }
  135. };
  136. template <typename T>
  137. constexpr auto get_bits(const bits<T>& b) noexcept
  138. { return b.value; }
  139. template <typename T>
  140. constexpr auto bit_count(const bits<T>& b) noexcept
  141. { return b.count; }
  142. template <typename T>
  143. constexpr std::size_t bit_offset(const bits<T>&) noexcept
  144. { return 0; }
  145. template <typename T>
  146. std::string to_string(const bits<T>& b) noexcept
  147. {
  148. std::string str{};
  149. auto count = bit_count(b);
  150. auto bits = get_bits(b);
  151. constexpr decltype(bits) first_bit = decltype(bits){1} << (std::numeric_limits<decltype(bits)>::digits - 1);
  152. while(count --> 0)
  153. {
  154. str += (bits & first_bit) ? '1' : '0';
  155. bits <<= 1;
  156. }
  157. return str;
  158. }
  159. } // namespace simple::compress
  160. #endif /* end of include guard */