#include "UtilityCommon.h" #include "./BitStream_v2.hpp" //================================================================================================== BitStream::BitStream(void* IN buffer, size_t buffer_length, bool writing) : buffer_ptr_(reinterpret_cast(buffer)) , buffer_end_(buffer_ptr_ + buffer_length) , pos_(buffer_ptr_) , offset_(0) { mode_ = (buffer_ptr_ && buffer_ptr_ < buffer_end_) ? eNone : eError; if (mode_ == eNone && writing) { ZeroMemory(buffer_ptr_, static_cast(buffer_end_ - buffer_ptr_)); }; } template __forceinline void BitStream::_WriteBitsUnit(const ConvT_* value, int write_bits) { const ulong write_bit_unit = sizeof(*value) * 8; BOOST_STATIC_ASSERT(write_bit_unit < (32 + 1)); assert(write_bits < write_bit_unit + 1); // value == 3, write_bits == 2 // // if ConvT_ == byte and offset_ == 9 // status = { pos == { 1, 0 } } // used = 9 & (8 - 1) --> 1 // remain = 8 - used(1) --> 7 // // 1 3 1 // pos = pos | (value << used) --> 00000001 | 00000110 // int used = offset_ & (write_bit_unit - 1); //mod int remain = write_bit_unit - used; //assume clear stream in 'not set region' ConvT_ filtered = *value; if (write_bit_unit != write_bits) { int offset = write_bit_unit - write_bits; if (offset != 0) // enable remove filtered = ConvT_(ConvT_(filtered << offset) >> offset); } ConvT_* pos = reinterpret_cast(buffer_ptr_); const int kTypeArrayOffset = boost::mpl::if_c, boost::mpl::if_c, boost::mpl::if_c, boost::mpl::void_>::type>::type>::type::value; // pos = &pos[offset_ >> kTypeArrayOffset]; // write *pos = *pos | ConvT_(filtered << used); int next_op = write_bits - remain; if (next_op > 0) { ++pos; *pos = *pos | ConvT_(filtered >> remain); } offset_ += write_bits; } //------------------------------------------------------------------------------ bool BitStream::WriteBits(const void* input, size_t write_bits, size_t input_size) { __TOUCHED(input_size); // warning check boundary in usage case if (write_bits == 0) { return true; //TODO more thinking! }; const int total_bits = static_cast(buffer_end_ - buffer_ptr_) << 3; int remains = total_bits - offset_; if (remains <= 0 || (ulong)remains < write_bits) { assert(!"index out of ranges"); return false; }; //8, 16, 32, 64? const uint16_t* offset_d2 = reinterpret_cast(input); while (16 <= write_bits) { _WriteBitsUnit(offset_d2, 16); ++offset_d2; write_bits -= 16; } const uint8_t* offset_d1 = reinterpret_cast(offset_d2); while (8 <= write_bits) { _WriteBitsUnit(offset_d1, 8); ++offset_d1; write_bits -= 8; } if (write_bits != 0) { _WriteBitsUnit(offset_d1, static_cast(write_bits)); }; return true; } //------------------------------------------------------------------------------ template __forceinline void BitStream::_ReadBitsUnit(ConvT_* value, int read_bits) const { const ulong read_bit_unit = sizeof(*value) * 8; BOOST_STATIC_ASSERT(read_bit_unit < (32 + 1)); assert(read_bits < read_bit_unit + 1); int skip = offset_ & (read_bit_unit - 1); //mod int remain = read_bit_unit - skip; ConvT_* pos = reinterpret_cast(buffer_ptr_); const int kTypeArrayOffset = boost::mpl::if_c, boost::mpl::if_c, boost::mpl::if_c, boost::mpl::void_>::type>::type>::type::value; // pos = &pos[offset_ >> kTypeArrayOffset]; ConvT_ filtered = *pos; int offset = remain - read_bits; int next_op = 0; if (offset > 0) { filtered = ConvT_(ConvT_(filtered << offset) >> (offset + skip)); } else { filtered = ConvT_(filtered >> skip); next_op = -offset; } if (next_op != 0) { // more read ++pos; next_op = read_bit_unit - next_op; // ex) 8 - 5(remain read bits) ConvT_ temp = ConvT_(ConvT_(*pos << next_op) >> next_op); // clear unused bits temp = ConvT_(temp << remain); filtered = filtered | temp; } offset_ += read_bits; *value = filtered; } //------------------------------------------------------------------------------ bool BitStream::ReadBits(void* output, size_t read_bits, size_t output_size) const { // warning check boundary in usage case ZeroMemory(output, output_size); if (read_bits == 0) { return true; //TODO more thinking! }; const int total_bits = static_cast(buffer_end_ - buffer_ptr_) << 3; int remains = total_bits - offset_; if (remains <= 0 || (ulong)remains < read_bits) { assert(!"index out of ranges"); return false; } uint16_t* offset_d2 = reinterpret_cast(output); while (16 <= read_bits) { _ReadBitsUnit(offset_d2, 16); ++offset_d2; read_bits -= 16; } uint8_t* offset_d1 = reinterpret_cast(offset_d2); while (8 <= read_bits) { _ReadBitsUnit(offset_d1, 8); ++offset_d1; read_bits -= 8; } if (read_bits != 0) { _ReadBitsUnit(offset_d1, static_cast(read_bits)); }; return true; } //==================================================================================================