read bits from base stream

PiperOrigin-RevId: 726515524
This commit is contained in:
Guogang Li
2025-02-13 09:17:14 -08:00
committed by Copybara-Service
parent 00e6b231f6
commit 788984f182
5 changed files with 97 additions and 0 deletions
+1
View File
@@ -514,6 +514,7 @@ let package = Package(
"internal/platform/feature_flags_test.cc",
"internal/platform/cancelable_alarm_test.cc",
"internal/platform/crypto_test.cc",
"internal/platform/base_input_stream_test.cc",
"internal/platform/byte_array_test.cc",
"internal/platform/bluetooth_utils_test.cc",
"internal/platform/credential_storage_impl_test.cc",
+1
View File
@@ -397,6 +397,7 @@ cc_test(
cc_test(
name = "platform_util_test",
srcs = [
"base_input_stream_test.cc",
"byte_utils_test.cc",
],
deps = [
+25
View File
@@ -38,6 +38,27 @@ ExceptionOr<ByteArray> BaseInputStream::Read(std::int64_t size) {
}
}
std::optional<std::uint8_t> BaseInputStream::ReadBits(int bits) {
if (bits > 8) {
return std::nullopt;
}
if (bits_unused_ == 0) {
if (!IsAvailable(1)) {
return std::nullopt;
}
bits_buffer_ = (uint8_t)buffer_.data()[position_++];
bits_unused_ = 8;
}
if (bits_unused_ < bits) {
return std::nullopt;
}
uint8_t mask = (1 << bits) - 1;
uint8_t value = (bits_buffer_ >> (bits_unused_ - bits)) & mask;
bits_unused_ -= bits;
return value;
}
std::optional<std::uint8_t> BaseInputStream::ReadUint8() {
constexpr int byte_size = sizeof(std::uint8_t);
std::optional<ByteArray> read_bytes = ReadBytes(byte_size);
@@ -153,6 +174,10 @@ std::optional<std::int64_t> BaseInputStream::ReadInt64() {
}
std::optional<ByteArray> BaseInputStream::ReadBytes(int size) {
if (bits_unused_ != 0) {
return std::nullopt;
}
ExceptionOr<ByteArray> read_bytes_result = Read(size);
if (!read_bytes_result.ok()) {
return std::nullopt;
+5
View File
@@ -47,6 +47,9 @@ class BaseInputStream : public InputStream {
return {Exception::kSuccess};
}
// Reads less than 8 bits from the stream, returning the value if available.
// The read bits cannot across a byte boundary.
std::optional<std::uint8_t> ReadBits(int bits);
std::optional<std::uint8_t> ReadUint8();
std::optional<std::int8_t> ReadInt8();
std::optional<std::uint16_t> ReadUint16();
@@ -62,6 +65,8 @@ class BaseInputStream : public InputStream {
}
private:
uint8_t bits_unused_{0};
uint8_t bits_buffer_{0};
ByteArray &buffer_;
size_t position_{0};
};
@@ -0,0 +1,65 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/base_input_stream.h"
#include <cstdint>
#include <string>
#include "gtest/gtest.h"
#include "internal/platform/byte_array.h"
namespace nearby {
namespace {
TEST(BaseInputStreamTest, ReadBits) {
std::string data{static_cast<char>(0b01011100)};
ByteArray byte_array(data);
BaseInputStream stream{byte_array};
EXPECT_EQ(stream.ReadBits(1), 0);
EXPECT_EQ(stream.ReadBits(2), 2);
EXPECT_EQ(stream.ReadBits(3), 7);
EXPECT_FALSE(stream.ReadBits(5).has_value());
EXPECT_EQ(stream.ReadBits(2), 0);
EXPECT_FALSE(stream.ReadBits(1).has_value());
}
TEST(BaseInputStreamTest, ReadBitsExceedsByteBoundary) {
std::string data = "ab";
ByteArray byte_array(data);
BaseInputStream stream{byte_array};
EXPECT_FALSE(stream.ReadBits(9).has_value());
EXPECT_EQ(stream.ReadBits(1), 0);
EXPECT_FALSE(stream.ReadInt16().has_value());
}
TEST(BaseInputStreamTest, ReadUintValues) {
std::string data = "\xff\xf1\x0f\x0e\x01\x02\x01\x01\x01\x02\x03\x04\x05\x06";
ByteArray byte_array(data);
BaseInputStream stream{byte_array};
EXPECT_EQ(stream.ReadUint16(), 0xfff1);
EXPECT_EQ(stream.ReadUint32(), 0x0f0e0102);
EXPECT_EQ(stream.ReadUint64(), 0x0101010203040506);
}
TEST(BaseInputStreamTest, ReadIntValues) {
std::string data = "\xff\xf1\x0f\x0e\x01\x02\x01\x01\x01\x02\x03\x04\x05\x06";
ByteArray byte_array(data);
BaseInputStream stream{byte_array};
EXPECT_EQ(stream.ReadInt16(), static_cast<int16_t>(0xfff1));
EXPECT_EQ(stream.ReadInt32(), static_cast<int32_t>(0x0f0e0102));
EXPECT_EQ(stream.ReadInt64(), static_cast<int64_t>(0x0101010203040506));
}
} // namespace
} // namespace nearby