/* * Copyright (C) 2015 ScyllaDB */ /* * This file is part of Scylla. * * Scylla is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Scylla is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Scylla. If not, see . */ #pragma once #include "types.hh" #include #include #include #include #include #include "utils/serialization.hh" #include "unimplemented.hh" enum class allow_prefixes { no, yes }; template class compound_type final { private: const std::vector _types; const bool _byte_order_equal; const bool _byte_order_comparable; const bool _is_reversed; public: static constexpr bool is_prefixable = AllowPrefixes == allow_prefixes::yes; using prefix_type = compound_type; using value_type = std::vector; using size_type = uint16_t; compound_type(std::vector types) : _types(std::move(types)) , _byte_order_equal(std::all_of(_types.begin(), _types.end(), [] (auto t) { return t->is_byte_order_equal(); })) , _byte_order_comparable(false) , _is_reversed(_types.size() == 1 && _types[0]->is_reversed()) { } compound_type(compound_type&&) = default; auto const& types() const { return _types; } bool is_singular() const { return _types.size() == 1; } prefix_type as_prefix() { return prefix_type(_types); } private: /* * Format: * ... * */ template static void serialize_value(RangeOfSerializedComponents&& values, bytes::iterator& out) { for (auto&& val : values) { assert(val.size() <= std::numeric_limits::max()); write(out, size_type(val.size())); out = std::copy(val.begin(), val.end(), out); } } template static size_t serialized_size(RangeOfSerializedComponents&& values) { size_t len = 0; for (auto&& val : values) { len += sizeof(size_type) + val.size(); } return len; } public: bytes serialize_single(bytes&& v) { return serialize_value({std::move(v)}); } template static bytes serialize_value(RangeOfSerializedComponents&& values) { auto size = serialized_size(values); if (size > std::numeric_limits::max()) { throw std::runtime_error(sprint("Key size too large: %d > %d", size, std::numeric_limits::max())); } bytes b(bytes::initialized_later(), size); auto i = b.begin(); serialize_value(values, i); return b; } template static bytes serialize_value(std::initializer_list values) { return serialize_value(boost::make_iterator_range(values.begin(), values.end())); } bytes serialize_optionals(const std::vector& values) { return serialize_value(values | boost::adaptors::transformed([] (const bytes_opt& bo) -> bytes_view { if (!bo) { throw std::logic_error("attempted to create key component from empty optional"); } return *bo; })); } bytes serialize_value_deep(const std::vector& values) { // TODO: Optimize std::vector partial; partial.reserve(values.size()); auto i = _types.begin(); for (auto&& component : values) { assert(i != _types.end()); partial.push_back((*i++)->decompose(component)); } return serialize_value(partial); } bytes decompose_value(const value_type& values) { return serialize_value(values); } class iterator : public std::iterator { private: bytes_view _v; bytes_view _current; private: void read_current() { size_type len; { if (_v.empty()) { _v = bytes_view(nullptr, 0); return; } len = read_simple(_v); if (_v.size() < len) { throw marshal_exception(); } } _current = bytes_view(_v.begin(), len); _v.remove_prefix(len); } public: struct end_iterator_tag {}; iterator(const bytes_view& v) : _v(v) { read_current(); } iterator(end_iterator_tag, const bytes_view& v) : _v(nullptr, 0) {} iterator& operator++() { read_current(); return *this; } iterator operator++(int) { iterator i(*this); ++(*this); return i; } const value_type& operator*() const { return _current; } const value_type* operator->() const { return &_current; } bool operator!=(const iterator& i) const { return _v.begin() != i._v.begin(); } bool operator==(const iterator& i) const { return _v.begin() == i._v.begin(); } }; static iterator begin(const bytes_view& v) { return iterator(v); } static iterator end(const bytes_view& v) { return iterator(typename iterator::end_iterator_tag(), v); } static boost::iterator_range components(const bytes_view& v) { return { begin(v), end(v) }; } value_type deserialize_value(bytes_view v) { std::vector result; result.reserve(_types.size()); std::transform(begin(v), end(v), std::back_inserter(result), [] (auto&& v) { return bytes(v.begin(), v.end()); }); return result; } bool less(bytes_view b1, bytes_view b2) { return compare(b1, b2) < 0; } size_t hash(bytes_view v) { if (_byte_order_equal) { return std::hash()(v); } auto t = _types.begin(); size_t h = 0; for (auto&& value : components(v)) { h ^= (*t)->hash(value); ++t; } return h; } int compare(bytes_view b1, bytes_view b2) { if (_byte_order_comparable) { if (_is_reversed) { return compare_unsigned(b2, b1); } else { return compare_unsigned(b1, b2); } } return lexicographical_tri_compare(_types.begin(), _types.end(), begin(b1), end(b1), begin(b2), end(b2), [] (auto&& type, auto&& v1, auto&& v2) { return type->compare(v1, v2); }); } // Retruns true iff given prefix has no missing components bool is_full(bytes_view v) const { assert(AllowPrefixes == allow_prefixes::yes); return std::distance(begin(v), end(v)) == (ssize_t)_types.size(); } bool is_empty(bytes_view v) const { return begin(v) == end(v); } void validate(bytes_view v) { // FIXME: implement warn(unimplemented::cause::VALIDATION); } bool equal(bytes_view v1, bytes_view v2) { if (_byte_order_equal) { return compare_unsigned(v1, v2) == 0; } // FIXME: call equal() on each component return compare(v1, v2) == 0; } }; using compound_prefix = compound_type;