mirror of
https://github.com/scylladb/scylladb.git
synced 2026-05-31 20:16:43 +00:00
db: rename tuple_type family to compound_type
tuples already have a meaning in Cassandra and in C++, let's not overload the word even more. Use compound, which is the word used in Origin as well.
This commit is contained in:
committed by
Tomasz Grabiec
parent
28f9f629c9
commit
f779c54d75
@@ -35,16 +35,16 @@ struct value_traits<bytes_opt> {
|
||||
enum class allow_prefixes { yes, no };
|
||||
|
||||
template<allow_prefixes AllowPrefixes = allow_prefixes::no>
|
||||
class tuple_type final {
|
||||
class compound_type final {
|
||||
private:
|
||||
const std::vector<shared_ptr<abstract_type>> _types;
|
||||
const bool _byte_order_equal;
|
||||
const bool _byte_order_comparable;
|
||||
public:
|
||||
using prefix_type = tuple_type<allow_prefixes::yes>;
|
||||
using prefix_type = compound_type<allow_prefixes::yes>;
|
||||
using value_type = std::vector<bytes>;
|
||||
|
||||
tuple_type(std::vector<shared_ptr<abstract_type>> types)
|
||||
compound_type(std::vector<shared_ptr<abstract_type>> types)
|
||||
: _types(std::move(types))
|
||||
, _byte_order_equal(std::all_of(_types.begin(), _types.end(), [] (auto t) {
|
||||
return t->is_byte_order_equal();
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
, _byte_order_comparable(_types.size() == 1 && _types[0]->is_byte_order_comparable())
|
||||
{ }
|
||||
|
||||
tuple_type(tuple_type&&) = default;
|
||||
compound_type(compound_type&&) = default;
|
||||
|
||||
auto const& types() {
|
||||
return _types;
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
* 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.
|
||||
* compounds their serialized form is equal to the serialized form of the component.
|
||||
*/
|
||||
template<typename Wrapped>
|
||||
void serialize_value(const std::vector<Wrapped>& values, bytes::iterator& out) {
|
||||
@@ -186,7 +186,7 @@ public:
|
||||
}
|
||||
public:
|
||||
struct end_iterator_tag {};
|
||||
iterator(const tuple_type& t, const bytes_view& v) : _types_left(t._types.size()), _v(v) {
|
||||
iterator(const compound_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) {}
|
||||
@@ -264,4 +264,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
using tuple_prefix = tuple_type<allow_prefixes::yes>;
|
||||
using compound_prefix = compound_type<allow_prefixes::yes>;
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <experimental/optional>
|
||||
#include <string.h>
|
||||
#include "types.hh"
|
||||
#include "tuple.hh"
|
||||
#include "compound.hh"
|
||||
#include "core/future.hh"
|
||||
#include "cql3/column_specification.hh"
|
||||
#include <limits>
|
||||
|
||||
124
keys.hh
124
keys.hh
@@ -34,107 +34,107 @@ class partition_key;
|
||||
class clustering_key;
|
||||
class clustering_key_prefix;
|
||||
|
||||
// Abstracts serialized tuple, managed by tuple_type.
|
||||
// Abstracts serialized compound, managed by compound_type.
|
||||
template <typename TopLevel>
|
||||
class tuple_wrapper {
|
||||
class compound_wrapper {
|
||||
protected:
|
||||
bytes _bytes;
|
||||
protected:
|
||||
tuple_wrapper(bytes&& b) : _bytes(std::move(b)) {}
|
||||
compound_wrapper(bytes&& b) : _bytes(std::move(b)) {}
|
||||
|
||||
static inline const auto& get_tuple_type(const schema& s) {
|
||||
return TopLevel::get_tuple_type(s);
|
||||
static inline const auto& get_compound_type(const schema& s) {
|
||||
return TopLevel::get_compound_type(s);
|
||||
}
|
||||
public:
|
||||
static TopLevel make_empty(const schema& s) {
|
||||
std::vector<bytes> v;
|
||||
v.resize(get_tuple_type(s)->types().size());
|
||||
v.resize(get_compound_type(s)->types().size());
|
||||
return from_exploded(s, v);
|
||||
}
|
||||
|
||||
static TopLevel from_exploded(const schema& s, const std::vector<bytes>& v) {
|
||||
return TopLevel::from_bytes(get_tuple_type(s)->serialize_value(v));
|
||||
return TopLevel::from_bytes(get_compound_type(s)->serialize_value(v));
|
||||
}
|
||||
|
||||
static TopLevel from_exploded(const schema& s, std::vector<bytes>&& v) {
|
||||
return TopLevel::from_bytes(get_tuple_type(s)->serialize_value(std::move(v)));
|
||||
return TopLevel::from_bytes(get_compound_type(s)->serialize_value(std::move(v)));
|
||||
}
|
||||
|
||||
// We don't allow optional values, but provide this method as an efficient adaptor
|
||||
static TopLevel from_optional_exploded(const schema& s, const std::vector<bytes_opt>& v) {
|
||||
return TopLevel::from_bytes(get_tuple_type(s)->serialize_optionals(v));
|
||||
return TopLevel::from_bytes(get_compound_type(s)->serialize_optionals(v));
|
||||
}
|
||||
|
||||
static TopLevel from_deeply_exploded(const schema& s, const std::vector<boost::any>& v) {
|
||||
return TopLevel::from_bytes(get_tuple_type(s)->serialize_value_deep(v));
|
||||
return TopLevel::from_bytes(get_compound_type(s)->serialize_value_deep(v));
|
||||
}
|
||||
|
||||
static TopLevel from_single_value(const schema& s, bytes v) {
|
||||
return TopLevel::from_bytes(get_tuple_type(s)->serialize_single(std::move(v)));
|
||||
return TopLevel::from_bytes(get_compound_type(s)->serialize_single(std::move(v)));
|
||||
}
|
||||
|
||||
// FIXME: return views
|
||||
std::vector<bytes> explode(const schema& s) const {
|
||||
return get_tuple_type(s)->deserialize_value(_bytes);
|
||||
return get_compound_type(s)->deserialize_value(_bytes);
|
||||
}
|
||||
|
||||
struct less_compare {
|
||||
typename TopLevel::tuple _t;
|
||||
less_compare(const schema& s) : _t(get_tuple_type(s)) {}
|
||||
typename TopLevel::compound _t;
|
||||
less_compare(const schema& s) : _t(get_compound_type(s)) {}
|
||||
bool operator()(const TopLevel& k1, const TopLevel& k2) const {
|
||||
return _t->less(k1, k2);
|
||||
}
|
||||
};
|
||||
|
||||
struct hashing {
|
||||
typename TopLevel::tuple _t;
|
||||
hashing(const schema& s) : _t(get_tuple_type(s)) {}
|
||||
typename TopLevel::compound _t;
|
||||
hashing(const schema& s) : _t(get_compound_type(s)) {}
|
||||
size_t operator()(const TopLevel& o) const {
|
||||
return _t->hash(o);
|
||||
}
|
||||
};
|
||||
|
||||
struct equality {
|
||||
typename TopLevel::tuple _t;
|
||||
equality(const schema& s) : _t(get_tuple_type(s)) {}
|
||||
typename TopLevel::compound _t;
|
||||
equality(const schema& s) : _t(get_compound_type(s)) {}
|
||||
bool operator()(const TopLevel& o1, const TopLevel& o2) const {
|
||||
return _t->equal(o1, o2);
|
||||
}
|
||||
};
|
||||
|
||||
bool equal(const schema& s, const TopLevel& other) const {
|
||||
return get_tuple_type(s)->equal(*this, other);
|
||||
return get_compound_type(s)->equal(*this, other);
|
||||
}
|
||||
|
||||
operator bytes_view() const {
|
||||
return _bytes;
|
||||
}
|
||||
|
||||
// begin() and end() return iterators over components of this tuple. The iterator yields a bytes_view to the component.
|
||||
// begin() and end() return iterators over components of this compound. The iterator yields a bytes_view to the component.
|
||||
auto begin(const schema& s) const {
|
||||
return get_tuple_type(s)->begin(_bytes);
|
||||
return get_compound_type(s)->begin(_bytes);
|
||||
}
|
||||
|
||||
// See begin()
|
||||
auto end(const schema& s) const {
|
||||
return get_tuple_type(s)->end(_bytes);
|
||||
return get_compound_type(s)->end(_bytes);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TopLevel, typename PrefixTopLevel>
|
||||
class prefix_view_on_full_tuple {
|
||||
class prefix_view_on_full_compound {
|
||||
public:
|
||||
using iterator = typename tuple_type<allow_prefixes::no>::iterator;
|
||||
using iterator = typename compound_type<allow_prefixes::no>::iterator;
|
||||
private:
|
||||
bytes_view _b;
|
||||
unsigned _prefix_len;
|
||||
iterator _begin;
|
||||
iterator _end;
|
||||
public:
|
||||
prefix_view_on_full_tuple(const schema& s, bytes_view b, unsigned prefix_len)
|
||||
prefix_view_on_full_compound(const schema& s, bytes_view b, unsigned prefix_len)
|
||||
: _b(b)
|
||||
, _prefix_len(prefix_len)
|
||||
, _begin(TopLevel::get_tuple_type(s)->begin(_b))
|
||||
, _begin(TopLevel::get_compound_type(s)->begin(_b))
|
||||
, _end(_begin)
|
||||
{
|
||||
std::advance(_end, prefix_len);
|
||||
@@ -144,13 +144,13 @@ public:
|
||||
iterator end() const { return _end; }
|
||||
|
||||
struct less_compare_with_prefix {
|
||||
typename PrefixTopLevel::tuple prefix_type;
|
||||
typename PrefixTopLevel::compound prefix_type;
|
||||
|
||||
less_compare_with_prefix(const schema& s)
|
||||
: prefix_type(PrefixTopLevel::get_tuple_type(s))
|
||||
: prefix_type(PrefixTopLevel::get_compound_type(s))
|
||||
{ }
|
||||
|
||||
bool operator()(const prefix_view_on_full_tuple& k1, const PrefixTopLevel& k2) const {
|
||||
bool operator()(const prefix_view_on_full_compound& k1, const PrefixTopLevel& k2) const {
|
||||
return lexicographical_tri_compare(
|
||||
prefix_type->types().begin(), prefix_type->types().end(),
|
||||
k1.begin(), k1.end(),
|
||||
@@ -158,7 +158,7 @@ public:
|
||||
tri_compare) < 0;
|
||||
}
|
||||
|
||||
bool operator()(const PrefixTopLevel& k1, const prefix_view_on_full_tuple& k2) const {
|
||||
bool operator()(const PrefixTopLevel& k1, const prefix_view_on_full_compound& k2) const {
|
||||
return lexicographical_tri_compare(
|
||||
prefix_type->types().begin(), prefix_type->types().end(),
|
||||
prefix_type->begin(k1), prefix_type->end(k1),
|
||||
@@ -169,16 +169,16 @@ public:
|
||||
};
|
||||
|
||||
template <typename TopLevel, typename PrefixTopLevel>
|
||||
class prefixable_full_tuple : public tuple_wrapper<TopLevel> {
|
||||
using base = tuple_wrapper<TopLevel>;
|
||||
class prefixable_full_compound : public compound_wrapper<TopLevel> {
|
||||
using base = compound_wrapper<TopLevel>;
|
||||
protected:
|
||||
prefixable_full_tuple(bytes&& b) : base(std::move(b)) {}
|
||||
prefixable_full_compound(bytes&& b) : base(std::move(b)) {}
|
||||
public:
|
||||
using prefix_view_type = prefix_view_on_full_tuple<TopLevel, PrefixTopLevel>;
|
||||
using prefix_view_type = prefix_view_on_full_compound<TopLevel, PrefixTopLevel>;
|
||||
|
||||
bool is_prefixed_by(const schema& s, const PrefixTopLevel& prefix) const {
|
||||
auto t = base::get_tuple_type(s);
|
||||
auto prefix_type = PrefixTopLevel::get_tuple_type(s);
|
||||
auto t = base::get_compound_type(s);
|
||||
auto prefix_type = PrefixTopLevel::get_compound_type(s);
|
||||
return ::is_prefixed_by(t->types().begin(),
|
||||
t->begin(*this), t->end(*this),
|
||||
prefix_type->begin(prefix), prefix_type->end(prefix),
|
||||
@@ -186,12 +186,12 @@ public:
|
||||
}
|
||||
|
||||
struct less_compare_with_prefix {
|
||||
typename PrefixTopLevel::tuple prefix_type;
|
||||
typename TopLevel::tuple full_type;
|
||||
typename PrefixTopLevel::compound prefix_type;
|
||||
typename TopLevel::compound full_type;
|
||||
|
||||
less_compare_with_prefix(const schema& s)
|
||||
: prefix_type(PrefixTopLevel::get_tuple_type(s))
|
||||
, full_type(TopLevel::get_tuple_type(s))
|
||||
: prefix_type(PrefixTopLevel::get_compound_type(s))
|
||||
, full_type(TopLevel::get_compound_type(s))
|
||||
{ }
|
||||
|
||||
bool operator()(const TopLevel& k1, const PrefixTopLevel& k2) const {
|
||||
@@ -213,15 +213,15 @@ public:
|
||||
|
||||
// In prefix equality two sequences are equal if any of them is a prefix
|
||||
// of the other. Otherwise lexicographical ordering is applied.
|
||||
// Note: full tuples sorted according to lexicographical ordering are also
|
||||
// Note: full compounds sorted according to lexicographical ordering are also
|
||||
// sorted according to prefix equality ordering.
|
||||
struct prefix_equality_less_compare {
|
||||
typename PrefixTopLevel::tuple prefix_type;
|
||||
typename TopLevel::tuple full_type;
|
||||
typename PrefixTopLevel::compound prefix_type;
|
||||
typename TopLevel::compound full_type;
|
||||
|
||||
prefix_equality_less_compare(const schema& s)
|
||||
: prefix_type(PrefixTopLevel::get_tuple_type(s))
|
||||
, full_type(TopLevel::get_tuple_type(s))
|
||||
: prefix_type(PrefixTopLevel::get_compound_type(s))
|
||||
, full_type(TopLevel::get_compound_type(s))
|
||||
{ }
|
||||
|
||||
bool operator()(const TopLevel& k1, const PrefixTopLevel& k2) const {
|
||||
@@ -245,13 +245,13 @@ public:
|
||||
};
|
||||
|
||||
template <typename TopLevel, typename FullTopLevel>
|
||||
class prefix_tuple_wrapper : public tuple_wrapper<TopLevel> {
|
||||
using base = tuple_wrapper<TopLevel>;
|
||||
class prefix_compound_wrapper : public compound_wrapper<TopLevel> {
|
||||
using base = compound_wrapper<TopLevel>;
|
||||
protected:
|
||||
prefix_tuple_wrapper(bytes&& b) : base(std::move(b)) {}
|
||||
prefix_compound_wrapper(bytes&& b) : base(std::move(b)) {}
|
||||
public:
|
||||
bool is_full(const schema& s) const {
|
||||
return TopLevel::get_tuple_type(s)->is_full(base::_bytes);
|
||||
return TopLevel::get_compound_type(s)->is_full(base::_bytes);
|
||||
}
|
||||
|
||||
// Can be called only if is_full()
|
||||
@@ -260,7 +260,7 @@ public:
|
||||
}
|
||||
|
||||
bool is_prefixed_by(const schema& s, const TopLevel& prefix) const {
|
||||
auto t = base::get_tuple_type(s);
|
||||
auto t = base::get_compound_type(s);
|
||||
return ::is_prefixed_by(t->types().begin(),
|
||||
t->begin(*this), t->end(*this),
|
||||
t->begin(prefix), t->end(prefix),
|
||||
@@ -268,17 +268,17 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class partition_key : public tuple_wrapper<partition_key> {
|
||||
class partition_key : public compound_wrapper<partition_key> {
|
||||
public:
|
||||
partition_key(bytes&& b) : tuple_wrapper<partition_key>(std::move(b)) {}
|
||||
partition_key(bytes&& b) : compound_wrapper<partition_key>(std::move(b)) {}
|
||||
public:
|
||||
using tuple = lw_shared_ptr<tuple_type<allow_prefixes::no>>;
|
||||
using compound = lw_shared_ptr<compound_type<allow_prefixes::no>>;
|
||||
|
||||
static partition_key from_bytes(bytes b) {
|
||||
return partition_key(std::move(b));
|
||||
}
|
||||
|
||||
static const tuple& get_tuple_type(const schema& s) {
|
||||
static const compound& get_compound_type(const schema& s) {
|
||||
return s.partition_key_type();
|
||||
}
|
||||
|
||||
@@ -305,17 +305,17 @@ public:
|
||||
friend std::ostream& operator<<(std::ostream& os, const exploded_clustering_prefix& ecp);
|
||||
};
|
||||
|
||||
class clustering_key : public prefixable_full_tuple<clustering_key, clustering_key_prefix> {
|
||||
class clustering_key : public prefixable_full_compound<clustering_key, clustering_key_prefix> {
|
||||
public:
|
||||
clustering_key(bytes&& b) : prefixable_full_tuple<clustering_key, clustering_key_prefix>(std::move(b)) {}
|
||||
clustering_key(bytes&& b) : prefixable_full_compound<clustering_key, clustering_key_prefix>(std::move(b)) {}
|
||||
public:
|
||||
using tuple = lw_shared_ptr<tuple_type<allow_prefixes::no>>;
|
||||
using compound = lw_shared_ptr<compound_type<allow_prefixes::no>>;
|
||||
|
||||
static clustering_key from_bytes(bytes b) {
|
||||
return clustering_key(std::move(b));
|
||||
}
|
||||
|
||||
static const tuple& get_tuple_type(const schema& s) {
|
||||
static const compound& get_compound_type(const schema& s) {
|
||||
return s.clustering_key_type();
|
||||
}
|
||||
|
||||
@@ -327,16 +327,16 @@ public:
|
||||
friend std::ostream& operator<<(std::ostream& out, const clustering_key& ck);
|
||||
};
|
||||
|
||||
class clustering_key_prefix : public prefix_tuple_wrapper<clustering_key_prefix, clustering_key> {
|
||||
clustering_key_prefix(bytes&& b) : prefix_tuple_wrapper<clustering_key_prefix, clustering_key>(std::move(b)) {}
|
||||
class clustering_key_prefix : public prefix_compound_wrapper<clustering_key_prefix, clustering_key> {
|
||||
clustering_key_prefix(bytes&& b) : prefix_compound_wrapper<clustering_key_prefix, clustering_key>(std::move(b)) {}
|
||||
public:
|
||||
using tuple = lw_shared_ptr<tuple_type<allow_prefixes::yes>>;
|
||||
using compound = lw_shared_ptr<compound_type<allow_prefixes::yes>>;
|
||||
|
||||
static clustering_key_prefix from_bytes(bytes b) {
|
||||
return clustering_key_prefix(std::move(b));
|
||||
}
|
||||
|
||||
static const tuple& get_tuple_type(const schema& s) {
|
||||
static const compound& get_compound_type(const schema& s) {
|
||||
return s.clustering_key_prefix_type();
|
||||
}
|
||||
|
||||
|
||||
@@ -37,8 +37,8 @@ schema::build_columns(const std::vector<column>& columns, column_definition::col
|
||||
}
|
||||
|
||||
void schema::rebuild() {
|
||||
_partition_key_type = make_lw_shared<tuple_type<>>(get_column_types(_raw._partition_key));
|
||||
_clustering_key_type = make_lw_shared<tuple_type<>>(get_column_types(_raw._clustering_key));
|
||||
_partition_key_type = make_lw_shared<compound_type<>>(get_column_types(_raw._partition_key));
|
||||
_clustering_key_type = make_lw_shared<compound_type<>>(get_column_types(_raw._clustering_key));
|
||||
_clustering_key_prefix_type = make_lw_shared(_clustering_key_type->as_prefix());
|
||||
|
||||
_thrift = thrift_schema();
|
||||
|
||||
14
schema.hh
14
schema.hh
@@ -12,7 +12,7 @@
|
||||
#include "cql3/column_specification.hh"
|
||||
#include "core/shared_ptr.hh"
|
||||
#include "types.hh"
|
||||
#include "tuple.hh"
|
||||
#include "compound.hh"
|
||||
#include "gc_clock.hh"
|
||||
#include "unimplemented.hh"
|
||||
#include "utils/UUID.hh"
|
||||
@@ -88,9 +88,9 @@ private:
|
||||
private:
|
||||
std::unordered_map<bytes, const column_definition*> _columns_by_name;
|
||||
std::map<bytes, const column_definition*, serialized_compare> _regular_columns_by_name;
|
||||
lw_shared_ptr<tuple_type<allow_prefixes::no>> _partition_key_type;
|
||||
lw_shared_ptr<tuple_type<allow_prefixes::no>> _clustering_key_type;
|
||||
lw_shared_ptr<tuple_type<allow_prefixes::yes>> _clustering_key_prefix_type;
|
||||
lw_shared_ptr<compound_type<allow_prefixes::no>> _partition_key_type;
|
||||
lw_shared_ptr<compound_type<allow_prefixes::no>> _clustering_key_type;
|
||||
lw_shared_ptr<compound_type<allow_prefixes::yes>> _clustering_key_prefix_type;
|
||||
thrift_schema _thrift;
|
||||
public:
|
||||
struct column {
|
||||
@@ -219,13 +219,13 @@ public:
|
||||
const sstring& cf_name() const {
|
||||
return _raw._cf_name;
|
||||
}
|
||||
const lw_shared_ptr<tuple_type<allow_prefixes::no>>& partition_key_type() const {
|
||||
const lw_shared_ptr<compound_type<allow_prefixes::no>>& partition_key_type() const {
|
||||
return _partition_key_type;
|
||||
}
|
||||
const lw_shared_ptr<tuple_type<allow_prefixes::no>>& clustering_key_type() const {
|
||||
const lw_shared_ptr<compound_type<allow_prefixes::no>>& clustering_key_type() const {
|
||||
return _clustering_key_type;
|
||||
}
|
||||
const lw_shared_ptr<tuple_type<allow_prefixes::yes>>& clustering_key_prefix_type() const {
|
||||
const lw_shared_ptr<compound_type<allow_prefixes::yes>>& clustering_key_prefix_type() const {
|
||||
return _clustering_key_prefix_type;
|
||||
}
|
||||
const data_type& regular_column_name_type() const {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include "types.hh"
|
||||
#include "tuple.hh"
|
||||
#include "compound.hh"
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_bytes_type_string_conversions) {
|
||||
BOOST_REQUIRE(bytes_type->equal(bytes_type->from_string("616263646566"), bytes_type->decompose(bytes{"abcdef"})));
|
||||
@@ -52,8 +52,8 @@ BOOST_AUTO_TEST_CASE(test_int32_type_string_conversions) {
|
||||
BOOST_REQUIRE_EQUAL(int32_type->to_string(bytes()), "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_tuple_type_compare) {
|
||||
tuple_type<> type({utf8_type, utf8_type, utf8_type});
|
||||
BOOST_AUTO_TEST_CASE(test_compound_type_compare) {
|
||||
compound_type<> type({utf8_type, utf8_type, utf8_type});
|
||||
|
||||
BOOST_REQUIRE(type.compare(
|
||||
type.serialize_value({bytes("a"), bytes("b"), bytes("c")}),
|
||||
@@ -99,7 +99,7 @@ unextract(std::experimental::optional<T> v) {
|
||||
template <typename T>
|
||||
using opt = std::experimental::optional<T>;
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_the_real_tuple) {
|
||||
BOOST_AUTO_TEST_CASE(test_tuple) {
|
||||
auto t = tuple_type_impl::get_instance({int32_type, long_type, utf8_type});
|
||||
using native_type = tuple_type_impl::native_type;
|
||||
using c_type = std::tuple<opt<int32_t>, opt<int64_t>, opt<sstring>>;
|
||||
|
||||
Reference in New Issue
Block a user