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