Chromium Code Reviews| 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..43cb4dbc14624ddb4c5031310eb179c60899c133 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,86 @@ |
| 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_); } |
| - bool is_null; |
| - Array<Key> keys; |
| - Array<Value> values; |
| + // Return null because key or value elements are not stored continuously in |
| + // memory. |
| + void* GetDataIfAvailable() { return nullptr; } |
| + |
| + protected: |
| + MaybeConstUserType& input_; |
| + MaybeConstIterator iter_; |
| +}; |
| + |
| +// Used as the UserTypeReader template parameter of ArraySerializer. |
| +template <typename MaybeConstUserType> |
| +class MapKeyReader : public MapReaderBase<MaybeConstUserType> { |
| + public: |
| + explicit MapKeyReader(MaybeConstUserType& input) : MapReaderBase(input) {} |
| + ~MapKeyReader() {} |
| + |
| + const typename Traits::Key& GetNext() { |
|
Ken Rockot(use gerrit already)
2016/05/27 16:07:39
Seems a lot of compiles don't like this use of Tra
yzshen1
2016/05/28 00:23:07
Done.
|
| + const typename Traits::Key& key = Traits::GetKey(iter_); |
| + Traits::AdvanceIterator(iter_); |
| + return key; |
| + } |
| +}; |
| + |
| +// Used as the UserTypeReader template parameter of ArraySerializer. |
| +template <typename MaybeConstUserType> |
| +class MapValueReader : public MapReaderBase<MaybeConstUserType> { |
| + public: |
| + explicit MapValueReader(MaybeConstUserType& input) : MapReaderBase(input) {} |
| + ~MapValueReader() {} |
| + |
| + using GetNextResult = |
| + decltype(Traits::GetValue(std::declval<MaybeConstIterator&>())); |
| + GetNextResult GetNext() { |
| + GetNextResult value = Traits::GetValue(iter_); |
| + Traits::AdvanceIterator(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 +103,37 @@ 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 = |
| + typename 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 = |
| + typename 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 +141,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. |
|
yzshen1
2016/05/26 21:58:30
(I think we can short-circuit now because of your
Ken Rockot(use gerrit already)
2016/05/27 16:07:39
Woohoo!
|
| - 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; |
| } |
| }; |