Revert "Add protobuf encoding/decoding logic."
This reverts commit 7208083bd3944948e3c512b1b66fd712faa3e351.
Change-Id: If719379558661c8cd7d8f4b413d16b5528d5b515
diff --git a/Android.mk b/Android.mk
index fec35c3..68dc90b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -20,8 +20,7 @@
LOCAL_MODULE := libnvram
LOCAL_SRC_FILES := \
blob.cpp \
- io.cpp \
- message_codec.cpp
+ io.cpp
LOCAL_STATIC_LIBRARIES := libbase
LOCAL_CFLAGS := -Wall -Werror -Wextra -fvisibility=hidden
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
diff --git a/include/nvram/compiler.h b/include/nvram/compiler.h
index efcba79..8d6ad05 100644
--- a/include/nvram/compiler.h
+++ b/include/nvram/compiler.h
@@ -30,9 +30,6 @@
// Check a condition, abort if it doesn't hold.
#define NVRAM_CHECK(cond) if (!(cond)) abort()
-// The noinline attribute is understood both by clang and GCC.
-#define NVRAM_NOINLINE __attribute__((noinline))
-
// The visibility attribute works both with clang and GCC.
#define NVRAM_EXPORT __attribute__((visibility("default")))
diff --git a/include/nvram/io.h b/include/nvram/io.h
index 87a716e..c61ac12 100644
--- a/include/nvram/io.h
+++ b/include/nvram/io.h
@@ -28,18 +28,16 @@
namespace nvram {
// Abstraction used by the protobuf decoder to read data. The idea here is that
-// |InputStreamBuffer| maintains a window of the data to be read. Access to the
-// contents of the current window is direct, i.e. doesn't need to go through
-// virtual dispatch to subclasses. Whenever the window is exhausted, the next
-// window must be set up. This latter operation is left for implementation of
-// the virtual |Advance()| member function in subclasses, which is entirely free
-// to pull its data from anywhere.
+// |InputStreamBuffer| maintains a window of the data to be read. Whenever the
+// window is exhausted, the next window must be set up. This latter operation is
+// left for implementation in subclasses, which is entirely free to pull its
+// data from anywhere.
class NVRAM_EXPORT InputStreamBuffer {
public:
- InputStreamBuffer() = default;
+ InputStreamBuffer();
InputStreamBuffer(const void* data, size_t size);
InputStreamBuffer(const void* start, const void* end);
- virtual ~InputStreamBuffer() = default;
+ virtual ~InputStreamBuffer();
// Checks whether the stream is exhausted;
bool Done();
@@ -83,7 +81,7 @@
// |delegate|. Note that |delegate| must remain valid throughout the life time
// of this |NestedInputStreamBuffer|.
NestedInputStreamBuffer(InputStreamBuffer* delegate, size_t size);
- ~NestedInputStreamBuffer() override = default;
+ ~NestedInputStreamBuffer() override;
private:
// InputStreamBuffer:
@@ -93,20 +91,13 @@
size_t remaining_;
};
-// Abstraction used by the protobuf decoder to output data. This class maintains
-// a current window of memory to write output to. Access to the current window's
-// bytes is direct and doesn't require virtual dispatch. Once the capacity of
-// the current window is exhausted, the virtual |Advance()| member function is
-// invoked to set up a new window. Subclasses are entirely free to implement
-// this operation as appropriate for their I/O mechanism, for example a
-// socket-based implementations might flush the buffer to the socket and reset
-// the window pointers to accept more output.
+// Abstraction used by the protobuf decoder to output data.
class NVRAM_EXPORT OutputStreamBuffer {
public:
- OutputStreamBuffer() = default;
+ OutputStreamBuffer();
OutputStreamBuffer(void* data, size_t size);
OutputStreamBuffer(void* data, void* end);
- virtual ~OutputStreamBuffer() = default;
+ virtual ~OutputStreamBuffer();
// Checks whether the stream is exhausted.
bool Done();
@@ -142,7 +133,7 @@
class NVRAM_EXPORT CountingOutputStreamBuffer : public OutputStreamBuffer {
public:
CountingOutputStreamBuffer();
- ~CountingOutputStreamBuffer() override = default;
+ ~CountingOutputStreamBuffer() override;
size_t bytes_written() const {
return bytes_written_ + (pos_ - scratch_space_);
@@ -156,13 +147,7 @@
// We share a single scratch buffer that all |CountingOutputStreamBuffer|
// instances use as the destination for writes. Its contents are pretty much
// unpredictable.
- //
- // TODO(mnissler): This adds a static 256 bytes memory allocation to each
- // process linking to this code. If that becomes a problem, we might want to
- // be smarter here and dynamically allocate a chunk of memory only when it's
- // needed, or maybe even map some address space that's not even backed by
- // actual memory (not sure that's possible).
- static constexpr size_t kScratchSpaceSize = 256;
+ static constexpr size_t kScratchSpaceSize = 1024;
static uint8_t scratch_space_[kScratchSpaceSize];
// Number of bytes that had been written when the last |Advance()| call
@@ -178,14 +163,14 @@
// |blob|, which will get resized as necessary. Note that |blob| must remain
// valid for the life time of the |BlobOutputStreamBuffer| object.
BlobOutputStreamBuffer(Blob* blob);
- ~BlobOutputStreamBuffer() override = default;
+ virtual ~BlobOutputStreamBuffer();
// Truncate the blob to match the current output size.
bool Truncate();
protected:
// OutputStreamBuffer:
- bool Advance() override;
+ virtual bool Advance() override;
private:
Blob* blob_;
diff --git a/include/nvram/message_codec.h b/include/nvram/message_codec.h
deleted file mode 100644
index 63359d9..0000000
--- a/include/nvram/message_codec.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * 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
- *
- * http://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.
- */
-
-#ifndef NVRAM_MESSAGE_CODEC_H_
-#define NVRAM_MESSAGE_CODEC_H_
-
-extern "C" {
-#include <stddef.h>
-#include <stdint.h>
-}
-
-#include <nvram/compiler.h>
-#include <nvram/io.h>
-
-namespace nvram {
-namespace proto {
-
-// |FieldDescriptor| describes a single proto field in a struct. We compile a
-// table of field descriptors for each struct that needs to be encoded or
-// decoded into the binary. See proto.hpp for the code that initializes the
-// static tables.
-struct FieldDescriptor {
- // A function to encode a struct field in protobuf wire format. |object| is a
- // pointer to the struct to read the value from, |writer| receives the output.
- using EncodeFunction = bool(const void* object, ProtoWriter* writer);
-
- // A function to encode a protobuf struct field from |reader|. The decoded
- // data is stored in the struct instance pointed at by |object|.
- using DecodeFunction = bool(void* object, ProtoReader* reader);
-
- constexpr FieldDescriptor(uint32_t field_number,
- WireType wire_type,
- EncodeFunction* encode_function,
- DecodeFunction* decode_function)
- : field_number(field_number),
- wire_type(wire_type),
- encode_function(encode_function),
- decode_function(decode_function) {}
-
- uint32_t field_number;
- WireType wire_type;
- EncodeFunction* encode_function;
- DecodeFunction* decode_function;
-};
-
-// A table-driven protobuf message encoder. Takes a pointer to a C++ object to
-// encode and a corresponding table of field descriptors. Provides functions to
-// encode the message data in protobuf wire format.
-class NVRAM_EXPORT MessageEncoderBase {
- public:
- // Initialize the encoder to encode |object|, using the descriptor table
- // passed in |descriptors|.
- MessageEncoderBase(const void* object,
- const FieldDescriptor* descriptors,
- size_t num_descriptors);
-
- // Convenience helper that constructs an encoder instance and invokes
- // |Encode()|.
- static bool Encode(const void* object,
- ProtoWriter* writer,
- const FieldDescriptor* descriptors,
- size_t num_descriptors);
-
- // Returns the encoded size of the object.
- size_t GetSize();
-
- // Encodes the object as a sequence of protobuf fields, wrapped in a
- // length-delimited container.
- bool Encode(ProtoWriter* writer);
-
- // Encodes the object as a sequence of protobuf fields without any wrapping.
- bool EncodeData(ProtoWriter* writer);
-
- private:
- // The pointer to the object to encode. This is a void pointer, so the encoder
- // logic can be generic and doesn't need to be instantiated for every struct
- // type. The encode function provided by the field descriptor will cast back
- // to the correct type.
- const void* object_;
-
- // Field descriptor table.
- const FieldDescriptor* descriptors_;
- size_t num_descriptors_;
-};
-
-// A protobuf message decoder, driven by a table of field descriptors. Consumes
-// data from a |ProtoReader|, decodes fields per the descriptor table and stores
-// it to a C++ object.
-class NVRAM_EXPORT MessageDecoderBase {
- public:
- // Initialize a decoder to store field data according to the |descriptors|
- // table in |object|.
- MessageDecoderBase(void* object,
- const FieldDescriptor* descriptors,
- size_t num_descriptors);
-
- // Convenience helper that constructs a decoder and invokes |Decode()|.
- static bool Decode(void* object,
- ProtoReader* reader,
- const FieldDescriptor* descriptors,
- size_t num_descriptors);
-
- // Decode a nested protobuf message wrapped in a length-delimited protobuf
- // field.
- bool Decode(ProtoReader* reader);
-
- // Decode a protobuf message from reader. This just reads the sequence of
- // fields, not taking into account any wrapping. This is suitable for the
- // topmost encoded message.
- bool DecodeData(ProtoReader* reader);
-
- private:
- // Looks up the |FieldDescriptor| for decoding the next field. The descriptor
- // must match the field number and wire type of the field. If no matching
- // descriptor is found, |nullptr| is returned.
- const FieldDescriptor* FindDescriptor(ProtoReader* reader) const;
-
- // The object to decode to. This is a void pointer to keep the decoder generic
- // and avoid type-specific code for each struct type. The decode function in
- // the field descriptor casts back to the struct type.
- void* object_;
-
- // Descriptor table.
- const FieldDescriptor* descriptors_;
- size_t num_descriptors_;
-};
-
-} // namespace proto
-} // namespace nvram
-
-#endif // NVRAM_MESSAGE_CODEC_H_
diff --git a/include/nvram/proto.hpp b/include/nvram/proto.hpp
deleted file mode 100644
index 4dee92e..0000000
--- a/include/nvram/proto.hpp
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * 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
- *
- * http://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.
- */
-
-// This file implements a simple protobuf encoder and decoder. The high-level
-// idea is to use C++ structs as data containers corresponding to protobuf
-// messages. A descriptor must be provided for a struct via a
-// |nvram::DescriptorForType| specialization that declares the protobuf fields
-// to encode and decode.
-// * Encoding works by going through the declared fields, and encode the
-// corresponding struct members in protobuf wire format.
-// * Decoding scans through the binary encoded message. It looks at the wire
-// tag decoded form the message to recover the field number as well as
-// the protobuf wire type (i.e. kind of encoding). The field number is then
-// used to locate the struct field declaration so the appropriate decoding
-// logic for the corresponding struct member can be invoked.
-// * The main dispatch point that ties member types to decoding and encoding
-// logic is the |nvram::proto::detail::Codec| template. The idea is that
-// |Codec<Type>| provides encoding and decoding logic for |Type|.
-//
-// The API for encoding and decoding is straightforward. Consider the following
-// Employee struct and its descriptor:
-// type:
-//
-// struct Employee {
-// uint32_t id;
-// std::string name;
-// std::vector<uint32_t> reports;
-// };
-//
-// template <>
-// struct DescriptorForType<Employee> {
-// static constexpr auto kFields =
-// MakeFieldList(MakeField(1, &Employee::id),
-// MakeField(2, &Employee::name),
-// MakeField(3, &Employee::reports));
-// };
-//
-// Encoding is simple:
-//
-// Employee employee;
-// uint8_t buffer[SIZE];
-// nvram::OutputStream stream(buffer, sizeof(buffer));
-// if (!nvram::proto::Encode(employee, &stream)) {
-// // Handle encoding failure.
-// }
-//
-// Note that |nvram::proto::GetSize()| can be used to determine a sufficient
-// buffer size.
-//
-// Decoding is similar:
-//
-// Employee employee;
-// nvram::InputStreamBuffer stream(buffer_start, buffer_size);
-// if (!nvram::proto::Decode(&employee, &stream)) {
-// // Handle decoding failure.
-// }
-//
-// Note that this file is not meant as a header to be included by all code that
-// needs to encode or decode messages. Rather, this header should only be
-// included by a .cpp file which can then instantiate the
-// |nvram::proto::Encode()| and |nvram::proto::Decode()| templates to obtain
-// encoders and decoders for the relevant message types. This approach results
-// in decode and encode logic getting compiled in only one translation unit,
-// which other code can link against.
-
-#ifndef NVRAM_PROTO_HPP_
-#define NVRAM_PROTO_HPP_
-
-extern "C" {
-#include <stdint.h>
-}
-
-#include <nvram/blob.h>
-#include <nvram/compiler.h>
-#include <nvram/io.h>
-#include <nvram/message_codec.h>
-#include <nvram/struct.h>
-#include <nvram/type_traits.h>
-#include <nvram/vector.h>
-
-namespace nvram {
-namespace proto {
-
-namespace detail {
-
-// A class template that performs encoding and decoding of a protobuf message
-// field of the C++ type |Type|. The base template is left undefined here,
-// specific implementations for relevant |Type|s are provided by template
-// specializations. Each specialization needs to provide the following members:
-// * |static constexpr WireType kWireType| indicates the wire type used for
-// encoded field data.
-// * |static bool Encode(const Type& object, ProtoWriter* writer)| writes the
-// encoded form of |object| to |writer|.
-// * |static bool Decode(Type& object, ProtoReader* reader)| decodes a field
-// from |reader| and places recovered data in |object|.
-//
-// |Codec| specializations are provided below for commonly-used types such as
-// integral and enum types, as well as structs with corresponding descriptors.
-// Additional specializations can be added as needed.
-template <typename Type, typename Enable = void>
-struct Codec {
- // The assert below fails unconditionally, but must depend on the |Type|
- // parameter so it only triggers at instantiation time. If this assert fires,
- // then you are attempting to encode or decode a struct that contains a field
- // of a C++ type for which there exists no code that implements encoding and
- // decoding for that type. To add encoding/decoding support for a type, you
- // can provide a Codec specialization.
- static_assert(sizeof(Type) == 0,
- "A Codec specialization must be provided for types "
- "that are to be used with the protobuf encoder.");
-};
-
-namespace {
-
-// Codec specific message field encoding function. Note that this is marked
-// noinline to prevent the compiler from inlining |Codec::Encode| for every
-// occurrence of a field of type |Type|.
-template <typename Codec, typename Type>
-bool EncodeField(const Type& value, ProtoWriter* writer) NVRAM_NOINLINE {
- return Codec::Encode(value, writer);
-}
-
-// Codec specific message field decoding function. Note that this is marked
-// noinline to prevent the compiler from inlining |Codec::Decode| for every
-// occurrence of a field of type |Type|.
-template <typename Codec, typename Type>
-bool DecodeField(Type& value, ProtoReader* reader) NVRAM_NOINLINE {
- return Codec::Decode(value, reader);
-}
-
-} // namespace
-
-// |Codec| specialization for Blob.
-template <>
-struct Codec<Blob> {
- static constexpr WireType kWireType = WireType::kLengthDelimited;
-
- static bool Encode(const Blob& blob, ProtoWriter* writer) {
- return writer->WriteLengthDelimited(blob.data(), blob.size());
- }
-
- static bool Decode(Blob& blob, ProtoReader* reader) {
- return blob.Resize(reader->field_size()) &&
- reader->ReadLengthDelimited(blob.data(), blob.size());
- }
-};
-
-// A helper to test whether a given |Type| should be handled by the Varint
-// |Codec| specialization. The |Type| needs to allow conversion from and to
-// |uint64_t|. This checks for static_cast conversion behavior instead of
-// implicit conversion in order to also match scoped enums.
-template <typename Type>
-struct IsVarintCompatible {
- template <typename From, typename To>
- struct IsCastConvertible {
- template <typename T>
- static decltype(static_cast<T>(declval<From>()), true_type()) test(int);
-
- template <typename T>
- static false_type test(...);
-
- static constexpr bool value = decltype(test<To>(0))::value;
- };
-
- static constexpr bool value = IsCastConvertible<Type, uint64_t>::value &&
- IsCastConvertible<uint64_t, Type>::value;
-};
-
-// |Codec| specialization for varint-encoded numeric fields.
-template <typename Type>
-struct Codec<Type, typename enable_if<IsVarintCompatible<Type>::value>::Type> {
- static constexpr WireType kWireType = WireType::kVarint;
-
- static bool Encode(const Type& value, ProtoWriter* writer) {
- return writer->WriteVarint(static_cast<uint64_t>(value));
- }
-
- static bool Decode(Type& value, ProtoReader* reader) {
- uint64_t raw_value;
- if (!reader->ReadVarint(&raw_value)) {
- return false;
- }
- value = static_cast<Type>(raw_value);
- return static_cast<uint64_t>(value) == raw_value;
- }
-};
-
-// |Codec| specialization for |Vector|.
-template <typename ElementType>
-struct Codec<Vector<ElementType>> {
- using ElementCodec = Codec<ElementType>;
- static constexpr WireType kWireType = ElementCodec::kWireType;
-
- static bool Encode(const Vector<ElementType>& vector, ProtoWriter* writer) {
- for (const ElementType& elem : vector) {
- if (!EncodeField<ElementCodec>(elem, writer)) {
- return false;
- }
- }
- return true;
- }
-
- static bool Decode(Vector<ElementType>& vector, ProtoReader* reader) {
- return vector.Resize(vector.size() + 1) &&
- DecodeField<ElementCodec>(vector[vector.size() - 1], reader);
- }
-};
-
-namespace {
-
-// |StructDescriptor| provides the |FieldDescriptor| table corresponding to
-// |StructType|. The table contains information about each field in the protobuf
-// encoding, e.g. field number and wire type.
-//
-// The |IndexSequence| template parameter is present purely for technical
-// reasons. It provides a sequence of indices, one for each entry in the field
-// declaration list for |StructType|. Having the index available simplifies
-// generation of the descriptor table entries.
-template <
- typename StructType,
- typename IndexSequence = decltype(
- make_index_sequence<DescriptorForType<StructType>::kFields.kSize>())>
-struct StructDescriptor;
-
-template <typename StructType, size_t... indices>
-struct StructDescriptor<StructType, index_sequence<indices...>> {
- private:
- static constexpr auto kFieldSpecList =
- DescriptorForType<StructType>::kFields;
- using FieldSpecs = typename remove_const<decltype(kFieldSpecList)>::Type;
-
- // A helper function used to preform a compile-time sanity check on the
- // declared field numbers to ensure that they're positive, unique and in
- // ascending order.
- template <typename FieldSpecList>
- static constexpr bool CheckFieldNumbersAscending(
- FieldSpecList list,
- uint32_t previous_field_number) {
- return list.kFieldSpec.kFieldNumber > previous_field_number &&
- CheckFieldNumbersAscending(list.kTail, list.kFieldSpec.kFieldNumber);
- }
- static constexpr bool CheckFieldNumbersAscending(FieldSpecList<>, uint32_t) {
- return true;
- }
-
- // If this fails, check your struct field declarations for the following:
- // * Field numbers must be positive.
- // * Field numbers must be unique.
- // * Fields must be declared in ascending field number order.
- static_assert(CheckFieldNumbersAscending(kFieldSpecList, 0),
- "Field numbers must be positive, unique and declared in "
- "ascending order.");
-
- // Provides the |FieldDescriptor| instance for the field specified by |index|.
- // Note that |index| is *not* the proto field number, but the zero-based index
- // in the field declaration list.
- template <size_t index>
- class FieldDescriptorBuilder {
- static constexpr auto kFieldSpec = kFieldSpecList.template Get<index>();
- using FieldSpecType = typename remove_const<decltype(kFieldSpec)>::Type;
- using MemberType = typename FieldSpecType::MemberType;
- using MemberCodec = Codec<FieldSpecType>;
-
- // Encodes a member. Retrieves a reference to the member within |object| and
- // calls the appropriate encoder.
- static bool EncodeMember(const void* object, ProtoWriter* writer) {
- constexpr auto spec = kFieldSpec;
- return EncodeField<MemberCodec>(
- spec.Get(*static_cast<const StructType*>(object)), writer);
- };
-
- // Decodes a member. Retrieves a const reference to the member within
- // |object| and calls the appropriate decoder.
- static bool DecodeMember(void* object, ProtoReader* reader) {
- constexpr auto spec = kFieldSpec;
- return DecodeField<MemberCodec>(
- spec.Get(*static_cast<StructType*>(object)), reader);
- };
-
- public:
- // Assemble the actual descriptor for the field. Note that this is still a
- // compile-time constant (i.e. has no linkage). However, the constant is
- // used below to initialize the entry in the static descriptor table.
- static constexpr FieldDescriptor kDescriptor =
- FieldDescriptor(kFieldSpec.kFieldNumber,
- MemberCodec::kWireType,
- &EncodeMember,
- &DecodeMember);
- };
-
- public:
- // Descriptor table size.
- static constexpr size_t kNumDescriptors = kFieldSpecList.kSize;
-
- // The actual descriptor table.
- static constexpr FieldDescriptor kDescriptors[] = {
- FieldDescriptorBuilder<indices>::kDescriptor...};
-};
-
-// Provide a definition of the |kDescriptors| array such that the descriptor
-// table gets emitted to static data.
-template <typename StructType, size_t... index>
-constexpr FieldDescriptor
- StructDescriptor<StructType, index_sequence<index...>>::kDescriptors[];
-
-// Note that G++ versions before 5.0 have a bug in handling parameter pack
-// expansions that result in an empty array initializer. To work around this,
-// the following specialization is provided for empty field lists.
-template <typename StructType>
-struct StructDescriptor<StructType, index_sequence<>> {
- static constexpr size_t kNumDescriptors = 0;
- static constexpr FieldDescriptor* kDescriptors = nullptr;
-};
-
-// A convenience class to initialize |MessageEncoderBase| with the descriptor
-// table corresponding to |StructType| as determined by |StructDescriptor|.
-template <typename StructType>
-class MessageEncoder : public MessageEncoderBase {
- public:
- MessageEncoder(const StructType& object)
- : MessageEncoderBase(&object,
- StructDescriptor<StructType>::kDescriptors,
- StructDescriptor<StructType>::kNumDescriptors) {}
-
- static bool Encode(const StructType& object, ProtoWriter* writer) {
- return MessageEncoderBase::Encode(
- &object, writer, StructDescriptor<StructType>::kDescriptors,
- StructDescriptor<StructType>::kNumDescriptors);
- }
-};
-
-// A convenience class to initialize |MessageDecoderBase| with the descriptor
-// table corresponding to |StructType| as determined by |StructDescriptor|.
-template <typename StructType>
-class MessageDecoder : public MessageDecoderBase {
- public:
- MessageDecoder(StructType& object)
- : MessageDecoderBase(&object,
- StructDescriptor<StructType>::kDescriptors,
- StructDescriptor<StructType>::kNumDescriptors) {}
-
- static bool Decode(StructType& object, ProtoReader* reader) {
- return MessageDecoderBase::Decode(
- &object, reader, StructDescriptor<StructType>::kDescriptors,
- StructDescriptor<StructType>::kNumDescriptors);
- }
-};
-
-} // namespace
-
-// |Codec| specialization for struct types. The second template parameter
-// evaluates to |void| if the appropriate |DescriptorForType| specialization
-// exists, enabling the |Codec| specialization for that case.
-//
-// Note that this template generates code for each struct type that needs to be
-// encoded and decoded. To avoid bloating the binary, we keep the type-dependent
-// code at the absolute minimum. The |MessageEncoder| and |MessageDecoder|
-// templates merely obtain the appropriate descriptor table for the struct type
-// and then invoke the type-agnostic encoder and decoder base classes.
-template <typename StructType>
-struct Codec<StructType,
- decltype(
- static_cast<void>(DescriptorForType<StructType>::kFields))> {
- static constexpr WireType kWireType = WireType::kLengthDelimited;
-
- static bool Encode(const StructType& object, ProtoWriter* writer) {
- return MessageEncoder<StructType>::Encode(object, writer);
- }
-
- static bool Decode(StructType& object, ProtoReader* reader) {
- return MessageDecoder<StructType>::Decode(object, reader);
- }
-};
-
-} // namespace detail
-
-// Get the encoded size of an object.
-template <typename Struct>
-size_t GetSize(const Struct& object) {
- detail::MessageEncoder<Struct> encoder(object);
- return encoder.GetSize();
-}
-
-// Encode |object| and write the result to |stream|. Returns true if successful,
-// false if encoding fails. Encoding may fail because |stream| doesn't have
-// enough room to hold the encoded data.
-template <typename Struct>
-bool Encode(const Struct& object, OutputStreamBuffer* stream) {
- ProtoWriter writer(stream);
- detail::MessageEncoder<Struct> encoder(object);
- return encoder.EncodeData(&writer);
-}
-
-// Decode |stream| and update |object| with the decoded information. Returns
-// true if successful, false if encoding fails. Failure conditions include:
-// * Binary data isn't valid with respect to the protobuf wire format.
-// * |stream| ends prematurely.
-// * Memory allocation in |object| to hold decoded data fails.
-template <typename Struct>
-bool Decode(Struct* object, InputStreamBuffer* stream) {
- ProtoReader reader(stream);
- detail::MessageDecoder<Struct> decoder(*object);
- return decoder.DecodeData(&reader);
-}
-
-} // namespace proto
-} // namespace nvram
-
-#endif // NVRAM_PROTO_HPP_
diff --git a/include/nvram/struct.h b/include/nvram/struct.h
deleted file mode 100644
index 7d38f73..0000000
--- a/include/nvram/struct.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * 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
- *
- * http://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.
- */
-
-// This file provides facilities to declare compile-time descriptors for C++
-// struct types. This enables generic code to access the declared struct
-// members in an object.
-//
-// For example, consider the following struct type:
-//
-// struct Employee {
-// uint32_t id;
-// std::string name;
-// std::vector<uint32_t> reports;
-// };
-//
-// The descriptor is declared as follows, providing access to |Employee|'s
-// members and assigning a unique field number to each of them:
-//
-// template <>
-// struct DescriptorForType<Employee> {
-// static constexpr auto kFields =
-// MakeFieldList(MakeField(1, &Employee::id),
-// MakeField(2, &Employee::name),
-// MakeField(3, &Employee::reports));
-// };
-//
-// Note that the |kFields| member is a constexpr, which creates a compile-time
-// constant, so the field meta data can be used in compile-time computations and
-// as template parameters.
-//
-// To access the declared members, there is a |Get()| member function template
-// on the declared field list, which allows to retrieve one of the field
-// specifications by index (zero-based declaration index, *not* field number).
-// Once you have the field spec for a field, you can use |FieldSpec::Get()| to
-// get a reference to the member within a struct instance. This can be used to
-// implement generic algorithms that make use of the descriptor behind the
-// scenes. Here is an example that shows how to build a generic comparator:
-//
-// template <typename Struct>
-// struct StructCompare {
-// template <typename Member>
-// int compareMember(const Member& left, const Member& right) {
-// return left < right ? -1 : (right < left ? 1 : 0);
-// }
-//
-// template <size_t... indices>
-// int compare(const Struct& left,
-// const Struct& right,
-// index_sequence<indices...>) {
-// constexpr auto kFieldSpecList = DescriptorForType<Struct>::kFields;
-// int results[] = {compareMember(
-// kFieldSpecList.template Get<indices>().Get(left),
-// kFieldSpecList.template Get<indices>().Get(right))...};
-// for (int result : results) {
-// if (result != 0) {
-// return result;
-// }
-// }
-//
-// return 0;
-// }
-//
-// bool operator()(const Struct& left, const Struct& right) {
-// constexpr auto kFieldSpecList = DescriptorForType<Struct>::kFields;
-// return compare(left, right,
-// make_index_sequence<kFieldSpecList.kSize>()) < 0;
-// }
-// };
-//
-// You can now use |StructCompare| as a key comparison function with std::set
-// like this:
-//
-// std::set<Employee, StructCompare<Employee>> employees;
-// employees.emplace(std::move(new_employee));
-//
-// The ability to write generic algorithms that can process arbitrarily-typed
-// struct fields comes at the cost of heavy usage of template constructs.
-// However, potential alternatives are not without drawbacks:
-// * Avoiding generic code entirely and writing the necessary operations for
-// each struct type manually is tedious and error-prone.
-// * Tool-generated code is just as hard to comprehend and maintain, and code
-// making use of the generated constructs may need to be generated as well.
-// * For the intended use in message serialization, there are existing message
-// serialization solutions such as protobuf. Unfortunately, our serialization
-// code needs to run in resource-constrained environments that don't provide
-// a C++ standard library (which is a dependency of the regular protobuf
-// implementation), and the library weighs in as a non-trivial dependency in
-// terms of code size.
-
-#ifndef NVRAM_STRUCT_H_
-#define NVRAM_STRUCT_H_
-
-#include <nvram/type_traits.h>
-
-namespace nvram {
-
-// This class template is used to resolve struct types to their corresponding
-// descriptors, which provide a list of struct fields that includes the field
-// numbers as well as the corresponding C++ struct members in |Struct|. See the
-// file comment above for an example.
-template <typename Struct>
-struct DescriptorForType;
-
-// |FieldSpec| describes a member field of the struct type |Struct|. The
-// template parameters capture the C++ |Member| type of the |Struct| member that
-// holds the field's data.
-//
-// Note that this class template is a literal type, i.e. can be used with
-// constexpr. As an implication, |FieldSpec| instances can be used as
-// compile-time data.
-template <typename Struct, typename Member>
-struct FieldSpec {
- using MemberType = Member;
-
- constexpr FieldSpec(uint32_t field_number, MemberType Struct::* member)
- : kFieldNumber(field_number), kMember(member) {}
-
- const MemberType& Get(const Struct& object) const {
- return object.*kMember;
- }
-
- MemberType& Get(Struct& object) const {
- return object.*kMember;
- }
-
- // The field number for this field.
- const uint32_t kFieldNumber;
-
- // A member pointer to the |Struct| member that holds the field data.
- MemberType Struct::*const kMember;
-};
-
-// A helper function template that enables template argument deduction to be
-// used to construct |FieldSpec| instances.
-template <typename Struct, typename Member>
-constexpr FieldSpec<Struct, Member> MakeField(uint32_t field_number,
- Member Struct::*member) {
- return FieldSpec<Struct, Member>(field_number, member);
-};
-
-// A simple type list intended to hold field specification values.
-//
-// Note that |FieldSpecList| is a literal type so can be used with constexpr to
-// hold compile-time data.
-template <typename... FieldSpec>
-struct FieldSpecList;
-
-namespace {
-
-// A helper template that extracts the field spec at |index| from a field spec
-// list.
-template <size_t index, typename... FieldSpec>
-struct FieldSpecLookup;
-
-// Recursion step: This specialization matches if |index| is larger than 0, and
-// the |Get()| definition just forwards to the list tail.
-template <size_t index, typename FieldSpec, typename... Tail>
-struct FieldSpecLookup<index, FieldSpec, Tail...> {
- using Prev = FieldSpecLookup<index - 1, Tail...>;
- using Type = typename Prev::Type;
- static constexpr Type Get(FieldSpecList<FieldSpec, Tail...> self) {
- return Prev::Get(self.kTail);
- }
-};
-
-// Recursion base case: |index| as reached 0, so |Get()| returns the field spec
-// corresponding to the current |FieldSpec|.
-template <typename FieldSpec, typename... Tail>
-struct FieldSpecLookup<0, FieldSpec, Tail...> {
- using Type = FieldSpec;
- static constexpr Type Get(FieldSpecList<FieldSpec, Tail...> self) {
- return self.kFieldSpec;
- }
-};
-
-// Produces an error message in case the provided |index| is too large, i.e.
-// doesn't match any field. This specialization only matches once the
-// |FieldSpec| parameters are exhausted.
-template <size_t index>
-struct FieldSpecLookup<index> {
- // Note that |index < 0| will never be satisfied, so this static assert
- // triggers unconditionally if this template specialization ever gets
- // instantiated. It will only be instantiated if |index| exceeds the number of
- // declared fields.
- //
- // Just putting |false| as the static_assert condition would seem a saner
- // alternative, but doesn't work since the static_assert would then be
- // evaluated at declaration time. Using the |index| parameter in the condition
- // forces evaluation to take place at template instantiation time.
- static_assert(index < 0, "Out-of-bounds |index| in field spec lookup.");
-};
-
-} // namespace
-
-// |FieldSpecList| specialization that holds the data of the front-most element
-// of |FieldSpecList|'s |Fields| arguments. Note that this class contains a
-// nested |FieldSpecList| instance with the front-most element removed, thus
-// inheriting the members for subsequent |Fields| arguments.
-template <typename FieldSpec, typename... Tail>
-struct FieldSpecList<FieldSpec, Tail...> {
- using List = FieldSpecList<FieldSpec, Tail...>;
- using TailList = FieldSpecList<Tail...>;
-
- constexpr FieldSpecList(FieldSpec field_spec, Tail... tail)
- : kFieldSpec(field_spec), kTail(tail...) {}
-
- template <size_t index>
- constexpr typename FieldSpecLookup<index, FieldSpec, Tail...>::Type Get()
- const {
- return FieldSpecLookup<index, FieldSpec, Tail...>::Get(*this);
- }
-
- static constexpr size_t kSize = TailList::kSize + 1;
- const FieldSpec kFieldSpec;
- const TailList kTail;
-};
-
-// |FieldSpecList| specialization acting as the recursion base case. This
-// doesn't have further members and thus stops the expansion of
-// |FieldSpecList|'s |Fields| parameter.
-template <>
-struct FieldSpecList<> {
- static constexpr size_t kSize = 0;
-};
-
-// Helper function template that enables convenient creation of |FieldSpecList|
-// instances by enabling template argument deduction.
-template <typename... FieldSpec>
-constexpr FieldSpecList<FieldSpec...> MakeFieldList(FieldSpec... field_spec) {
- return FieldSpecList<FieldSpec...>(field_spec...);
-}
-
-} // namespace nvram
-
-#endif // NVRAM_STRUCT_H_
diff --git a/include/nvram/type_traits.h b/include/nvram/type_traits.h
deleted file mode 100644
index 2d3ce17..0000000
--- a/include/nvram/type_traits.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * 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
- *
- * http://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.
- */
-
-#ifndef NVRAM_TYPE_TRAITS_H_
-#define NVRAM_TYPE_TRAITS_H_
-
-extern "C" {
-#include <stddef.h>
-}
-
-// A subset of utilities similar to what is available in <type_traits>. We have
-// our own standalone version here since not all target platforms have a full
-// C++ standard library.
-
-namespace nvram {
-
-template <typename T>
-struct remove_const {
- using Type = T;
-};
-template <typename T>
-struct remove_const<const T> {
- using Type = T;
-};
-
-template <typename T>
-struct remove_reference {
- using Type = T;
-};
-template <typename T>
-struct remove_reference<T&> {
- using Type = T;
-};
-template <typename T>
-struct remove_reference<T&&> {
- using Type = T;
-};
-
-template <bool value, typename T = void>
-struct enable_if {};
-
-template <typename T>
-struct enable_if<true, T> {
- using Type = T;
-};
-
-template <typename T, T const_value>
-struct integral_constant {
- static constexpr T value = const_value;
-};
-
-using true_type = integral_constant<bool, true>;
-using false_type = integral_constant<bool, false>;
-
-template <typename T>
-T declval();
-
-template <size_t... index>
-struct index_sequence {};
-
-template <size_t size, size_t... indices>
-struct make_index_sequence_builder {
- using Type = typename make_index_sequence_builder<size - 1,
- size - 1,
- indices...>::Type;
-};
-
-template <size_t... indices>
-struct make_index_sequence_builder<0, indices...> {
- using Type = index_sequence<indices...>;
-};
-
-template <size_t size>
-constexpr typename make_index_sequence_builder<size>::Type
-make_index_sequence(){
- return typename make_index_sequence_builder<size>::Type();
-};
-
-} // namespace nvram
-
-#endif // NVRAM_TYPE_TRAITS_H_
diff --git a/io.cpp b/io.cpp
index c783d3c..faf9068 100644
--- a/io.cpp
+++ b/io.cpp
@@ -71,6 +71,8 @@
} // namespace
+InputStreamBuffer::InputStreamBuffer() = default;
+
InputStreamBuffer::InputStreamBuffer(const void* data, size_t size)
: InputStreamBuffer(data, static_cast<const uint8_t*>(data) + size) {}
@@ -80,6 +82,8 @@
NVRAM_CHECK(pos_ <= end_);
}
+InputStreamBuffer::~InputStreamBuffer() = default;
+
bool InputStreamBuffer::Done() {
return pos_ >= end_ && !Advance();
}
@@ -139,6 +143,8 @@
delegate_(delegate),
remaining_(size) {}
+NestedInputStreamBuffer::~NestedInputStreamBuffer() = default;
+
bool NestedInputStreamBuffer::Advance() {
remaining_ -= end_ - delegate_->pos_;
if (remaining_ == 0) {
@@ -151,6 +157,8 @@
return status;
}
+OutputStreamBuffer::OutputStreamBuffer() = default;
+
OutputStreamBuffer::OutputStreamBuffer(void* data, size_t size)
: OutputStreamBuffer(data, static_cast<uint8_t*>(data) + size) {}
@@ -159,6 +167,8 @@
NVRAM_CHECK(pos_ <= end_);
}
+OutputStreamBuffer::~OutputStreamBuffer() = default;
+
bool OutputStreamBuffer::Done() {
return pos_ >= end_ && !Advance();
}
@@ -200,6 +210,8 @@
CountingOutputStreamBuffer::CountingOutputStreamBuffer()
: OutputStreamBuffer(scratch_space_, kScratchSpaceSize) {}
+CountingOutputStreamBuffer::~CountingOutputStreamBuffer() = default;
+
bool CountingOutputStreamBuffer::Advance() {
bytes_written_ += pos_ - scratch_space_;
pos_ = scratch_space_;
@@ -212,6 +224,8 @@
BlobOutputStreamBuffer::BlobOutputStreamBuffer(Blob* blob)
: OutputStreamBuffer(blob->data(), blob->size()), blob_(blob) {}
+BlobOutputStreamBuffer::~BlobOutputStreamBuffer() = default;
+
bool BlobOutputStreamBuffer::Advance() {
ptrdiff_t offset = pos_ - blob_->data();
if (!blob_->Resize(max<size_t>(blob_->size() * 2, 32))) {
diff --git a/message_codec.cpp b/message_codec.cpp
deleted file mode 100644
index d1df715..0000000
--- a/message_codec.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * 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
- *
- * http://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 <nvram/message_codec.h>
-
-namespace nvram {
-namespace proto {
-
-MessageEncoderBase::MessageEncoderBase(const void* object,
- const FieldDescriptor* descriptors,
- size_t num_descriptors)
- : object_(object),
- descriptors_(descriptors),
- num_descriptors_(num_descriptors) {}
-
-bool MessageEncoderBase::Encode(const void* object,
- ProtoWriter* writer,
- const FieldDescriptor* descriptors,
- size_t num_descriptors) {
- MessageEncoderBase encoder(object, descriptors, num_descriptors);
- return encoder.Encode(writer);
-}
-
-size_t MessageEncoderBase::GetSize() {
- CountingOutputStreamBuffer counting_stream;
- ProtoWriter writer(&counting_stream);
- return EncodeData(&writer) ? counting_stream.bytes_written() : 0;
-}
-
-bool MessageEncoderBase::Encode(ProtoWriter* writer) {
- // We need to compute the total size of all struct fields up front in order to
- // write a length delimiter that designates the end of the encoded nested
- // message. Note that computing the size of |object| requires a second
- // |EncodeData()| call in addition to the one that actually encodes the data.
- // When handling nested message structures, each level triggers its own size
- // computation, which are redundant with those performed by the levels above.
- //
- // For now, we just accept this inefficiency in the interest of keeping things
- // simple and correct. If this ever becomes a performance problem for deeply
- // nested structs here are some options:
- // * Reserve bytes in |writer| for the encoded size. Once |Encode()|
- // completes, it is known how many bytes were required, at which point the
- // size field can be updated. The drawback with this solution is that
- // varint encoding is variable length, so we'd have to write a degenerated
- // varint that may occupy more bytes than actually required.
- // * Cache encoded sizes in the struct. This is the solution implemented in
- // the regular protobuf implementation. This is relatively straightforward,
- // but at the expense of holding data in struct that doesn't really belong
- // there.
- // * Make a first pass over the struct tree, compute sizes and cache them in
- // some auxiliary data structure held in the encoder. This is probably the
- // cleanest solution, but comes at the expense of having to thread the size
- // cache data structure through the encoding logic.
- return writer->WriteLengthHeader(GetSize()) && EncodeData(writer);
-}
-
-bool MessageEncoderBase::EncodeData(ProtoWriter* writer) {
- for (size_t i = 0; i < num_descriptors_; ++i) {
- const FieldDescriptor& desc = descriptors_[i];
- writer->set_field_number(desc.field_number);
- if (!desc.encode_function(object_, writer)) {
- return false;
- }
- }
-
- return true;
-}
-
-MessageDecoderBase::MessageDecoderBase(void* object,
- const FieldDescriptor* descriptors,
- size_t num_descriptors)
- : object_(object),
- descriptors_(descriptors),
- num_descriptors_(num_descriptors) {}
-
-bool MessageDecoderBase::Decode(void* object,
- ProtoReader* reader,
- const FieldDescriptor* descriptors,
- size_t num_descriptors) {
- MessageDecoderBase decoder(object, descriptors, num_descriptors);
- return decoder.Decode(reader);
-}
-
-bool MessageDecoderBase::Decode(ProtoReader* reader) {
- NestedInputStreamBuffer nested_stream_buffer(reader->stream_buffer(),
- reader->field_size());
- ProtoReader nested_reader(&nested_stream_buffer);
- return DecodeData(&nested_reader) && nested_reader.Done();
-}
-
-bool MessageDecoderBase::DecodeData(ProtoReader* reader) {
- while (!reader->Done()) {
- if (!reader->ReadWireTag()) {
- return false;
- }
- const FieldDescriptor* desc = FindDescriptor(reader);
- if (desc) {
- if (!desc->decode_function(object_, reader)) {
- return false;
- }
- } else {
- // Unknown field number or wire type mismatch. Skip field data.
- if (!reader->SkipField()) {
- return false;
- }
- }
- }
-
- return true;
-}
-
-const FieldDescriptor* MessageDecoderBase::FindDescriptor(
- ProtoReader* reader) const {
- for (size_t i = 0; i < num_descriptors_; ++i) {
- const FieldDescriptor& desc = descriptors_[i];
- if (reader->field_number() == desc.field_number &&
- reader->wire_type() == desc.wire_type) {
- return &desc;
- }
- }
- return nullptr;
-}
-
-} // namespace nvram
-} // namespace proto