| Index: mojo/public/cpp/bindings/lib/map_serialization.h
|
| diff --git a/mojo/public/cpp/bindings/lib/map_serialization.h b/mojo/public/cpp/bindings/lib/map_serialization.h
|
| index 56ef68d3162f90f0ff73707fbb23e92f35ba6ae8..91e404e478abe9518e6790da88073fa4c70cc4c1 100644
|
| --- a/mojo/public/cpp/bindings/lib/map_serialization.h
|
| +++ b/mojo/public/cpp/bindings/lib/map_serialization.h
|
| @@ -5,7 +5,10 @@
|
| #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_MAP_SERIALIZATION_H_
|
| #define MOJO_PUBLIC_CPP_BINDINGS_LIB_MAP_SERIALIZATION_H_
|
|
|
| +#include <type_traits>
|
| +
|
| #include "mojo/public/cpp/bindings/array.h"
|
| +#include "mojo/public/cpp/bindings/lib/array_serialization.h"
|
| #include "mojo/public/cpp/bindings/lib/map_data_internal.h"
|
| #include "mojo/public/cpp/bindings/lib/serialization_forward.h"
|
| #include "mojo/public/cpp/bindings/map.h"
|
| @@ -13,44 +16,93 @@
|
| namespace mojo {
|
| namespace internal {
|
|
|
| -template <typename Key, typename Value>
|
| -struct MapContext {
|
| - explicit MapContext(bool in_is_null) : is_null(in_is_null) {}
|
| +template <typename MaybeConstUserType>
|
| +class MapReaderBase {
|
| + public:
|
| + using UserType = typename std::remove_const<MaybeConstUserType>::type;
|
| + using Traits = MapTraits<UserType>;
|
| + using MaybeConstIterator =
|
| + decltype(Traits::GetBegin(std::declval<MaybeConstUserType&>()));
|
| +
|
| + explicit MapReaderBase(MaybeConstUserType& input)
|
| + : input_(input), iter_(Traits::GetBegin(input_)) {}
|
| + ~MapReaderBase() {}
|
| +
|
| + size_t GetSize() const { return Traits::GetSize(input_); }
|
| +
|
| + // Return null because key or value elements are not stored continuously in
|
| + // memory.
|
| + void* GetDataIfExists() { return nullptr; }
|
| +
|
| + protected:
|
| + MaybeConstUserType& input_;
|
| + MaybeConstIterator iter_;
|
| +};
|
| +
|
| +// Used as the UserTypeReader template parameter of ArraySerializer.
|
| +template <typename MaybeConstUserType>
|
| +class MapKeyReader : public MapReaderBase<MaybeConstUserType> {
|
| + public:
|
| + using Base = MapReaderBase<MaybeConstUserType>;
|
| + using Traits = typename Base::Traits;
|
| +
|
| + explicit MapKeyReader(MaybeConstUserType& input) : Base(input) {}
|
| + ~MapKeyReader() {}
|
|
|
| - bool is_null;
|
| - Array<Key> keys;
|
| - Array<Value> values;
|
| + const typename Traits::Key& GetNext() {
|
| + const typename Traits::Key& key = Traits::GetKey(this->iter_);
|
| + Traits::AdvanceIterator(this->iter_);
|
| + return key;
|
| + }
|
| +};
|
| +
|
| +// Used as the UserTypeReader template parameter of ArraySerializer.
|
| +template <typename MaybeConstUserType>
|
| +class MapValueReader : public MapReaderBase<MaybeConstUserType> {
|
| + public:
|
| + using Base = MapReaderBase<MaybeConstUserType>;
|
| + using Traits = typename Base::Traits;
|
| + using MaybeConstIterator = typename Base::MaybeConstIterator;
|
| +
|
| + explicit MapValueReader(MaybeConstUserType& input) : Base(input) {}
|
| + ~MapValueReader() {}
|
| +
|
| + using GetNextResult =
|
| + decltype(Traits::GetValue(std::declval<MaybeConstIterator&>()));
|
| + GetNextResult GetNext() {
|
| + GetNextResult value = Traits::GetValue(this->iter_);
|
| + Traits::AdvanceIterator(this->iter_);
|
| + return value;
|
| + }
|
| };
|
|
|
| template <typename Key, typename Value, typename MaybeConstUserType>
|
| struct Serializer<Map<Key, Value>, MaybeConstUserType> {
|
| using UserType = typename std::remove_const<MaybeConstUserType>::type;
|
| - using UserKey = typename UserType::Key;
|
| - using UserValue = typename UserType::Value;
|
| + using Traits = MapTraits<UserType>;
|
| + using UserKey = typename Traits::Key;
|
| + using UserValue = typename Traits::Value;
|
| using Data = typename Map<Key, Value>::Data_;
|
| -
|
| - static_assert(std::is_same<MaybeConstUserType, UserType>::value,
|
| - "Only support serialization of non-const Maps.");
|
| - static_assert(IsSpecializationOf<Map, UserType>::value,
|
| - "Custom mapping of mojom map is not supported yet.");
|
| -
|
| - static size_t PrepareToSerialize(UserType& input,
|
| + using KeyArraySerializer = ArraySerializer<Array<Key>,
|
| + Array<UserKey>,
|
| + MapKeyReader<MaybeConstUserType>>;
|
| + using ValueArraySerializer =
|
| + ArraySerializer<Array<Value>,
|
| + Array<UserValue>,
|
| + MapValueReader<MaybeConstUserType>>;
|
| +
|
| + static size_t PrepareToSerialize(MaybeConstUserType& input,
|
| SerializationContext* context) {
|
| - auto map_context = new MapContext<UserKey, UserValue>(input.is_null());
|
| - if (!context->custom_contexts)
|
| - context->custom_contexts.reset(new std::queue<void*>());
|
| - context->custom_contexts->push(map_context);
|
| -
|
| - if (!input)
|
| + if (CallIsNullIfExists<Traits>(input))
|
| return 0;
|
|
|
| - input.DecomposeMapTo(&map_context->keys, &map_context->values);
|
| -
|
| size_t struct_overhead = sizeof(Data);
|
| + MapKeyReader<MaybeConstUserType> key_reader(input);
|
| size_t keys_size =
|
| - internal::PrepareToSerialize<Array<Key>>(map_context->keys, context);
|
| - size_t values_size = internal::PrepareToSerialize<Array<Value>>(
|
| - map_context->values, context);
|
| + KeyArraySerializer::GetSerializedSize(&key_reader, context);
|
| + MapValueReader<MaybeConstUserType> value_reader(input);
|
| + size_t values_size =
|
| + ValueArraySerializer::GetSerializedSize(&value_reader, context);
|
|
|
| return struct_overhead + keys_size + values_size;
|
| }
|
| @@ -58,31 +110,36 @@ struct Serializer<Map<Key, Value>, MaybeConstUserType> {
|
| // We don't need an ArrayValidateParams instance for key validation since
|
| // we can deduce it from the Key type. (which can only be primitive types or
|
| // non-nullable strings.)
|
| - static void Serialize(UserType& input,
|
| + static void Serialize(MaybeConstUserType& input,
|
| Buffer* buf,
|
| Data** output,
|
| const ArrayValidateParams* value_validate_params,
|
| SerializationContext* context) {
|
| - std::unique_ptr<MapContext<UserKey, UserValue>> map_context(
|
| - static_cast<MapContext<UserKey, UserValue>*>(
|
| - context->custom_contexts->front()));
|
| - context->custom_contexts->pop();
|
| -
|
| - if (map_context->is_null) {
|
| + if (CallIsNullIfExists<Traits>(input)) {
|
| *output = nullptr;
|
| return;
|
| }
|
|
|
| auto result = Data::New(buf);
|
| if (result) {
|
| - const ArrayValidateParams* key_validate_params =
|
| - MapKeyValidateParamsFactory<
|
| - typename GetDataTypeAsArrayElement<Key>::Data>::Get();
|
| - internal::Serialize<Array<Key>>(map_context->keys, buf, &result->keys.ptr,
|
| - key_validate_params, context);
|
| - internal::Serialize<Array<Value>>(map_context->values, buf,
|
| - &result->values.ptr,
|
| - value_validate_params, context);
|
| + result->keys.ptr = Array<Key>::Data_::New(Traits::GetSize(input), buf);
|
| + if (result->keys.ptr) {
|
| + const ArrayValidateParams* key_validate_params =
|
| + MapKeyValidateParamsFactory<
|
| + typename GetDataTypeAsArrayElement<Key>::Data>::Get();
|
| + MapKeyReader<MaybeConstUserType> key_reader(input);
|
| + KeyArraySerializer::SerializeElements(
|
| + &key_reader, buf, result->keys.ptr, key_validate_params, context);
|
| + }
|
| +
|
| + result->values.ptr =
|
| + Array<Value>::Data_::New(Traits::GetSize(input), buf);
|
| + if (result->values.ptr) {
|
| + MapValueReader<MaybeConstUserType> value_reader(input);
|
| + ValueArraySerializer::SerializeElements(&value_reader, buf,
|
| + result->values.ptr,
|
| + value_validate_params, context);
|
| + }
|
| }
|
| *output = result;
|
| }
|
| @@ -90,26 +147,26 @@ struct Serializer<Map<Key, Value>, MaybeConstUserType> {
|
| static bool Deserialize(Data* input,
|
| UserType* output,
|
| SerializationContext* context) {
|
| - bool success = true;
|
| - if (input) {
|
| - Array<UserKey> keys;
|
| - Array<UserValue> values;
|
| -
|
| - // Note that we rely on complete deserialization taking place in order to
|
| - // transfer ownership of all encoded handles. Therefore we don't
|
| - // short-circuit on failure here.
|
| - if (!internal::Deserialize<Array<Key>>(input->keys.ptr, &keys, context))
|
| - success = false;
|
| - if (!internal::Deserialize<Array<Value>>(input->values.ptr, &values,
|
| - context)) {
|
| - success = false;
|
| - }
|
| + if (!input)
|
| + return CallSetToNullIfExists<Traits>(output);
|
|
|
| - *output = UserType(std::move(keys), std::move(values));
|
| - } else {
|
| - *output = nullptr;
|
| + Array<UserKey> keys;
|
| + Array<UserValue> values;
|
| +
|
| + if (!KeyArraySerializer::DeserializeElements(input->keys.ptr, &keys,
|
| + context) ||
|
| + !ValueArraySerializer::DeserializeElements(input->values.ptr, &values,
|
| + context)) {
|
| + return false;
|
| }
|
| - return success;
|
| +
|
| + DCHECK_EQ(keys.size(), values.size());
|
| + size_t size = keys.size();
|
| + Traits::SetToEmpty(output);
|
| +
|
| + for (size_t i = 0; i < size; ++i)
|
| + Traits::Insert(*output, std::move(keys[i]), std::move(values[i]));
|
| + return true;
|
| }
|
| };
|
|
|
|
|