Chromium Code Reviews| Index: components/tracing/core/proto_utils.h |
| diff --git a/components/tracing/core/proto_utils.h b/components/tracing/core/proto_utils.h |
| index 68599199688e98f0182aeb874a4e6e15e0585f2d..23eaba624ab902204291217eef4d7e7c66c75ae5 100644 |
| --- a/components/tracing/core/proto_utils.h |
| +++ b/components/tracing/core/proto_utils.h |
| @@ -10,13 +10,14 @@ |
| #include <type_traits> |
| #include "base/logging.h" |
| -#include "base/macros.h" |
| -#include "components/tracing/tracing_export.h" |
| namespace tracing { |
| namespace v2 { |
| namespace proto { |
| +// TODO(kraynov) Change namespace to tracing::proto::internal. |
| +// This stuff is required in headers and it's too low-level to be exposed. |
| + |
| // See https://developers.google.com/protocol-buffers/docs/encoding wire types. |
| enum : uint32_t { |
| @@ -30,69 +31,65 @@ enum : uint32_t { |
| constexpr size_t kMessageLengthFieldSize = 4; |
| constexpr size_t kMaxMessageLength = (1u << (kMessageLengthFieldSize * 7)) - 1; |
| -// Returns the number of bytes sufficient to encode the largest |
| -// |int_size_in_bits|-bits integer using a non-redundant varint encoding. |
| -template <typename T> |
| -constexpr size_t GetMaxVarIntEncodedSize() { |
| - return (sizeof(T) * 8 + 6) / 7; |
| -} |
| +// Varint maximum encoded size == (sizeof(T) * 8 + 6) / 7. |
| +// Tag is encoded as 32-bit varint (5 bytes at most). |
| +// Largest possible singilar value is 64-bit varint (10 bytes at most). |
| +constexpr size_t kMaxTagEncodedSize = 5; |
| +constexpr size_t kMaxSingilarFieldEncodedSize = 15; |
| -// Variable-length field types: (s)int32, (s)int64, bool, enum. |
| -inline uint32_t MakeTagVarInt(uint32_t field_id) { |
| +// Proto types: (int|uint|sint)(32|64), bool, enum. |
| +constexpr uint32_t MakeTagVarInt(uint32_t field_id) { |
| return (field_id << 3) | kFieldTypeVarInt; |
| } |
| -// Length-limited field types: string, bytes, embedded messages. |
| -inline uint32_t MakeTagLengthDelimited(uint32_t field_id) { |
| - return (field_id << 3) | kFieldTypeLengthDelimited; |
| +// Proto types: fixed64, sfixed64, fixed32, sfixed32, double, float. |
| +template <typename T> |
| +constexpr uint32_t MakeTagFixed(uint32_t field_id) { |
| + static_assert(sizeof(T) == 8 || sizeof(T) == 4, "Value must be 4 or 8 bytes"); |
| + return (field_id << 3) | |
| + (sizeof(T) == 8 ? kFieldTypeFixed64 : kFieldTypeFixed32); |
| } |
| -// 32-bit fixed-length field types: fixed32, sfixed32, float. |
| -inline uint32_t MakeTagFixed32(uint32_t field_id) { |
| - return (field_id << 3) | kFieldTypeFixed32; |
| +// Proto types: string, bytes, embedded messages. |
| +constexpr uint32_t MakeTagLengthDelimited(uint32_t field_id) { |
| + return (field_id << 3) | kFieldTypeLengthDelimited; |
| } |
| -// 64-bit fixed-length field types: fixed64, sfixed64, double. |
| -inline uint32_t MakeTagFixed64(uint32_t field_id) { |
| - return (field_id << 3) | kFieldTypeFixed64; |
| +// Proto tipes: sint64, sint32. |
| +template <typename T> |
| +inline typename std::make_unsigned<T>::type ZigZagEncode(T value) { |
| + return (value << 1) ^ (value >> (sizeof(T) * 8 - 1)); |
| } |
| template <typename T> |
| -inline uint8_t* WriteVarIntInternal(T value, uint8_t* target) { |
| - static_assert(std::is_unsigned<T>::value, "value must be unsigned"); |
| - while (value >= 0x80) { |
| - *target++ = static_cast<uint8_t>(value | 0x80); |
| - value >>= 7; |
| +inline uint8_t* WriteVarInt(T value, uint8_t* target) { |
| + // Avoid arithmetic (sign expanding) shifts. |
| + typedef typename std::make_unsigned<T>::type unsigned_T; |
| + unsigned_T unsigned_value = static_cast<unsigned_T>(value); |
| + |
| + while (unsigned_value >= 0x80) { |
| + *target++ = static_cast<uint8_t>(unsigned_value | 0x80); |
| + unsigned_value >>= 7; |
| } |
| - *target = static_cast<uint8_t>(value); |
| + *target = static_cast<uint8_t>(unsigned_value); |
| return target + 1; |
| } |
| -inline uint8_t* WriteVarIntU32(uint32_t value, uint8_t* target) { |
| - return WriteVarIntInternal<uint32_t>(value, target); |
| -} |
| - |
| -inline uint8_t* WriteVarIntU64(uint64_t value, uint8_t* target) { |
| - return WriteVarIntInternal<uint64_t>(value, target); |
| -} |
| - |
| -// TODO(kraynov): add support for signed integers and zig-zag encoding. |
| - |
| // Writes a fixed-size redundant encoding of the given |value|. This is |
| -// used to backfill fixed-size reservations for the length field using a |
| +// used to backfill fixed-size reservations for the length of field using a |
| // non-canonical varint encoding (e.g. \x81\x80\x80\x00 instead of \x01). |
| // See https://github.com/google/protobuf/issues/1530. |
| // In particular, this is used for nested messages. The size of a nested message |
| -// is not known until all its field have been written. A fixed amount of bytes |
| -// is reserved to encode the size field and backfilled at the end. |
| -template <size_t LENGTH> |
| -void WriteRedundantVarIntU32(uint32_t value, uint8_t* buf) { |
| - for (size_t i = 0; i < LENGTH; ++i) { |
| - const uint8_t msb = (i < LENGTH - 1) ? 0x80 : 0; |
| +// is not known until all its field have been written. |
| +// A fixed kMessageLengthFieldSize amount of bytes is reserved to encode |
| +// the size field and backfilled at the end. |
| +inline void WriteRedundantLength(uint32_t value, uint8_t* buf) { |
| + DCHECK_LT(value, kMaxMessageLength) << "Message is too large"; |
| + for (size_t i = 0; i < kMessageLengthFieldSize; ++i) { |
| + const uint8_t msb = (i < kMessageLengthFieldSize - 1) ? 0x80 : 0; |
| buf[i] = static_cast<uint8_t>((value & 0x7F) | msb); |
|
alph
2016/08/08 19:59:50
nit: & 0x7F is redundant
kraynov
2016/08/09 12:32:04
Done.
|
| value >>= 7; |
| } |
| - DCHECK_EQ(0u, value) << "Buffer too short to encode the given value"; |
| } |
| } // namespace proto |