Added a BitBufferWriter subclass that contains methods for writing bit and byte-sized data, along with exponential golomb encoded data.

This pattern (read-only base, writable subclass) was picked to maintain a *Buffer option that doesn't copy the source bits when parsing. ByteBuffer and Buffer both copy. I'm open to discussion on what the type relationship would be, though :)

Tests have been added to ensure the symmetric nature of read/write operations.

BUG=
R=bcornell@google.com, pthatcher@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/45259005

Cr-Commit-Position: refs/heads/master@{#9107}
diff --git a/webrtc/base/bitbuffer.cc b/webrtc/base/bitbuffer.cc
index f41962a..7530838 100644
--- a/webrtc/base/bitbuffer.cc
+++ b/webrtc/base/bitbuffer.cc
@@ -10,6 +10,7 @@
 
 #include "webrtc/base/bitbuffer.h"
 
+#include <algorithm>
 #include <limits>
 
 #include "webrtc/base/checks.h"
@@ -19,8 +20,7 @@
 // Returns the lowest (right-most) |bit_count| bits in |byte|.
 uint8 LowestBits(uint8 byte, size_t bit_count) {
   DCHECK_LE(bit_count, 8u);
-  uint8 mask_shift = 8 - static_cast<uint8>(bit_count);
-  return byte & (0xFF >> mask_shift);
+  return byte & ((1 << bit_count) - 1);
 }
 
 // Returns the highest (left-most) |bit_count| bits in |byte|, shifted to the
@@ -32,6 +32,41 @@
   return (byte & mask) >> shift;
 }
 
+// Returns the highest byte of |val| in a uint8.
+uint8 HighestByte(uint64 val) {
+  return static_cast<uint8>(val >> 56);
+}
+
+// Returns the result of writing partial data from |source|, of
+// |source_bit_count| size in the highest bits, to |target| at
+// |target_bit_offset| from the highest bit.
+uint8 WritePartialByte(uint8 source, size_t source_bit_count,
+                       uint8 target, size_t target_bit_offset) {
+  DCHECK(target_bit_offset < 8);
+  DCHECK(source_bit_count < 9);
+  DCHECK(source_bit_count <= (8 - target_bit_offset));
+  // Generate a mask for just the bits we're going to overwrite, so:
+  uint8 mask =
+      // The number of bits we want, in the most significant bits...
+      static_cast<uint8>(0xFF << (8 - source_bit_count))
+      // ...shifted over to the target offset from the most signficant bit.
+      >> target_bit_offset;
+
+  // We want the target, with the bits we'll overwrite masked off, or'ed with
+  // the bits from the source we want.
+  return (target & ~mask) | (source >> target_bit_offset);
+}
+
+// Counts the number of bits used in the binary representation of val.
+size_t CountBits(uint64 val) {
+  size_t bit_count = 0;
+  while (val != 0) {
+    bit_count++;
+    val >>= 1;
+  }
+  return bit_count;
+}
+
 }  // namespace
 
 namespace rtc {
@@ -143,12 +178,104 @@
   // read the value.
   size_t value_bit_count = zero_bit_count + 1;
   if (value_bit_count > 32 || !ReadBits(val, value_bit_count)) {
-    byte_offset_ = original_byte_offset;
-    bit_offset_ = original_bit_offset;
+    CHECK(Seek(original_byte_offset, original_bit_offset));
     return false;
   }
   *val -= 1;
   return true;
 }
 
+void BitBuffer::GetCurrentOffset(
+    size_t* out_byte_offset, size_t* out_bit_offset) {
+  CHECK(out_byte_offset != NULL);
+  CHECK(out_bit_offset != NULL);
+  *out_byte_offset = byte_offset_;
+  *out_bit_offset = bit_offset_;
+}
+
+bool BitBuffer::Seek(size_t byte_offset, size_t bit_offset) {
+  if (byte_offset > byte_count_ || bit_offset > 7 ||
+      (byte_offset == byte_count_ && bit_offset > 0)) {
+    return false;
+  }
+  byte_offset_ = byte_offset;
+  bit_offset_ = bit_offset;
+  return true;
+}
+
+BitBufferWriter::BitBufferWriter(uint8* bytes, size_t byte_count)
+  : BitBuffer(bytes, byte_count), writable_bytes_(bytes) {
+}
+
+bool BitBufferWriter::WriteUInt8(uint8 val) {
+  return WriteBits(val, sizeof(uint8) * 8);
+}
+
+bool BitBufferWriter::WriteUInt16(uint16 val) {
+  return WriteBits(val, sizeof(uint16) * 8);
+}
+
+bool BitBufferWriter::WriteUInt32(uint32 val) {
+  return WriteBits(val, sizeof(uint32) * 8);
+}
+
+bool BitBufferWriter::WriteBits(uint64 val, size_t bit_count) {
+  if (bit_count > RemainingBitCount()) {
+    return false;
+  }
+  size_t total_bits = bit_count;
+
+  // For simplicity, push the bits we want to read from val to the highest bits.
+  val <<= (sizeof(uint64) * 8 - bit_count);
+
+  uint8* bytes = writable_bytes_ + byte_offset_;
+
+  // The first byte is relatively special; the bit offset to write to may put us
+  // in the middle of the byte, and the total bit count to write may require we
+  // save the bits at the end of the byte.
+  size_t remaining_bits_in_current_byte = 8 - bit_offset_;
+  size_t bits_in_first_byte =
+      std::min(bit_count, remaining_bits_in_current_byte);
+  *bytes = WritePartialByte(
+      HighestByte(val), bits_in_first_byte, *bytes, bit_offset_);
+  if (bit_count <= remaining_bits_in_current_byte) {
+    // Nothing left to write, so quit early.
+    return ConsumeBits(total_bits);
+  }
+
+  // Subtract what we've written from the bit count, shift it off the value, and
+  // write the remaining full bytes.
+  val <<= bits_in_first_byte;
+  bytes++;
+  bit_count -= bits_in_first_byte;
+  while (bit_count >= 8) {
+    *bytes++ = HighestByte(val);
+    val <<= 8;
+    bit_count -= 8;
+  }
+
+  // Last byte may also be partial, so write the remaining bits from the top of
+  // val.
+  if (bit_count > 0) {
+    *bytes = WritePartialByte(HighestByte(val), bit_count, *bytes, 0);
+  }
+
+  // All done! Consume the bits we've written.
+  return ConsumeBits(total_bits);
+}
+
+bool BitBufferWriter::WriteExponentialGolomb(uint32 val) {
+  // We don't support reading UINT32_MAX, because it doesn't fit in a uint32
+  // when encoded, so don't support writing it either.
+  if (val == std::numeric_limits<uint32>::max()) {
+    return false;
+  }
+  uint64 val_to_encode = static_cast<uint64>(val) + 1;
+
+  // We need to write CountBits(val+1) 0s and then val+1. Since val (as a
+  // uint64) has leading zeros, we can just write the total golomb encoded size
+  // worth of bits, knowing the value will appear last.
+  return WriteBits(val_to_encode, CountBits(val_to_encode) * 2 - 1);
+}
+
 }  // namespace rtc
diff --git a/webrtc/base/bitbuffer.h b/webrtc/base/bitbuffer.h
index 356a817..5aa1f13 100644
--- a/webrtc/base/bitbuffer.h
+++ b/webrtc/base/bitbuffer.h
@@ -16,14 +16,20 @@
 namespace rtc {
 
 // A class, similar to ByteBuffer, that can parse bit-sized data out of a set of
-// bytes. Has a similar API to the read-only parts of ByteBuffer, plus methods
-// for reading bit-sized data and processing exponential golomb encoded data.
+// bytes. Has a similar API to ByteBuffer, plus methods for reading bit-sized
+// and exponential golomb encoded data. For a writable version, use
+// BitBufferWriter. Unlike ByteBuffer, this class doesn't make a copy of the
+// source bytes, so it can be used on read-only data.
 // Sizes/counts specify bits/bytes, for clarity.
 // Byte order is assumed big-endian/network.
 class BitBuffer {
  public:
   BitBuffer(const uint8* bytes, size_t byte_count);
 
+  // Gets the current offset, in bytes/bits, from the start of the buffer. The
+  // bit offset is the offset into the current byte, in the range [0,7].
+  void GetCurrentOffset(size_t* out_byte_offset, size_t* out_bit_offset);
+
   // The remaining bits in the byte buffer.
   uint64 RemainingBitCount() const;
 
@@ -34,14 +40,15 @@
   bool ReadUInt32(uint32* val);
 
   // Reads bit-sized values from the buffer. Returns false if there isn't enough
-  // data left for the specified type.
+  // data left for the specified bit count..
   bool ReadBits(uint32* val, size_t bit_count);
 
   // Peeks bit-sized values from the buffer. Returns false if there isn't enough
-  // data left for the specified type. Doesn't move the current read offset.
+  // data left for the specified number of bits. Doesn't move the current
+  // offset.
   bool PeekBits(uint32* val, size_t bit_count);
 
-  // Reads the exponential golomb encoded value at the current bit offset.
+  // Reads the exponential golomb encoded value at the current offset.
   // Exponential golomb values are encoded as:
   // 1) x = source val + 1
   // 2) In binary, write [countbits(x) - 1] 0s, then x
@@ -58,7 +65,11 @@
   // there aren't enough bits left in the buffer.
   bool ConsumeBits(size_t bit_count);
 
- private:
+  // Sets the current offset to the provied byte/bit offsets. The bit
+  // offset is from the given byte, in the range [0,7].
+  bool Seek(size_t byte_offset, size_t bit_offset);
+
+ protected:
   const uint8* const bytes_;
   // The total size of |bytes_|.
   size_t byte_count_;
@@ -70,6 +81,35 @@
   DISALLOW_COPY_AND_ASSIGN(BitBuffer);
 };
 
+// A BitBuffer API for write operations. Supports symmetric write APIs to the
+// reading APIs of BitBuffer. Note that the read/write offset is shared with the
+// BitBuffer API, so both reading and writing will consume bytes/bits.
+class BitBufferWriter : public BitBuffer {
+ public:
+  // Constructs a bit buffer for the writable buffer of |bytes|.
+  BitBufferWriter(uint8* bytes, size_t byte_count);
+
+  // Writes byte-sized values from the buffer. Returns false if there isn't
+  // enough data left for the specified type.
+  bool WriteUInt8(uint8 val);
+  bool WriteUInt16(uint16 val);
+  bool WriteUInt32(uint32 val);
+
+  // Writes bit-sized values to the buffer. Returns false if there isn't enough
+  // room left for the specified number of bits.
+  bool WriteBits(uint64 val, size_t bit_count);
+
+  // Writes the exponential golomb encoded version of the supplied value.
+  // Returns false if there isn't enough room left for the value.
+  bool WriteExponentialGolomb(uint32 val);
+
+ private:
+  // The buffer, as a writable array.
+  uint8* const writable_bytes_;
+
+  DISALLOW_COPY_AND_ASSIGN(BitBufferWriter);
+};
+
 }  // namespace rtc
 
 #endif  // WEBRTC_BASE_BITBUFFER_H_
diff --git a/webrtc/base/bitbuffer_unittest.cc b/webrtc/base/bitbuffer_unittest.cc
index 143ea6f..21cffd6 100644
--- a/webrtc/base/bitbuffer_unittest.cc
+++ b/webrtc/base/bitbuffer_unittest.cc
@@ -135,6 +135,39 @@
   EXPECT_FALSE(buffer.ReadBits(&val, 1));
 }
 
+TEST(BitBufferTest, SetOffsetValues) {
+  uint8 bytes[4] = {0};
+  BitBufferWriter buffer(bytes, 4);
+
+  size_t byte_offset, bit_offset;
+  // Bit offsets are [0,7].
+  EXPECT_TRUE(buffer.Seek(0, 0));
+  EXPECT_TRUE(buffer.Seek(0, 7));
+  buffer.GetCurrentOffset(&byte_offset, &bit_offset);
+  EXPECT_EQ(0u, byte_offset);
+  EXPECT_EQ(7u, bit_offset);
+  EXPECT_FALSE(buffer.Seek(0, 8));
+  buffer.GetCurrentOffset(&byte_offset, &bit_offset);
+  EXPECT_EQ(0u, byte_offset);
+  EXPECT_EQ(7u, bit_offset);
+  // Byte offsets are [0,length]. At byte offset length, the bit offset must be
+  // 0.
+  EXPECT_TRUE(buffer.Seek(0, 0));
+  EXPECT_TRUE(buffer.Seek(2, 4));
+  buffer.GetCurrentOffset(&byte_offset, &bit_offset);
+  EXPECT_EQ(2u, byte_offset);
+  EXPECT_EQ(4u, bit_offset);
+  EXPECT_TRUE(buffer.Seek(4, 0));
+  EXPECT_FALSE(buffer.Seek(5, 0));
+  buffer.GetCurrentOffset(&byte_offset, &bit_offset);
+  EXPECT_EQ(4u, byte_offset);
+  EXPECT_EQ(0u, bit_offset);
+  EXPECT_FALSE(buffer.Seek(4, 1));
+
+  // Passing a NULL out parameter is death.
+  EXPECT_DEATH(buffer.GetCurrentOffset(&byte_offset, NULL), "");
+}
+
 uint64 GolombEncoded(uint32 val) {
   val++;
   uint32 bit_counter = val;
@@ -146,19 +179,23 @@
   return static_cast<uint64>(val) << (64 - (bit_count * 2 - 1));
 }
 
-TEST(BitBufferTest, GolombString) {
-  char test_string[] = "my precious";
-  for (size_t i = 0; i < ARRAY_SIZE(test_string); ++i) {
-    uint64 encoded_val = GolombEncoded(test_string[i]);
-    // Use ByteBuffer to convert to bytes, to account for endianness (BitBuffer
-    // requires network order).
-    ByteBuffer byteBuffer;
+TEST(BitBufferTest, GolombUint32Values) {
+  ByteBuffer byteBuffer;
+  byteBuffer.Resize(16);
+  BitBuffer buffer(reinterpret_cast<const uint8*>(byteBuffer.Data()),
+                   byteBuffer.Capacity());
+  // Test over the uint32 range with a large enough step that the test doesn't
+  // take forever. Around 20,000 iterations should do.
+  const int kStep = std::numeric_limits<uint32>::max() / 20000;
+  for (uint32 i = 0; i < std::numeric_limits<uint32>::max() - kStep;
+       i += kStep) {
+    uint64 encoded_val = GolombEncoded(i);
+    byteBuffer.Clear();
     byteBuffer.WriteUInt64(encoded_val);
-    BitBuffer buffer(reinterpret_cast<const uint8*>(byteBuffer.Data()),
-                     byteBuffer.Length());
     uint32 decoded_val;
+    EXPECT_TRUE(buffer.Seek(0, 0));
     EXPECT_TRUE(buffer.ReadExponentialGolomb(&decoded_val));
-    EXPECT_EQ(test_string[i], static_cast<char>(decoded_val));
+    EXPECT_EQ(i, decoded_val);
   }
 }
 
@@ -180,4 +217,87 @@
   EXPECT_EQ(0x01FEu, decoded_val);
 }
 
+TEST(BitBufferWriterTest, SymmetricReadWrite) {
+  uint8 bytes[16] = {0};
+  BitBufferWriter buffer(bytes, 4);
+
+  // Write some bit data at various sizes.
+  EXPECT_TRUE(buffer.WriteBits(0x2u, 3));
+  EXPECT_TRUE(buffer.WriteBits(0x1u, 2));
+  EXPECT_TRUE(buffer.WriteBits(0x53u, 7));
+  EXPECT_TRUE(buffer.WriteBits(0x0u, 2));
+  EXPECT_TRUE(buffer.WriteBits(0x1u, 1));
+  EXPECT_TRUE(buffer.WriteBits(0x1ABCDu, 17));
+  // That should be all that fits in the buffer.
+  EXPECT_FALSE(buffer.WriteBits(1, 1));
+
+  EXPECT_TRUE(buffer.Seek(0, 0));
+  uint32 val;
+  EXPECT_TRUE(buffer.ReadBits(&val, 3));
+  EXPECT_EQ(0x2u, val);
+  EXPECT_TRUE(buffer.ReadBits(&val, 2));
+  EXPECT_EQ(0x1u, val);
+  EXPECT_TRUE(buffer.ReadBits(&val, 7));
+  EXPECT_EQ(0x53u, val);
+  EXPECT_TRUE(buffer.ReadBits(&val, 2));
+  EXPECT_EQ(0x0u, val);
+  EXPECT_TRUE(buffer.ReadBits(&val, 1));
+  EXPECT_EQ(0x1u, val);
+  EXPECT_TRUE(buffer.ReadBits(&val, 17));
+  EXPECT_EQ(0x1ABCDu, val);
+  // And there should be nothing left.
+  EXPECT_FALSE(buffer.ReadBits(&val, 1));
+}
+
+TEST(BitBufferWriterTest, SymmetricBytesMisaligned) {
+  uint8 bytes[16] = {0};
+  BitBufferWriter buffer(bytes, 16);
+
+  // Offset 3, to get things misaligned.
+  EXPECT_TRUE(buffer.ConsumeBits(3));
+  EXPECT_TRUE(buffer.WriteUInt8(0x12u));
+  EXPECT_TRUE(buffer.WriteUInt16(0x3456u));
+  EXPECT_TRUE(buffer.WriteUInt32(0x789ABCDEu));
+
+  buffer.Seek(0, 3);
+  uint8 val8;
+  uint16 val16;
+  uint32 val32;
+  EXPECT_TRUE(buffer.ReadUInt8(&val8));
+  EXPECT_EQ(0x12u, val8);
+  EXPECT_TRUE(buffer.ReadUInt16(&val16));
+  EXPECT_EQ(0x3456u, val16);
+  EXPECT_TRUE(buffer.ReadUInt32(&val32));
+  EXPECT_EQ(0x789ABCDEu, val32);
+}
+
+TEST(BitBufferWriterTest, SymmetricGolomb) {
+  char test_string[] = "my precious";
+  uint8 bytes[64] = {0};
+  BitBufferWriter buffer(bytes, 64);
+  for (size_t i = 0; i < ARRAY_SIZE(test_string); ++i) {
+    EXPECT_TRUE(buffer.WriteExponentialGolomb(test_string[i]));
+  }
+  buffer.Seek(0, 0);
+  for (size_t i = 0; i < ARRAY_SIZE(test_string); ++i) {
+    uint32 val;
+    EXPECT_TRUE(buffer.ReadExponentialGolomb(&val));
+    EXPECT_LE(val, std::numeric_limits<uint8>::max());
+    EXPECT_EQ(test_string[i], static_cast<char>(val));
+  }
+}
+
+TEST(BitBufferWriterTest, WriteClearsBits) {
+  uint8 bytes[] = {0xFF, 0xFF};
+  BitBufferWriter buffer(bytes, 2);
+  EXPECT_TRUE(buffer.ConsumeBits(3));
+  EXPECT_TRUE(buffer.WriteBits(0, 1));
+  EXPECT_EQ(0xEFu, bytes[0]);
+  EXPECT_TRUE(buffer.WriteBits(0, 3));
+  EXPECT_EQ(0xE1u, bytes[0]);
+  EXPECT_TRUE(buffer.WriteBits(0, 2));
+  EXPECT_EQ(0xE0u, bytes[0]);
+  EXPECT_EQ(0x7F, bytes[1]);
+}
+
 }  // namespace rtc