/* * Copyright (C) 2014-present ScyllaDB */ /* * SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0 */ #pragma once #include #include #include #include #include "exceptions/exceptions.hh" #include "types/types.hh" #include "types/collection.hh" class user_type_impl; namespace Json { class Value; } class map_type_impl final : public concrete_type>, collection_type_impl> { using map_type = shared_ptr; using intern = type_interning_helper; data_type _keys; data_type _values; data_type _key_value_pair_type; public: static shared_ptr get_instance(data_type keys, data_type values, bool is_multi_cell); map_type_impl(data_type keys, data_type values, bool is_multi_cell); const data_type& get_keys_type() const { return _keys; } const data_type& get_values_type() const { return _values; } virtual data_type name_comparator() const override { return _keys; } virtual data_type value_comparator() const override { return _values; } virtual data_type freeze() const override; virtual bool is_compatible_with_frozen(const collection_type_impl& previous) const override; virtual bool is_value_compatible_with_frozen(const collection_type_impl& previous) const override; static std::strong_ordering compare_maps(data_type keys_comparator, data_type values_comparator, managed_bytes_view o1, managed_bytes_view o2); using abstract_type::deserialize; using collection_type_impl::deserialize; template data_value deserialize(View v) const; static bytes serialize_partially_deserialized_form(const std::vector>& v); static managed_bytes serialize_partially_deserialized_form_fragmented(const std::vector>& v); // Serializes a map using the internal cql serialization format // Takes a range of pair template requires std::convertible_to, std::pair> static bytes serialize_to_bytes(const Range& map_range); // Serializes a map using the internal cql serialization format // Takes a range of pair template requires std::convertible_to, std::pair> static managed_bytes serialize_to_managed_bytes(const Range& map_range); }; data_value make_map_value(data_type tuple_type, map_type_impl::native_type value); template requires std::convertible_to, std::pair> bytes map_type_impl::serialize_to_bytes(const Range& map_range) { size_t serialized_len = 4; size_t map_size = 0; for (const std::pair& elem : map_range) { serialized_len += 4 + elem.first.size() + 4 + elem.second.size(); map_size += 1; } if (map_size > std::numeric_limits::max()) { throw exceptions::invalid_request_exception( fmt::format("Map size too large: {} > {}", map_size, std::numeric_limits::max())); } bytes result(bytes::initialized_later(), serialized_len); bytes::iterator out = result.begin(); write_collection_size(out, map_size); for (const std::pair& elem : map_range) { if (elem.first.size() > std::numeric_limits::max()) { throw exceptions::invalid_request_exception( fmt::format("Map key size too large: {} bytes > {}", map_size, std::numeric_limits::max())); } if (elem.second.size() > std::numeric_limits::max()) { throw exceptions::invalid_request_exception( fmt::format("Map value size too large: {} bytes > {}", map_size, std::numeric_limits::max())); } write_collection_value(out, elem.first); write_collection_value(out, elem.second); } return result; } template requires std::convertible_to, std::pair> managed_bytes map_type_impl::serialize_to_managed_bytes(const Range& map_range) { size_t serialized_len = 4; size_t map_size = 0; for (const std::pair& elem : map_range) { serialized_len += 4 + elem.first.size() + 4 + elem.second.size(); map_size += 1; } if (map_size > std::numeric_limits::max()) { throw exceptions::invalid_request_exception( fmt::format("Map size too large: {} > {}", map_size, std::numeric_limits::max())); } managed_bytes result(managed_bytes::initialized_later(), serialized_len); managed_bytes_mutable_view out(result); write_collection_size(out, map_size); for (const std::pair& elem : map_range) { if (elem.first.size() > std::numeric_limits::max()) { throw exceptions::invalid_request_exception( fmt::format("Map key size too large: {} bytes > {}", map_size, std::numeric_limits::max())); } if (elem.second.size() > std::numeric_limits::max()) { throw exceptions::invalid_request_exception( fmt::format("Map value size too large: {} bytes > {}", map_size, std::numeric_limits::max())); } write_collection_value(out, elem.first); write_collection_value(out, elem.second); } return result; }