123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- #ifndef SIMPLE_COMPRESS_ITERATOR_HPP
- #define SIMPLE_COMPRESS_ITERATOR_HPP
- #include <type_traits> // std::enable_if_t std::is_same_v std::is_unsigned_v
- #include <iterator> // std::output_iterator_tag std::iterator_traits
- #include <limits> // std::numeric_limits
- #include <cstddef> // std::size_t
- #include <utility> // std::forward
- #include <algorithm> // std::min
- #include "bits.hpp" // bit_count bit_offset get_bits
- namespace simple::compress
- {
- template <typename It, typename Value = typename std::iterator_traits<It>::value_type,
- std::enable_if_t<std::is_unsigned_v<std::underlying_type_t<Value>>>* = nullptr>
- struct out_bits
- {
- using value_type = Value;
- using difference_type = void;
- using pointer = void;
- using reference = void;
- using iterator_category = std::output_iterator_tag;
- It out;
- value_type value;
- std::size_t bit_index;
- template <typename I,
- std::enable_if_t<std::is_same_v<I,It>>* = nullptr>
- explicit out_bits(I&& out) :
- out(std::forward<It>(out)),
- value{}, bit_index{0}
- {}
- out_bits(out_bits&) = delete;
- out_bits(out_bits&& other) : out(other.out), value(other.value), bit_index(other.bit_index)
- { other.bit_index = 0; }
- out_bits& operator=(out_bits&) = delete;
- out_bits& operator=(out_bits&& other)
- {
- std::swap(out, other.out);
- std::swap(value, other.value);
- std::swap(bit_index, other.bit_index);
- return *this;
- }
- out_bits& operator++() { return *this; }
- // move only can't have postincrement
- class proxy
- {
- It& out;
- Value& value;
- std::size_t& bit_index;
- proxy(It& out, Value& value, std::size_t& bit_index)
- : out(out), value(value), bit_index(bit_index) {}
- friend struct out_bits;
- public:
- proxy() = delete;
- proxy(const proxy&) = delete;
- proxy(const proxy&&) = delete;
- proxy& operator=(const proxy&) = delete;
- proxy& operator=(const proxy&&) = delete;
- template <typename T>
- const proxy& operator=(T&& x) const
- {
- auto count = bit_count(x);
- auto offset = bit_offset(x);
- auto bits = get_bits(x);
- constexpr auto type_width = std::numeric_limits<decltype(bits)>::digits;
- constexpr auto out_width = std::numeric_limits<std::underlying_type_t<Value>>::digits;
- if constexpr (type_width >= out_width)
- {
- constexpr auto type_shift = type_width - out_width;
- std::size_t i = 0;
- while(i != count)
- {
- value |= static_cast<Value>(bits
- << (offset+i)
- >> (type_shift + bit_index)
- );
- using std::min;
- auto written = min(count-i, out_width - bit_index);
- i += written;
- bit_index += written;
- if(bit_index == out_width)
- {
- // TODO: out_end
- *out = value;
- ++out;
- value = Value{};
- bit_index = 0;
- }
- }
- }
- else
- {
- // TODO this is actually the easier case
- static_assert(type_width < out_width, "not implemented");
- }
- return *this;
- }
- };
- const proxy operator*()
- {
- return {out, value, bit_index};
- }
- ~out_bits()
- {
- if(bit_index != 0)
- *out = value;
- }
- };
- template <typename It> out_bits(It&&) -> out_bits<It>;
- } // namespace simple::compress
- #endif /* end of include guard */
|