/* * Copyright (C) 2015 Cloudius Systems, Ltd. */ #pragma once #include "types.hh" #include #include #include #include #include "util/serialization.hh" #include "unimplemented.hh" // value_traits is meant to abstract away whether we are working on 'bytes' // elements or 'bytes_opt' elements. We don't support optional values, but // there are some generic layers which use this code which provide us with // data in that format. In order to avoid allocation and rewriting that data // into a new vector just to throw it away soon after that, we accept that // format too. template struct value_traits { static const T& unwrap(const T& t) { return t; } }; template<> struct value_traits { static const bytes& unwrap(const bytes_opt& t) { assert(t); return *t; } }; enum class allow_prefixes { yes, no }; template class tuple_type final { private: const std::vector> _types; const bool _byte_order_equal; const bool _byte_order_comparable; public: using prefix_type = tuple_type; using value_type = std::vector; tuple_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(_types.size() == 1 && _types[0]->is_byte_order_comparable()) { } tuple_type(tuple_type&&) = default; auto const& types() { return _types; } prefix_type as_prefix() { return prefix_type(_types); } /* * Format: * ...(len(value_n))? * * The value corresponding to the last component of types doesn't have its length encoded, * its length is deduced from the input range. * * serialize_value() and serialize_optionals() for single element rely on the fact that for a single-element * tuples their serialized form is equal to the serialized form of the component. */ template void serialize_value(const std::vector& values, bytes::iterator& out) { if (AllowPrefixes == allow_prefixes::yes) { assert(values.size() <= _types.size()); } else { assert(values.size() == _types.size()); } size_t n_left = _types.size(); for (auto&& wrapped : values) { auto&& val = value_traits::unwrap(wrapped); assert(val.size() <= std::numeric_limits::max()); if (--n_left) { write(out, uint16_t(val.size())); } out = std::copy(val.begin(), val.end(), out); } } template size_t serialized_size(const std::vector& values) { size_t len = 0; size_t n_left = _types.size(); for (auto&& wrapped : values) { auto&& val = value_traits::unwrap(wrapped); assert(val.size() <= std::numeric_limits::max()); if (--n_left) { len += sizeof(uint16_t); } len += val.size(); } return len; } bytes serialize_single(bytes&& v) { if (AllowPrefixes == allow_prefixes::no) { assert(_types.size() == 1); } else { if (_types.size() > 1) { std::vector vec; vec.reserve(1); vec.emplace_back(std::move(v)); return ::serialize_value(*this, vec); } } return std::move(v); } bytes serialize_value(const std::vector& values) { return ::serialize_value(*this, values); } bytes serialize_value(std::vector&& values) { if (_types.size() == 1 && values.size() == 1) { return std::move(values[0]); } return ::serialize_value(*this, values); } bytes serialize_optionals(const std::vector& values) { return ::serialize_value(*this, values); } bytes serialize_optionals(std::vector&& values) { if (_types.size() == 1 && values.size() == 1) { assert(values[0]); return std::move(*values[0]); } return ::serialize_value(*this, values); } 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(*this, values); } class iterator : public std::iterator { private: ssize_t _types_left; bytes_view _v; value_type _current; private: void read_current() { if (_types_left == 0) { if (!_v.empty()) { throw marshal_exception(); } _v = bytes_view(nullptr, 0); return; } if (_v.empty()) { if (AllowPrefixes == allow_prefixes::yes) { _v = bytes_view(nullptr, 0); return; } else { throw marshal_exception(); } } uint16_t len; if (_types_left == 1) { len = _v.size(); } else { 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 tuple_type& t, const bytes_view& v) : _types_left(t._types.size()), _v(v) { read_current(); } iterator(end_iterator_tag, const bytes_view& v) : _v(nullptr, 0) {} iterator& operator++() { --_types_left; read_current(); return *this; } 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(); } }; iterator begin(const bytes_view& v) const { return iterator(*this, v); } iterator end(const bytes_view& v) const { return iterator(typename iterator::end_iterator_tag(), v); } auto iter_items(const bytes_view& v) { return boost::iterator_range(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 : iter_items(v)) { h ^= (*t)->hash(value); ++t; } return h; } int compare(bytes_view b1, bytes_view b2) { if (_byte_order_comparable) { 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); }); } bytes from_string(sstring_view s) { throw std::runtime_error("not implemented"); } sstring to_string(const bytes& b) { throw std::runtime_error("not implemented"); } // 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(); } 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 tuple_prefix = tuple_type;