diff options
Diffstat (limited to 'absl/log/internal/proto.cc')
-rw-r--r-- | absl/log/internal/proto.cc | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/absl/log/internal/proto.cc b/absl/log/internal/proto.cc new file mode 100644 index 00000000..80d78eed --- /dev/null +++ b/absl/log/internal/proto.cc @@ -0,0 +1,214 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/log/internal/proto.h" + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <cstring> + +#include "absl/base/attributes.h" +#include "absl/base/config.h" +#include "absl/types/span.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace log_internal { +namespace { +void EncodeRawVarint(uint64_t value, size_t size, absl::Span<char> *buf) { + for (size_t s = 0; s < size; s++) { + (*buf)[s] = (value & 0x7f) | (s + 1 == size ? 0 : 0x80); + value >>= 7; + } + buf->remove_prefix(size); +} +constexpr uint64_t MakeTagType(uint64_t tag, WireType type) { + return tag << 3 | static_cast<uint64_t>(type); +} +} // namespace + +bool EncodeVarint(uint64_t tag, uint64_t value, absl::Span<char> *buf) { + const uint64_t tag_type = MakeTagType(tag, WireType::kVarint); + const uint64_t tag_type_size = VarintSize(tag_type); + const uint64_t value_size = VarintSize(value); + if (tag_type_size + value_size > buf->size()) { + buf->remove_suffix(buf->size()); + return false; + } + EncodeRawVarint(tag_type, tag_type_size, buf); + EncodeRawVarint(value, value_size, buf); + return true; +} + +bool Encode64Bit(uint64_t tag, uint64_t value, absl::Span<char> *buf) { + const uint64_t tag_type = MakeTagType(tag, WireType::k64Bit); + const uint64_t tag_type_size = VarintSize(tag_type); + if (tag_type_size + sizeof(value) > buf->size()) { + buf->remove_suffix(buf->size()); + return false; + } + EncodeRawVarint(tag_type, tag_type_size, buf); + for (size_t s = 0; s < sizeof(value); s++) { + (*buf)[s] = value & 0xff; + value >>= 8; + } + buf->remove_prefix(sizeof(value)); + return true; +} + +bool Encode32Bit(uint64_t tag, uint32_t value, absl::Span<char> *buf) { + const uint64_t tag_type = MakeTagType(tag, WireType::k32Bit); + const uint64_t tag_type_size = VarintSize(tag_type); + if (tag_type_size + sizeof(value) > buf->size()) { + buf->remove_suffix(buf->size()); + return false; + } + EncodeRawVarint(tag_type, tag_type_size, buf); + for (size_t s = 0; s < sizeof(value); s++) { + (*buf)[s] = value & 0xff; + value >>= 8; + } + buf->remove_prefix(sizeof(value)); + return true; +} + +bool EncodeBytes(uint64_t tag, absl::Span<const char> value, + absl::Span<char> *buf) { + const uint64_t tag_type = MakeTagType(tag, WireType::kLengthDelimited); + const uint64_t tag_type_size = VarintSize(tag_type); + uint64_t length = value.size(); + const uint64_t length_size = VarintSize(length); + if (tag_type_size + length_size + value.size() > buf->size()) { + buf->remove_suffix(buf->size()); + return false; + } + EncodeRawVarint(tag_type, tag_type_size, buf); + EncodeRawVarint(length, length_size, buf); + memcpy(buf->data(), value.data(), value.size()); + buf->remove_prefix(value.size()); + return true; +} + +bool EncodeBytesTruncate(uint64_t tag, absl::Span<const char> value, + absl::Span<char> *buf) { + const uint64_t tag_type = MakeTagType(tag, WireType::kLengthDelimited); + const uint64_t tag_type_size = VarintSize(tag_type); + uint64_t length = value.size(); + const uint64_t length_size = VarintSize(length); + if (tag_type_size + length_size <= buf->size() && + tag_type_size + length_size + value.size() > buf->size()) { + value.remove_suffix(tag_type_size + length_size + value.size() - + buf->size()); + length = value.size(); + } + if (tag_type_size + length_size + value.size() > buf->size()) { + buf->remove_suffix(buf->size()); + return false; + } + EncodeRawVarint(tag_type, tag_type_size, buf); + EncodeRawVarint(length, length_size, buf); + memcpy(buf->data(), value.data(), value.size()); + buf->remove_prefix(value.size()); + return true; +} + +ABSL_MUST_USE_RESULT absl::Span<char> EncodeMessageStart( + uint64_t tag, uint64_t max_size, absl::Span<char> *buf) { + const uint64_t tag_type = MakeTagType(tag, WireType::kLengthDelimited); + const uint64_t tag_type_size = VarintSize(tag_type); + max_size = std::min<uint64_t>(max_size, buf->size()); + const uint64_t length_size = VarintSize(max_size); + if (tag_type_size + length_size > buf->size()) { + buf->remove_suffix(buf->size()); + return absl::Span<char>(); + } + EncodeRawVarint(tag_type, tag_type_size, buf); + const absl::Span<char> ret = buf->subspan(0, length_size); + EncodeRawVarint(0, length_size, buf); + return ret; +} + +void EncodeMessageLength(absl::Span<char> msg, const absl::Span<char> *buf) { + if (!msg.data()) return; + const uint64_t length_size = msg.size(); + EncodeRawVarint(buf->data() - msg.data() - length_size, length_size, &msg); +} + +namespace { +uint64_t DecodeVarint(absl::Span<const char> *buf) { + uint64_t value = 0; + size_t s = 0; + while (s < buf->size()) { + value |= static_cast<uint64_t>(static_cast<unsigned char>((*buf)[s]) & 0x7f) + << 7 * s; + if (!((*buf)[s++] & 0x80)) break; + } + buf->remove_prefix(s); + return value; +} + +uint64_t Decode64Bit(absl::Span<const char> *buf) { + uint64_t value = 0; + size_t s = 0; + while (s < buf->size()) { + value |= static_cast<uint64_t>(static_cast<unsigned char>((*buf)[s])) + << 8 * s; + if (++s == sizeof(value)) break; + } + buf->remove_prefix(s); + return value; +} + +uint32_t Decode32Bit(absl::Span<const char> *buf) { + uint32_t value = 0; + size_t s = 0; + while (s < buf->size()) { + value |= static_cast<uint32_t>(static_cast<unsigned char>((*buf)[s])) + << 8 * s; + if (++s == sizeof(value)) break; + } + buf->remove_prefix(s); + return value; +} +} // namespace + +bool ProtoField::DecodeFrom(absl::Span<const char> *data) { + if (data->empty()) return false; + const uint64_t tag_type = DecodeVarint(data); + tag_ = tag_type >> 3; + type_ = static_cast<WireType>(tag_type & 0x07); + switch (type_) { + case WireType::kVarint: + value_ = DecodeVarint(data); + break; + case WireType::k64Bit: + value_ = Decode64Bit(data); + break; + case WireType::kLengthDelimited: { + value_ = DecodeVarint(data); + data_ = data->subspan(0, std::min<size_t>(value_, data->size())); + data->remove_prefix(data_.size()); + break; + } + case WireType::k32Bit: + value_ = Decode32Bit(data); + break; + } + return true; +} + +} // namespace log_internal +ABSL_NAMESPACE_END +} // namespace absl |