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