Files
scylla/types/vector.hh
Jan Łakomy 9561ae5fc8 types: implement vector_type_impl
The vector is a fixed-length array of non-null
specified type elements.

Implement serialization, deserialization, comparison,
JSON and Lua support, and other functionalities.

Co-authored-by: Dawid Pawlik <501149991dp@gmail.com>
2025-01-26 19:36:41 +01:00

123 lines
4.1 KiB
C++

/*
* Copyright (C) 2024-present ScyllaDB
*/
/*
* SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0
*/
#pragma once
#include "types/types.hh"
#include "exceptions/exceptions.hh"
#include "vint-serialization.hh"
class vector_type_impl : public concrete_type<std::vector<data_value>> {
using intern = type_interning_helper<vector_type_impl, data_type, size_t>;
protected:
data_type _elements_type;
size_t _dimension;
public:
vector_type_impl(data_type elements_type, size_t dimension);
static shared_ptr<const vector_type_impl> get_instance(data_type type, size_t dimension);
data_type get_elements_type() const {
return _elements_type;
}
size_t get_dimension() const {
return _dimension;
}
static std::strong_ordering compare_vectors(data_type elements_comparator, size_t dimension,
managed_bytes_view o1, managed_bytes_view o2);
std::vector<managed_bytes> split_fragmented(FragmentedView auto v) const {
std::vector<managed_bytes> elements;
for (size_t i = 0; i < _dimension; ++i) {
auto element = read_vector_element(v, _elements_type->value_length_if_fixed());
elements.push_back(managed_bytes(element));
}
return elements;
}
template <typename Range> // range of managed_bytes or managed_bytes_view
requires requires (Range it) { {*std::begin(it)} -> std::convertible_to<managed_bytes_view>; }
static managed_bytes build_value_fragmented(Range&& range, std::optional<size_t> value_length_if_fixed) {
bool is_fixed_length = value_length_if_fixed.has_value();
size_t size = 0;
for (auto&& v : range) {
size += v.size();
if (!is_fixed_length) {
size += (size_t)unsigned_vint::serialized_size(v.size());
}
}
auto ret = bytes(bytes::initialized_later(), size);
auto out = ret.begin();
for (auto&& v : range) {
if (!is_fixed_length) {
out += unsigned_vint::serialize(v.size(), out);
}
auto read_bytes = [v] (bytes_view element_bytes) {return read_simple_bytes(element_bytes, v.size());};
auto element = with_linearized(managed_bytes_view(v), read_bytes);
out = std::copy_n(element.begin(), element.size(), out);
}
return managed_bytes(ret);
}
template <typename RangeOf_bytes> // also accepts bytes_view
requires requires (RangeOf_bytes it) { {*std::begin(it)} -> std::convertible_to<bytes_view>; }
static bytes build_value(RangeOf_bytes&& range, std::optional<size_t> value_length_if_fixed) {
bool is_fixed_length = value_length_if_fixed.has_value();
size_t size = 0;
for (auto&& v : range) {
size += v.size();
if (!is_fixed_length) {
size += (size_t)unsigned_vint::serialized_size(v.size());
}
}
auto ret = bytes(bytes::initialized_later(), size);
auto out = ret.begin();
for (auto&& v : range) {
if (!is_fixed_length) {
out += unsigned_vint::serialize(v.size(), out);
}
out = std::copy_n(v.begin(), v.size(), out);
}
return ret;
}
private:
static sstring make_name(data_type type, size_t dimension);
};
template <FragmentedView View>
View read_vector_element(View& v, std::optional<size_t> value_length_if_fixed) {
uint64_t element_size;
if (value_length_if_fixed) {
element_size = value_length_if_fixed.value();
} else {
element_size = with_linearized(v, unsigned_vint::deserialize);
v.remove_prefix(unsigned_vint::serialized_size(element_size));
}
if (element_size == 0) {
throw exceptions::invalid_request_exception("null/unset is not supported inside vectors");
}
if ((size_t)element_size > v.size_bytes()) {
throw exceptions::invalid_request_exception("Not enough bytes to read a vector element");
}
return read_simple_bytes(v, element_size);
}
data_value make_vector_value(data_type type, vector_type_impl::native_type value);