iterator.hpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #ifndef SIMPLE_COMPRESS_ITERATOR_HPP
  2. #define SIMPLE_COMPRESS_ITERATOR_HPP
  3. #include <type_traits> // std::enable_if_t std::is_same_v std::is_unsigned_v
  4. #include <iterator> // std::output_iterator_tag std::iterator_traits
  5. #include <limits> // std::numeric_limits
  6. #include <cstddef> // std::size_t
  7. #include <utility> // std::forward
  8. #include <algorithm> // std::min
  9. #include "bits.hpp" // bit_count bit_offset get_bits
  10. namespace simple::compress
  11. {
  12. template <typename It, typename Value = typename std::iterator_traits<It>::value_type,
  13. std::enable_if_t<std::is_unsigned_v<std::underlying_type_t<Value>>>* = nullptr>
  14. struct out_bits
  15. {
  16. using value_type = Value;
  17. using difference_type = void;
  18. using pointer = void;
  19. using reference = void;
  20. using iterator_category = std::output_iterator_tag;
  21. It out;
  22. value_type value;
  23. std::size_t bit_index;
  24. template <typename I,
  25. std::enable_if_t<std::is_same_v<I,It>>* = nullptr>
  26. explicit out_bits(I&& out) :
  27. out(std::forward<It>(out)),
  28. value{}, bit_index{0}
  29. {}
  30. out_bits(out_bits&) = delete;
  31. out_bits(out_bits&& other) : out(other.out), value(other.value), bit_index(other.bit_index)
  32. { other.bit_index = 0; }
  33. out_bits& operator=(out_bits&) = delete;
  34. out_bits& operator=(out_bits&& other)
  35. {
  36. std::swap(out, other.out);
  37. std::swap(value, other.value);
  38. std::swap(bit_index, other.bit_index);
  39. return *this;
  40. }
  41. out_bits& operator++() { return *this; }
  42. // move only can't have postincrement
  43. class proxy
  44. {
  45. It& out;
  46. Value& value;
  47. std::size_t& bit_index;
  48. proxy(It& out, Value& value, std::size_t& bit_index)
  49. : out(out), value(value), bit_index(bit_index) {}
  50. friend struct out_bits;
  51. public:
  52. proxy() = delete;
  53. proxy(const proxy&) = delete;
  54. proxy(const proxy&&) = delete;
  55. proxy& operator=(const proxy&) = delete;
  56. proxy& operator=(const proxy&&) = delete;
  57. template <typename T>
  58. const proxy& operator=(T&& x) const
  59. {
  60. auto count = bit_count(x);
  61. auto offset = bit_offset(x);
  62. auto bits = get_bits(x);
  63. constexpr auto type_width = std::numeric_limits<decltype(bits)>::digits;
  64. constexpr auto out_width = std::numeric_limits<std::underlying_type_t<Value>>::digits;
  65. if constexpr (type_width >= out_width)
  66. {
  67. constexpr auto type_shift = type_width - out_width;
  68. std::size_t i = 0;
  69. while(i != count)
  70. {
  71. value |= static_cast<Value>(bits
  72. << (offset+i)
  73. >> (type_shift + bit_index)
  74. );
  75. using std::min;
  76. auto written = min(count-i, out_width - bit_index);
  77. i += written;
  78. bit_index += written;
  79. if(bit_index == out_width)
  80. {
  81. // TODO: out_end
  82. *out = value;
  83. ++out;
  84. value = Value{};
  85. bit_index = 0;
  86. }
  87. }
  88. }
  89. else
  90. {
  91. // TODO this is actually the easier case
  92. static_assert(type_width < out_width, "not implemented");
  93. }
  94. return *this;
  95. }
  96. };
  97. const proxy operator*()
  98. {
  99. return {out, value, bit_index};
  100. }
  101. ~out_bits()
  102. {
  103. if(bit_index != 0)
  104. *out = value;
  105. }
  106. };
  107. template <typename It> out_bits(It&&) -> out_bits<It>;
  108. } // namespace simple::compress
  109. #endif /* end of include guard */