Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Pimenov <m@maps.me>2015-07-15 17:04:19 +0300
committerAlex Zolotarev <alex@maps.me>2015-09-23 02:56:23 +0300
commit4b670d0671e6172ad41048ab8048a6a1a508902e (patch)
tree43e9da9292d7f29037b4e2f5ab44731b89cc4874 /coding/bit_streams.hpp
parentc82b3e927f383a5a77863bd58b74ac1bbdc3675d (diff)
[omim] [coding] BitReader and BitWriter.
Diffstat (limited to 'coding/bit_streams.hpp')
-rw-r--r--coding/bit_streams.hpp141
1 files changed, 113 insertions, 28 deletions
diff --git a/coding/bit_streams.hpp b/coding/bit_streams.hpp
index 93d585f696..2751403cbf 100644
--- a/coding/bit_streams.hpp
+++ b/coding/bit_streams.hpp
@@ -1,42 +1,127 @@
-// Author: Artyom Polkovnikov.
-// Bits source and sink for sequential read and write of bits.
-
#pragma once
+#include "std/algorithm.hpp"
#include "std/cstdint.hpp"
+#include "std/limits.hpp"
+
+#include "base/assert.hpp"
+#include "base/logging.hpp"
-// Forward declarations.
-class Reader;
-class Writer;
+namespace
+{
+uint64_t const kByteMask = (static_cast<uint64_t>(1) << CHAR_BIT) - 1;
+} // namespace
-class BitSink
+template <typename TWriter>
+class BitWriter
{
public:
- BitSink(Writer & writer);
- // Note! Last byte is flushed in destructor.
- ~BitSink();
- uint64_t NumBitsWritten() const { return m_size; }
- // Write writeSize number of bits from least significant side of bits number.
- void Write(uint64_t bits, uint32_t writeSize);
+ BitWriter(TWriter & writer) : m_writer(writer), m_buf(0), m_bitsWritten(0) {}
+
+ ~BitWriter()
+ {
+ try
+ {
+ Flush();
+ }
+ catch (...)
+ {
+ LOG(LWARNING, ("Caught an exception when flushing BitWriter."));
+ }
+ }
+
+ // Writes up to CHAR_BIT-1 last bits if they have not been written yet
+ // and pads them with zeros.
+ void Flush()
+ {
+ if (m_bitsWritten % CHAR_BIT != 0)
+ m_writer.Write(&m_buf, 1);
+ }
+
+ // Returns the number of bits that have been sent to BitWriter,
+ // including those that are in m_buf and are possibly
+ // not flushed yet.
+ uint64_t BitsWritten() const { return m_bitsWritten; }
+
+ // Writes n bits starting with the least significant bit.
+ // They are written one byte at a time so endianness is of no concern.
+ // All the other bits except for the first n must be set to zero.
+ void Write(uint8_t bits, uint32_t n)
+ {
+ if (n == 0)
+ return;
+ CHECK_LESS_OR_EQUAL(n, CHAR_BIT, ());
+ uint32_t bufferedBits = m_bitsWritten % CHAR_BIT;
+ m_bitsWritten += n;
+ if (n + bufferedBits > 8)
+ {
+ uint8_t b = (bits << bufferedBits) | m_buf;
+ m_writer.Write(&b, 1);
+ m_buf = bits >> (8 - bufferedBits);
+ }
+ else
+ {
+ if (bufferedBits > 0)
+ {
+ bits = (bits << bufferedBits) | m_buf;
+ n += bufferedBits;
+ }
+ if (n == CHAR_BIT)
+ {
+ m_writer.Write(&bits, 1);
+ bits = 0;
+ }
+ m_buf = bits;
+ }
+ }
+
private:
- Writer & m_writer;
- uint8_t m_lastByte;
- uint64_t m_size;
- uint64_t m_totalBits;
+ TWriter & m_writer;
+ uint8_t m_buf;
+ uint64_t m_bitsWritten;
};
-class BitSource
+template <typename TReader>
+class BitReader
{
public:
- BitSource(Reader & reader);
- uint64_t NumBitsRead() const { return m_totalBitsRead; }
- // Read readSize number of bits, return it as least significant bits of 64-bit number.
- uint64_t Read(uint32_t readSize);
+ BitReader(TReader & reader) : m_reader(reader), m_bitsRead(0), m_bufferedBits(0), m_buf(0) {}
+
+ // Returns the total number of bits read from this BitReader.
+ uint32_t BitsRead() const { return m_bitsRead; }
+
+ // Reads n bits and returns them as the least significant bits of an 8-bit number.
+ // The underlying m_reader is supposed to be byte-aligned (which is the
+ // case when it reads from the place that was written with BitWriter) because
+ // Read may use one lookahead byte.
+ uint8_t Read(uint32_t n)
+ {
+ if (n == 0)
+ return 0;
+ CHECK_LESS_OR_EQUAL(n, CHAR_BIT, ());
+ m_bitsRead += n;
+ uint8_t result = 0;
+ if (n <= m_bufferedBits)
+ {
+ result = m_buf & (kByteMask >> (CHAR_BIT - n));
+ m_bufferedBits -= n;
+ m_buf >>= n;
+ }
+ else
+ {
+ uint8_t nextByte;
+ m_reader.Read(&nextByte, 1);
+ uint32_t low = n - m_bufferedBits;
+ result = ((nextByte & (kByteMask >> (CHAR_BIT - low))) << m_bufferedBits) | m_buf;
+ m_buf = nextByte >> low;
+ m_bufferedBits = CHAR_BIT - low;
+ }
+ return result;
+ }
+
private:
- Reader & m_reader;
- uint64_t m_serialCur;
- uint64_t m_serialEnd;
- uint64_t m_bits;
- uint32_t m_bitsSize;
- uint64_t m_totalBitsRead;
+ TReader & m_reader;
+ uint32_t m_bitsRead;
+ uint32_t m_bufferedBits;
+ uint8_t m_buf;
};