From 2695dd408908a242e2766149db6ebadd4ac037da Mon Sep 17 00:00:00 2001 From: Edwin Wu Date: Tue, 11 Nov 2025 17:38:36 -0800 Subject: [PATCH] [BLEREFACTOR]:Refactor byte_utils global functions PiperOrigin-RevId: 831134984 --- .../implementation/base_endpoint_channel.cc | 28 ++------ connections/listeners.h | 2 +- connections/listeners_test.cc | 7 +- internal/platform/byte_utils.cc | 34 ++++++++- internal/platform/byte_utils.h | 29 ++++---- internal/platform/byte_utils_test.cc | 69 +++++++++++++++++-- 6 files changed, 121 insertions(+), 48 deletions(-) diff --git a/connections/implementation/base_endpoint_channel.cc b/connections/implementation/base_endpoint_channel.cc index a4aac598..b34785d0 100644 --- a/connections/implementation/base_endpoint_channel.cc +++ b/connections/implementation/base_endpoint_channel.cc @@ -31,6 +31,7 @@ #include "connections/implementation/offline_frames.h" #include "internal/flags/nearby_flags.h" #include "internal/platform/byte_array.h" +#include "internal/platform/byte_utils.h" #include "internal/platform/exception.h" #include "internal/platform/implementation/system_clock.h" #include "internal/platform/input_stream.h" @@ -49,38 +50,17 @@ using ::location::nearby::proto::connections::Medium::BLE_L2CAP; using DisconnectionReason = ::location::nearby::proto::connections::DisconnectionReason; -std::int32_t BytesToInt(const ByteArray& bytes) { - const char* int_bytes = bytes.data(); - - std::int32_t result = 0; - result |= (static_cast(int_bytes[0]) & 0x0FF) << 24; - result |= (static_cast(int_bytes[1]) & 0x0FF) << 16; - result |= (static_cast(int_bytes[2]) & 0x0FF) << 8; - result |= (static_cast(int_bytes[3]) & 0x0FF); - - return result; -} - -ByteArray IntToBytes(std::int32_t value) { - char int_bytes[sizeof(std::int32_t)]; - int_bytes[0] = static_cast((value >> 24) & 0x0FF); - int_bytes[1] = static_cast((value >> 16) & 0x0FF); - int_bytes[2] = static_cast((value >> 8) & 0x0FF); - int_bytes[3] = static_cast((value) & 0x0FF); - - return ByteArray(int_bytes, sizeof(int_bytes)); -} - ExceptionOr ReadInt(InputStream* reader) { ExceptionOr read_bytes = reader->ReadExactly(sizeof(std::int32_t)); if (!read_bytes.ok()) { return ExceptionOr(read_bytes.exception()); } - return ExceptionOr(BytesToInt(std::move(read_bytes.result()))); + return ExceptionOr( + byte_utils::BytesToInt(std::move(read_bytes.result()))); } Exception WriteInt(OutputStream* writer, std::int32_t value) { - return writer->Write(IntToBytes(value)); + return writer->Write(byte_utils::IntToBytes(value)); } } // namespace diff --git a/connections/listeners.h b/connections/listeners.h index ad909594..2a3aeca6 100644 --- a/connections/listeners.h +++ b/connections/listeners.h @@ -49,7 +49,7 @@ using ResultCallback = absl::AnyInvocable; struct ConnectionResponseInfo { std::string GetAuthenticationDigits() { - return ByteUtils::ToFourDigitString(raw_authentication_token); + return byte_utils::ToFourDigitString(raw_authentication_token); } ByteArray remote_endpoint_info; diff --git a/connections/listeners_test.cc b/connections/listeners_test.cc index 0f5cd34a..3ff7bdfe 100644 --- a/connections/listeners_test.cc +++ b/connections/listeners_test.cc @@ -14,13 +14,14 @@ #include "connections/listeners.h" -#include #include #include -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" +#include "absl/strings/string_view.h" +#include "connections/medium_selector.h" +#include "connections/payload.h" +#include "connections/status.h" #include "internal/platform/byte_array.h" namespace nearby { diff --git a/internal/platform/byte_utils.cc b/internal/platform/byte_utils.cc index d3bc4230..09e91b2c 100644 --- a/internal/platform/byte_utils.cc +++ b/internal/platform/byte_utils.cc @@ -14,6 +14,7 @@ #include "internal/platform/byte_utils.h" +#include #include #include @@ -22,8 +23,18 @@ #include "internal/platform/stream_reader.h" namespace nearby { +namespace byte_utils { -std::string ByteUtils::ToFourDigitString(ByteArray& bytes) { +namespace { +// The biggest prime number under 10000, used as a mod base to trim integers +// into 4 digits. +constexpr int kHashBasePrime = 9973; + +// The hash multiplier. +constexpr int kHashBaseMultiplier = 31; +} // namespace + +std::string ToFourDigitString(const ByteArray& bytes) { int multiplier = 1; int hashCode = 0; @@ -36,4 +47,25 @@ std::string ByteUtils::ToFourDigitString(ByteArray& bytes) { return absl::StrFormat("%04d", abs(hashCode)); } +int32_t BytesToInt(const ByteArray& bytes) { + const char* int_bytes = bytes.data(); + int32_t result = 0; + for (int i = 0; i < bytes.size() && i < 4; ++i) { + result <<= 8; + result |= static_cast(int_bytes[i]) & 0x0FF; + } + return result; +} + +ByteArray IntToBytes(int32_t value) { + ByteArray result(sizeof(int32_t)); + char* buffer = result.data(); + buffer[0] = static_cast((value >> 24) & 0x0FF); + buffer[1] = static_cast((value >> 16) & 0x0FF); + buffer[2] = static_cast((value >> 8) & 0x0FF); + buffer[3] = static_cast(value & 0x0FF); + return result; +} + +} // namespace byte_utils } // namespace nearby diff --git a/internal/platform/byte_utils.h b/internal/platform/byte_utils.h index a69ef2d3..3a4c4ce5 100644 --- a/internal/platform/byte_utils.h +++ b/internal/platform/byte_utils.h @@ -15,23 +15,28 @@ #ifndef PLATFORM_BASE_BYTE_UTILS_H_ #define PLATFORM_BASE_BYTE_UTILS_H_ +#include #include + #include "internal/platform/byte_array.h" -namespace nearby { +// TODO(edwinwu): Remove this namespace and move all the functions into +// ByteArray class. +namespace nearby::byte_utils { -class ByteUtils { - public: - static std::string ToFourDigitString(ByteArray& bytes); +// Generates a four-digit numeric string representation of a byte array. +std::string ToFourDigitString(const ByteArray& bytes); - private: - // The biggest prime number under 10000, used as a mod base to trim integers - // into 4 digits. - static constexpr int kHashBasePrime = 9973; - // The hash multiplier. - static constexpr int kHashBaseMultiplier = 31; -}; +// Converts a ByteArray to a 32-bit integer in big-endian format. +// It reads min(4, bytes.size()) bytes from input ByteArray; bytes[0] is +// read as MSB, bytes[1] as second byte, and so on. If bytes.size() < 4, +// bytes will be read to high order bytes of result and low order bytes +// will be 0. +int32_t BytesToInt(const ByteArray& bytes); -} // namespace nearby +// Converts a 32-bit integer to a 4-byte ByteArray in big-endian format. +ByteArray IntToBytes(int32_t value); + +} // namespace nearby::byte_utils #endif // PLATFORM_BASE_BYTE_UTILS_H_ diff --git a/internal/platform/byte_utils_test.cc b/internal/platform/byte_utils_test.cc index 8b604972..4b560251 100644 --- a/internal/platform/byte_utils_test.cc +++ b/internal/platform/byte_utils_test.cc @@ -14,7 +14,9 @@ #include "internal/platform/byte_utils.h" +#include #include +#include #include "gtest/gtest.h" #include "absl/strings/string_view.h" @@ -26,12 +28,12 @@ constexpr absl::string_view kFooBytes{"rawABCDE"}; constexpr absl::string_view kFooFourDigitsToken{"0392"}; constexpr absl::string_view kEmptyFourDigitsToken{"0000"}; constexpr absl::string_view kNegativeBytes{"raw\xd5\x01\xe4\x03\x81"}; -constexpr absl::string_view kNegativeFourDigitsToken{"9084"}; +constexpr absl::string_view kNegativeFourDigitsToken{"6251"}; TEST(ByteUtilsTest, ToFourDigitStringCorrect) { ByteArray bytes{std::string(kFooBytes)}; - auto four_digit_string = ByteUtils::ToFourDigitString(bytes); + auto four_digit_string = byte_utils::ToFourDigitString(bytes); EXPECT_EQ(std::string(kFooFourDigitsToken), four_digit_string); } @@ -39,17 +41,70 @@ TEST(ByteUtilsTest, ToFourDigitStringCorrect) { TEST(ByteUtilsTest, ToFourDigitStringNegativeCorrect) { ByteArray bytes{std::string(kNegativeBytes)}; - auto four_digit_string = ByteUtils::ToFourDigitString(bytes); + auto four_digit_string = byte_utils::ToFourDigitString(bytes); - EXPECT_EQ(std::string(kNegativeFourDigitsToken), kNegativeFourDigitsToken); + EXPECT_EQ(std::string(kNegativeFourDigitsToken), four_digit_string); } -TEST(ByteUtilsTest, TestEmptyByteArrayCorrect) { - ByteArray bytes; +TEST(ByteUtilsTest, ToFourDigitStringHandlesEmptyInput) { + ByteArray bytes{}; - auto four_digit_string = ByteUtils::ToFourDigitString(bytes); + auto four_digit_string = byte_utils::ToFourDigitString(bytes); EXPECT_EQ(std::string(kEmptyFourDigitsToken), four_digit_string); } +TEST(ByteUtilsTest, IntToBytesThenBytesToIntIsSymmetric) { + constexpr std::int32_t kTestValue = 123456789; + + ByteArray bytes = byte_utils::IntToBytes(kTestValue); + + EXPECT_EQ(kTestValue, byte_utils::BytesToInt(bytes)); +} + +TEST(ByteUtilsTest, IntToBytesThenBytesToIntIsSymmetricNegative) { + constexpr std::int32_t kTestValue = -123456789; + + ByteArray bytes = byte_utils::IntToBytes(kTestValue); + + EXPECT_EQ(kTestValue, byte_utils::BytesToInt(bytes)); +} + +TEST(ByteUtilsTest, BytesToIntHandlesZero) { + ByteArray bytes({'\0', '\0', '\0', '\0'}); + EXPECT_EQ(0, byte_utils::BytesToInt(bytes)); +} + +TEST(ByteUtilsTest, BytesToIntHandlesNegative) { + ByteArray bytes({'\xff', '\xff', '\xff', '\xff'}); + EXPECT_EQ(-1, byte_utils::BytesToInt(bytes)); +} + +TEST(ByteUtilsTest, BytesToIntHandlesNegativeLarge) { + ByteArray bytes({'\x80', '\x00', '\x00', '\x00'}); + EXPECT_EQ(std::numeric_limits::min(), + byte_utils::BytesToInt(bytes)); +} + +TEST(ByteUtilsTest, IntToBytesHandlesZero) { + ByteArray expected_bytes({'\0', '\0', '\0', '\0'}); + EXPECT_EQ(expected_bytes, byte_utils::IntToBytes(0)); +} + +TEST(ByteUtilsTest, HandlesInt32Max) { + constexpr std::int32_t kMaxValue = std::numeric_limits::max(); + + ByteArray bytes = byte_utils::IntToBytes(kMaxValue); + + EXPECT_EQ(kMaxValue, byte_utils::BytesToInt(bytes)); +} + +TEST(ByteUtilsTest, HandlesInt32Min) { + constexpr std::int32_t kMinValue = std::numeric_limits::min(); + + ByteArray bytes = byte_utils::IntToBytes(kMinValue); + + EXPECT_EQ(kMinValue, byte_utils::BytesToInt(bytes)); +} + } // namespace nearby