[iwyu] Further reduce metadata_batch.h footprint by moving implementations to .cc file (#29595)

* Cleanup

* iwyu

* fix

* Add flag

* sweep1

* fixes

* speedup

* fixes

* fix

* fix

* fix

* Cleanup

* Automated change: Fix sanity tests

* Automated change: Fix sanity tests

* fix

* fix

* fix

* fix

* fix

* fix

* x

* x

* Automated change: Fix sanity tests

Co-authored-by: ctiller <ctiller@users.noreply.github.com>
pull/29624/head
Craig Tiller 3 years ago committed by GitHub
parent ecde2a9f26
commit acc8128b76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      src/core/ext/transport/chttp2/transport/writing.cc
  2. 258
      src/core/lib/transport/metadata_batch.cc
  3. 344
      src/core/lib/transport/metadata_batch.h
  4. 2
      src/core/lib/transport/parsed_metadata.h

@ -49,7 +49,6 @@
#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/chunked_vector.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/gprpp/ref_counted.h"

@ -16,13 +16,271 @@
#include "src/core/lib/transport/metadata_batch.h"
#include <string.h>
#include <algorithm>
#include "absl/strings/escaping.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/timeout_encoding.h"
namespace grpc_core {
namespace metadata_detail {
void DebugStringBuilder::Add(absl::string_view key, absl::string_view value) {
if (!out_.empty()) out_.append(", ");
absl::StrAppend(&out_, absl::CEscape(key), ": ", absl::CEscape(value));
}
void UnknownMap::Append(absl::string_view key, Slice value) {
unknown_.EmplaceBack(Slice::FromCopiedString(key), value.Ref());
}
void UnknownMap::Remove(absl::string_view key) {
unknown_.SetEnd(std::remove_if(unknown_.begin(), unknown_.end(),
[key](const std::pair<Slice, Slice>& p) {
return p.first.as_string_view() == key;
}));
}
absl::optional<absl::string_view> UnknownMap::GetStringValue(
absl::string_view key, std::string* backing) const {
absl::optional<absl::string_view> out;
for (const auto& p : unknown_) {
if (p.first.as_string_view() == key) {
if (!out.has_value()) {
out = p.second.as_string_view();
} else {
out = *backing = absl::StrCat(*out, ",", p.second.as_string_view());
}
}
}
return out;
}
} // namespace metadata_detail
ContentTypeMetadata::MementoType ContentTypeMetadata::ParseMemento(
Slice value, MetadataParseErrorFn on_error) {
auto out = kInvalid;
auto value_string = value.as_string_view();
if (value_string == "application/grpc") {
out = kApplicationGrpc;
} else if (absl::StartsWith(value_string, "application/grpc;")) {
out = kApplicationGrpc;
} else if (absl::StartsWith(value_string, "application/grpc+")) {
out = kApplicationGrpc;
} else if (value_string.empty()) {
out = kEmpty;
} else {
on_error("invalid value", value);
}
return out;
}
StaticSlice ContentTypeMetadata::Encode(ValueType x) {
switch (x) {
case kEmpty:
return StaticSlice::FromStaticString("");
case kApplicationGrpc:
return StaticSlice::FromStaticString("application/grpc");
case kInvalid:
return StaticSlice::FromStaticString("application/grpc+unknown");
}
GPR_UNREACHABLE_CODE(
return StaticSlice::FromStaticString("unrepresentable value"));
}
const char* ContentTypeMetadata::DisplayValue(MementoType content_type) {
switch (content_type) {
case ValueType::kApplicationGrpc:
return "application/grpc";
case ValueType::kEmpty:
return "";
default:
return "<discarded-invalid-value>";
}
}
GrpcTimeoutMetadata::MementoType GrpcTimeoutMetadata::ParseMemento(
Slice value, MetadataParseErrorFn on_error) {
auto timeout = ParseTimeout(value);
if (!timeout.has_value()) {
on_error("invalid value", value);
return Duration::Infinity();
}
return *timeout;
}
GrpcTimeoutMetadata::ValueType GrpcTimeoutMetadata::MementoToValue(
MementoType timeout) {
if (timeout == Duration::Infinity()) {
return Timestamp::InfFuture();
}
return ExecCtx::Get()->Now() + timeout;
}
Slice GrpcTimeoutMetadata::Encode(ValueType x) {
return Timeout::FromDuration(x - ExecCtx::Get()->Now()).Encode();
}
TeMetadata::MementoType TeMetadata::ParseMemento(
Slice value, MetadataParseErrorFn on_error) {
auto out = kInvalid;
if (value == "trailers") {
out = kTrailers;
} else {
on_error("invalid value", value);
}
return out;
}
const char* TeMetadata::DisplayValue(MementoType te) {
switch (te) {
case ValueType::kTrailers:
return "trailers";
default:
return "<discarded-invalid-value>";
}
}
HttpSchemeMetadata::ValueType HttpSchemeMetadata::Parse(
absl::string_view value, MetadataParseErrorFn on_error) {
if (value == "http") {
return kHttp;
} else if (value == "https") {
return kHttps;
}
on_error("invalid value", Slice::FromCopiedBuffer(value));
return kInvalid;
}
StaticSlice HttpSchemeMetadata::Encode(ValueType x) {
switch (x) {
case kHttp:
return StaticSlice::FromStaticString("http");
case kHttps:
return StaticSlice::FromStaticString("https");
default:
abort();
}
}
const char* HttpSchemeMetadata::DisplayValue(MementoType content_type) {
switch (content_type) {
case kHttp:
return "http";
case kHttps:
return "https";
default:
return "<discarded-invalid-value>";
}
}
HttpMethodMetadata::MementoType HttpMethodMetadata::ParseMemento(
Slice value, MetadataParseErrorFn on_error) {
auto out = kInvalid;
auto value_string = value.as_string_view();
if (value_string == "POST") {
out = kPost;
} else if (value_string == "PUT") {
out = kPut;
} else if (value_string == "GET") {
out = kGet;
} else {
on_error("invalid value", value);
}
return out;
}
StaticSlice HttpMethodMetadata::Encode(ValueType x) {
switch (x) {
case kPost:
return StaticSlice::FromStaticString("POST");
case kPut:
return StaticSlice::FromStaticString("PUT");
case kGet:
return StaticSlice::FromStaticString("GET");
default:
abort();
}
}
const char* HttpMethodMetadata::DisplayValue(MementoType content_type) {
switch (content_type) {
case kPost:
return "POST";
case kGet:
return "GET";
case kPut:
return "PUT";
default:
return "<discarded-invalid-value>";
}
}
CompressionAlgorithmBasedMetadata::MementoType
CompressionAlgorithmBasedMetadata::ParseMemento(Slice value,
MetadataParseErrorFn on_error) {
auto algorithm = ParseCompressionAlgorithm(value.as_string_view());
if (!algorithm.has_value()) {
on_error("invalid value", value);
return GRPC_COMPRESS_NONE;
}
return *algorithm;
}
Duration GrpcRetryPushbackMsMetadata::ParseMemento(
Slice value, MetadataParseErrorFn on_error) {
int64_t out;
if (!absl::SimpleAtoi(value.as_string_view(), &out)) {
on_error("not an integer", value);
return Duration::NegativeInfinity();
}
return Duration::Milliseconds(out);
}
Slice LbCostBinMetadata::Encode(const ValueType& x) {
auto slice =
MutableSlice::CreateUninitialized(sizeof(double) + x.name.length());
memcpy(slice.data(), &x.cost, sizeof(double));
memcpy(slice.data() + sizeof(double), x.name.data(), x.name.length());
return Slice(std::move(slice));
}
std::string LbCostBinMetadata::DisplayValue(MementoType x) {
return absl::StrCat(x.name, ":", x.cost);
}
LbCostBinMetadata::MementoType LbCostBinMetadata::ParseMemento(
Slice value, MetadataParseErrorFn on_error) {
if (value.length() < sizeof(double)) {
on_error("too short", value);
return {0, ""};
}
MementoType out;
memcpy(&out.cost, value.data(), sizeof(double));
out.name =
std::string(reinterpret_cast<const char*>(value.data()) + sizeof(double),
value.length() - sizeof(double));
return out;
}
std::string GrpcStreamNetworkState::DisplayValue(ValueType x) {
switch (x) {
case kNotSentOnWire:
return "not sent on wire";
case kNotSeenByServer:
return "not seen by server";
}
}
std::string PeerString::DisplayValue(ValueType x) { return std::string(x); }
const std::string& GrpcStatusContext::DisplayValue(const std::string& x) {
return x;
}
} // namespace grpc_core

@ -22,9 +22,7 @@
#include <grpc/support/port_platform.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <cstdint>
#include <string>
#include <type_traits>
@ -33,9 +31,7 @@
#include "absl/container/inlined_vector.h"
#include "absl/functional/function_ref.h"
#include "absl/meta/type_traits.h"
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
@ -47,11 +43,9 @@
#include "src/core/lib/gprpp/chunked_vector.h"
#include "src/core/lib/gprpp/table.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/transport/parsed_metadata.h"
#include "src/core/lib/transport/timeout_encoding.h"
namespace grpc_core {
@ -67,23 +61,9 @@ struct GrpcTimeoutMetadata {
using ValueType = Timestamp;
using MementoType = Duration;
static absl::string_view key() { return "grpc-timeout"; }
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) {
auto timeout = ParseTimeout(value);
if (!timeout.has_value()) {
on_error("invalid value", value);
return Duration::Infinity();
}
return *timeout;
}
static ValueType MementoToValue(MementoType timeout) {
if (timeout == Duration::Infinity()) {
return Timestamp::InfFuture();
}
return ExecCtx::Get()->Now() + timeout;
}
static Slice Encode(ValueType x) {
return Timeout::FromDuration(x - ExecCtx::Get()->Now()).Encode();
}
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error);
static ValueType MementoToValue(MementoType timeout);
static Slice Encode(ValueType x);
static std::string DisplayValue(MementoType x) { return x.ToString(); }
};
@ -99,28 +79,13 @@ struct TeMetadata {
};
using MementoType = ValueType;
static absl::string_view key() { return "te"; }
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) {
auto out = kInvalid;
if (value == "trailers") {
out = kTrailers;
} else {
on_error("invalid value", value);
}
return out;
}
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error);
static ValueType MementoToValue(MementoType te) { return te; }
static StaticSlice Encode(ValueType x) {
GPR_ASSERT(x == kTrailers);
return StaticSlice::FromStaticString("trailers");
}
static const char* DisplayValue(MementoType te) {
switch (te) {
case ValueType::kTrailers:
return "trailers";
default:
return "<discarded-invalid-value>";
}
}
static const char* DisplayValue(MementoType te);
};
// content-type metadata trait.
@ -136,47 +101,13 @@ struct ContentTypeMetadata {
};
using MementoType = ValueType;
static absl::string_view key() { return "content-type"; }
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) {
auto out = kInvalid;
auto value_string = value.as_string_view();
if (value_string == "application/grpc") {
out = kApplicationGrpc;
} else if (absl::StartsWith(value_string, "application/grpc;")) {
out = kApplicationGrpc;
} else if (absl::StartsWith(value_string, "application/grpc+")) {
out = kApplicationGrpc;
} else if (value_string.empty()) {
out = kEmpty;
} else {
on_error("invalid value", value);
}
return out;
}
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error);
static ValueType MementoToValue(MementoType content_type) {
return content_type;
}
static StaticSlice Encode(ValueType x) {
switch (x) {
case kEmpty:
return StaticSlice::FromStaticString("");
case kApplicationGrpc:
return StaticSlice::FromStaticString("application/grpc");
case kInvalid:
return StaticSlice::FromStaticString("application/grpc+unknown");
}
GPR_UNREACHABLE_CODE(
return StaticSlice::FromStaticString("unrepresentable value"));
}
static const char* DisplayValue(MementoType content_type) {
switch (content_type) {
case ValueType::kApplicationGrpc:
return "application/grpc";
case ValueType::kEmpty:
return "";
default:
return "<discarded-invalid-value>";
}
}
static StaticSlice Encode(ValueType x);
static const char* DisplayValue(MementoType content_type);
};
// scheme metadata trait.
@ -193,38 +124,12 @@ struct HttpSchemeMetadata {
return Parse(value.as_string_view(), on_error);
}
static ValueType Parse(absl::string_view value,
MetadataParseErrorFn on_error) {
if (value == "http") {
return kHttp;
} else if (value == "https") {
return kHttps;
}
on_error("invalid value", Slice::FromCopiedBuffer(value));
return kInvalid;
}
MetadataParseErrorFn on_error);
static ValueType MementoToValue(MementoType content_type) {
return content_type;
}
static StaticSlice Encode(ValueType x) {
switch (x) {
case kHttp:
return StaticSlice::FromStaticString("http");
case kHttps:
return StaticSlice::FromStaticString("https");
default:
abort();
}
}
static const char* DisplayValue(MementoType content_type) {
switch (content_type) {
case kHttp:
return "http";
case kHttps:
return "https";
default:
return "<discarded-invalid-value>";
}
}
static StaticSlice Encode(ValueType x);
static const char* DisplayValue(MementoType content_type);
};
// method metadata trait.
@ -238,47 +143,12 @@ struct HttpMethodMetadata {
};
using MementoType = ValueType;
static absl::string_view key() { return ":method"; }
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) {
auto out = kInvalid;
auto value_string = value.as_string_view();
if (value_string == "POST") {
out = kPost;
} else if (value_string == "PUT") {
out = kPut;
} else if (value_string == "GET") {
out = kGet;
} else {
on_error("invalid value", value);
}
return out;
}
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error);
static ValueType MementoToValue(MementoType content_type) {
return content_type;
}
static StaticSlice Encode(ValueType x) {
switch (x) {
case kPost:
return StaticSlice::FromStaticString("POST");
case kPut:
return StaticSlice::FromStaticString("PUT");
case kGet:
return StaticSlice::FromStaticString("GET");
default:
abort();
}
}
static const char* DisplayValue(MementoType content_type) {
switch (content_type) {
case kPost:
return "POST";
case kGet:
return "GET";
case kPut:
return "PUT";
default:
return "<discarded-invalid-value>";
}
}
static StaticSlice Encode(ValueType x);
static const char* DisplayValue(MementoType content_type);
};
// Base type for metadata pertaining to a single compression algorithm
@ -286,14 +156,7 @@ struct HttpMethodMetadata {
struct CompressionAlgorithmBasedMetadata {
using ValueType = grpc_compression_algorithm;
using MementoType = ValueType;
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) {
auto algorithm = ParseCompressionAlgorithm(value.as_string_view());
if (!algorithm.has_value()) {
on_error("invalid value", value);
return GRPC_COMPRESS_NONE;
}
return *algorithm;
}
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error);
static ValueType MementoToValue(MementoType x) { return x; }
static Slice Encode(ValueType x) {
GPR_ASSERT(x != GRPC_COMPRESS_ALGORITHMS_COUNT);
@ -401,9 +264,9 @@ struct HttpPathMetadata : public SimpleSliceBasedMetadata {
static absl::string_view key() { return ":path"; }
};
// We separate SimpleIntBasedMetadata into two pieces: one that does not depend
// on the invalid value, and one that does. This allows the compiler to easily
// see the functions that are shared, and helps reduce code bloat here.
// We separate SimpleIntBasedMetadata into two pieces: one that does not
// depend on the invalid value, and one that does. This allows the compiler to
// easily see the functions that are shared, and helps reduce code bloat here.
template <typename Int>
struct SimpleIntBasedMetadataBase {
using ValueType = Int;
@ -449,14 +312,7 @@ struct GrpcRetryPushbackMsMetadata {
static ValueType MementoToValue(MementoType x) { return x; }
static Slice Encode(Duration x) { return Slice::FromInt64(x.millis()); }
static int64_t DisplayValue(Duration x) { return x.millis(); }
static Duration ParseMemento(Slice value, MetadataParseErrorFn on_error) {
int64_t out;
if (!absl::SimpleAtoi(value.as_string_view(), &out)) {
on_error("not an integer", value);
return Duration::NegativeInfinity();
}
return Duration::Milliseconds(out);
}
static Duration ParseMemento(Slice value, MetadataParseErrorFn on_error);
};
// :status metadata trait.
@ -499,28 +355,9 @@ struct LbCostBinMetadata {
};
using MementoType = ValueType;
static ValueType MementoToValue(MementoType value) { return value; }
static Slice Encode(const ValueType& x) {
auto slice =
MutableSlice::CreateUninitialized(sizeof(double) + x.name.length());
memcpy(slice.data(), &x.cost, sizeof(double));
memcpy(slice.data() + sizeof(double), x.name.data(), x.name.length());
return Slice(std::move(slice));
}
static std::string DisplayValue(MementoType x) {
return absl::StrCat(x.name, ":", x.cost);
}
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) {
if (value.length() < sizeof(double)) {
on_error("too short", value);
return {0, ""};
}
MementoType out;
memcpy(&out.cost, value.data(), sizeof(double));
out.name = std::string(
reinterpret_cast<const char*>(value.data()) + sizeof(double),
value.length() - sizeof(double));
return out;
}
static Slice Encode(const ValueType& x);
static std::string DisplayValue(MementoType x);
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error);
};
// Annotation added by a transport to note whether a failed request was never
@ -532,14 +369,7 @@ struct GrpcStreamNetworkState {
kNotSentOnWire,
kNotSeenByServer,
};
static std::string DisplayValue(ValueType x) {
switch (x) {
case kNotSentOnWire:
return "not sent on wire";
case kNotSeenByServer:
return "not seen by server";
}
}
static std::string DisplayValue(ValueType x);
};
// Annotation added by a server transport to note the peer making a request.
@ -547,7 +377,7 @@ struct PeerString {
static absl::string_view DebugKey() { return "PeerString"; }
static constexpr bool kRepeatable = false;
using ValueType = absl::string_view;
static std::string DisplayValue(ValueType x) { return std::string(x); }
static std::string DisplayValue(ValueType x);
};
// Annotation added by various systems to describe the reason for a failure.
@ -555,7 +385,7 @@ struct GrpcStatusContext {
static absl::string_view DebugKey() { return "GrpcStatusContext"; }
static constexpr bool kRepeatable = true;
using ValueType = std::string;
static const std::string& DisplayValue(const std::string& x) { return x; }
static const std::string& DisplayValue(const std::string& x);
};
namespace metadata_detail {
@ -576,11 +406,10 @@ class DebugStringBuilder {
std::string out_;
};
// IsEncodable: Given a trait, determine if that trait is encodable, or is just
// a value attached to a MetadataMap.
// We use the presence of the key() static method to determine if a trait is
// encodable or not - encodable traits have string names, and non-encodable
// traits do not.
// IsEncodable: Given a trait, determine if that trait is encodable, or is
// just a value attached to a MetadataMap. We use the presence of the key()
// static method to determine if a trait is encodable or not - encodable
// traits have string names, and non-encodable traits do not.
template <typename Trait, typename Ignored = void>
struct IsEncodableTrait {
static const bool value = false;
@ -630,8 +459,8 @@ struct NameLookup<void> {
};
// Helper to take a slice to a memento to a value.
// By splitting this part out we can scale code size as the number of (memento,
// value) types, rather than as the number of traits.
// By splitting this part out we can scale code size as the number of
// (memento, value) types, rather than as the number of traits.
template <typename ParseMementoFn, typename MementoToValueFn>
struct ParseValue {
template <ParseMementoFn parse_memento, MementoToValueFn memento_to_value>
@ -680,8 +509,8 @@ class ParseHelper {
};
// This is an "Op" type for NameLookup.
// Used for MetadataMap::Append, its Found/NotFound methods turn a slice into a
// value and add it to a container.
// Used for MetadataMap::Append, its Found/NotFound methods turn a slice into
// a value and add it to a container.
template <typename Container>
class AppendHelper {
public:
@ -698,7 +527,7 @@ class AppendHelper {
}
GPR_ATTRIBUTE_NOINLINE void NotFound(absl::string_view key) {
container_->AppendUnknown(key, std::move(value_));
container_->unknown_.Append(key, std::move(value_));
}
private:
@ -721,7 +550,7 @@ class RemoveHelper {
}
GPR_ATTRIBUTE_NOINLINE void NotFound(absl::string_view key) {
container_->RemoveUnknown(key);
container_->unknown_.Remove(key);
}
private:
@ -729,8 +558,8 @@ class RemoveHelper {
};
// This is an "Op" type for NameLookup.
// Used for MetadataMap::GetStringValue, its Found/NotFound methods generated a
// string value from the container.
// Used for MetadataMap::GetStringValue, its Found/NotFound methods generated
// a string value from the container.
template <typename Container>
class GetStringValueHelper {
public:
@ -780,7 +609,7 @@ class GetStringValueHelper {
GPR_ATTRIBUTE_NOINLINE absl::optional<absl::string_view> NotFound(
absl::string_view key) {
return container_->GetStringValueUnknown(key, backing_);
return container_->unknown_.GetStringValue(key, backing_);
}
private:
@ -793,7 +622,17 @@ using LogFn = absl::FunctionRef<void(absl::string_view, absl::string_view)>;
template <typename T>
struct AdaptDisplayValueToLog {
static std::string ToString(const T& value) { return absl::StrCat(value); }
static std::string ToString(const T& value) { return std::to_string(value); }
};
template <>
struct AdaptDisplayValueToLog<std::string> {
static std::string ToString(const std::string& value) { return value; }
};
template <>
struct AdaptDisplayValueToLog<const std::string&> {
static std::string ToString(const std::string& value) { return value; }
};
template <>
@ -949,7 +788,7 @@ class CopySink {
}
void Encode(const Slice& key, const Slice& value) {
dst_->AppendUnknown(key.as_string_view(), value.Ref());
dst_->unknown_.Append(key.as_string_view(), value.Ref());
}
private:
@ -1005,6 +844,31 @@ class TransportSizeEncoder {
uint32_t size_ = 0;
};
// Handle unknown (non-trait-based) fields in the metadata map.
class UnknownMap {
public:
explicit UnknownMap(Arena* arena) : unknown_(arena) {}
using BackingType = ChunkedVector<std::pair<Slice, Slice>, 10>;
void Append(absl::string_view key, Slice value);
void Remove(absl::string_view key);
absl::optional<absl::string_view> GetStringValue(absl::string_view key,
std::string* backing) const;
BackingType::ConstForwardIterator begin() const { return unknown_.cbegin(); }
BackingType::ConstForwardIterator end() const { return unknown_.cend(); }
bool empty() const { return unknown_.empty(); }
size_t size() const { return unknown_.size(); }
void Clear() { unknown_.Clear(); }
Arena* arena() const { return unknown_.arena(); }
private:
// Backing store for added metadata.
ChunkedVector<std::pair<Slice, Slice>, 10> unknown_;
};
} // namespace metadata_detail
// Helper function for encoders
@ -1065,21 +929,23 @@ MetadataValueAsSlice(typename Which::ValueType value) {
// // Parse a memento from a slice
// // Takes ownership of value
// // Calls fn in the case of an error that should be reported to the user
// static MementoType ParseMemento(Slice value, MementoParseErrorFn fn) { ...
// static MementoType ParseMemento(Slice value, MementoParseErrorFn fn) {
// ...
// }
// // Convert a memento to a value
// static ValueType MementoToValue(MementoType memento) { ... }
// // Convert a value to its canonical text wire format (the format that
// // ParseMemento will accept!)
// static Slice Encode(const ValueType& value);
// // Convert a value to something that can be passed to StrCat and displayed
// // Convert a value to something that can be passed to StrCat and
// displayed
// // for debugging
// static SomeStrCatableType DisplayValue(MementoType value) { ... }
// };
//
// Non-encodable traits are determined by missing the key() method, and have the
// following signature (and by convention omit the Metadata part of the type
// name):
// Non-encodable traits are determined by missing the key() method, and have
// the following signature (and by convention omit the Metadata part of the
// type name):
// // Traits for the GrpcXyz field:
// struct GrpcXyz {
// // The string key that should be used for debug dumps - should not be a
@ -1089,7 +955,8 @@ MetadataValueAsSlice(typename Which::ValueType value) {
// static constexpr bool kRepeatable = ...;
// // The type that's stored on MetadataBatch
// using ValueType = ...;
// // Convert a value to something that can be passed to StrCat and displayed
// // Convert a value to something that can be passed to StrCat and
// displayed
// // for debugging
// static SomeStrCatableType DisplayValue(ValueType value) { ... }
// };
@ -1102,10 +969,10 @@ MetadataValueAsSlice(typename Which::ValueType value) {
// in the compression table. This is what mementos are used for.
//
// A trait offers the capability to turn a slice into a memento via
// ParseMemento. This is exposed to users of MetadataMap via the Parse() method,
// that returns a ParsedMetadata object. That ParsedMetadata object can in turn
// be used to set the same value on many different MetadataMaps without having
// to reparse.
// ParseMemento. This is exposed to users of MetadataMap via the Parse()
// method, that returns a ParsedMetadata object. That ParsedMetadata object
// can in turn be used to set the same value on many different MetadataMaps
// without having to reparse.
//
// Implementation wise, ParsedMetadata is a type erased wrapper around
// MementoType. When we set a value on MetadataMap, we first turn that memento
@ -1309,36 +1176,9 @@ class MetadataMap {
template <typename Which>
using Value = metadata_detail::Value<Which>;
void AppendUnknown(absl::string_view key, Slice value) {
unknown_.EmplaceBack(Slice::FromCopiedString(key), value.Ref());
}
void RemoveUnknown(absl::string_view key) {
unknown_.SetEnd(std::remove_if(unknown_.begin(), unknown_.end(),
[key](const std::pair<Slice, Slice>& p) {
return p.first.as_string_view() == key;
}));
}
absl::optional<absl::string_view> GetStringValueUnknown(
absl::string_view key, std::string* backing) const {
absl::optional<absl::string_view> out;
for (const auto& p : unknown_) {
if (p.first.as_string_view() == key) {
if (!out.has_value()) {
out = p.second.as_string_view();
} else {
out = *backing = absl::StrCat(*out, ",", p.second.as_string_view());
}
}
}
return out;
}
// Table of known metadata types.
Table<Value<Traits>...> table_;
// Backing store for added metadata.
ChunkedVector<std::pair<Slice, Slice>, 10> unknown_;
metadata_detail::UnknownMap unknown_;
};
// Ok/not-ok check for metadata maps that contain GrpcStatusMetadata, so that
@ -1356,8 +1196,8 @@ template <typename Derived, typename... Traits>
MetadataMap<Derived, Traits...>::MetadataMap(MetadataMap&& other) noexcept
: table_(std::move(other.table_)), unknown_(std::move(other.unknown_)) {}
// We never create MetadataMap directly, instead we create Derived, but we want
// to be able to move it without redeclaring this.
// We never create MetadataMap directly, instead we create Derived, but we
// want to be able to move it without redeclaring this.
// NOLINTNEXTLINE(misc-unconventional-assign-operator)
template <typename Derived, typename... Traits>
Derived& MetadataMap<Derived, Traits...>::operator=(

@ -378,7 +378,7 @@ ParsedMetadata<MetadataContainer>::KeyValueVTable(absl::string_view key) {
};
static const auto set = [](const Buffer& value, MetadataContainer* map) {
auto* p = static_cast<KV*>(value.pointer);
map->AppendUnknown(p->first.as_string_view(), p->second.Ref());
map->unknown_.Append(p->first.as_string_view(), p->second.Ref());
};
static const auto with_new_value = [](Slice* value, MetadataParseErrorFn,
ParsedMetadata* result) {

Loading…
Cancel
Save