Use absl::variant to reduce storage space of structured header items
Protected by none.
PiperOrigin-RevId: 478056092
diff --git a/quiche/common/structured_headers.cc b/quiche/common/structured_headers.cc
index b348c22..3ab0058 100644
--- a/quiche/common/structured_headers.cc
+++ b/quiche/common/structured_headers.cc
@@ -720,37 +720,30 @@
} // namespace
Item::Item() {}
-Item::Item(const std::string& value, Item::ItemType type)
- : type_(type), string_value_(value) {}
-Item::Item(std::string&& value, Item::ItemType type)
- : type_(type), string_value_(std::move(value)) {
- QUICHE_CHECK(type_ == kStringType || type_ == kTokenType ||
- type_ == kByteSequenceType);
+Item::Item(std::string value, Item::ItemType type) {
+ switch (type) {
+ case kStringType:
+ value_.emplace<kStringType>(std::move(value));
+ break;
+ case kTokenType:
+ value_.emplace<kTokenType>(std::move(value));
+ break;
+ case kByteSequenceType:
+ value_.emplace<kByteSequenceType>(std::move(value));
+ break;
+ default:
+ QUICHE_CHECK(false);
+ break;
+ }
}
Item::Item(const char* value, Item::ItemType type)
: Item(std::string(value), type) {}
-Item::Item(int64_t value) : type_(kIntegerType), integer_value_(value) {}
-Item::Item(double value) : type_(kDecimalType), decimal_value_(value) {}
-Item::Item(bool value) : type_(kBooleanType), boolean_value_(value) {}
+Item::Item(int64_t value) : value_(value) {}
+Item::Item(double value) : value_(value) {}
+Item::Item(bool value) : value_(value) {}
bool operator==(const Item& lhs, const Item& rhs) {
- if (lhs.type_ != rhs.type_) return false;
- switch (lhs.type_) {
- case Item::kNullType:
- return true;
- case Item::kStringType:
- case Item::kTokenType:
- case Item::kByteSequenceType:
- return lhs.string_value_ == rhs.string_value_;
- case Item::kIntegerType:
- return lhs.integer_value_ == rhs.integer_value_;
- case Item::kDecimalType:
- return lhs.decimal_value_ == rhs.decimal_value_;
- case Item::kBooleanType:
- return lhs.boolean_value_ == rhs.boolean_value_;
- }
- QUICHE_NOTREACHED();
- return false;
+ return lhs.value_ == rhs.value_;
}
ParameterizedItem::ParameterizedItem(const ParameterizedItem&) = default;
diff --git a/quiche/common/structured_headers.h b/quiche/common/structured_headers.h
index f0eda84..844f673 100644
--- a/quiche/common/structured_headers.h
+++ b/quiche/common/structured_headers.h
@@ -13,6 +13,7 @@
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
+#include "absl/types/variant.h"
#include "quiche/common/platform/api/quiche_export.h"
#include "quiche/common/platform/api/quiche_logging.h"
@@ -73,8 +74,7 @@
// Constructors for string-like items: Strings, Tokens and Byte Sequences.
Item(const char* value, Item::ItemType type = kStringType);
- Item(const std::string& value, Item::ItemType type = kStringType);
- Item(std::string&& value, Item::ItemType type = kStringType);
+ Item(std::string value, Item::ItemType type = kStringType);
QUICHE_EXPORT_PRIVATE friend bool operator==(const Item& lhs,
const Item& rhs);
@@ -82,43 +82,49 @@
return !(lhs == rhs);
}
- bool is_null() const { return type_ == kNullType; }
- bool is_integer() const { return type_ == kIntegerType; }
- bool is_decimal() const { return type_ == kDecimalType; }
- bool is_string() const { return type_ == kStringType; }
- bool is_token() const { return type_ == kTokenType; }
- bool is_byte_sequence() const { return type_ == kByteSequenceType; }
- bool is_boolean() const { return type_ == kBooleanType; }
+ bool is_null() const { return Type() == kNullType; }
+ bool is_integer() const { return Type() == kIntegerType; }
+ bool is_decimal() const { return Type() == kDecimalType; }
+ bool is_string() const { return Type() == kStringType; }
+ bool is_token() const { return Type() == kTokenType; }
+ bool is_byte_sequence() const { return Type() == kByteSequenceType; }
+ bool is_boolean() const { return Type() == kBooleanType; }
int64_t GetInteger() const {
- QUICHE_CHECK_EQ(type_, kIntegerType);
- return integer_value_;
+ const auto* value = absl::get_if<int64_t>(&value_);
+ QUICHE_CHECK(value);
+ return *value;
}
double GetDecimal() const {
- QUICHE_CHECK_EQ(type_, kDecimalType);
- return decimal_value_;
+ const auto* value = absl::get_if<double>(&value_);
+ QUICHE_CHECK(value);
+ return *value;
}
bool GetBoolean() const {
- QUICHE_CHECK_EQ(type_, kBooleanType);
- return boolean_value_;
+ const auto* value = absl::get_if<bool>(&value_);
+ QUICHE_CHECK(value);
+ return *value;
}
// TODO(iclelland): Split up accessors for String, Token and Byte Sequence.
const std::string& GetString() const {
- QUICHE_CHECK(type_ == kStringType || type_ == kTokenType ||
- type_ == kByteSequenceType);
- return string_value_;
+ struct Visitor {
+ const std::string* operator()(const absl::monostate&) { return nullptr; }
+ const std::string* operator()(const int64_t&) { return nullptr; }
+ const std::string* operator()(const double&) { return nullptr; }
+ const std::string* operator()(const std::string& value) { return &value; }
+ const std::string* operator()(const bool&) { return nullptr; }
+ };
+ const std::string* value = absl::visit(Visitor(), value_);
+ QUICHE_CHECK(value);
+ return *value;
}
- ItemType Type() const { return type_; }
+ ItemType Type() const { return static_cast<ItemType>(value_.index()); }
private:
- ItemType type_ = kNullType;
- // TODO(iclelland): Make this class more memory-efficient, replacing the
- // values here with a union or std::variant (when available).
- int64_t integer_value_ = 0;
- std::string string_value_;
- double decimal_value_;
- bool boolean_value_;
+ absl::variant<absl::monostate, int64_t, double, std::string, std::string,
+ std::string, bool>
+ value_;
};
// Holds a ParameterizedIdentifier (draft 9 only). The contained Item must be a