Inroduce BitstreamReader class to parse sequences of bits

With intent to replace BitBuffer.
This version is optimised for binary size and readability of the parsers
at the cost of slower parsing of invalid bitstreams

Bug: None
Change-Id: Ib054e2a7758b9a69cbf2559e739465b104a7dcf3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/230244
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#34886}
diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn
index 809bb4a..ac1b813 100644
--- a/rtc_base/BUILD.gn
+++ b/rtc_base/BUILD.gn
@@ -36,6 +36,23 @@
   }
 }
 
+rtc_source_set("bitstream_reader") {
+  sources = [
+    "bitstream_reader.cc",
+    "bitstream_reader.h",
+  ]
+  deps = [
+    ":checks",
+    ":safe_conversions",
+    "../api:array_view",
+  ]
+  absl_deps = [
+    "//third_party/abseil-cpp/absl/base:core_headers",
+    "//third_party/abseil-cpp/absl/numeric:bits",
+    "//third_party/abseil-cpp/absl/strings",
+  ]
+}
+
 rtc_source_set("compile_assert_c") {
   sources = [ "compile_assert_c.h" ]
 }
@@ -1323,6 +1340,7 @@
         "atomic_ops_unittest.cc",
         "base64_unittest.cc",
         "bit_buffer_unittest.cc",
+        "bitstream_reader_unittest.cc",
         "bounded_inline_vector_unittest.cc",
         "buffer_queue_unittest.cc",
         "buffer_unittest.cc",
@@ -1366,6 +1384,7 @@
         sources += [ "win/windows_version_unittest.cc" ]
       }
       deps = [
+        ":bitstream_reader",
         ":bounded_inline_vector",
         ":checks",
         ":criticalsection",
@@ -1406,6 +1425,7 @@
       absl_deps = [
         "//third_party/abseil-cpp/absl/base:core_headers",
         "//third_party/abseil-cpp/absl/memory",
+        "//third_party/abseil-cpp/absl/numeric:bits",
         "//third_party/abseil-cpp/absl/types:optional",
       ]
     }
diff --git a/rtc_base/bitstream_reader.cc b/rtc_base/bitstream_reader.cc
new file mode 100644
index 0000000..0bb6049
--- /dev/null
+++ b/rtc_base/bitstream_reader.cc
@@ -0,0 +1,133 @@
+/*
+ *  Copyright 2021 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/bitstream_reader.h"
+
+#include <stdint.h>
+
+#include "absl/numeric/bits.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+
+uint64_t BitstreamReader::ReadBits(int bits) {
+  RTC_DCHECK_GE(bits, 0);
+  RTC_DCHECK_LE(bits, 64);
+  set_last_read_is_verified(false);
+
+  if (remaining_bits_ < bits) {
+    remaining_bits_ -= bits;
+    return 0;
+  }
+
+  int remaining_bits_in_first_byte = remaining_bits_ % 8;
+  remaining_bits_ -= bits;
+  if (bits < remaining_bits_in_first_byte) {
+    // Reading fewer bits than what's left in the current byte, just
+    // return the portion of this byte that is needed.
+    int offset = (remaining_bits_in_first_byte - bits);
+    return ((*bytes_) >> offset) & ((1 << bits) - 1);
+  }
+
+  uint64_t result = 0;
+  if (remaining_bits_in_first_byte > 0) {
+    // Read all bits that were left in the current byte and consume that byte.
+    bits -= remaining_bits_in_first_byte;
+    uint8_t mask = (1 << remaining_bits_in_first_byte) - 1;
+    result = static_cast<uint64_t>(*bytes_ & mask) << bits;
+    ++bytes_;
+  }
+
+  // Read as many full bytes as we can.
+  while (bits >= 8) {
+    bits -= 8;
+    result |= uint64_t{*bytes_} << bits;
+    ++bytes_;
+  }
+  // Whatever is left to read is smaller than a byte, so grab just the needed
+  // bits and shift them into the lowest bits.
+  if (bits > 0) {
+    result |= (*bytes_ >> (8 - bits));
+  }
+  return result;
+}
+
+int BitstreamReader::ReadBit() {
+  set_last_read_is_verified(false);
+  --remaining_bits_;
+  if (remaining_bits_ < 0) {
+    return 0;
+  }
+
+  int bit_position = remaining_bits_ % 8;
+  if (bit_position == 0) {
+    // Read the last bit from current byte and move to the next byte.
+    return (*bytes_++) & 0x01;
+  }
+
+  return (*bytes_ >> bit_position) & 0x01;
+}
+
+void BitstreamReader::ConsumeBits(int bits) {
+  RTC_DCHECK_GE(bits, 0);
+  set_last_read_is_verified(false);
+
+  int remaining_bytes = (remaining_bits_ + 7) / 8;
+  remaining_bits_ -= bits;
+  int new_remaining_bytes = (remaining_bits_ + 7) / 8;
+  // When `remaining_bits_` is negative, `BitstreamReader` is in failure state
+  // and `bytes_' member no longer used, thus its value doesn't matter.
+  // In such case it doesn't matter that negative integer division rounds up
+  // instead of down and thus this byte adjustement might seem incorrect.
+  bytes_ += (remaining_bytes - new_remaining_bytes);
+}
+
+uint32_t BitstreamReader::ReadNonSymmetric(uint32_t num_values) {
+  RTC_DCHECK_GT(num_values, 0);
+  RTC_DCHECK_LE(num_values, uint32_t{1} << 31);
+
+  int width = absl::bit_width(num_values);
+  uint32_t num_min_bits_values = (uint32_t{1} << width) - num_values;
+
+  uint64_t val = ReadBits(width - 1);
+  if (val < num_min_bits_values) {
+    return val;
+  }
+  return (val << 1) + ReadBit() - num_min_bits_values;
+}
+
+uint32_t BitstreamReader::ReadExponentialGolomb() {
+  // Count the number of leading 0.
+  int zero_bit_count = 0;
+  while (ReadBit() == 0) {
+    if (++zero_bit_count >= 32) {
+      // Golob value won't fit into 32 bits of the return value. Fail the parse.
+      Invalidate();
+      return 0;
+    }
+  }
+
+  // The bit count of the value is the number of zeros + 1.
+  // However the first '1' was already read above.
+  return (uint32_t{1} << zero_bit_count) +
+         rtc::dchecked_cast<uint32_t>(ReadBits(zero_bit_count)) - 1;
+}
+
+int BitstreamReader::ReadSignedExponentialGolomb() {
+  uint32_t unsigned_val = ReadExponentialGolomb();
+  if ((unsigned_val & 1) == 0) {
+    return -static_cast<int>(unsigned_val / 2);
+  } else {
+    return (unsigned_val + 1) / 2;
+  }
+}
+
+}  // namespace webrtc
diff --git a/rtc_base/bitstream_reader.h b/rtc_base/bitstream_reader.h
new file mode 100644
index 0000000..8c0f66f
--- /dev/null
+++ b/rtc_base/bitstream_reader.h
@@ -0,0 +1,142 @@
+/*
+ *  Copyright 2021 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_BITSTREAM_READER_H_
+#define RTC_BASE_BITSTREAM_READER_H_
+
+#include <stdint.h>
+
+#include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+
+// A class to parse sequence of bits. Byte order is assumed big-endian/network.
+// This class is optimized for successful parsing and binary size.
+// Individual calls to `Read` and `ConsumeBits` never fail. Instead they may
+// change the class state into 'failure state'. User of this class should verify
+// parsing by checking if class is in that 'failure state' by calling `Ok`.
+// That verification can be done once after multiple reads.
+class BitstreamReader {
+ public:
+  explicit BitstreamReader(
+      rtc::ArrayView<const uint8_t> bytes ABSL_ATTRIBUTE_LIFETIME_BOUND);
+  explicit BitstreamReader(
+      absl::string_view bytes ABSL_ATTRIBUTE_LIFETIME_BOUND);
+  BitstreamReader(const BitstreamReader&) = default;
+  BitstreamReader& operator=(const BitstreamReader&) = default;
+  ~BitstreamReader();
+
+  // Return number of unread bits in the buffer, or negative number if there
+  // was a reading error.
+  int RemainingBitCount() const;
+
+  // Returns `true` iff all calls to `Read` and `ConsumeBits` were successful.
+  bool Ok() const { return RemainingBitCount() >= 0; }
+
+  // Sets `BitstreamReader` into the failure state.
+  void Invalidate() { remaining_bits_ = -1; }
+
+  // Moves current read position forward. `bits` must be non-negative.
+  void ConsumeBits(int bits);
+
+  // Reads single bit. Returns 0 or 1.
+  ABSL_MUST_USE_RESULT int ReadBit();
+
+  // Reads `bits` from the bitstream. `bits` must be in range [0, 64].
+  // Returns an unsigned integer in range [0, 2^bits - 1].
+  // On failure sets `BitstreamReader` into the failure state and returns 0.
+  ABSL_MUST_USE_RESULT uint64_t ReadBits(int bits);
+
+  // Reads unsigned integer of fixed width.
+  template <typename T,
+            typename std::enable_if<std::is_unsigned<T>::value &&
+                                    sizeof(T) <= 8>::type* = nullptr>
+  ABSL_MUST_USE_RESULT T Read() {
+    return rtc::dchecked_cast<T>(ReadBits(sizeof(T) * 8));
+  }
+
+  // Reads single bit as boolean.
+  template <>
+  ABSL_MUST_USE_RESULT bool Read<bool>() {
+    return ReadBit() != 0;
+  }
+
+  // Reads value in range [0, `num_values` - 1].
+  // This encoding is similar to ReadBits(val, Ceil(Log2(num_values)),
+  // but reduces wastage incurred when encoding non-power of two value ranges
+  // Non symmetric values are encoded as:
+  // 1) n = bit_width(num_values)
+  // 2) k = (1 << n) - num_values
+  // Value v in range [0, k - 1] is encoded in (n-1) bits.
+  // Value v in range [k, num_values - 1] is encoded as (v+k) in n bits.
+  // https://aomediacodec.github.io/av1-spec/#nsn
+  uint32_t ReadNonSymmetric(uint32_t num_values);
+
+  // Reads exponential golomb encoded value.
+  // On failure sets `BitstreamReader` into the failure state and returns
+  // unspecified value.
+  // Exponential golomb values are encoded as:
+  // 1) x = source val + 1
+  // 2) In binary, write [bit_width(x) - 1] 0s, then x
+  // To decode, we count the number of leading 0 bits, read that many + 1 bits,
+  // and increment the result by 1.
+  // Fails the parsing if the value wouldn't fit in a uint32_t.
+  uint32_t ReadExponentialGolomb();
+
+  // Reads signed exponential golomb values at the current offset. Signed
+  // exponential golomb values are just the unsigned values mapped to the
+  // sequence 0, 1, -1, 2, -2, etc. in order.
+  // On failure sets `BitstreamReader` into the failure state and returns
+  // unspecified value.
+  int ReadSignedExponentialGolomb();
+
+ private:
+  void set_last_read_is_verified(bool value) const;
+
+  // Next byte with at least one unread bit.
+  const uint8_t* bytes_;
+
+  // Number of bits remained to read.
+  int remaining_bits_;
+
+  // Unused in release mode.
+  mutable bool last_read_is_verified_ = true;
+};
+
+inline BitstreamReader::BitstreamReader(rtc::ArrayView<const uint8_t> bytes)
+    : bytes_(bytes.data()), remaining_bits_(bytes.size() * 8) {}
+
+inline BitstreamReader::BitstreamReader(absl::string_view bytes)
+    : bytes_(reinterpret_cast<const uint8_t*>(bytes.data())),
+      remaining_bits_(bytes.size() * 8) {}
+
+inline BitstreamReader::~BitstreamReader() {
+  RTC_DCHECK(last_read_is_verified_) << "Latest calls to Read or ConsumeBit "
+                                        "were not checked with Ok function.";
+}
+
+inline void BitstreamReader::set_last_read_is_verified(bool value) const {
+#ifdef RTC_DCHECK_IS_ON
+  last_read_is_verified_ = value;
+#endif
+}
+
+inline int BitstreamReader::RemainingBitCount() const {
+  set_last_read_is_verified(true);
+  return remaining_bits_;
+}
+
+}  // namespace webrtc
+
+#endif  // RTC_BASE_BITSTREAM_READER_H_
diff --git a/rtc_base/bitstream_reader_unittest.cc b/rtc_base/bitstream_reader_unittest.cc
new file mode 100644
index 0000000..45c4eca
--- /dev/null
+++ b/rtc_base/bitstream_reader_unittest.cc
@@ -0,0 +1,335 @@
+/*
+ *  Copyright 2021 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/bitstream_reader.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <array>
+#include <limits>
+
+#include "absl/numeric/bits.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "rtc_base/checks.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+TEST(BitstreamReaderTest, InDebugModeRequiresToCheckOkStatusBeforeDestruction) {
+  const uint8_t bytes[32] = {};
+  absl::optional<BitstreamReader> reader(absl::in_place, bytes);
+
+  EXPECT_GE(reader->ReadBits(7), 0u);
+#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(OS_ANDROID)
+  EXPECT_DEATH(reader = absl::nullopt, "");
+#endif
+  EXPECT_TRUE(reader->Ok());
+  reader = absl::nullopt;
+}
+
+TEST(BitstreamReaderTest, InDebugModeMayCheckRemainingBitsInsteadOfOkStatus) {
+  const uint8_t bytes[32] = {};
+  absl::optional<BitstreamReader> reader(absl::in_place, bytes);
+
+  EXPECT_GE(reader->ReadBit(), 0);
+#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(OS_ANDROID)
+  EXPECT_DEATH(reader = absl::nullopt, "");
+#endif
+  EXPECT_GE(reader->RemainingBitCount(), 0);
+  reader = absl::nullopt;
+}
+
+TEST(BitstreamReaderTest, ConsumeBits) {
+  const uint8_t bytes[32] = {};
+  BitstreamReader reader(bytes);
+
+  int total_bits = 32 * 8;
+  EXPECT_EQ(reader.RemainingBitCount(), total_bits);
+  reader.ConsumeBits(3);
+  total_bits -= 3;
+  EXPECT_EQ(reader.RemainingBitCount(), total_bits);
+  reader.ConsumeBits(3);
+  total_bits -= 3;
+  EXPECT_EQ(reader.RemainingBitCount(), total_bits);
+  reader.ConsumeBits(15);
+  total_bits -= 15;
+  EXPECT_EQ(reader.RemainingBitCount(), total_bits);
+  reader.ConsumeBits(67);
+  total_bits -= 67;
+  EXPECT_EQ(reader.RemainingBitCount(), total_bits);
+  EXPECT_TRUE(reader.Ok());
+
+  reader.ConsumeBits(32 * 8);
+  EXPECT_FALSE(reader.Ok());
+  EXPECT_LT(reader.RemainingBitCount(), 0);
+}
+
+TEST(BitstreamReaderTest, ReadBit) {
+  const uint8_t bytes[] = {0b0100'0001, 0b1011'0001};
+  BitstreamReader reader(bytes);
+  // First byte.
+  EXPECT_EQ(reader.ReadBit(), 0);
+  EXPECT_EQ(reader.ReadBit(), 1);
+  EXPECT_EQ(reader.ReadBit(), 0);
+  EXPECT_EQ(reader.ReadBit(), 0);
+
+  EXPECT_EQ(reader.ReadBit(), 0);
+  EXPECT_EQ(reader.ReadBit(), 0);
+  EXPECT_EQ(reader.ReadBit(), 0);
+  EXPECT_EQ(reader.ReadBit(), 1);
+
+  // Second byte.
+  EXPECT_EQ(reader.ReadBit(), 1);
+  EXPECT_EQ(reader.ReadBit(), 0);
+  EXPECT_EQ(reader.ReadBit(), 1);
+  EXPECT_EQ(reader.ReadBit(), 1);
+
+  EXPECT_EQ(reader.ReadBit(), 0);
+  EXPECT_EQ(reader.ReadBit(), 0);
+  EXPECT_EQ(reader.ReadBit(), 0);
+  EXPECT_EQ(reader.ReadBit(), 1);
+
+  EXPECT_TRUE(reader.Ok());
+  // Try to read beyound the buffer.
+  EXPECT_EQ(reader.ReadBit(), 0);
+  EXPECT_FALSE(reader.Ok());
+}
+
+TEST(BitstreamReaderTest, ReadBoolConsumesSingleBit) {
+  const uint8_t bytes[] = {0b1010'1010};
+  BitstreamReader reader(bytes);
+  ASSERT_EQ(reader.RemainingBitCount(), 8);
+  EXPECT_TRUE(reader.Read<bool>());
+  EXPECT_EQ(reader.RemainingBitCount(), 7);
+}
+
+TEST(BitstreamReaderTest, ReadBytesAligned) {
+  const uint8_t bytes[] = {0x0A,        //
+                           0xBC,        //
+                           0xDE, 0xF1,  //
+                           0x23, 0x45, 0x67, 0x89};
+  BitstreamReader reader(bytes);
+  EXPECT_EQ(reader.Read<uint8_t>(), 0x0Au);
+  EXPECT_EQ(reader.Read<uint8_t>(), 0xBCu);
+  EXPECT_EQ(reader.Read<uint16_t>(), 0xDEF1u);
+  EXPECT_EQ(reader.Read<uint32_t>(), 0x23456789u);
+  EXPECT_TRUE(reader.Ok());
+}
+
+TEST(BitstreamReaderTest, ReadBytesOffset4) {
+  const uint8_t bytes[] = {0x0A, 0xBC, 0xDE, 0xF1, 0x23,
+                           0x45, 0x67, 0x89, 0x0A};
+  BitstreamReader reader(bytes);
+  reader.ConsumeBits(4);
+
+  EXPECT_EQ(reader.Read<uint8_t>(), 0xABu);
+  EXPECT_EQ(reader.Read<uint8_t>(), 0xCDu);
+  EXPECT_EQ(reader.Read<uint16_t>(), 0xEF12u);
+  EXPECT_EQ(reader.Read<uint32_t>(), 0x34567890u);
+  EXPECT_TRUE(reader.Ok());
+}
+
+TEST(BitstreamReaderTest, ReadBytesOffset3) {
+  // The pattern we'll check against is counting down from 0b1111. It looks
+  // weird here because it's all offset by 3.
+  // Byte pattern is:
+  //    56701234
+  //  0b00011111,
+  //  0b11011011,
+  //  0b10010111,
+  //  0b01010011,
+  //  0b00001110,
+  //  0b11001010,
+  //  0b10000110,
+  //  0b01000010
+  //       xxxxx <-- last 5 bits unused.
+
+  // The bytes. It almost looks like counting down by two at a time, except the
+  // jump at 5->3->0, since that's when the high bit is turned off.
+  const uint8_t bytes[] = {0x1F, 0xDB, 0x97, 0x53, 0x0E, 0xCA, 0x86, 0x42};
+
+  BitstreamReader reader(bytes);
+  reader.ConsumeBits(3);
+  EXPECT_EQ(reader.Read<uint8_t>(), 0xFEu);
+  EXPECT_EQ(reader.Read<uint16_t>(), 0xDCBAu);
+  EXPECT_EQ(reader.Read<uint32_t>(), 0x98765432u);
+  EXPECT_TRUE(reader.Ok());
+
+  // 5 bits left unread. Not enough to read a uint8_t.
+  EXPECT_EQ(reader.RemainingBitCount(), 5);
+  EXPECT_EQ(reader.Read<uint8_t>(), 0);
+  EXPECT_FALSE(reader.Ok());
+}
+
+TEST(BitstreamReaderTest, ReadBits) {
+  const uint8_t bytes[] = {0b010'01'101, 0b0011'00'1'0};
+  BitstreamReader reader(bytes);
+  EXPECT_EQ(reader.ReadBits(3), 0b010u);
+  EXPECT_EQ(reader.ReadBits(2), 0b01u);
+  EXPECT_EQ(reader.ReadBits(7), 0b101'0011u);
+  EXPECT_EQ(reader.ReadBits(2), 0b00u);
+  EXPECT_EQ(reader.ReadBits(1), 0b1u);
+  EXPECT_EQ(reader.ReadBits(1), 0b0u);
+  EXPECT_TRUE(reader.Ok());
+
+  EXPECT_EQ(reader.ReadBits(1), 0u);
+  EXPECT_FALSE(reader.Ok());
+}
+
+TEST(BitstreamReaderTest, ReadZeroBits) {
+  BitstreamReader reader(rtc::ArrayView<const uint8_t>(nullptr, 0));
+
+  EXPECT_EQ(reader.ReadBits(0), 0u);
+  EXPECT_TRUE(reader.Ok());
+}
+
+TEST(BitstreamReaderTest, ReadBitFromEmptyArray) {
+  BitstreamReader reader(rtc::ArrayView<const uint8_t>(nullptr, 0));
+
+  // Trying to read from the empty array shouldn't dereference the pointer,
+  // i.e. shouldn't crash.
+  EXPECT_EQ(reader.ReadBit(), 0);
+  EXPECT_FALSE(reader.Ok());
+}
+
+TEST(BitstreamReaderTest, ReadBitsFromEmptyArray) {
+  BitstreamReader reader(rtc::ArrayView<const uint8_t>(nullptr, 0));
+
+  // Trying to read from the empty array shouldn't dereference the pointer,
+  // i.e. shouldn't crash.
+  EXPECT_EQ(reader.ReadBits(1), 0u);
+  EXPECT_FALSE(reader.Ok());
+}
+
+TEST(BitstreamReaderTest, ReadBits64) {
+  const uint8_t bytes[] = {0x4D, 0x32, 0xAB, 0x54, 0x00, 0xFF, 0xFE, 0x01,
+                           0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89};
+  BitstreamReader reader(bytes);
+
+  EXPECT_EQ(reader.ReadBits(33), 0x4D32AB5400FFFE01u >> (64 - 33));
+
+  constexpr uint64_t kMask31Bits = (1ull << 32) - 1;
+  EXPECT_EQ(reader.ReadBits(31), 0x4D32AB5400FFFE01ull & kMask31Bits);
+
+  EXPECT_EQ(reader.ReadBits(64), 0xABCDEF0123456789ull);
+  EXPECT_TRUE(reader.Ok());
+
+  // Nothing more to read.
+  EXPECT_EQ(reader.ReadBit(), 0);
+  EXPECT_FALSE(reader.Ok());
+}
+
+TEST(BitstreamReaderTest, CanPeekBitsUsingCopyConstructor) {
+  // BitstreamReader doesn't have peek function. To simulate it, user may use
+  // cheap BitstreamReader copy constructor.
+  const uint8_t bytes[] = {0x0A, 0xBC};
+  BitstreamReader reader(bytes);
+  reader.ConsumeBits(4);
+  ASSERT_EQ(reader.RemainingBitCount(), 12);
+
+  BitstreamReader peeker = reader;
+  EXPECT_EQ(peeker.ReadBits(8), 0xABu);
+  EXPECT_EQ(peeker.RemainingBitCount(), 4);
+
+  EXPECT_EQ(reader.RemainingBitCount(), 12);
+  // Can resume reading from before peeker was created.
+  EXPECT_EQ(reader.ReadBits(4), 0xAu);
+  EXPECT_EQ(reader.RemainingBitCount(), 8);
+}
+
+TEST(BitstreamReaderTest,
+     ReadNonSymmetricSameNumberOfBitsWhenNumValuesPowerOf2) {
+  const uint8_t bytes[2] = {0xf3, 0xa0};
+  BitstreamReader reader(bytes);
+
+  ASSERT_EQ(reader.RemainingBitCount(), 16);
+  EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0xfu);
+  EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0x3u);
+  EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0xau);
+  EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0x0u);
+  EXPECT_EQ(reader.RemainingBitCount(), 0);
+  EXPECT_TRUE(reader.Ok());
+}
+
+TEST(BitstreamReaderTest, ReadNonSymmetricOnlyValueConsumesZeroBits) {
+  const uint8_t bytes[2] = {};
+  BitstreamReader reader(bytes);
+
+  ASSERT_EQ(reader.RemainingBitCount(), 16);
+  EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1), 0u);
+  EXPECT_EQ(reader.RemainingBitCount(), 16);
+}
+
+std::array<uint8_t, 8> GolombEncoded(uint32_t val) {
+  int val_width = absl::bit_width(val + 1);
+  int total_width = 2 * val_width - 1;
+  uint64_t representation = (uint64_t{val} + 1) << (64 - total_width);
+  std::array<uint8_t, 8> result;
+  for (int i = 0; i < 8; ++i) {
+    result[i] = representation >> (7 - i) * 8;
+  }
+  return result;
+}
+
+TEST(BitstreamReaderTest, GolombUint32Values) {
+  // Test over the uint32_t 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_t>::max() / 20000;
+  for (uint32_t i = 0; i < std::numeric_limits<uint32_t>::max() - kStep;
+       i += kStep) {
+    std::array<uint8_t, 8> buffer = GolombEncoded(i);
+    BitstreamReader reader(buffer);
+    // Use assert instead of EXPECT to avoid spamming thousands of failed
+    // expectation when this test fails.
+    ASSERT_EQ(reader.ReadExponentialGolomb(), i);
+    EXPECT_TRUE(reader.Ok());
+  }
+}
+
+TEST(BitstreamReaderTest, SignedGolombValues) {
+  uint8_t golomb_bits[][1] = {
+      {0b1'0000000}, {0b010'00000}, {0b011'00000}, {0b00100'000}, {0b00111'000},
+  };
+  int expected[] = {0, 1, -1, 2, -3};
+  for (size_t i = 0; i < sizeof(golomb_bits); ++i) {
+    BitstreamReader reader(golomb_bits[i]);
+    EXPECT_EQ(reader.ReadSignedExponentialGolomb(), expected[i])
+        << "Mismatch in expected/decoded value for golomb_bits[" << i
+        << "]: " << static_cast<int>(golomb_bits[i][0]);
+    EXPECT_TRUE(reader.Ok());
+  }
+}
+
+TEST(BitstreamReaderTest, NoGolombOverread) {
+  const uint8_t bytes[] = {0x00, 0xFF, 0xFF};
+  // Make sure the bit buffer correctly enforces byte length on golomb reads.
+  // If it didn't, the above buffer would be valid at 3 bytes.
+  BitstreamReader reader1(rtc::MakeArrayView(bytes, 1));
+  // When parse fails, `ReadExponentialGolomb` may return any number.
+  reader1.ReadExponentialGolomb();
+  EXPECT_FALSE(reader1.Ok());
+
+  BitstreamReader reader2(rtc::MakeArrayView(bytes, 2));
+  reader2.ReadExponentialGolomb();
+  EXPECT_FALSE(reader2.Ok());
+
+  BitstreamReader reader3(bytes);
+  // Golomb should have read 9 bits, so 0x01FF, and since it is golomb, the
+  // result is 0x01FF - 1 = 0x01FE.
+  EXPECT_EQ(reader3.ReadExponentialGolomb(), 0x01FEu);
+  EXPECT_TRUE(reader3.Ok());
+}
+
+}  // namespace
+}  // namespace webrtc