Add a convenient kBufferSize member to QuicInlinedStringView This CL also makes minor corrections to the class's contract and clarifies the property tests. PiperOrigin-RevId: 770313484
diff --git a/quiche/quic/core/quic_inlined_string_view.h b/quiche/quic/core/quic_inlined_string_view.h index 23d01fc..d3e2a92 100644 --- a/quiche/quic/core/quic_inlined_string_view.h +++ b/quiche/quic/core/quic_inlined_string_view.h
@@ -18,25 +18,28 @@ namespace quic { // QuicInlinedStringView<kSize> is a class that is similar to absl::string_view, -// with a notable distinction that it can inline up to `kSize` characters -// (between 15 and 127). +// with a notable distinction that it can inline up to `kSize - 1` characters +// (between 15 and 253 characters). // // Important use notes: // - QuicInlinedStringView makes no assumptions about ownership of non-inlined // data; its primary purpose is to be a building block for other data // structures. // - Unlike a regular string_view, the data pointer for QuicInlinedStringView -// will start pointing to a different location if inlined. -// - The string will be inlined iff its size is strictly below kSize; this is -// a guaranteeed API behavior. +// will start pointing to a different location if the string is inlined and +// non-empty. For empty strings, the data pointer is always nullptr. +// - The string will be inlined iff its size is strictly below kSize; this is a +// guaranteed API behavior. template <size_t kSize> class QUICHE_NO_EXPORT QuicInlinedStringView { public: - // The largest size of a string that can be inlined. + // The largest size of a string that can be inlined by + // `QuicInlinedStringView<kSize>`. static constexpr size_t kMaxInlinedSize = kSize - 1; + static constexpr size_t kBufferSize = kSize; static_assert(kSize >= 16); - static_assert(kSize < 255); + static_assert(kSize <= 254); QuicInlinedStringView() { clear(); } explicit QuicInlinedStringView(absl::string_view source) {
diff --git a/quiche/quic/core/quic_inlined_string_view_fuzz_test.cc b/quiche/quic/core/quic_inlined_string_view_fuzz_test.cc index d330853..61260d0 100644 --- a/quiche/quic/core/quic_inlined_string_view_fuzz_test.cc +++ b/quiche/quic/core/quic_inlined_string_view_fuzz_test.cc
@@ -29,28 +29,29 @@ EXPECT_EQ(quic_view.size(), view.size()); EXPECT_EQ(quic_view.view(), view); EXPECT_EQ(quic_view.IsInlined(), view.size() < kSize); + EXPECT_EQ(quic_view.data() == nullptr, view.empty()); QuicInlinedStringView<kSize> quic_view_copy(quic_view); EXPECT_EQ(quic_view_copy.empty(), view.empty()); EXPECT_EQ(quic_view_copy.size(), view.size()); EXPECT_EQ(quic_view_copy.view(), view); EXPECT_EQ(quic_view_copy.IsInlined(), view.size() < kSize); + EXPECT_EQ(quic_view_copy.data() == nullptr, view.empty()); } static void IsEmptyAfterClear(absl::string_view view) { QuicInlinedStringView<kSize> quic_view(view); quic_view.clear(); EXPECT_TRUE(quic_view.empty()); + EXPECT_EQ(quic_view.size(), 0); + EXPECT_TRUE(quic_view.IsInlined()); } - static void DifferentDataPointersWhenInlined(absl::string_view view) { + static void NonEmptyStringHasDifferentDataPointerWhenInlined( + absl::string_view view) { QuicInlinedStringView<kSize> quic_view(view); - if (!quic_view.empty()) { - const bool pointers_equal = view.data() == quic_view.data(); - EXPECT_EQ(!pointers_equal, quic_view.IsInlined()); - } else { - EXPECT_EQ(quic_view.data(), nullptr); - } + const bool pointers_equal = view.data() == quic_view.data(); + EXPECT_EQ(!pointers_equal, quic_view.IsInlined()); } }; @@ -61,21 +62,21 @@ // - The value of 254 was chosen because it's the largest value supported by // `QuicInlinedStringView`. constexpr size_t kRealisticSize = - decltype(BufferedSliceInlining::slice)::kMaxInlinedSize + 1; + decltype(BufferedSliceInlining::slice)::kBufferSize; static_assert(kRealisticSize == 16); -void NeverCrashes16(absl::string_view view) { +void AccessorsAreCorrect16(absl::string_view view) { Properties<16>::AccessorsAreCorrect(view); } -void NeverCrashes24(absl::string_view view) { +void AccessorsAreCorrect24(absl::string_view view) { Properties<24>::AccessorsAreCorrect(view); } -void NeverCrashes254(absl::string_view view) { +void AccessorsAreCorrect254(absl::string_view view) { Properties<254>::AccessorsAreCorrect(view); } -FUZZ_TEST(QuicInlinedStringViewTest, NeverCrashes16); -FUZZ_TEST(QuicInlinedStringViewTest, NeverCrashes24); -FUZZ_TEST(QuicInlinedStringViewTest, NeverCrashes254); +FUZZ_TEST(QuicInlinedStringViewFuzzTest, AccessorsAreCorrect16); +FUZZ_TEST(QuicInlinedStringViewFuzzTest, AccessorsAreCorrect24); +FUZZ_TEST(QuicInlinedStringViewFuzzTest, AccessorsAreCorrect254); void IsEmptyAfterClear16(absl::string_view view) { Properties<16>::IsEmptyAfterClear(view); @@ -86,22 +87,31 @@ void IsEmptyAfterClear254(absl::string_view view) { Properties<254>::IsEmptyAfterClear(view); } -FUZZ_TEST(QuicInlinedStringViewTest, IsEmptyAfterClear16); -FUZZ_TEST(QuicInlinedStringViewTest, IsEmptyAfterClear24); -FUZZ_TEST(QuicInlinedStringViewTest, IsEmptyAfterClear254); +FUZZ_TEST(QuicInlinedStringViewFuzzTest, IsEmptyAfterClear16); +FUZZ_TEST(QuicInlinedStringViewFuzzTest, IsEmptyAfterClear24); +FUZZ_TEST(QuicInlinedStringViewFuzzTest, IsEmptyAfterClear254); -void DifferentDataPointersWhenInlined16(absl::string_view view) { - Properties<16>::DifferentDataPointersWhenInlined(view); +void NonEmptyStringHasDifferentDataPointerWhenInlined16( + absl::string_view view) { + Properties<16>::NonEmptyStringHasDifferentDataPointerWhenInlined(view); } -void DifferentDataPointersWhenInlined24(absl::string_view view) { - Properties<24>::DifferentDataPointersWhenInlined(view); +void NonEmptyStringHasDifferentDataPointerWhenInlined24( + absl::string_view view) { + Properties<24>::NonEmptyStringHasDifferentDataPointerWhenInlined(view); } -void DifferentDataPointersWhenInlined254(absl::string_view view) { - Properties<254>::DifferentDataPointersWhenInlined(view); +void NonEmptyStringHasDifferentDataPointerWhenInlined254( + absl::string_view view) { + Properties<254>::NonEmptyStringHasDifferentDataPointerWhenInlined(view); } -FUZZ_TEST(QuicInlinedStringViewTest, DifferentDataPointersWhenInlined16); -FUZZ_TEST(QuicInlinedStringViewTest, DifferentDataPointersWhenInlined24); -FUZZ_TEST(QuicInlinedStringViewTest, DifferentDataPointersWhenInlined254); +FUZZ_TEST(QuicInlinedStringViewFuzzTest, + NonEmptyStringHasDifferentDataPointerWhenInlined16) + .WithDomains(fuzztest::Arbitrary<std::string>().WithMinSize(1)); +FUZZ_TEST(QuicInlinedStringViewFuzzTest, + NonEmptyStringHasDifferentDataPointerWhenInlined24) + .WithDomains(fuzztest::Arbitrary<std::string>().WithMinSize(1)); +FUZZ_TEST(QuicInlinedStringViewFuzzTest, + NonEmptyStringHasDifferentDataPointerWhenInlined254) + .WithDomains(fuzztest::Arbitrary<std::string>().WithMinSize(1)); } // namespace } // namespace quic
diff --git a/quiche/quic/core/quic_inlined_string_view_test.cc b/quiche/quic/core/quic_inlined_string_view_test.cc index 66b062a..f717087 100644 --- a/quiche/quic/core/quic_inlined_string_view_test.cc +++ b/quiche/quic/core/quic_inlined_string_view_test.cc
@@ -70,5 +70,29 @@ reinterpret_cast<uintptr_t>(view_external_copy.data())); } +TEST(QuicInlinedStringViewTest, IsEmptyAfterClear) { + QuicInlinedStringView<24> view("foo"); + view.clear(); + ASSERT_TRUE(view.empty()); + ASSERT_EQ(view.size(), 0); + ASSERT_TRUE(view.IsInlined()); +} + +TEST(QuicInlinedStringViewTest, + NonEmptyStringHasDifferentDataPointerWhenInlined) { + absl::string_view view = "foo"; + QuicInlinedStringView<24> quic_view(view); + EXPECT_TRUE(quic_view.IsInlined()); + EXPECT_NE(view.data(), quic_view.data()); +} + +TEST(QuicInlinedStringViewTest, + NonEmptyStringHasSameDataPointerWhenNotInlined) { + std::string big_string(300, 'a'); + QuicInlinedStringView<24> quic_view(big_string); + EXPECT_FALSE(quic_view.IsInlined()); + EXPECT_EQ(quic_view.data(), big_string.data()); +} + } // namespace } // namespace quic