From 8b1f52eb9d521ac31a8cc6885252875440dd4850 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 8 Jun 2022 23:38:26 +0300 Subject: [PATCH 01/16] Using a 'unique tuple' as a replacement for std::tuple --- dev/column.h | 20 +- dev/function.h | 23 +- dev/functional/cxx_compiler_quirks.h | 6 + dev/functional/cxx_core_features.h | 7 + dev/functional/pack.h | 24 ++ dev/functional/type_at.h | 56 ++++ dev/functional/unique_tuple.h | 103 +++++++ dev/get_prepared_statement.h | 5 +- dev/implementations/column_definitions.h | 2 +- dev/pointer_value.h | 3 +- dev/serializing_util.h | 3 +- dev/statement_serializer.h | 9 +- dev/storage_lookup.h | 8 +- dev/table.h | 6 +- dev/tuple_helper/tuple_filter.h | 37 ++- dev/tuple_helper/tuple_iteration.h | 10 +- dev/tuple_helper/tuple_traits.h | 3 + include/sqlite_orm/sqlite_orm.h | 336 +++++++++++++++++++---- 18 files changed, 557 insertions(+), 104 deletions(-) create mode 100644 dev/functional/pack.h create mode 100644 dev/functional/type_at.h create mode 100644 dev/functional/unique_tuple.h diff --git a/dev/column.h b/dev/column.h index 7c46f82d2..bb83ff642 100644 --- a/dev/column.h +++ b/dev/column.h @@ -51,8 +51,7 @@ namespace sqlite_orm { /** * Setter member function to write a field value */ - SQLITE_ORM_NOUNIQUEADDRESS - const setter_type setter; + SQLITE_ORM_NOUNIQUEADDRESS const setter_type setter; /** * Simplified interface for `NOT NULL` constraint @@ -69,10 +68,9 @@ namespace sqlite_orm { */ template struct column_constraints { - using constraints_type = std::tuple; + using constraints_type = mpl::uple; - SQLITE_ORM_NOUNIQUEADDRESS - const constraints_type constraints; + SQLITE_ORM_NOUNIQUEADDRESS const constraints_type constraints; /** * Checks whether contraints are of trait `Trait` @@ -105,9 +103,9 @@ namespace sqlite_orm { template struct column_t : column_identifier, column_field, column_constraints { #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED - column_t(std::string name, G memberPointer, S setter, std::tuple op) : + column_t(std::string name, G memberPointer, S setter, mpl::uple op) : column_identifier{move(name)}, column_field{memberPointer, setter}, column_constraints{ - move(op)} {} + std::move(op)} {} #endif }; @@ -144,7 +142,7 @@ namespace sqlite_orm { internal::column_t make_column(std::string name, M m, Op... constraints) { static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), m, {}, std::make_tuple(constraints...)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), m, {}, mpl::make_unique_tuple(constraints...)}); } /** @@ -160,7 +158,8 @@ namespace sqlite_orm { "Getter and setter must get and set same data type"); static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), getter, setter, std::make_tuple(constraints...)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {move(name), getter, setter, mpl::make_unique_tuple(constraints...)}); } /** @@ -177,6 +176,7 @@ namespace sqlite_orm { "Getter and setter must get and set same data type"); static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), getter, setter, std::make_tuple(constraints...)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {move(name), getter, setter, mpl::make_unique_tuple(constraints...)}); } } diff --git a/dev/function.h b/dev/function.h index 69665a7ba..2685cb1b0 100644 --- a/dev/function.h +++ b/dev/function.h @@ -10,6 +10,8 @@ #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" +#include "functional/type_at.h" +#include "functional/unique_tuple.h" namespace sqlite_orm { @@ -203,13 +205,13 @@ namespace sqlite_orm { } template SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant) { - using func_arg_t = std::tuple_element_t; - using passed_arg_t = unpacked_arg_t>; + using func_arg_t = mpl::element_at_t; + using passed_arg_t = unpacked_arg_t>; #ifdef SQLITE_ORM_RELAXED_CONSTEXPR constexpr bool valid = validate_pointer_value_type, - unpacked_arg_t>>( + mpl::element_at_t, + unpacked_arg_t>>( polyfill::bool_constant < (polyfill::is_specialization_of_v) || (polyfill::is_specialization_of_v) > {}); @@ -217,8 +219,8 @@ namespace sqlite_orm { #else return validate_pointer_value_types(polyfill::index_constant{}) && validate_pointer_value_type, - unpacked_arg_t>>( + mpl::element_at_t, + unpacked_arg_t>>( polyfill::bool_constant < (polyfill::is_specialization_of_v) || (polyfill::is_specialization_of_v) > {}); #endif @@ -230,13 +232,14 @@ namespace sqlite_orm { */ template internal::function_call func(Args... args) { - using args_tuple = std::tuple; - using function_args_tuple = typename internal::callable_arguments::args_tuple; - constexpr auto argsCount = std::tuple_size::value; + using namespace internal; + using args_pack = mpl::pack; + using function_args_tuple = typename callable_arguments::args_tuple; + constexpr auto argsCount = args_pack::size(); constexpr auto functionArgsCount = std::tuple_size::value; static_assert((argsCount == functionArgsCount && !std::is_same>::value && - internal::validate_pointer_value_types( + internal::validate_pointer_value_types, args_pack>( polyfill::index_constant(functionArgsCount, argsCount) - 1>{})) || std::is_same>::value, "Number of arguments does not match"); diff --git a/dev/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index ab84d2980..96ef947c4 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -28,3 +28,9 @@ #if defined(_MSC_VER) && (_MSC_VER < 1920) #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #endif + +#if defined(_MSC_VER) && !defined(__clang__) // MSVC +#define SQLITE_ORM_MSVC_EMPTYBASES __declspec(empty_bases) +#else +#define SQLITE_ORM_MSVC_EMPTYBASES +#endif diff --git a/dev/functional/cxx_core_features.h b/dev/functional/cxx_core_features.h index 354f710a2..7ee7ba2d8 100644 --- a/dev/functional/cxx_core_features.h +++ b/dev/functional/cxx_core_features.h @@ -12,6 +12,13 @@ #define SQLITE_ORM_HAS_INCLUDE(file) 0L #endif +// If possible, use an intrinsic provided by Clang +#if defined(__has_builtin) +#if __has_builtin(__type_pack_element) +#define SQLITE_ORM_HAS_TYPE_PACK_ELEMENT_INTRINSIC +#endif +#endif + #if __cpp_aggregate_nsdmi >= 201304L #define SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED #endif diff --git a/dev/functional/pack.h b/dev/functional/pack.h new file mode 100644 index 000000000..8868725f8 --- /dev/null +++ b/dev/functional/pack.h @@ -0,0 +1,24 @@ +#pragma once + +#include "cxx_universal.h" + +namespace sqlite_orm { + namespace internal { + namespace mpl { + + template + struct pack { + static constexpr size_t size() { + return sizeof...(T); + } + }; + + template + struct indexed_type { + using type = T; + }; + } + } + + namespace mpl = internal::mpl; +} diff --git a/dev/functional/type_at.h b/dev/functional/type_at.h new file mode 100644 index 000000000..b14a98851 --- /dev/null +++ b/dev/functional/type_at.h @@ -0,0 +1,56 @@ +#pragma once + +#include // std::integral_constant, std::index_sequence, std::make_index_sequence +#include + +#include "cxx_universal.h" +#include "pack.h" + +namespace sqlite_orm { + namespace internal { + namespace mpl { + + template + struct pack> : pack {}; + +#ifndef SQLITE_ORM_HAS_TYPE_PACK_ELEMENT_INTRINSIC + namespace td { + template + struct indexer; + + template + struct indexer, T...> : indexed_type... {}; + + template + indexed_type get_indexed_type(const indexed_type&); + } +#endif + + template + struct type_at { +#ifdef SQLITE_ORM_HAS_TYPE_PACK_ELEMENT_INTRINSIC + using type = __type_pack_element; +#else + using Indexer = td::indexer, T...>; + // implementation note: needs to be aliased on its own [SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION] + using indexed_t = decltype(td::get_indexed_type(Indexer{})); + using type = typename indexed_t::type; +#endif + }; + + template + struct type_at> : type_at {}; + + template + struct type_at> : type_at {}; + + template + using type_at_t = typename type_at::type; + + template + using element_at_t = typename type_at::type; + } + } + + namespace mpl = internal::mpl; +} diff --git a/dev/functional/unique_tuple.h b/dev/functional/unique_tuple.h new file mode 100644 index 000000000..39ffd8d5a --- /dev/null +++ b/dev/functional/unique_tuple.h @@ -0,0 +1,103 @@ +#pragma once + +#include // std::integral_constant, std::decay, std::is_constructible, std::enable_if +#include // std::move, std::forward + +#include "cxx_universal.h" +#include "cxx_type_traits_polyfill.h" +#include "type_at.h" + +namespace _sqlite_orm { + // short names defined in a short namespace to reduce symbol lengths, + // since those types are used as a building block; + // (seen in boost hana) + + /* + * element of a unique tuple + */ + template + struct uplem { + SQLITE_ORM_NOUNIQUEADDRESS X element; + }; +} + +namespace sqlite_orm { + namespace internal { + namespace mpl { + using ::_sqlite_orm::uplem; + + /* + * unique tuple + */ + template + struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { + constexpr uple() = default; + + template...>, bool> = true> + constexpr uple(U&&... t) : uplem{std::forward(t)}... {} + + constexpr uple(uple&& other) = default; + constexpr uple(const uple& other) = default; + }; + + template + uple...> make_unique_tuple(X&&... t) { + return {std::forward(t)...}; + } + + template + struct type_at> : type_at {}; + } + } + + namespace mpl = mpl; +} + +// retain stl tuple interface for `uple` +namespace std { + template + struct tuple_size> : integral_constant {}; + + template + decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { + using namespace sqlite_orm::mpl; + const uplem>& elem = tpl; + return (elem.element); + } + + template + decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { + using namespace sqlite_orm::mpl; + uplem>& elem = tpl; + return (elem.element); + } + + template + decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { + using namespace sqlite_orm::mpl; + uplem>& elem = tpl; + return std::move(elem.element); + } + + template + decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { + using sqlite_orm::mpl::uplem; + const uplem& elem = tpl; + return (elem.element); + } + + template + decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { + using sqlite_orm::mpl::uplem; + uplem& elem = tpl; + return (elem.element); + } + + template + decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { + using sqlite_orm::mpl::uplem; + uplem& elem = tpl; + return std::move(elem.element); + } +} diff --git a/dev/get_prepared_statement.h b/dev/get_prepared_statement.h index fc30aefe4..976d00630 100644 --- a/dev/get_prepared_statement.h +++ b/dev/get_prepared_statement.h @@ -3,6 +3,7 @@ #include // std::is_same, std::decay, std::remove_reference #include "functional/static_magic.h" +#include "functional/type_at.h" #include "prepared_statement.h" #include "ast_iterator.h" #include "expression_object_type.h" @@ -125,7 +126,7 @@ namespace sqlite_orm { using expression_type = typename statement_type::expression_type; using node_tuple = internal::node_tuple_t; using bind_tuple = internal::bindable_filter_t; - using result_type = std::tuple_element_t(N), bind_tuple>; + using result_type = mpl::element_at_t(N), bind_tuple>; const result_type* result = nullptr; internal::iterate_ast(statement.expression, [&result, index = -1](auto& node) mutable { using node_type = std::decay_t; @@ -150,7 +151,7 @@ namespace sqlite_orm { using expression_type = typename statement_type::expression_type; using node_tuple = internal::node_tuple_t; using bind_tuple = internal::bindable_filter_t; - using result_type = std::tuple_element_t(N), bind_tuple>; + using result_type = mpl::element_at_t(N), bind_tuple>; result_type* result = nullptr; internal::iterate_ast(statement.expression, [&result, index = -1](auto& node) mutable { diff --git a/dev/implementations/column_definitions.h b/dev/implementations/column_definitions.h index a637bd883..b2c83fc61 100644 --- a/dev/implementations/column_definitions.h +++ b/dev/implementations/column_definitions.h @@ -27,7 +27,7 @@ namespace sqlite_orm { [&value](auto& constraints, auto op_index_sequence) { using default_op_index_sequence = decltype(op_index_sequence); constexpr size_t opIndex = first_index_sequence_value(default_op_index_sequence{}); - value = std::make_unique(serialize_default_value(get(constraints))); + value = std::make_unique(serialize_default_value(std::get(constraints))); }, this->constraints, default_op_index_sequence{}); diff --git a/dev/pointer_value.h b/dev/pointer_value.h index 36d37cd25..f0bfaac3e 100644 --- a/dev/pointer_value.h +++ b/dev/pointer_value.h @@ -64,8 +64,7 @@ namespace sqlite_orm { class pointer_binding { P* p_; - SQLITE_ORM_NOUNIQUEADDRESS - D d_; + SQLITE_ORM_NOUNIQUEADDRESS D d_; protected: // Constructing pointer bindings must go through bindable_pointer() diff --git a/dev/serializing_util.h b/dev/serializing_util.h index 125cd666c..178d4a1a9 100644 --- a/dev/serializing_util.h +++ b/dev/serializing_util.h @@ -13,6 +13,7 @@ #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" +#include "functional/type_at.h" #include "tuple_helper/tuple_iteration.h" #include "error_code.h" #include "serializer_context.h" @@ -331,7 +332,7 @@ namespace sqlite_orm { std::ostream& operator<<(std::ostream& ss, std::tuple&, PredFnCls, L, Ctx, Obj> tpl) { - using check_if_excluded = polyfill::remove_cvref_t>; + using check_if_excluded = polyfill::remove_cvref_t>; auto& excluded = get<2>(tpl); auto& context = get<3>(tpl); auto& object = get<4>(tpl); diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 5b6caa08c..5254c9357 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -15,6 +15,7 @@ #include "functional/cxx_universal.h" #include "functional/cxx_functional_polyfill.h" #include "functional/mpl.h" +#include "functional/type_at.h" #include "tuple_helper/tuple_filter.h" #include "ast/upsert_clause.h" #include "ast/excluded.h" @@ -699,9 +700,7 @@ namespace sqlite_orm { ss << "NOT IN"; } ss << " "; - using args_type = std::tuple; - const bool theOnlySelect = - std::tuple_size::value == 1 && is_select_v>; + constexpr bool theOnlySelect = sizeof...(Args) == 1 && is_select_v>; if(!theOnlySelect) { ss << "("; } @@ -847,7 +846,7 @@ namespace sqlite_orm { ss << "FOREIGN KEY(" << streaming_mapped_columns_expressions(fk.columns, context) << ") REFERENCES "; { using references_type_t = typename std::decay_t::references_type; - using first_reference_t = std::tuple_element_t<0, references_type_t>; + using first_reference_t = mpl::element_at_t<0, references_type_t>; using first_reference_mapped_type = table_type_of_t; auto refTableName = lookup_table_name(context.db_objects); ss << streaming_identifier(refTableName); @@ -1503,7 +1502,7 @@ namespace sqlite_orm { ss << "UNIQUE "; } using elements_type = typename std::decay_t::elements_type; - using head_t = typename std::tuple_element_t<0, elements_type>::column_type; + using head_t = typename mpl::element_at_t<0, elements_type>::column_type; using indexed_type = table_type_of_t; ss << "INDEX IF NOT EXISTS " << streaming_identifier(statement.name) << " ON " << streaming_identifier(lookup_table_name(context.db_objects)); diff --git a/dev/storage_lookup.h b/dev/storage_lookup.h index d7ce8e3fd..2fe35dbb0 100644 --- a/dev/storage_lookup.h +++ b/dev/storage_lookup.h @@ -1,10 +1,10 @@ #pragma once #include // std::true_type, std::false_type, std::remove_const, std::enable_if -#include #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" +#include "functional/unique_tuple.h" #include "type_traits.h" namespace sqlite_orm { @@ -14,7 +14,7 @@ namespace sqlite_orm { struct storage_t; template - using db_objects_tuple = std::tuple; + using db_objects_tuple = mpl::uple; template struct is_storage : std::false_type {}; @@ -65,7 +65,7 @@ namespace sqlite_orm { struct storage_pick_table> : storage_pick_table {}; #else template - struct storage_pick_table> : storage_pick_table {}; + struct storage_pick_table> : storage_pick_table {}; #endif /** @@ -92,7 +92,7 @@ namespace sqlite_orm { struct storage_find_table> : storage_find_table {}; #else template - struct storage_find_table> : storage_find_table {}; + struct storage_find_table> : storage_find_table {}; #endif /** diff --git a/dev/table.h b/dev/table.h index 8ecc5a976..591245756 100644 --- a/dev/table.h +++ b/dev/table.h @@ -11,6 +11,8 @@ #include "functional/cxx_functional_polyfill.h" #include "functional/static_magic.h" #include "functional/mpl.h" +#include "functional/type_at.h" +#include "functional/unique_tuple.h" #include "typed_comparator.h" #include "tuple_helper/index_sequence_util.h" #include "tuple_helper/tuple_filter.h" @@ -107,7 +109,7 @@ namespace sqlite_orm { filter_tuple_sequence_t, is_generated_always>; constexpr size_t opIndex = first_index_sequence_value(generated_op_index_sequence{}); - result = &get(column.constraints).storage; + result = &std::get(column.constraints).storage; }); #endif return result; @@ -288,7 +290,7 @@ namespace sqlite_orm { * * The mapped object type is determined implicitly from the first column definition. */ - template>::object_type> + template::object_type> internal::table_t make_table(std::string name, Cs... args) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( return {move(name), std::make_tuple(std::forward(args)...)}); diff --git a/dev/tuple_helper/tuple_filter.h b/dev/tuple_helper/tuple_filter.h index f2edd51b8..46547cde2 100644 --- a/dev/tuple_helper/tuple_filter.h +++ b/dev/tuple_helper/tuple_filter.h @@ -1,9 +1,11 @@ #pragma once -#include // std::integral_constant, std::index_sequence, std::conditional, std::declval +#include // std::integral_constant, std::index_sequence, std::make_index_sequence, std::conditional, std::declval #include // std::tuple #include "../functional/cxx_universal.h" +#include "../functional/type_at.h" +#include "../functional/unique_tuple.h" namespace sqlite_orm { namespace internal { @@ -22,9 +24,14 @@ namespace sqlite_orm { template struct tuple_from_index_sequence; - template - struct tuple_from_index_sequence> { - using type = std::tuple...>; + template + struct tuple_from_index_sequence, std::index_sequence> { + using type = std::tuple...>; + }; + + template + struct tuple_from_index_sequence, std::index_sequence> { + using type = mpl::uple...>; }; template @@ -48,9 +55,15 @@ namespace sqlite_orm { struct filter_tuple_sequence; #ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence> - : concat_idx_seq>>::value, + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>>::value, + std::index_sequence, + std::index_sequence<>>...> {}; + + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>>::value, std::index_sequence, std::index_sequence<>>...> {}; #else @@ -64,9 +77,13 @@ namespace sqlite_orm { using type = std::index_sequence; }; - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence> - : concat_idx_seq>, Pred>::type...> {}; + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>, Pred>::type...> {}; + + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>, Pred>::type...> {}; #endif template auto call_impl(Function& f, FunctionPointer functionPointer, Tuple t, std::index_sequence) { - return (f.*functionPointer)(std::get(move(t))...); + return (f.*functionPointer)(std::get(std::move(t))...); } template auto call(Function& f, FunctionPointer functionPointer, Tuple t) { constexpr size_t size = std::tuple_size::value; - return call_impl(f, functionPointer, move(t), std::make_index_sequence{}); + return call_impl(f, functionPointer, std::move(t), std::make_index_sequence{}); } template auto call(Function& f, Tuple t) { - return call(f, &Function::operator(), move(t)); + return call(f, &Function::operator(), std::move(t)); } #if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) && defined(SQLITE_ORM_IF_CONSTEXPR_SUPPORTED) @@ -67,7 +67,7 @@ namespace sqlite_orm { #ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED template void iterate_tuple(std::index_sequence, L&& lambda) { - (lambda((std::tuple_element_t*)nullptr), ...); + (lambda((mpl::element_at_t*)nullptr), ...); } #else template @@ -75,7 +75,7 @@ namespace sqlite_orm { template void iterate_tuple(std::index_sequence, L&& lambda) { - lambda((std::tuple_element_t*)nullptr); + lambda((mpl::element_at_t*)nullptr); iterate_tuple(std::index_sequence{}, std::forward(lambda)); } #endif diff --git a/dev/tuple_helper/tuple_traits.h b/dev/tuple_helper/tuple_traits.h index 7de97f8f7..614a06611 100644 --- a/dev/tuple_helper/tuple_traits.h +++ b/dev/tuple_helper/tuple_traits.h @@ -5,6 +5,7 @@ #include "../functional/cxx_type_traits_polyfill.h" #include "../functional/mpl.h" +#include "../functional/unique_tuple.h" namespace sqlite_orm { namespace internal { @@ -15,6 +16,8 @@ namespace sqlite_orm { struct tuple_has {}; template class TraitFn, class... Types> struct tuple_has> : polyfill::disjunction...> {}; + template class TraitFn, class... Types> + struct tuple_has> : polyfill::disjunction...> {}; /* * Trait metafunction class that checks whether a tuple contains a type with given trait. diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 947a69140..4e8252595 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -46,6 +46,13 @@ using std::nullptr_t; #define SQLITE_ORM_HAS_INCLUDE(file) 0L #endif +// If possible, use an intrinsic provided by Clang +#if defined(__has_builtin) +#if __has_builtin(__type_pack_element) +#define SQLITE_ORM_HAS_TYPE_PACK_ELEMENT_INTRINSIC +#endif +#endif + #if __cpp_aggregate_nsdmi >= 201304L #define SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED #endif @@ -136,6 +143,12 @@ using std::nullptr_t; #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #endif +#if defined(_MSC_VER) && !defined(__clang__) // MSVC +#define SQLITE_ORM_MSVC_EMPTYBASES __declspec(empty_bases) +#else +#define SQLITE_ORM_MSVC_EMPTYBASES +#endif + namespace sqlite_orm { namespace internal { namespace polyfill { @@ -993,6 +1006,191 @@ namespace sqlite_orm { // #include "../functional/mpl.h" +// #include "../functional/unique_tuple.h" + +#include // std::integral_constant, std::decay, std::is_constructible, std::enable_if +#include // std::move, std::forward + +// #include "cxx_universal.h" + +// #include "cxx_type_traits_polyfill.h" + +// #include "type_at.h" + +#include // std::integral_constant, std::index_sequence, std::make_index_sequence +#include + +// #include "cxx_universal.h" + +// #include "pack.h" + +// #include "cxx_universal.h" + +namespace sqlite_orm { + namespace internal { + namespace mpl { + + template + struct pack { + static constexpr size_t size() { + return sizeof...(T); + } + }; + + template + struct indexed_type { + using type = T; + }; + } + } + + namespace mpl = internal::mpl; +} + +namespace sqlite_orm { + namespace internal { + namespace mpl { + + template + struct pack> : pack {}; + +#ifndef SQLITE_ORM_HAS_TYPE_PACK_ELEMENT_INTRINSIC + namespace td { + template + struct indexer; + + template + struct indexer, T...> : indexed_type... {}; + + template + indexed_type get_indexed_type(const indexed_type&); + } +#endif + + template + struct type_at { +#ifdef SQLITE_ORM_HAS_TYPE_PACK_ELEMENT_INTRINSIC + using type = __type_pack_element; +#else + using Indexer = td::indexer, T...>; + // implementation note: needs to be aliased on its own [SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION] + using indexed_t = decltype(td::get_indexed_type(Indexer{})); + using type = typename indexed_t::type; +#endif + }; + + template + struct type_at> : type_at {}; + + template + struct type_at> : type_at {}; + + template + using type_at_t = typename type_at::type; + + template + using element_at_t = typename type_at::type; + } + } + + namespace mpl = internal::mpl; +} + +namespace _sqlite_orm { + // short names defined in a short namespace to reduce symbol lengths, + // since those types are used as a building block; + // (seen in boost hana) + + /* + * element of a unique tuple + */ + template + struct uplem { + SQLITE_ORM_NOUNIQUEADDRESS X element; + }; +} + +namespace sqlite_orm { + namespace internal { + namespace mpl { + using ::_sqlite_orm::uplem; + + /* + * unique tuple + */ + template + struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { + constexpr uple() = default; + + template...>, bool> = true> + constexpr uple(U&&... t) : uplem{std::forward(t)}... {} + + constexpr uple(uple&& other) = default; + constexpr uple(const uple& other) = default; + }; + + template + uple...> make_unique_tuple(X&&... t) { + return {std::forward(t)...}; + } + + template + struct type_at> : type_at {}; + } + } + + namespace mpl = mpl; +} + +// retain stl tuple interface for `uple` +namespace std { + template + struct tuple_size> : integral_constant {}; + + template + decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { + using namespace sqlite_orm::mpl; + const uplem>& elem = tpl; + return (elem.element); + } + + template + decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { + using namespace sqlite_orm::mpl; + uplem>& elem = tpl; + return (elem.element); + } + + template + decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { + using namespace sqlite_orm::mpl; + uplem>& elem = tpl; + return std::move(elem.element); + } + + template + decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { + using sqlite_orm::mpl::uplem; + const uplem& elem = tpl; + return (elem.element); + } + + template + decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { + using sqlite_orm::mpl::uplem; + uplem& elem = tpl; + return (elem.element); + } + + template + decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { + using sqlite_orm::mpl::uplem; + uplem& elem = tpl; + return std::move(elem.element); + } +} + namespace sqlite_orm { namespace internal { /* @@ -1002,6 +1200,8 @@ namespace sqlite_orm { struct tuple_has {}; template class TraitFn, class... Types> struct tuple_has> : polyfill::disjunction...> {}; + template class TraitFn, class... Types> + struct tuple_has> : polyfill::disjunction...> {}; /* * Trait metafunction class that checks whether a tuple contains a type with given trait. @@ -1040,11 +1240,15 @@ namespace sqlite_orm { } // #include "tuple_helper/tuple_filter.h" -#include // std::integral_constant, std::index_sequence, std::conditional, std::declval +#include // std::integral_constant, std::index_sequence, std::make_index_sequence, std::conditional, std::declval #include // std::tuple // #include "../functional/cxx_universal.h" +// #include "../functional/type_at.h" + +// #include "../functional/unique_tuple.h" + namespace sqlite_orm { namespace internal { @@ -1062,9 +1266,14 @@ namespace sqlite_orm { template struct tuple_from_index_sequence; - template - struct tuple_from_index_sequence> { - using type = std::tuple...>; + template + struct tuple_from_index_sequence, std::index_sequence> { + using type = std::tuple...>; + }; + + template + struct tuple_from_index_sequence, std::index_sequence> { + using type = mpl::uple...>; }; template @@ -1088,9 +1297,15 @@ namespace sqlite_orm { struct filter_tuple_sequence; #ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence> - : concat_idx_seq>>::value, + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>>::value, + std::index_sequence, + std::index_sequence<>>...> {}; + + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>>::value, std::index_sequence, std::index_sequence<>>...> {}; #else @@ -1104,9 +1319,13 @@ namespace sqlite_orm { using type = std::index_sequence; }; - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence> - : concat_idx_seq>, Pred>::type...> {}; + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>, Pred>::type...> {}; + + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>, Pred>::type...> {}; #endif template struct column_constraints { - using constraints_type = std::tuple; + using constraints_type = mpl::uple; - SQLITE_ORM_NOUNIQUEADDRESS - const constraints_type constraints; + SQLITE_ORM_NOUNIQUEADDRESS const constraints_type constraints; /** * Checks whether contraints are of trait `Trait` @@ -2219,9 +2436,9 @@ namespace sqlite_orm { template struct column_t : column_identifier, column_field, column_constraints { #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED - column_t(std::string name, G memberPointer, S setter, std::tuple op) : + column_t(std::string name, G memberPointer, S setter, mpl::uple op) : column_identifier{move(name)}, column_field{memberPointer, setter}, column_constraints{ - move(op)} {} + std::move(op)} {} #endif }; @@ -2258,7 +2475,7 @@ namespace sqlite_orm { internal::column_t make_column(std::string name, M m, Op... constraints) { static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), m, {}, std::make_tuple(constraints...)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), m, {}, mpl::make_unique_tuple(constraints...)}); } /** @@ -2274,7 +2491,8 @@ namespace sqlite_orm { "Getter and setter must get and set same data type"); static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), getter, setter, std::make_tuple(constraints...)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {move(name), getter, setter, mpl::make_unique_tuple(constraints...)}); } /** @@ -2291,7 +2509,8 @@ namespace sqlite_orm { "Getter and setter must get and set same data type"); static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), getter, setter, std::make_tuple(constraints...)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {move(name), getter, setter, mpl::make_unique_tuple(constraints...)}); } } #pragma once @@ -7623,8 +7842,7 @@ namespace sqlite_orm { class pointer_binding { P* p_; - SQLITE_ORM_NOUNIQUEADDRESS - D d_; + SQLITE_ORM_NOUNIQUEADDRESS D d_; protected: // Constructing pointer bindings must go through bindable_pointer() @@ -9074,12 +9292,13 @@ namespace sqlite_orm { // #include "storage_lookup.h" #include // std::true_type, std::false_type, std::remove_const, std::enable_if -#include // #include "functional/cxx_universal.h" // #include "functional/cxx_type_traits_polyfill.h" +// #include "functional/unique_tuple.h" + // #include "type_traits.h" namespace sqlite_orm { @@ -9089,7 +9308,7 @@ namespace sqlite_orm { struct storage_t; template - using db_objects_tuple = std::tuple; + using db_objects_tuple = mpl::uple; template struct is_storage : std::false_type {}; @@ -9140,7 +9359,7 @@ namespace sqlite_orm { struct storage_pick_table> : storage_pick_table {}; #else template - struct storage_pick_table> : storage_pick_table {}; + struct storage_pick_table> : storage_pick_table {}; #endif /** @@ -9167,7 +9386,7 @@ namespace sqlite_orm { struct storage_find_table> : storage_find_table {}; #else template - struct storage_find_table> : storage_find_table {}; + struct storage_find_table> : storage_find_table {}; #endif /** @@ -9250,6 +9469,10 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" +// #include "functional/type_at.h" + +// #include "functional/unique_tuple.h" + namespace sqlite_orm { struct arg_values; @@ -9442,13 +9665,13 @@ namespace sqlite_orm { } template SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant) { - using func_arg_t = std::tuple_element_t; - using passed_arg_t = unpacked_arg_t>; + using func_arg_t = mpl::element_at_t; + using passed_arg_t = unpacked_arg_t>; #ifdef SQLITE_ORM_RELAXED_CONSTEXPR constexpr bool valid = validate_pointer_value_type, - unpacked_arg_t>>( + mpl::element_at_t, + unpacked_arg_t>>( polyfill::bool_constant < (polyfill::is_specialization_of_v) || (polyfill::is_specialization_of_v) > {}); @@ -9456,8 +9679,8 @@ namespace sqlite_orm { #else return validate_pointer_value_types(polyfill::index_constant{}) && validate_pointer_value_type, - unpacked_arg_t>>( + mpl::element_at_t, + unpacked_arg_t>>( polyfill::bool_constant < (polyfill::is_specialization_of_v) || (polyfill::is_specialization_of_v) > {}); #endif @@ -9469,13 +9692,14 @@ namespace sqlite_orm { */ template internal::function_call func(Args... args) { - using args_tuple = std::tuple; - using function_args_tuple = typename internal::callable_arguments::args_tuple; - constexpr auto argsCount = std::tuple_size::value; + using namespace internal; + using args_pack = mpl::pack; + using function_args_tuple = typename callable_arguments::args_tuple; + constexpr auto argsCount = args_pack::size(); constexpr auto functionArgsCount = std::tuple_size::value; static_assert((argsCount == functionArgsCount && !std::is_same>::value && - internal::validate_pointer_value_types( + internal::validate_pointer_value_types, args_pack>( polyfill::index_constant(functionArgsCount, argsCount) - 1>{})) || std::is_same>::value, "Number of arguments does not match"); @@ -9844,6 +10068,10 @@ namespace sqlite_orm { // #include "functional/mpl.h" +// #include "functional/type_at.h" + +// #include "functional/unique_tuple.h" + // #include "typed_comparator.h" // #include "tuple_helper/index_sequence_util.h" @@ -9923,18 +10151,18 @@ namespace sqlite_orm { // got it form here https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer template auto call_impl(Function& f, FunctionPointer functionPointer, Tuple t, std::index_sequence) { - return (f.*functionPointer)(std::get(move(t))...); + return (f.*functionPointer)(std::get(std::move(t))...); } template auto call(Function& f, FunctionPointer functionPointer, Tuple t) { constexpr size_t size = std::tuple_size::value; - return call_impl(f, functionPointer, move(t), std::make_index_sequence{}); + return call_impl(f, functionPointer, std::move(t), std::make_index_sequence{}); } template auto call(Function& f, Tuple t) { - return call(f, &Function::operator(), move(t)); + return call(f, &Function::operator(), std::move(t)); } #if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) && defined(SQLITE_ORM_IF_CONSTEXPR_SUPPORTED) @@ -9975,7 +10203,7 @@ namespace sqlite_orm { #ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED template void iterate_tuple(std::index_sequence, L&& lambda) { - (lambda((std::tuple_element_t*)nullptr), ...); + (lambda((mpl::element_at_t*)nullptr), ...); } #else template @@ -9983,7 +10211,7 @@ namespace sqlite_orm { template void iterate_tuple(std::index_sequence, L&& lambda) { - lambda((std::tuple_element_t*)nullptr); + lambda((mpl::element_at_t*)nullptr); iterate_tuple(std::index_sequence{}, std::forward(lambda)); } #endif @@ -10129,7 +10357,7 @@ namespace sqlite_orm { filter_tuple_sequence_t, is_generated_always>; constexpr size_t opIndex = first_index_sequence_value(generated_op_index_sequence{}); - result = &get(column.constraints).storage; + result = &std::get(column.constraints).storage; }); #endif return result; @@ -10310,7 +10538,7 @@ namespace sqlite_orm { * * The mapped object type is determined implicitly from the first column definition. */ - template>::object_type> + template::object_type> internal::table_t make_table(std::string name, Cs... args) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( return {move(name), std::make_tuple(std::forward(args)...)}); @@ -12545,6 +12773,8 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" +// #include "functional/type_at.h" + // #include "tuple_helper/tuple_iteration.h" // #include "error_code.h" @@ -12866,7 +13096,7 @@ namespace sqlite_orm { std::ostream& operator<<(std::ostream& ss, std::tuple&, PredFnCls, L, Ctx, Obj> tpl) { - using check_if_excluded = polyfill::remove_cvref_t>; + using check_if_excluded = polyfill::remove_cvref_t>; auto& excluded = get<2>(tpl); auto& context = get<3>(tpl); auto& object = get<4>(tpl); @@ -14587,6 +14817,8 @@ namespace sqlite_orm { // #include "functional/mpl.h" +// #include "functional/type_at.h" + // #include "tuple_helper/tuple_filter.h" // #include "ast/upsert_clause.h" @@ -15574,9 +15806,7 @@ namespace sqlite_orm { ss << "NOT IN"; } ss << " "; - using args_type = std::tuple; - const bool theOnlySelect = - std::tuple_size::value == 1 && is_select_v>; + constexpr bool theOnlySelect = sizeof...(Args) == 1 && is_select_v>; if(!theOnlySelect) { ss << "("; } @@ -15722,7 +15952,7 @@ namespace sqlite_orm { ss << "FOREIGN KEY(" << streaming_mapped_columns_expressions(fk.columns, context) << ") REFERENCES "; { using references_type_t = typename std::decay_t::references_type; - using first_reference_t = std::tuple_element_t<0, references_type_t>; + using first_reference_t = mpl::element_at_t<0, references_type_t>; using first_reference_mapped_type = table_type_of_t; auto refTableName = lookup_table_name(context.db_objects); ss << streaming_identifier(refTableName); @@ -16378,7 +16608,7 @@ namespace sqlite_orm { ss << "UNIQUE "; } using elements_type = typename std::decay_t::elements_type; - using head_t = typename std::tuple_element_t<0, elements_type>::column_type; + using head_t = typename mpl::element_at_t<0, elements_type>::column_type; using indexed_type = table_type_of_t; ss << "INDEX IF NOT EXISTS " << streaming_identifier(statement.name) << " ON " << streaming_identifier(lookup_table_name(context.db_objects)); @@ -18660,6 +18890,8 @@ namespace sqlite_orm { // #include "functional/static_magic.h" +// #include "functional/type_at.h" + // #include "prepared_statement.h" // #include "ast_iterator.h" @@ -18784,7 +19016,7 @@ namespace sqlite_orm { using expression_type = typename statement_type::expression_type; using node_tuple = internal::node_tuple_t; using bind_tuple = internal::bindable_filter_t; - using result_type = std::tuple_element_t(N), bind_tuple>; + using result_type = mpl::element_at_t(N), bind_tuple>; const result_type* result = nullptr; internal::iterate_ast(statement.expression, [&result, index = -1](auto& node) mutable { using node_type = std::decay_t; @@ -18809,7 +19041,7 @@ namespace sqlite_orm { using expression_type = typename statement_type::expression_type; using node_tuple = internal::node_tuple_t; using bind_tuple = internal::bindable_filter_t; - using result_type = std::tuple_element_t(N), bind_tuple>; + using result_type = mpl::element_at_t(N), bind_tuple>; result_type* result = nullptr; internal::iterate_ast(statement.expression, [&result, index = -1](auto& node) mutable { @@ -18988,7 +19220,7 @@ namespace sqlite_orm { [&value](auto& constraints, auto op_index_sequence) { using default_op_index_sequence = decltype(op_index_sequence); constexpr size_t opIndex = first_index_sequence_value(default_op_index_sequence{}); - value = std::make_unique(serialize_default_value(get(constraints))); + value = std::make_unique(serialize_default_value(std::get(constraints))); }, this->constraints, default_op_index_sequence{}); From b87d1cd248c5aeef1c26f6296e3ecbebcd41ae89 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 9 Jun 2022 02:40:15 +0300 Subject: [PATCH 02/16] Using a custom tuple implementation in favor of std::tuple --- dev/functional/cxx_core_features.h | 4 + dev/functional/pack.h | 21 +- dev/functional/tuple.h | 115 +++++++++ dev/functional/type_at.h | 17 +- dev/functional/unique_tuple.h | 10 +- dev/index.h | 13 +- dev/table.h | 8 +- dev/tuple_helper/tuple_filter.h | 31 ++- dev/tuple_helper/tuple_traits.h | 6 + dev/tuple_helper/tuple_transformer.h | 6 + include/sqlite_orm/sqlite_orm.h | 238 +++++++++++++++--- .../static_tests/functional/tuple_filter.cpp | 15 +- 12 files changed, 421 insertions(+), 63 deletions(-) create mode 100644 dev/functional/tuple.h diff --git a/dev/functional/cxx_core_features.h b/dev/functional/cxx_core_features.h index 7ee7ba2d8..b54641916 100644 --- a/dev/functional/cxx_core_features.h +++ b/dev/functional/cxx_core_features.h @@ -64,6 +64,10 @@ #define SQLITE_ORM_NOUNIQUEADDRESS #endif +#if __cpp_conditional_explicit >= 201806L +#define SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED +#endif + #if __cpp_consteval >= 201811L #define SQLITE_ORM_CONSTEVAL consteval #else diff --git a/dev/functional/pack.h b/dev/functional/pack.h index 8868725f8..b7ea37b33 100644 --- a/dev/functional/pack.h +++ b/dev/functional/pack.h @@ -2,21 +2,32 @@ #include "cxx_universal.h" +namespace _sqlite_orm { + // short names defined in a short namespace to reduce symbol lengths, + // since those types are used as a building block; + // (seen in boost hana) + + template + struct indexed_type { + using type = T; + }; +} + namespace sqlite_orm { namespace internal { namespace mpl { + using _sqlite_orm::indexed_type; + + template + indexed_type get_indexed_type(const indexed_type&); + template struct pack { static constexpr size_t size() { return sizeof...(T); } }; - - template - struct indexed_type { - using type = T; - }; } } diff --git a/dev/functional/tuple.h b/dev/functional/tuple.h new file mode 100644 index 000000000..1af91d7ff --- /dev/null +++ b/dev/functional/tuple.h @@ -0,0 +1,115 @@ +#pragma once + +#include // std::integral_constant, std::decay, std::is_constructible, std::enable_if +#include // std::move, std::forward + +#include "cxx_universal.h" +#include "cxx_type_traits_polyfill.h" +#include "pack.h" +#include "type_at.h" + +namespace _sqlite_orm { + // short names defined in a short namespace to reduce symbol lengths, + // since those types are used as a building block; + // (seen in boost hana) + + /* + * element of a tuple + */ + template + struct tuplem : indexed_type { + SQLITE_ORM_NOUNIQUEADDRESS X element; + + tuplem(X t) : element{std::move(t)} {} + }; +} + +namespace sqlite_orm { + namespace internal { + namespace mpl { + using ::_sqlite_orm::tuplem; + + template + struct basic_tuple; + + template + struct basic_tuple, X...> : tuplem... { +#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED + constexpr basic_tuple() = default; + + template...>, bool> = true> + constexpr basic_tuple(U&&... t) : tuplem{std::forward(t)}... {} +#endif + }; + + /* + * tuple + */ + template + struct SQLITE_ORM_MSVC_EMPTYBASES tuple final : basic_tuple, X...> { +#ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED + constexpr explicit(!polyfill::conjunction_v...>) tuple() = default; +#else + constexpr tuple() = default; +#endif + + template...>, bool> = true> + constexpr tuple(U&&... t) : basic_tuple, X...>{std::forward(t)...} {} + + constexpr tuple(const tuple& other) = default; + constexpr tuple(tuple&& other) = default; + }; + + template + auto make_tuple(X&&... t) { + return tuple...>{std::forward(t)...}; + } + + template + struct type_at> { + using indexed_t = decltype(get_indexed_type(std::declval>())); + using type = typename indexed_t::type; + }; + } + } + + namespace mpl = mpl; +} + +// retain stl tuple interface for `tuple` +namespace std { + template + struct tuple_size> : integral_constant {}; + + template + decltype(auto) get(const sqlite_orm::mpl::tuple& tpl) noexcept { + using namespace sqlite_orm::mpl; + const tuplem>>& elem = tpl; + return (elem.element); + } + + template + decltype(auto) get(sqlite_orm::mpl::tuple& tpl) noexcept { + using namespace sqlite_orm::mpl; + tuplem>>& elem = tpl; + return (elem.element); + } + + template + decltype(auto) get(sqlite_orm::mpl::tuple&& tpl) noexcept { + using namespace sqlite_orm::mpl; + tuplem>>& elem = tpl; + return std::move(elem.element); + } + + template + decltype(auto) get(const sqlite_orm::mpl::tuple&) noexcept = delete; + + template + decltype(auto) get(sqlite_orm::mpl::tuple&) noexcept = delete; + + template + decltype(auto) get(sqlite_orm::mpl::tuple&&) noexcept = delete; +} diff --git a/dev/functional/type_at.h b/dev/functional/type_at.h index b14a98851..dde4ad7bc 100644 --- a/dev/functional/type_at.h +++ b/dev/functional/type_at.h @@ -10,9 +10,6 @@ namespace sqlite_orm { namespace internal { namespace mpl { - template - struct pack> : pack {}; - #ifndef SQLITE_ORM_HAS_TYPE_PACK_ELEMENT_INTRINSIC namespace td { template @@ -20,9 +17,6 @@ namespace sqlite_orm { template struct indexer, T...> : indexed_type... {}; - - template - indexed_type get_indexed_type(const indexed_type&); } #endif @@ -33,7 +27,7 @@ namespace sqlite_orm { #else using Indexer = td::indexer, T...>; // implementation note: needs to be aliased on its own [SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION] - using indexed_t = decltype(td::get_indexed_type(Indexer{})); + using indexed_t = decltype(get_indexed_type(Indexer{})); using type = typename indexed_t::type; #endif }; @@ -49,8 +43,17 @@ namespace sqlite_orm { template using element_at_t = typename type_at::type; + + template + struct pack> : pack {}; } } namespace mpl = internal::mpl; } + +// retain stl tuple interface for `tuple` +namespace std { + template + struct tuple_size> : integral_constant {}; +} diff --git a/dev/functional/unique_tuple.h b/dev/functional/unique_tuple.h index 39ffd8d5a..1fb7b8a1f 100644 --- a/dev/functional/unique_tuple.h +++ b/dev/functional/unique_tuple.h @@ -31,19 +31,23 @@ namespace sqlite_orm { */ template struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { +#ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED + constexpr explicit(!polyfill::conjunction_v...>) uple() = default; +#else constexpr uple() = default; +#endif template...>, bool> = true> constexpr uple(U&&... t) : uplem{std::forward(t)}... {} - constexpr uple(uple&& other) = default; constexpr uple(const uple& other) = default; + constexpr uple(uple&& other) = default; }; template - uple...> make_unique_tuple(X&&... t) { - return {std::forward(t)...}; + auto make_unique_tuple(X&&... t) { + return uple...>{std::forward(t)...}; } template diff --git a/dev/index.h b/dev/index.h index 36e25815d..3508e81b3 100644 --- a/dev/index.h +++ b/dev/index.h @@ -5,6 +5,7 @@ #include // std::forward #include "functional/cxx_universal.h" +#include "functional/tuple.h" #include "tuple_helper/tuple_filter.h" #include "indexed_column.h" @@ -23,7 +24,7 @@ namespace sqlite_orm { template struct index_t : index_base { - using elements_type = std::tuple; + using elements_type = mpl::tuple; using object_type = void; #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED @@ -38,20 +39,18 @@ namespace sqlite_orm { template internal::index_t()))...> make_index(std::string name, Cols... cols) { - using cols_tuple = std::tuple; - static_assert(internal::count_tuple::value <= 1, + static_assert(internal::count_tuple, internal::is_where>::value <= 1, "amount of where arguments can be 0 or 1"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {move(name), false, mpl::make_tuple(internal::make_indexed_column(std::move(cols))...)}); } template internal::index_t()))...> make_unique_index(std::string name, Cols... cols) { - using cols_tuple = std::tuple; - static_assert(internal::count_tuple::value <= 1, + static_assert(internal::count_tuple, internal::is_where>::value <= 1, "amount of where arguments can be 0 or 1"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), true, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {move(name), true, mpl::make_tuple(internal::make_indexed_column(std::move(cols))...)}); } } diff --git a/dev/table.h b/dev/table.h index 591245756..24412d6b5 100644 --- a/dev/table.h +++ b/dev/table.h @@ -12,7 +12,7 @@ #include "functional/static_magic.h" #include "functional/mpl.h" #include "functional/type_at.h" -#include "functional/unique_tuple.h" +#include "functional/tuple.h" #include "typed_comparator.h" #include "tuple_helper/index_sequence_util.h" #include "tuple_helper/tuple_filter.h" @@ -42,7 +42,7 @@ namespace sqlite_orm { template struct table_t : basic_table { using object_type = T; - using elements_type = std::tuple; + using elements_type = mpl::tuple; static constexpr bool is_without_rowid_v = WithoutRowId; using is_without_rowid = polyfill::bool_constant; @@ -293,7 +293,7 @@ namespace sqlite_orm { template::object_type> internal::table_t make_table(std::string name, Cs... args) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), std::make_tuple(std::forward(args)...)}); + return {move(name), mpl::make_tuple(std::forward(args)...)}); } /** @@ -304,6 +304,6 @@ namespace sqlite_orm { template internal::table_t make_table(std::string name, Cs... args) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), std::make_tuple(std::forward(args)...)}); + return {move(name), mpl::make_tuple(std::forward(args)...)}); } } diff --git a/dev/tuple_helper/tuple_filter.h b/dev/tuple_helper/tuple_filter.h index 46547cde2..2cf46c73c 100644 --- a/dev/tuple_helper/tuple_filter.h +++ b/dev/tuple_helper/tuple_filter.h @@ -5,7 +5,9 @@ #include "../functional/cxx_universal.h" #include "../functional/type_at.h" +#include "../functional/pack.h" #include "../functional/unique_tuple.h" +#include "../functional/tuple.h" namespace sqlite_orm { namespace internal { @@ -34,6 +36,11 @@ namespace sqlite_orm { using type = mpl::uple...>; }; + template + struct tuple_from_index_sequence, std::index_sequence> { + using type = mpl::tuple...>; + }; + template using tuple_from_index_sequence_t = typename tuple_from_index_sequence::type; @@ -57,13 +64,25 @@ namespace sqlite_orm { #ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION template class Pred, template class Proj, size_t... Idx> struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>>::value, + : concat_idx_seq>>>::value, std::index_sequence, std::index_sequence<>>...> {}; template class Pred, template class Proj, size_t... Idx> struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>>::value, + : concat_idx_seq>>>::value, + std::index_sequence, + std::index_sequence<>>...> {}; + + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>>>::value, + std::index_sequence, + std::index_sequence<>>...> {}; + + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>>>::value, std::index_sequence, std::index_sequence<>>...> {}; #else @@ -84,6 +103,14 @@ namespace sqlite_orm { template class Pred, template class Proj, size_t... Idx> struct filter_tuple_sequence, Pred, Proj, std::index_sequence> : concat_idx_seq>, Pred>::type...> {}; + + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>, Pred>::type...> {}; + + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>, Pred>::type...> {}; #endif template class TraitFn, class Tuple> struct tuple_has {}; + template class TraitFn, class... Types> struct tuple_has> : polyfill::disjunction...> {}; + template class TraitFn, class... Types> struct tuple_has> : polyfill::disjunction...> {}; + template class TraitFn, class... Types> + struct tuple_has> : polyfill::disjunction...> {}; + /* * Trait metafunction class that checks whether a tuple contains a type with given trait. */ diff --git a/dev/tuple_helper/tuple_transformer.h b/dev/tuple_helper/tuple_transformer.h index 9c7a73c43..87ca254d8 100644 --- a/dev/tuple_helper/tuple_transformer.h +++ b/dev/tuple_helper/tuple_transformer.h @@ -3,6 +3,7 @@ #include // std::tuple #include "../functional/mpl.h" +#include "../functional/tuple.h" namespace sqlite_orm { namespace internal { @@ -15,6 +16,11 @@ namespace sqlite_orm { using type = std::tuple...>; }; + template class Op> + struct tuple_transformer, Op> { + using type = std::tuple...>; + }; + /* * Transform specified tuple. * diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 4e8252595..08fec1a66 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -98,6 +98,10 @@ using std::nullptr_t; #define SQLITE_ORM_NOUNIQUEADDRESS #endif +#if __cpp_conditional_explicit >= 201806L +#define SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED +#endif + #if __cpp_consteval >= 201811L #define SQLITE_ORM_CONSTEVAL consteval #else @@ -1026,21 +1030,32 @@ namespace sqlite_orm { // #include "cxx_universal.h" +namespace _sqlite_orm { + // short names defined in a short namespace to reduce symbol lengths, + // since those types are used as a building block; + // (seen in boost hana) + + template + struct indexed_type { + using type = T; + }; +} + namespace sqlite_orm { namespace internal { namespace mpl { + using _sqlite_orm::indexed_type; + + template + indexed_type get_indexed_type(const indexed_type&); + template struct pack { static constexpr size_t size() { return sizeof...(T); } }; - - template - struct indexed_type { - using type = T; - }; } } @@ -1051,9 +1066,6 @@ namespace sqlite_orm { namespace internal { namespace mpl { - template - struct pack> : pack {}; - #ifndef SQLITE_ORM_HAS_TYPE_PACK_ELEMENT_INTRINSIC namespace td { template @@ -1061,9 +1073,6 @@ namespace sqlite_orm { template struct indexer, T...> : indexed_type... {}; - - template - indexed_type get_indexed_type(const indexed_type&); } #endif @@ -1074,7 +1083,7 @@ namespace sqlite_orm { #else using Indexer = td::indexer, T...>; // implementation note: needs to be aliased on its own [SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION] - using indexed_t = decltype(td::get_indexed_type(Indexer{})); + using indexed_t = decltype(get_indexed_type(Indexer{})); using type = typename indexed_t::type; #endif }; @@ -1090,12 +1099,21 @@ namespace sqlite_orm { template using element_at_t = typename type_at::type; + + template + struct pack> : pack {}; } } namespace mpl = internal::mpl; } +// retain stl tuple interface for `tuple` +namespace std { + template + struct tuple_size> : integral_constant {}; +} + namespace _sqlite_orm { // short names defined in a short namespace to reduce symbol lengths, // since those types are used as a building block; @@ -1120,19 +1138,23 @@ namespace sqlite_orm { */ template struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { +#ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED + constexpr explicit(!polyfill::conjunction_v...>) uple() = default; +#else constexpr uple() = default; +#endif template...>, bool> = true> constexpr uple(U&&... t) : uplem{std::forward(t)}... {} - constexpr uple(uple&& other) = default; constexpr uple(const uple& other) = default; + constexpr uple(uple&& other) = default; }; template - uple...> make_unique_tuple(X&&... t) { - return {std::forward(t)...}; + auto make_unique_tuple(X&&... t) { + return uple...>{std::forward(t)...}; } template @@ -1191,6 +1213,125 @@ namespace std { } } +// #include "../functional/tuple.h" + +#include // std::integral_constant, std::decay, std::is_constructible, std::enable_if +#include // std::move, std::forward + +// #include "cxx_universal.h" + +// #include "cxx_type_traits_polyfill.h" + +// #include "pack.h" + +// #include "type_at.h" + +namespace _sqlite_orm { + // short names defined in a short namespace to reduce symbol lengths, + // since those types are used as a building block; + // (seen in boost hana) + + /* + * element of a tuple + */ + template + struct tuplem : indexed_type { + SQLITE_ORM_NOUNIQUEADDRESS X element; + + tuplem(X t) : element{std::move(t)} {} + }; +} + +namespace sqlite_orm { + namespace internal { + namespace mpl { + using ::_sqlite_orm::tuplem; + + template + struct basic_tuple; + + template + struct basic_tuple, X...> : tuplem... { +#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED + constexpr basic_tuple() = default; + + template...>, bool> = true> + constexpr basic_tuple(U&&... t) : tuplem{std::forward(t)}... {} +#endif + }; + + /* + * tuple + */ + template + struct SQLITE_ORM_MSVC_EMPTYBASES tuple final : basic_tuple, X...> { +#ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED + constexpr explicit(!polyfill::conjunction_v...>) tuple() = default; +#else + constexpr tuple() = default; +#endif + + template...>, bool> = true> + constexpr tuple(U&&... t) : basic_tuple, X...>{std::forward(t)...} {} + + constexpr tuple(const tuple& other) = default; + constexpr tuple(tuple&& other) = default; + }; + + template + auto make_tuple(X&&... t) { + return tuple...>{std::forward(t)...}; + } + + template + struct type_at> { + using indexed_t = decltype(get_indexed_type(std::declval>())); + using type = typename indexed_t::type; + }; + } + } + + namespace mpl = mpl; +} + +// retain stl tuple interface for `tuple` +namespace std { + template + struct tuple_size> : integral_constant {}; + + template + decltype(auto) get(const sqlite_orm::mpl::tuple& tpl) noexcept { + using namespace sqlite_orm::mpl; + const tuplem>>& elem = tpl; + return (elem.element); + } + + template + decltype(auto) get(sqlite_orm::mpl::tuple& tpl) noexcept { + using namespace sqlite_orm::mpl; + tuplem>>& elem = tpl; + return (elem.element); + } + + template + decltype(auto) get(sqlite_orm::mpl::tuple&& tpl) noexcept { + using namespace sqlite_orm::mpl; + tuplem>>& elem = tpl; + return std::move(elem.element); + } + + template + decltype(auto) get(const sqlite_orm::mpl::tuple&) noexcept = delete; + + template + decltype(auto) get(sqlite_orm::mpl::tuple&) noexcept = delete; + + template + decltype(auto) get(sqlite_orm::mpl::tuple&&) noexcept = delete; +} + namespace sqlite_orm { namespace internal { /* @@ -1198,11 +1339,16 @@ namespace sqlite_orm { */ template class TraitFn, class Tuple> struct tuple_has {}; + template class TraitFn, class... Types> struct tuple_has> : polyfill::disjunction...> {}; + template class TraitFn, class... Types> struct tuple_has> : polyfill::disjunction...> {}; + template class TraitFn, class... Types> + struct tuple_has> : polyfill::disjunction...> {}; + /* * Trait metafunction class that checks whether a tuple contains a type with given trait. */ @@ -1247,8 +1393,12 @@ namespace sqlite_orm { // #include "../functional/type_at.h" +// #include "../functional/pack.h" + // #include "../functional/unique_tuple.h" +// #include "../functional/tuple.h" + namespace sqlite_orm { namespace internal { @@ -1276,6 +1426,11 @@ namespace sqlite_orm { using type = mpl::uple...>; }; + template + struct tuple_from_index_sequence, std::index_sequence> { + using type = mpl::tuple...>; + }; + template using tuple_from_index_sequence_t = typename tuple_from_index_sequence::type; @@ -1299,13 +1454,25 @@ namespace sqlite_orm { #ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION template class Pred, template class Proj, size_t... Idx> struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>>::value, + : concat_idx_seq>>>::value, std::index_sequence, std::index_sequence<>>...> {}; template class Pred, template class Proj, size_t... Idx> struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>>::value, + : concat_idx_seq>>>::value, + std::index_sequence, + std::index_sequence<>>...> {}; + + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>>>::value, + std::index_sequence, + std::index_sequence<>>...> {}; + + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>>>::value, std::index_sequence, std::index_sequence<>>...> {}; #else @@ -1326,6 +1493,14 @@ namespace sqlite_orm { template class Pred, template class Proj, size_t... Idx> struct filter_tuple_sequence, Pred, Proj, std::index_sequence> : concat_idx_seq>, Pred>::type...> {}; + + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>, Pred>::type...> {}; + + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence, Pred, Proj, std::index_sequence> + : concat_idx_seq>, Pred>::type...> {}; #endif template struct index_t : index_base { - using elements_type = std::tuple; + using elements_type = mpl::tuple; using object_type = void; #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED @@ -9116,21 +9293,19 @@ namespace sqlite_orm { template internal::index_t()))...> make_index(std::string name, Cols... cols) { - using cols_tuple = std::tuple; - static_assert(internal::count_tuple::value <= 1, + static_assert(internal::count_tuple, internal::is_where>::value <= 1, "amount of where arguments can be 0 or 1"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {move(name), false, mpl::make_tuple(internal::make_indexed_column(std::move(cols))...)}); } template internal::index_t()))...> make_unique_index(std::string name, Cols... cols) { - using cols_tuple = std::tuple; - static_assert(internal::count_tuple::value <= 1, + static_assert(internal::count_tuple, internal::is_where>::value <= 1, "amount of where arguments can be 0 or 1"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), true, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {move(name), true, mpl::make_tuple(internal::make_indexed_column(std::move(cols))...)}); } } #pragma once @@ -9266,6 +9441,8 @@ namespace sqlite_orm { // #include "../functional/mpl.h" +// #include "../functional/tuple.h" + namespace sqlite_orm { namespace internal { @@ -9277,6 +9454,11 @@ namespace sqlite_orm { using type = std::tuple...>; }; + template class Op> + struct tuple_transformer, Op> { + using type = std::tuple...>; + }; + /* * Transform specified tuple. * @@ -10070,7 +10252,7 @@ namespace sqlite_orm { // #include "functional/type_at.h" -// #include "functional/unique_tuple.h" +// #include "functional/tuple.h" // #include "typed_comparator.h" @@ -10290,7 +10472,7 @@ namespace sqlite_orm { template struct table_t : basic_table { using object_type = T; - using elements_type = std::tuple; + using elements_type = mpl::tuple; static constexpr bool is_without_rowid_v = WithoutRowId; using is_without_rowid = polyfill::bool_constant; @@ -10541,7 +10723,7 @@ namespace sqlite_orm { template::object_type> internal::table_t make_table(std::string name, Cs... args) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), std::make_tuple(std::forward(args)...)}); + return {move(name), mpl::make_tuple(std::forward(args)...)}); } /** @@ -10552,7 +10734,7 @@ namespace sqlite_orm { template internal::table_t make_table(std::string name, Cs... args) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), std::make_tuple(std::forward(args)...)}); + return {move(name), mpl::make_tuple(std::forward(args)...)}); } } #pragma once diff --git a/tests/static_tests/functional/tuple_filter.cpp b/tests/static_tests/functional/tuple_filter.cpp index 552c8c122..615ce823e 100644 --- a/tests/static_tests/functional/tuple_filter.cpp +++ b/tests/static_tests/functional/tuple_filter.cpp @@ -3,7 +3,6 @@ #include // std::is_same using namespace sqlite_orm; -using std::make_tuple; namespace { struct User { @@ -35,7 +34,7 @@ TEST_CASE("tuple_filter") { TEST_CASE("count_tuple") { using internal::count_tuple; { - auto t = make_tuple(where(is_equal(&User::id, 5)), limit(5), order_by(&User::name)); + auto t = std::make_tuple(where(is_equal(&User::id, 5)), limit(5), order_by(&User::name)); using T = decltype(t); STATIC_REQUIRE(count_tuple::value == 1); STATIC_REQUIRE(count_tuple::value == 0); @@ -43,8 +42,9 @@ TEST_CASE("count_tuple") { STATIC_REQUIRE(count_tuple::value == 1); } { - auto t = - make_tuple(where(lesser_than(&User::id, 10)), where(greater_than(&User::id, 5)), group_by(&User::name)); + auto t = std::make_tuple(where(lesser_than(&User::id, 10)), + where(greater_than(&User::id, 5)), + group_by(&User::name)); using T = decltype(t); STATIC_REQUIRE(count_tuple::value == 2); STATIC_REQUIRE(count_tuple::value == 1); @@ -52,7 +52,7 @@ TEST_CASE("count_tuple") { STATIC_REQUIRE(count_tuple::value == 0); } { - auto t = make_tuple(group_by(&User::name), limit(10, offset(5))); + auto t = std::make_tuple(group_by(&User::name), limit(10, offset(5))); using T = decltype(t); STATIC_REQUIRE(count_tuple::value == 0); STATIC_REQUIRE(count_tuple::value == 1); @@ -60,7 +60,8 @@ TEST_CASE("count_tuple") { STATIC_REQUIRE(count_tuple::value == 1); } { - auto t = make_tuple(where(is_null(&User::name)), order_by(&User::id), multi_order_by(order_by(&User::name))); + auto t = + std::make_tuple(where(is_null(&User::name)), order_by(&User::id), multi_order_by(order_by(&User::name))); using T = decltype(t); STATIC_REQUIRE(count_tuple::value == 1); STATIC_REQUIRE(count_tuple::value == 0); @@ -68,7 +69,7 @@ TEST_CASE("count_tuple") { STATIC_REQUIRE(count_tuple::value == 0); } { - auto t = make_tuple(dynamic_order_by(make_storage(""))); + auto t = std::make_tuple(dynamic_order_by(make_storage(""))); using T = decltype(t); STATIC_REQUIRE(count_tuple::value == 0); STATIC_REQUIRE(count_tuple::value == 0); From 79aea3984fec9cd49dbfdf2829cc267a10feac54 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 9 Jun 2022 02:40:32 +0300 Subject: [PATCH 03/16] Improved custom tuple implementation --- dev/ast_iterator.h | 12 + dev/column.h | 4 +- dev/function.h | 15 +- dev/functional/fast_and.h | 22 ++ dev/functional/pack.h | 2 +- dev/functional/tuple.h | 67 ++++- dev/functional/unique_tuple.h | 47 +++- dev/index.h | 4 +- dev/node_tuple.h | 13 +- dev/storage_base.h | 16 +- dev/table.h | 3 +- dev/tuple_helper/tuple_filter.h | 48 +--- dev/values_to_tuple.h | 3 +- include/sqlite_orm/sqlite_orm.h | 262 ++++++++++++------- tests/pointer_passing_interface.cpp | 2 + tests/static_tests/function_static_tests.cpp | 28 +- 16 files changed, 354 insertions(+), 194 deletions(-) create mode 100644 dev/functional/fast_and.h diff --git a/dev/ast_iterator.h b/dev/ast_iterator.h index 460ec8507..f66f29de6 100644 --- a/dev/ast_iterator.h +++ b/dev/ast_iterator.h @@ -318,6 +318,18 @@ namespace sqlite_orm { } }; + template + struct ast_iterator, void> { + using node_type = mpl::tuple; + + template + void operator()(const node_type& node, L& lambda) const { + iterate_tuple(node, [&lambda](auto& v) { + iterate_ast(v, lambda); + }); + } + }; + template struct ast_iterator, void> { using node_type = group_by_with_having; diff --git a/dev/column.h b/dev/column.h index bb83ff642..ed63e3ee9 100644 --- a/dev/column.h +++ b/dev/column.h @@ -23,7 +23,7 @@ namespace sqlite_orm { /** * Column name. */ - const std::string name; + std::string name; }; struct empty_setter {}; @@ -70,7 +70,7 @@ namespace sqlite_orm { struct column_constraints { using constraints_type = mpl::uple; - SQLITE_ORM_NOUNIQUEADDRESS const constraints_type constraints; + SQLITE_ORM_NOUNIQUEADDRESS constraints_type constraints; /** * Checks whether contraints are of trait `Trait` diff --git a/dev/function.h b/dev/function.h index 2685cb1b0..cfa7797a1 100644 --- a/dev/function.h +++ b/dev/function.h @@ -3,7 +3,6 @@ #include #include #include // std::string -#include // std::tuple #include // std::function #include // std::min #include // std::move, std::forward @@ -11,7 +10,7 @@ #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" #include "functional/type_at.h" -#include "functional/unique_tuple.h" +#include "functional/tuple.h" namespace sqlite_orm { @@ -102,14 +101,14 @@ namespace sqlite_orm { template struct member_function_arguments { using member_function_type = R (O::*)(Args...) const; - using tuple_type = std::tuple...>; + using tuple_type = mpl::tuple...>; using return_type = R; }; template struct member_function_arguments { using member_function_type = R (O::*)(Args...); - using tuple_type = std::tuple...>; + using tuple_type = mpl::tuple...>; using return_type = R; }; @@ -134,7 +133,7 @@ namespace sqlite_orm { template struct function_call { using function_type = F; - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; args_tuple args; }; @@ -238,12 +237,12 @@ namespace sqlite_orm { constexpr auto argsCount = args_pack::size(); constexpr auto functionArgsCount = std::tuple_size::value; static_assert((argsCount == functionArgsCount && - !std::is_same>::value && + !std::is_same>::value && internal::validate_pointer_value_types, args_pack>( polyfill::index_constant(functionArgsCount, argsCount) - 1>{})) || - std::is_same>::value, + std::is_same>::value, "Number of arguments does not match"); - return {std::make_tuple(std::forward(args)...)}; + return {mpl::make_tuple(std::forward(args)...)}; } } diff --git a/dev/functional/fast_and.h b/dev/functional/fast_and.h new file mode 100644 index 000000000..999efcadf --- /dev/null +++ b/dev/functional/fast_and.h @@ -0,0 +1,22 @@ +#pragma once + +#include "cxx_universal.h" +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION +#include +#else +#include "cxx_type_traits_polyfill.h" +#endif + +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION +namespace sqlite_orm { + namespace internal { + + template + struct fast_and : std::is_same, fast_and<(v, true)...>> {}; + } +} + +#define SQLITE_ORM_FAST_AND(...) ::sqlite_orm::internal::fast_and<__VA_ARGS__::value...>::value +#else +#define SQLITE_ORM_FAST_AND(...) polyfill::conjunction_v<__VA_ARGS__...> +#endif diff --git a/dev/functional/pack.h b/dev/functional/pack.h index b7ea37b33..0b258f62e 100644 --- a/dev/functional/pack.h +++ b/dev/functional/pack.h @@ -5,7 +5,7 @@ namespace _sqlite_orm { // short names defined in a short namespace to reduce symbol lengths, // since those types are used as a building block; - // (seen in boost hana) + // (as seen in boost hana) template struct indexed_type { diff --git a/dev/functional/tuple.h b/dev/functional/tuple.h index 1af91d7ff..3f7679fd6 100644 --- a/dev/functional/tuple.h +++ b/dev/functional/tuple.h @@ -1,17 +1,18 @@ #pragma once -#include // std::integral_constant, std::decay, std::is_constructible, std::enable_if +#include // std::integral_constant, std::decay, std::is_constructible, std::is_default_constructible, std::enable_if #include // std::move, std::forward #include "cxx_universal.h" #include "cxx_type_traits_polyfill.h" +#include "fast_and.h" #include "pack.h" #include "type_at.h" namespace _sqlite_orm { // short names defined in a short namespace to reduce symbol lengths, // since those types are used as a building block; - // (seen in boost hana) + // (as seen in boost hana) /* * element of a tuple @@ -20,7 +21,10 @@ namespace _sqlite_orm { struct tuplem : indexed_type { SQLITE_ORM_NOUNIQUEADDRESS X element; - tuplem(X t) : element{std::move(t)} {} + constexpr tuplem() = default; + + template + constexpr tuplem(Y&& y) : element(std::forward(y)) {} }; } @@ -37,9 +41,14 @@ namespace sqlite_orm { #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED constexpr basic_tuple() = default; - template...>, bool> = true> - constexpr basic_tuple(U&&... t) : tuplem{std::forward(t)}... {} +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + template + constexpr basic_tuple(Y&&... y) : tuplem(std::forward(y))... {} +#else + template + constexpr basic_tuple(bool /*force instantiation of ctor*/, Y&&... y) : + tuplem(std::forward(y))... {} +#endif #endif }; @@ -47,24 +56,54 @@ namespace sqlite_orm { * tuple */ template - struct SQLITE_ORM_MSVC_EMPTYBASES tuple final : basic_tuple, X...> { + struct SQLITE_ORM_MSVC_EMPTYBASES tuple final : basic_tuple, X...> { + private: + using base_type = basic_tuple, X...>; + + template + constexpr tuple(std::index_sequence, Other&& other) : + base_type{std::get(std::forward(other))...} {} + + public: #ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED - constexpr explicit(!polyfill::conjunction_v...>) tuple() = default; + template...>, bool> = true> + constexpr explicit(!SQLITE_ORM_FAST_AND(std::is_default_constructible)) tuple() : base_type{} {} #else - constexpr tuple() = default; + template...>, bool> = true> + constexpr tuple() : base_type{} {} #endif - template...>, bool> = true> - constexpr tuple(U&&... t) : basic_tuple, X...>{std::forward(t)...} {} + template), bool> = true> +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + constexpr tuple(Y&&... y) : base_type{std::forward(y)...} { + } +#else + constexpr tuple(Y&&... y) : base_type{true, std::forward(y)...} { + } +#endif constexpr tuple(const tuple& other) = default; constexpr tuple(tuple&& other) = default; + + template), bool> = true> + constexpr tuple(const tuple& other) : tuple{std::make_index_sequence, other} {} + + template), bool> = true> + constexpr tuple(tuple&& other) : + tuple{std::make_index_sequence, std::move(other)} {} + }; + + template<> + struct tuple<> final { + constexpr tuple() = default; }; template - auto make_tuple(X&&... t) { - return tuple...>{std::forward(t)...}; + constexpr auto make_tuple(X&&... x) { + return tuple...>{std::forward(x)...}; } template diff --git a/dev/functional/unique_tuple.h b/dev/functional/unique_tuple.h index 1fb7b8a1f..f9421a099 100644 --- a/dev/functional/unique_tuple.h +++ b/dev/functional/unique_tuple.h @@ -1,16 +1,17 @@ #pragma once -#include // std::integral_constant, std::decay, std::is_constructible, std::enable_if +#include // std::integral_constant, std::decay, std::is_constructible, std::is_default_constructible, std::enable_if #include // std::move, std::forward #include "cxx_universal.h" #include "cxx_type_traits_polyfill.h" +#include "fast_and.h" #include "type_at.h" namespace _sqlite_orm { // short names defined in a short namespace to reduce symbol lengths, // since those types are used as a building block; - // (seen in boost hana) + // (as seen in boost hana) /* * element of a unique tuple @@ -18,6 +19,11 @@ namespace _sqlite_orm { template struct uplem { SQLITE_ORM_NOUNIQUEADDRESS X element; + + constexpr uplem() = default; + + template + constexpr uplem(Y&& y) : element(std::forward(y)) {} }; } @@ -27,27 +33,48 @@ namespace sqlite_orm { using ::_sqlite_orm::uplem; /* - * unique tuple + * unique tuple, which allows only distinct types. */ template struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { + private: + template + constexpr uple(std::index_sequence, Other&& other) : + base_type{std::get(std::forward(other))...} {} + + public: #ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED - constexpr explicit(!polyfill::conjunction_v...>) uple() = default; + template...>, bool> = true> + constexpr explicit(!SQLITE_ORM_FAST_AND(std::is_default_constructible)) uple() {} #else - constexpr uple() = default; + template), bool> = true> + constexpr uple() {} #endif - template...>, bool> = true> - constexpr uple(U&&... t) : uplem{std::forward(t)}... {} + template), bool> = true> + constexpr uple(Y&&... y) : uplem(std::forward(y))... {} constexpr uple(const uple& other) = default; constexpr uple(uple&& other) = default; + + template), bool> = true> + constexpr uple(const uple& other) : uple{std::make_index_sequence, other} {} + + template), bool> = true> + constexpr uple(uple&& other) : uple{std::make_index_sequence, std::move(other)} {} + }; + + template<> + struct uple<> final { + constexpr uple() = default; }; template - auto make_unique_tuple(X&&... t) { - return uple...>{std::forward(t)...}; + constexpr auto make_unique_tuple(X&&... x) { + return uple...>{std::forward(x)...}; } template diff --git a/dev/index.h b/dev/index.h index 3508e81b3..c40f2bc1b 100644 --- a/dev/index.h +++ b/dev/index.h @@ -1,6 +1,6 @@ #pragma once -#include // std::tuple, std::make_tuple, std::declval +#include // std::declval #include // std::string #include // std::forward @@ -29,7 +29,7 @@ namespace sqlite_orm { #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED index_t(std::string name_, bool unique_, elements_type elements_) : - index_base{move(name_), unique_}, elements(move(elements_)) {} + index_base{move(name_), unique_}, elements(std::move(elements_)) {} #endif elements_type elements; diff --git a/dev/node_tuple.h b/dev/node_tuple.h index 7173bdfce..33bcfacc3 100644 --- a/dev/node_tuple.h +++ b/dev/node_tuple.h @@ -5,6 +5,8 @@ #include // std::reference_wrapper #include "functional/cxx_optional.h" +#include "functional/type_at.h" +#include "functional/tuple.h" #include "tuple_helper/tuple_filter.h" #include "conditions.h" #include "operators.h" @@ -43,18 +45,18 @@ namespace sqlite_orm { struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> : node_tuple> {}; + struct node_tuple, void> : node_tuple> {}; template struct node_tuple, void> { - using args_tuple = node_tuple_t>; + using args_tuple = node_tuple_t>; using expression_tuple = node_tuple_t; using type = conc_tuple_t; }; template struct node_tuple, std::tuple>, void> - : node_tuple> {}; + : node_tuple> {}; template struct node_tuple, void> { @@ -161,6 +163,11 @@ namespace sqlite_orm { using type = conc_tuple_t...>; }; + template + struct node_tuple, void> { + using type = conc_tuple_t...>; + }; + template struct node_tuple, void> { using type = conc_tuple_t...>; diff --git a/dev/storage_base.h b/dev/storage_base.h index 77ea936f7..db0172b32 100644 --- a/dev/storage_base.h +++ b/dev/storage_base.h @@ -239,10 +239,9 @@ namespace sqlite_orm { auto name = ss.str(); using args_tuple = typename callable_arguments::args_tuple; using return_type = typename callable_arguments::return_type; - auto argsCount = int(std::tuple_size::value); - if(std::is_same>::value) { - argsCount = -1; - } + constexpr auto argsCount = std::is_same>::value + ? -1 + : int(std::tuple_size::value); this->scalarFunctions.emplace_back(new user_defined_scalar_function_t{ move(name), argsCount, @@ -302,10 +301,9 @@ namespace sqlite_orm { auto name = ss.str(); using args_tuple = typename callable_arguments::args_tuple; using return_type = typename callable_arguments::return_type; - auto argsCount = int(std::tuple_size::value); - if(std::is_same>::value) { - argsCount = -1; - } + constexpr auto argsCount = std::is_same>::value + ? -1 + : int(std::tuple_size::value); this->aggregateFunctions.emplace_back(new user_defined_aggregate_function_t{ move(name), argsCount, @@ -319,7 +317,7 @@ namespace sqlite_orm { args_tuple argsTuple; using tuple_size = std::tuple_size; values_to_tuple{}(values, argsTuple, argsCount); - call(function, &F::step, move(argsTuple)); + call(function, &F::step, std::move(argsTuple)); }, /* finalCall = */ [](sqlite3_context* context, void* functionVoidPointer) { diff --git a/dev/table.h b/dev/table.h index 24412d6b5..f3301c2ea 100644 --- a/dev/table.h +++ b/dev/table.h @@ -50,7 +50,8 @@ namespace sqlite_orm { elements_type elements; #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED - table_t(std::string name_, elements_type elements_) : basic_table{move(name_)}, elements{move(elements_)} {} + table_t(std::string name_, elements_type elements_) : + basic_table{move(name_)}, elements{std::move(elements_)} {} #endif table_t without_rowid() const { diff --git a/dev/tuple_helper/tuple_filter.h b/dev/tuple_helper/tuple_filter.h index 2cf46c73c..89b6396aa 100644 --- a/dev/tuple_helper/tuple_filter.h +++ b/dev/tuple_helper/tuple_filter.h @@ -28,17 +28,17 @@ namespace sqlite_orm { template struct tuple_from_index_sequence, std::index_sequence> { - using type = std::tuple...>; + using type = std::tuple>...>; }; template struct tuple_from_index_sequence, std::index_sequence> { - using type = mpl::uple...>; + using type = mpl::uple>...>; }; template struct tuple_from_index_sequence, std::index_sequence> { - using type = mpl::tuple...>; + using type = mpl::tuple>...>; }; template @@ -62,27 +62,9 @@ namespace sqlite_orm { struct filter_tuple_sequence; #ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>>>::value, - std::index_sequence, - std::index_sequence<>>...> {}; - - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>>>::value, - std::index_sequence, - std::index_sequence<>>...> {}; - - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>>>::value, - std::index_sequence, - std::index_sequence<>>...> {}; - - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>>>::value, + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence> + : concat_idx_seq>>::value, std::index_sequence, std::index_sequence<>>...> {}; #else @@ -96,21 +78,9 @@ namespace sqlite_orm { using type = std::index_sequence; }; - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>, Pred>::type...> {}; - - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>, Pred>::type...> {}; - - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>, Pred>::type...> {}; - - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>, Pred>::type...> {}; + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence> + : concat_idx_seq>, Pred>::type...> {}; #endif template // std::tuple, std::tuple_size, std::get #include "functional/cxx_universal.h" +#include "functional/tuple.h" #include "row_extractor.h" #include "arg_values.h" @@ -18,7 +19,7 @@ namespace sqlite_orm { (*this)(values, tuple, std::make_index_sequence::value>{}); } - void operator()(sqlite3_value** values, std::tuple& tuple, int argsCount) const { + void operator()(sqlite3_value** values, mpl::tuple& tuple, int argsCount) const { std::get<0>(tuple) = arg_values(argsCount, values); } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 08fec1a66..72ca3e3fa 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -1012,13 +1012,38 @@ namespace sqlite_orm { // #include "../functional/unique_tuple.h" -#include // std::integral_constant, std::decay, std::is_constructible, std::enable_if +#include // std::integral_constant, std::decay, std::is_constructible, std::is_default_constructible, std::enable_if #include // std::move, std::forward // #include "cxx_universal.h" // #include "cxx_type_traits_polyfill.h" +// #include "fast_and.h" + +// #include "cxx_universal.h" + +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION +#include +#else +// #include "cxx_type_traits_polyfill.h" + +#endif + +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION +namespace sqlite_orm { + namespace internal { + + template + struct fast_and : std::is_same, fast_and<(v, true)...>> {}; + } +} + +#define SQLITE_ORM_FAST_AND(...) ::sqlite_orm::internal::fast_and<__VA_ARGS__::value...>::value +#else +#define SQLITE_ORM_FAST_AND(...) polyfill::conjunction_v<__VA_ARGS__...> +#endif + // #include "type_at.h" #include // std::integral_constant, std::index_sequence, std::make_index_sequence @@ -1033,7 +1058,7 @@ namespace sqlite_orm { namespace _sqlite_orm { // short names defined in a short namespace to reduce symbol lengths, // since those types are used as a building block; - // (seen in boost hana) + // (as seen in boost hana) template struct indexed_type { @@ -1117,7 +1142,7 @@ namespace std { namespace _sqlite_orm { // short names defined in a short namespace to reduce symbol lengths, // since those types are used as a building block; - // (seen in boost hana) + // (as seen in boost hana) /* * element of a unique tuple @@ -1125,6 +1150,11 @@ namespace _sqlite_orm { template struct uplem { SQLITE_ORM_NOUNIQUEADDRESS X element; + + constexpr uplem() = default; + + template + constexpr uplem(Y&& y) : element(std::forward(y)) {} }; } @@ -1134,27 +1164,48 @@ namespace sqlite_orm { using ::_sqlite_orm::uplem; /* - * unique tuple + * unique tuple, which allows only distinct types. */ template struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { + private: + template + constexpr uple(std::index_sequence, Other&& other) : + base_type{std::get(std::forward(other))...} {} + + public: #ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED - constexpr explicit(!polyfill::conjunction_v...>) uple() = default; + template...>, bool> = true> + constexpr explicit(!SQLITE_ORM_FAST_AND(std::is_default_constructible)) uple() {} #else - constexpr uple() = default; + template), bool> = true> + constexpr uple() {} #endif - template...>, bool> = true> - constexpr uple(U&&... t) : uplem{std::forward(t)}... {} + template), bool> = true> + constexpr uple(Y&&... y) : uplem(std::forward(y))... {} constexpr uple(const uple& other) = default; constexpr uple(uple&& other) = default; + + template), bool> = true> + constexpr uple(const uple& other) : uple{std::make_index_sequence, other} {} + + template), bool> = true> + constexpr uple(uple&& other) : uple{std::make_index_sequence, std::move(other)} {} + }; + + template<> + struct uple<> final { + constexpr uple() = default; }; template - auto make_unique_tuple(X&&... t) { - return uple...>{std::forward(t)...}; + constexpr auto make_unique_tuple(X&&... x) { + return uple...>{std::forward(x)...}; } template @@ -1215,13 +1266,15 @@ namespace std { // #include "../functional/tuple.h" -#include // std::integral_constant, std::decay, std::is_constructible, std::enable_if +#include // std::integral_constant, std::decay, std::is_constructible, std::is_default_constructible, std::enable_if #include // std::move, std::forward // #include "cxx_universal.h" // #include "cxx_type_traits_polyfill.h" +// #include "fast_and.h" + // #include "pack.h" // #include "type_at.h" @@ -1229,7 +1282,7 @@ namespace std { namespace _sqlite_orm { // short names defined in a short namespace to reduce symbol lengths, // since those types are used as a building block; - // (seen in boost hana) + // (as seen in boost hana) /* * element of a tuple @@ -1238,7 +1291,10 @@ namespace _sqlite_orm { struct tuplem : indexed_type { SQLITE_ORM_NOUNIQUEADDRESS X element; - tuplem(X t) : element{std::move(t)} {} + constexpr tuplem() = default; + + template + constexpr tuplem(Y&& y) : element(std::forward(y)) {} }; } @@ -1255,9 +1311,14 @@ namespace sqlite_orm { #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED constexpr basic_tuple() = default; - template...>, bool> = true> - constexpr basic_tuple(U&&... t) : tuplem{std::forward(t)}... {} +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + template + constexpr basic_tuple(Y&&... y) : tuplem(std::forward(y))... {} +#else + template + constexpr basic_tuple(bool /*force instantiation of ctor*/, Y&&... y) : + tuplem(std::forward(y))... {} +#endif #endif }; @@ -1265,24 +1326,54 @@ namespace sqlite_orm { * tuple */ template - struct SQLITE_ORM_MSVC_EMPTYBASES tuple final : basic_tuple, X...> { + struct SQLITE_ORM_MSVC_EMPTYBASES tuple final : basic_tuple, X...> { + private: + using base_type = basic_tuple, X...>; + + template + constexpr tuple(std::index_sequence, Other&& other) : + base_type{std::get(std::forward(other))...} {} + + public: #ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED - constexpr explicit(!polyfill::conjunction_v...>) tuple() = default; + template...>, bool> = true> + constexpr explicit(!SQLITE_ORM_FAST_AND(std::is_default_constructible)) tuple() : base_type{} {} #else - constexpr tuple() = default; + template...>, bool> = true> + constexpr tuple() : base_type{} {} #endif - template...>, bool> = true> - constexpr tuple(U&&... t) : basic_tuple, X...>{std::forward(t)...} {} + template), bool> = true> +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + constexpr tuple(Y&&... y) : base_type{std::forward(y)...} { + } +#else + constexpr tuple(Y&&... y) : base_type{true, std::forward(y)...} { + } +#endif constexpr tuple(const tuple& other) = default; constexpr tuple(tuple&& other) = default; + + template), bool> = true> + constexpr tuple(const tuple& other) : tuple{std::make_index_sequence, other} {} + + template), bool> = true> + constexpr tuple(tuple&& other) : + tuple{std::make_index_sequence, std::move(other)} {} + }; + + template<> + struct tuple<> final { + constexpr tuple() = default; }; template - auto make_tuple(X&&... t) { - return tuple...>{std::forward(t)...}; + constexpr auto make_tuple(X&&... x) { + return tuple...>{std::forward(x)...}; } template @@ -1418,17 +1509,17 @@ namespace sqlite_orm { template struct tuple_from_index_sequence, std::index_sequence> { - using type = std::tuple...>; + using type = std::tuple>...>; }; template struct tuple_from_index_sequence, std::index_sequence> { - using type = mpl::uple...>; + using type = mpl::uple>...>; }; template struct tuple_from_index_sequence, std::index_sequence> { - using type = mpl::tuple...>; + using type = mpl::tuple>...>; }; template @@ -1452,27 +1543,9 @@ namespace sqlite_orm { struct filter_tuple_sequence; #ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>>>::value, - std::index_sequence, - std::index_sequence<>>...> {}; - - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>>>::value, - std::index_sequence, - std::index_sequence<>>...> {}; - - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>>>::value, - std::index_sequence, - std::index_sequence<>>...> {}; - - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>>>::value, + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence> + : concat_idx_seq>>::value, std::index_sequence, std::index_sequence<>>...> {}; #else @@ -1486,21 +1559,9 @@ namespace sqlite_orm { using type = std::index_sequence; }; - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>, Pred>::type...> {}; - - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>, Pred>::type...> {}; - - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>, Pred>::type...> {}; - - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence, Pred, Proj, std::index_sequence> - : concat_idx_seq>, Pred>::type...> {}; + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence> + : concat_idx_seq>, Pred>::type...> {}; #endif template; - SQLITE_ORM_NOUNIQUEADDRESS const constraints_type constraints; + SQLITE_ORM_NOUNIQUEADDRESS constraints_type constraints; /** * Checks whether contraints are of trait `Trait` @@ -9181,7 +9242,7 @@ namespace sqlite_orm { } #pragma once -#include // std::tuple, std::make_tuple, std::declval +#include // std::declval #include // std::string #include // std::forward @@ -9283,7 +9344,7 @@ namespace sqlite_orm { #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED index_t(std::string name_, bool unique_, elements_type elements_) : - index_base{move(name_), unique_}, elements(move(elements_)) {} + index_base{move(name_), unique_}, elements(std::move(elements_)) {} #endif elements_type elements; @@ -9642,7 +9703,6 @@ namespace sqlite_orm { #include #include #include // std::string -#include // std::tuple #include // std::function #include // std::min #include // std::move, std::forward @@ -9653,7 +9713,7 @@ namespace sqlite_orm { // #include "functional/type_at.h" -// #include "functional/unique_tuple.h" +// #include "functional/tuple.h" namespace sqlite_orm { @@ -9744,14 +9804,14 @@ namespace sqlite_orm { template struct member_function_arguments { using member_function_type = R (O::*)(Args...) const; - using tuple_type = std::tuple...>; + using tuple_type = mpl::tuple...>; using return_type = R; }; template struct member_function_arguments { using member_function_type = R (O::*)(Args...); - using tuple_type = std::tuple...>; + using tuple_type = mpl::tuple...>; using return_type = R; }; @@ -9776,7 +9836,7 @@ namespace sqlite_orm { template struct function_call { using function_type = F; - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; args_tuple args; }; @@ -9880,12 +9940,12 @@ namespace sqlite_orm { constexpr auto argsCount = args_pack::size(); constexpr auto functionArgsCount = std::tuple_size::value; static_assert((argsCount == functionArgsCount && - !std::is_same>::value && + !std::is_same>::value && internal::validate_pointer_value_types, args_pack>( polyfill::index_constant(functionArgsCount, argsCount) - 1>{})) || - std::is_same>::value, + std::is_same>::value, "Number of arguments does not match"); - return {std::make_tuple(std::forward(args)...)}; + return {mpl::make_tuple(std::forward(args)...)}; } } @@ -10480,7 +10540,8 @@ namespace sqlite_orm { elements_type elements; #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED - table_t(std::string name_, elements_type elements_) : basic_table{move(name_)}, elements{move(elements_)} {} + table_t(std::string name_, elements_type elements_) : + basic_table{move(name_)}, elements{std::move(elements_)} {} #endif table_t without_rowid() const { @@ -12466,6 +12527,18 @@ namespace sqlite_orm { } }; + template + struct ast_iterator, void> { + using node_type = mpl::tuple; + + template + void operator()(const node_type& node, L& lambda) const { + iterate_tuple(node, [&lambda](auto& v) { + iterate_ast(v, lambda); + }); + } + }; + template struct ast_iterator, void> { using node_type = group_by_with_having; @@ -13882,6 +13955,8 @@ namespace sqlite_orm { // #include "functional/cxx_universal.h" +// #include "functional/tuple.h" + // #include "row_extractor.h" // #include "arg_values.h" @@ -14040,7 +14115,7 @@ namespace sqlite_orm { (*this)(values, tuple, std::make_index_sequence::value>{}); } - void operator()(sqlite3_value** values, std::tuple& tuple, int argsCount) const { + void operator()(sqlite3_value** values, mpl::tuple& tuple, int argsCount) const { std::get<0>(tuple) = arg_values(argsCount, values); } @@ -14285,10 +14360,9 @@ namespace sqlite_orm { auto name = ss.str(); using args_tuple = typename callable_arguments::args_tuple; using return_type = typename callable_arguments::return_type; - auto argsCount = int(std::tuple_size::value); - if(std::is_same>::value) { - argsCount = -1; - } + constexpr auto argsCount = std::is_same>::value + ? -1 + : int(std::tuple_size::value); this->scalarFunctions.emplace_back(new user_defined_scalar_function_t{ move(name), argsCount, @@ -14348,10 +14422,9 @@ namespace sqlite_orm { auto name = ss.str(); using args_tuple = typename callable_arguments::args_tuple; using return_type = typename callable_arguments::return_type; - auto argsCount = int(std::tuple_size::value); - if(std::is_same>::value) { - argsCount = -1; - } + constexpr auto argsCount = std::is_same>::value + ? -1 + : int(std::tuple_size::value); this->aggregateFunctions.emplace_back(new user_defined_aggregate_function_t{ move(name), argsCount, @@ -14365,7 +14438,7 @@ namespace sqlite_orm { args_tuple argsTuple; using tuple_size = std::tuple_size; values_to_tuple{}(values, argsTuple, argsCount); - call(function, &F::step, move(argsTuple)); + call(function, &F::step, std::move(argsTuple)); }, /* finalCall = */ [](sqlite3_context* context, void* functionVoidPointer) { @@ -18748,6 +18821,10 @@ namespace sqlite_orm { #include // std::reference_wrapper // #include "functional/cxx_optional.h" +// #include "functional/type_at.h" + +// #include "functional/tuple.h" + // #include "tuple_helper/tuple_filter.h" // #include "conditions.h" @@ -18798,18 +18875,18 @@ namespace sqlite_orm { struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> : node_tuple> {}; + struct node_tuple, void> : node_tuple> {}; template struct node_tuple, void> { - using args_tuple = node_tuple_t>; + using args_tuple = node_tuple_t>; using expression_tuple = node_tuple_t; using type = conc_tuple_t; }; template struct node_tuple, std::tuple>, void> - : node_tuple> {}; + : node_tuple> {}; template struct node_tuple, void> { @@ -18916,6 +18993,11 @@ namespace sqlite_orm { using type = conc_tuple_t...>; }; + template + struct node_tuple, void> { + using type = conc_tuple_t...>; + }; + template struct node_tuple, void> { using type = conc_tuple_t...>; diff --git a/tests/pointer_passing_interface.cpp b/tests/pointer_passing_interface.cpp index 529371286..48877800f 100644 --- a/tests/pointer_passing_interface.cpp +++ b/tests/pointer_passing_interface.cpp @@ -29,6 +29,8 @@ namespace { } TEST_CASE("pointer-passing") { + polyfill::conjunction_v>; + polyfill::conjunction_v>>; // accept and return a pointer of type "carray" struct pass_thru_pointer_fn { using bindable_carray_ptr_t = static_carray_pointer_binding; diff --git a/tests/static_tests/function_static_tests.cpp b/tests/static_tests/function_static_tests.cpp index 44790b948..c82956a59 100644 --- a/tests/static_tests/function_static_tests.cpp +++ b/tests/static_tests/function_static_tests.cpp @@ -43,12 +43,12 @@ TEST_CASE("function static") { STATIC_REQUIRE(std::is_same::value); using ArgumentsTuple = internal::member_function_arguments::tuple_type; - using ExpectedArgumentsTuple = std::tuple; + using ExpectedArgumentsTuple = mpl::tuple; STATIC_REQUIRE(std::is_same::value); STATIC_REQUIRE(std::is_same::return_type, double>::value); STATIC_REQUIRE( - std::is_same::args_tuple, std::tuple>::value); + std::is_same::args_tuple, mpl::tuple>::value); } SECTION("double(double)") { struct Function { @@ -65,12 +65,12 @@ TEST_CASE("function static") { STATIC_REQUIRE(std::is_same::value); using ArgumentsTuple = internal::member_function_arguments::tuple_type; - using ExpectedArgumentsTuple = std::tuple; + using ExpectedArgumentsTuple = mpl::tuple; STATIC_REQUIRE(std::is_same::value); STATIC_REQUIRE(std::is_same::return_type, double>::value); STATIC_REQUIRE( - std::is_same::args_tuple, std::tuple>::value); + std::is_same::args_tuple, mpl::tuple>::value); } SECTION("int(std::string) const") { struct Function { @@ -87,12 +87,12 @@ TEST_CASE("function static") { STATIC_REQUIRE(std::is_same::value); using ArgumentsTuple = internal::member_function_arguments::tuple_type; - using ExpectedArgumentsTuple = std::tuple; + using ExpectedArgumentsTuple = mpl::tuple; STATIC_REQUIRE(std::is_same::value); STATIC_REQUIRE(std::is_same::return_type, int>::value); STATIC_REQUIRE( - std::is_same::args_tuple, std::tuple>::value); + std::is_same::args_tuple, mpl::tuple>::value); } SECTION("int(std::string)") { struct Function { @@ -109,12 +109,12 @@ TEST_CASE("function static") { STATIC_REQUIRE(std::is_same::value); using ArgumentsTuple = internal::member_function_arguments::tuple_type; - using ExpectedArgumentsTuple = std::tuple; + using ExpectedArgumentsTuple = mpl::tuple; STATIC_REQUIRE(std::is_same::value); STATIC_REQUIRE(std::is_same::return_type, int>::value); STATIC_REQUIRE( - std::is_same::args_tuple, std::tuple>::value); + std::is_same::args_tuple, mpl::tuple>::value); } SECTION("std::string(const std::string &, const std::string &) const") { struct Function { @@ -131,12 +131,12 @@ TEST_CASE("function static") { STATIC_REQUIRE(std::is_same::value); using ArgumentsTuple = internal::member_function_arguments::tuple_type; - using ExpectedArgumentsTuple = std::tuple; + using ExpectedArgumentsTuple = mpl::tuple; STATIC_REQUIRE(std::is_same::value); STATIC_REQUIRE(std::is_same::return_type, std::string>::value); STATIC_REQUIRE(std::is_same::args_tuple, - std::tuple>::value); + mpl::tuple>::value); } SECTION("std::string(const std::string &, const std::string &)") { struct Function { @@ -153,12 +153,12 @@ TEST_CASE("function static") { STATIC_REQUIRE(std::is_same::value); using ArgumentsTuple = internal::member_function_arguments::tuple_type; - using ExpectedArgumentsTuple = std::tuple; + using ExpectedArgumentsTuple = mpl::tuple; STATIC_REQUIRE(std::is_same::value); STATIC_REQUIRE(std::is_same::return_type, std::string>::value); STATIC_REQUIRE(std::is_same::args_tuple, - std::tuple>::value); + mpl::tuple>::value); } } } @@ -190,7 +190,7 @@ TEST_CASE("function static") { STATIC_REQUIRE(std::is_same::value); STATIC_REQUIRE(std::is_same::return_type, int>::value); - STATIC_REQUIRE(std::is_same::args_tuple, std::tuple>::value); + STATIC_REQUIRE(std::is_same::args_tuple, mpl::tuple>::value); } SECTION("void(std::string) const & std::string()") { struct Function { @@ -218,7 +218,7 @@ TEST_CASE("function static") { STATIC_REQUIRE(std::is_same::return_type, std::string>::value); STATIC_REQUIRE( - std::is_same::args_tuple, std::tuple>::value); + std::is_same::args_tuple, mpl::tuple>::value); } } } From 0c1136859be851bebe7125ff50c67de46f98535c Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 10 Jun 2022 01:09:51 +0300 Subject: [PATCH 04/16] Some more using custom tuple --- dev/functional/cxx_compiler_quirks.h | 7 ++ dev/functional/tuple.h | 61 +++++----- dev/functional/unique_tuple.h | 28 +++-- dev/prepared_statement.h | 72 ++++++----- dev/view.h | 2 +- include/sqlite_orm/sqlite_orm.h | 171 +++++++++++++++------------ 6 files changed, 185 insertions(+), 156 deletions(-) diff --git a/dev/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index 96ef947c4..6bba37c11 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -27,6 +27,7 @@ #if defined(_MSC_VER) && (_MSC_VER < 1920) #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION +#define SQLITE_ORM_BROKEN_CONSTEXPR_DELEGATING_CTORS #endif #if defined(_MSC_VER) && !defined(__clang__) // MSVC @@ -34,3 +35,9 @@ #else #define SQLITE_ORM_MSVC_EMPTYBASES #endif + +#ifndef SQLITE_ORM_BROKEN_CONSTEXPR_DELEGATING_CTORS +#define SQLITE_ORM_DELEGATING_CONSTEXPR constexpr +#else +#define SQLITE_ORM_DELEGATING_CONSTEXPR +#endif diff --git a/dev/functional/tuple.h b/dev/functional/tuple.h index 3f7679fd6..ed0d0041a 100644 --- a/dev/functional/tuple.h +++ b/dev/functional/tuple.h @@ -33,23 +33,22 @@ namespace sqlite_orm { namespace mpl { using ::_sqlite_orm::tuplem; + struct from_variadic_t {}; + template struct basic_tuple; template struct basic_tuple, X...> : tuplem... { -#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED constexpr basic_tuple() = default; -#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION - template - constexpr basic_tuple(Y&&... y) : tuplem(std::forward(y))... {} -#else template - constexpr basic_tuple(bool /*force instantiation of ctor*/, Y&&... y) : - tuplem(std::forward(y))... {} -#endif -#endif + constexpr basic_tuple(from_variadic_t, Y&&... y) : tuplem(std::forward(y))... {} + + // copy/move constructor + template + SQLITE_ORM_DELEGATING_CONSTEXPR basic_tuple(Other&& other) : + basic_tuple{from_variadic_t{}, std::get(std::forward(other))...} {} }; /* @@ -60,10 +59,6 @@ namespace sqlite_orm { private: using base_type = basic_tuple, X...>; - template - constexpr tuple(std::index_sequence, Other&& other) : - base_type{std::get(std::forward(other))...} {} - public: #ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED template), bool> = true> -#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION - constexpr tuple(Y&&... y) : base_type{std::forward(y)...} { - } -#else - constexpr tuple(Y&&... y) : base_type{true, std::forward(y)...} { - } -#endif - - constexpr tuple(const tuple& other) = default; - constexpr tuple(tuple&& other) = default; + SQLITE_ORM_DELEGATING_CONSTEXPR tuple(Y&&... y) : base_type{from_variadic_t{}, std::forward(y)...} {} template), bool> = true> - constexpr tuple(const tuple& other) : tuple{std::make_index_sequence, other} {} + constexpr tuple(const tuple& other) : base_type{other} {} template), bool> = true> - constexpr tuple(tuple&& other) : - tuple{std::make_index_sequence, std::move(other)} {} + constexpr tuple(tuple&& other) : base_type{std::move(other)} {} + + // The two following constructors are required to make sure that + // the tuple(Y&&...) constructor is _not_ preferred over the copy + // constructor for unary tuples containing a type that is constructible + // from tuple<...>. + + template...>, + bool> = true> + constexpr tuple(const tuple& other) : base_type{other} {} + + template< + class... Void, + std::enable_if_t...>, bool> = true> + constexpr tuple(tuple&& other) : base_type{std::move(other)} {} }; template<> @@ -101,10 +101,13 @@ namespace sqlite_orm { constexpr tuple() = default; }; - template - constexpr auto make_tuple(X&&... x) { - return tuple...>{std::forward(x)...}; + namespace adl { + template + constexpr auto make_tuple(X&&... x) { + return tuple...>{std::forward(x)...}; + } } + using adl::make_tuple; template struct type_at> { diff --git a/dev/functional/unique_tuple.h b/dev/functional/unique_tuple.h index f9421a099..5c105712e 100644 --- a/dev/functional/unique_tuple.h +++ b/dev/functional/unique_tuple.h @@ -37,12 +37,6 @@ namespace sqlite_orm { */ template struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { - private: - template - constexpr uple(std::index_sequence, Other&& other) : - base_type{std::get(std::forward(other))...} {} - - public: #ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED template...>, bool> = true> @@ -56,15 +50,27 @@ namespace sqlite_orm { template), bool> = true> constexpr uple(Y&&... y) : uplem(std::forward(y))... {} - constexpr uple(const uple& other) = default; - constexpr uple(uple&& other) = default; - template), bool> = true> - constexpr uple(const uple& other) : uple{std::make_index_sequence, other} {} + constexpr uple(const uple& other) : uplem(std::get(other))... {} template), bool> = true> - constexpr uple(uple&& other) : uple{std::make_index_sequence, std::move(other)} {} + constexpr uple(uple&& other) : uplem(std::get(std::move(other)))... {} + + // The two following constructors are required to make sure that + // the tuple(Y&&...) constructor is _not_ preferred over the copy + // constructor for unary tuples containing a type that is constructible + // from uple<...>. + + template...>, + bool> = true> + constexpr uple(const uple& other) : uplem(std::get(other))... {} + + template< + class... Void, + std::enable_if_t...>, bool> = true> + constexpr uple(uple&& other) : uplem(std::get(std::move(other)))... {} }; template<> diff --git a/dev/prepared_statement.h b/dev/prepared_statement.h index 3baf97832..0d88ba513 100644 --- a/dev/prepared_statement.h +++ b/dev/prepared_statement.h @@ -10,6 +10,7 @@ #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" #include "functional/cxx_functional_polyfill.h" +#include "functional/tuple.h" #include "tuple_helper/tuple_filter.h" #include "connection_holder.h" #include "select_constraints.h" @@ -95,7 +96,7 @@ namespace sqlite_orm { using type = T; using return_type = R; - using conditions_type = std::tuple; + using conditions_type = mpl::tuple; conditions_type conditions; }; @@ -105,7 +106,7 @@ namespace sqlite_orm { using type = T; using return_type = R; - using conditions_type = std::tuple; + using conditions_type = mpl::tuple; conditions_type conditions; }; @@ -116,7 +117,7 @@ namespace sqlite_orm { using type = T; using return_type = R; - using conditions_type = std::tuple; + using conditions_type = mpl::tuple; conditions_type conditions; }; @@ -128,7 +129,7 @@ namespace sqlite_orm { template struct update_all_t, Wargs...> { using set_type = set_t; - using conditions_type = std::tuple; + using conditions_type = mpl::tuple; set_type set; conditions_type conditions; @@ -137,7 +138,7 @@ namespace sqlite_orm { template struct remove_all_t { using type = T; - using conditions_type = std::tuple; + using conditions_type = mpl::tuple; conditions_type conditions; }; @@ -145,7 +146,7 @@ namespace sqlite_orm { template struct get_t { using type = T; - using ids_type = std::tuple; + using ids_type = mpl::tuple; ids_type ids; }; @@ -153,7 +154,7 @@ namespace sqlite_orm { template struct get_pointer_t { using type = T; - using ids_type = std::tuple; + using ids_type = mpl::tuple; ids_type ids; }; @@ -162,7 +163,7 @@ namespace sqlite_orm { template struct get_optional_t { using type = T; - using ids_type = std::tuple; + using ids_type = mpl::tuple; ids_type ids; }; @@ -178,7 +179,7 @@ namespace sqlite_orm { template struct remove_t { using type = T; - using ids_type = std::tuple; + using ids_type = mpl::tuple; ids_type ids; }; @@ -252,7 +253,7 @@ namespace sqlite_orm { template struct insert_raw_t { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; args_tuple args; }; @@ -265,7 +266,7 @@ namespace sqlite_orm { template struct replace_raw_t { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; args_tuple args; }; @@ -372,7 +373,7 @@ namespace sqlite_orm { */ template internal::insert_raw_t insert(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; using internal::count_tuple; using internal::is_columns; using internal::is_insert_constraint; @@ -444,7 +445,7 @@ namespace sqlite_orm { */ template internal::replace_raw_t replace(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; using internal::count_tuple; using internal::is_columns; using internal::is_into; @@ -586,8 +587,8 @@ namespace sqlite_orm { */ template internal::remove_t remove(Ids... ids) { - std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + mpl::tuple idsTuple{std::forward(ids)...}; + return {std::move(idsTuple)}; } /** @@ -609,8 +610,7 @@ namespace sqlite_orm { */ template internal::get_t get(Ids... ids) { - std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {mpl::make_tuple(std::forward(ids)...)}; } /** @@ -620,8 +620,7 @@ namespace sqlite_orm { */ template internal::get_pointer_t get_pointer(Ids... ids) { - std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {mpl::make_tuple(std::forward(ids)...)}; } #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED @@ -632,8 +631,7 @@ namespace sqlite_orm { */ template internal::get_optional_t get_optional(Ids... ids) { - std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {mpl::make_tuple(std::forward(ids)...)}; } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED @@ -644,10 +642,10 @@ namespace sqlite_orm { */ template internal::remove_all_t remove_all(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -657,10 +655,10 @@ namespace sqlite_orm { */ template internal::get_all_t, Args...> get_all(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -671,10 +669,10 @@ namespace sqlite_orm { */ template internal::get_all_t get_all(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -683,10 +681,10 @@ namespace sqlite_orm { */ template internal::update_all_t, Wargs...> update_all(internal::set_t set, Wargs... wh) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(wh)...}; - return {std::move(set), move(conditions)}; + return {std::move(set), std::move(conditions)}; } /** @@ -696,10 +694,10 @@ namespace sqlite_orm { */ template internal::get_all_pointer_t>, Args...> get_all_pointer(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** * Create a get all pointer statement. @@ -709,10 +707,10 @@ namespace sqlite_orm { */ template internal::get_all_pointer_t get_all_pointer(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED @@ -723,10 +721,10 @@ namespace sqlite_orm { */ template internal::get_all_optional_t>, Args...> get_all_optional(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -737,10 +735,10 @@ namespace sqlite_orm { */ template internal::get_all_optional_t get_all_optional(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED } diff --git a/dev/view.h b/dev/view.h index f96d6ff23..e062df98b 100644 --- a/dev/view.h +++ b/dev/view.h @@ -37,7 +37,7 @@ namespace sqlite_orm { get_all_t, Args...> args; view_t(storage_type& stor, decltype(connection) conn, Args&&... args_) : - storage(stor), connection(std::move(conn)), args{std::make_tuple(std::forward(args_)...)} {} + storage(stor), connection(std::move(conn)), args{mpl::make_tuple(std::forward(args_)...)} {} size_t size() { return this->storage.template count(); diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 72ca3e3fa..5142ff90a 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -145,6 +145,7 @@ using std::nullptr_t; #if defined(_MSC_VER) && (_MSC_VER < 1920) #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION +#define SQLITE_ORM_BROKEN_CONSTEXPR_DELEGATING_CTORS #endif #if defined(_MSC_VER) && !defined(__clang__) // MSVC @@ -153,6 +154,12 @@ using std::nullptr_t; #define SQLITE_ORM_MSVC_EMPTYBASES #endif +#ifndef SQLITE_ORM_BROKEN_CONSTEXPR_DELEGATING_CTORS +#define SQLITE_ORM_DELEGATING_CONSTEXPR constexpr +#else +#define SQLITE_ORM_DELEGATING_CONSTEXPR +#endif + namespace sqlite_orm { namespace internal { namespace polyfill { @@ -1168,12 +1175,6 @@ namespace sqlite_orm { */ template struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { - private: - template - constexpr uple(std::index_sequence, Other&& other) : - base_type{std::get(std::forward(other))...} {} - - public: #ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED template...>, bool> = true> @@ -1187,15 +1188,27 @@ namespace sqlite_orm { template), bool> = true> constexpr uple(Y&&... y) : uplem(std::forward(y))... {} - constexpr uple(const uple& other) = default; - constexpr uple(uple&& other) = default; - template), bool> = true> - constexpr uple(const uple& other) : uple{std::make_index_sequence, other} {} + constexpr uple(const uple& other) : uplem(std::get(other))... {} template), bool> = true> - constexpr uple(uple&& other) : uple{std::make_index_sequence, std::move(other)} {} + constexpr uple(uple&& other) : uplem(std::get(std::move(other)))... {} + + // The two following constructors are required to make sure that + // the tuple(Y&&...) constructor is _not_ preferred over the copy + // constructor for unary tuples containing a type that is constructible + // from uple<...>. + + template...>, + bool> = true> + constexpr uple(const uple& other) : uplem(std::get(other))... {} + + template< + class... Void, + std::enable_if_t...>, bool> = true> + constexpr uple(uple&& other) : uplem(std::get(std::move(other)))... {} }; template<> @@ -1303,23 +1316,22 @@ namespace sqlite_orm { namespace mpl { using ::_sqlite_orm::tuplem; + struct from_variadic_t {}; + template struct basic_tuple; template struct basic_tuple, X...> : tuplem... { -#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED constexpr basic_tuple() = default; -#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION template - constexpr basic_tuple(Y&&... y) : tuplem(std::forward(y))... {} -#else - template - constexpr basic_tuple(bool /*force instantiation of ctor*/, Y&&... y) : - tuplem(std::forward(y))... {} -#endif -#endif + constexpr basic_tuple(from_variadic_t, Y&&... y) : tuplem(std::forward(y))... {} + + // copy/move constructor + template + SQLITE_ORM_DELEGATING_CONSTEXPR basic_tuple(Other&& other) : + basic_tuple{from_variadic_t{}, std::get(std::forward(other))...} {} }; /* @@ -1330,10 +1342,6 @@ namespace sqlite_orm { private: using base_type = basic_tuple, X...>; - template - constexpr tuple(std::index_sequence, Other&& other) : - base_type{std::get(std::forward(other))...} {} - public: #ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED template), bool> = true> -#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION - constexpr tuple(Y&&... y) : base_type{std::forward(y)...} { - } -#else - constexpr tuple(Y&&... y) : base_type{true, std::forward(y)...} { - } -#endif - - constexpr tuple(const tuple& other) = default; - constexpr tuple(tuple&& other) = default; + SQLITE_ORM_DELEGATING_CONSTEXPR tuple(Y&&... y) : base_type{from_variadic_t{}, std::forward(y)...} {} template), bool> = true> - constexpr tuple(const tuple& other) : tuple{std::make_index_sequence, other} {} + constexpr tuple(const tuple& other) : base_type{other} {} template), bool> = true> - constexpr tuple(tuple&& other) : - tuple{std::make_index_sequence, std::move(other)} {} + constexpr tuple(tuple&& other) : base_type{std::move(other)} {} + + // The two following constructors are required to make sure that + // the tuple(Y&&...) constructor is _not_ preferred over the copy + // constructor for unary tuples containing a type that is constructible + // from tuple<...>. + + template...>, + bool> = true> + constexpr tuple(const tuple& other) : base_type{other} {} + + template< + class... Void, + std::enable_if_t...>, bool> = true> + constexpr tuple(tuple&& other) : base_type{std::move(other)} {} }; template<> @@ -1371,10 +1384,13 @@ namespace sqlite_orm { constexpr tuple() = default; }; - template - constexpr auto make_tuple(X&&... x) { - return tuple...>{std::forward(x)...}; + namespace adl { + template + constexpr auto make_tuple(X&&... x) { + return tuple...>{std::forward(x)...}; + } } + using adl::make_tuple; template struct type_at> { @@ -11241,6 +11257,8 @@ namespace sqlite_orm { // #include "functional/cxx_functional_polyfill.h" +// #include "functional/tuple.h" + // #include "tuple_helper/tuple_filter.h" // #include "connection_holder.h" @@ -11510,7 +11528,7 @@ namespace sqlite_orm { using type = T; using return_type = R; - using conditions_type = std::tuple; + using conditions_type = mpl::tuple; conditions_type conditions; }; @@ -11520,7 +11538,7 @@ namespace sqlite_orm { using type = T; using return_type = R; - using conditions_type = std::tuple; + using conditions_type = mpl::tuple; conditions_type conditions; }; @@ -11531,7 +11549,7 @@ namespace sqlite_orm { using type = T; using return_type = R; - using conditions_type = std::tuple; + using conditions_type = mpl::tuple; conditions_type conditions; }; @@ -11543,7 +11561,7 @@ namespace sqlite_orm { template struct update_all_t, Wargs...> { using set_type = set_t; - using conditions_type = std::tuple; + using conditions_type = mpl::tuple; set_type set; conditions_type conditions; @@ -11552,7 +11570,7 @@ namespace sqlite_orm { template struct remove_all_t { using type = T; - using conditions_type = std::tuple; + using conditions_type = mpl::tuple; conditions_type conditions; }; @@ -11560,7 +11578,7 @@ namespace sqlite_orm { template struct get_t { using type = T; - using ids_type = std::tuple; + using ids_type = mpl::tuple; ids_type ids; }; @@ -11568,7 +11586,7 @@ namespace sqlite_orm { template struct get_pointer_t { using type = T; - using ids_type = std::tuple; + using ids_type = mpl::tuple; ids_type ids; }; @@ -11577,7 +11595,7 @@ namespace sqlite_orm { template struct get_optional_t { using type = T; - using ids_type = std::tuple; + using ids_type = mpl::tuple; ids_type ids; }; @@ -11593,7 +11611,7 @@ namespace sqlite_orm { template struct remove_t { using type = T; - using ids_type = std::tuple; + using ids_type = mpl::tuple; ids_type ids; }; @@ -11667,7 +11685,7 @@ namespace sqlite_orm { template struct insert_raw_t { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; args_tuple args; }; @@ -11680,7 +11698,7 @@ namespace sqlite_orm { template struct replace_raw_t { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; args_tuple args; }; @@ -11787,7 +11805,7 @@ namespace sqlite_orm { */ template internal::insert_raw_t insert(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; using internal::count_tuple; using internal::is_columns; using internal::is_insert_constraint; @@ -11859,7 +11877,7 @@ namespace sqlite_orm { */ template internal::replace_raw_t replace(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; using internal::count_tuple; using internal::is_columns; using internal::is_into; @@ -12001,8 +12019,8 @@ namespace sqlite_orm { */ template internal::remove_t remove(Ids... ids) { - std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + mpl::tuple idsTuple{std::forward(ids)...}; + return {std::move(idsTuple)}; } /** @@ -12024,8 +12042,7 @@ namespace sqlite_orm { */ template internal::get_t get(Ids... ids) { - std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {mpl::make_tuple(std::forward(ids)...)}; } /** @@ -12035,8 +12052,7 @@ namespace sqlite_orm { */ template internal::get_pointer_t get_pointer(Ids... ids) { - std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {mpl::make_tuple(std::forward(ids)...)}; } #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED @@ -12047,8 +12063,7 @@ namespace sqlite_orm { */ template internal::get_optional_t get_optional(Ids... ids) { - std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {mpl::make_tuple(std::forward(ids)...)}; } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED @@ -12059,10 +12074,10 @@ namespace sqlite_orm { */ template internal::remove_all_t remove_all(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -12072,10 +12087,10 @@ namespace sqlite_orm { */ template internal::get_all_t, Args...> get_all(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -12086,10 +12101,10 @@ namespace sqlite_orm { */ template internal::get_all_t get_all(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -12098,10 +12113,10 @@ namespace sqlite_orm { */ template internal::update_all_t, Wargs...> update_all(internal::set_t set, Wargs... wh) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(wh)...}; - return {std::move(set), move(conditions)}; + return {std::move(set), std::move(conditions)}; } /** @@ -12111,10 +12126,10 @@ namespace sqlite_orm { */ template internal::get_all_pointer_t>, Args...> get_all_pointer(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** * Create a get all pointer statement. @@ -12124,10 +12139,10 @@ namespace sqlite_orm { */ template internal::get_all_pointer_t get_all_pointer(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED @@ -12138,10 +12153,10 @@ namespace sqlite_orm { */ template internal::get_all_optional_t>, Args...> get_all_optional(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -12152,10 +12167,10 @@ namespace sqlite_orm { */ template internal::get_all_optional_t get_all_optional(Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED } @@ -12942,7 +12957,7 @@ namespace sqlite_orm { get_all_t, Args...> args; view_t(storage_type& stor, decltype(connection) conn, Args&&... args_) : - storage(stor), connection(std::move(conn)), args{std::make_tuple(std::forward(args_)...)} {} + storage(stor), connection(std::move(conn)), args{mpl::make_tuple(std::forward(args_)...)} {} size_t size() { return this->storage.template count(); From 5d4f8ffc44598dd268a782de94f51a9b5afaa039 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Sat, 11 Jun 2022 22:39:37 +0300 Subject: [PATCH 05/16] Unit tests for custom tuple Unit tests take from boost hana. Refined tuple and unique tuple implementation --- dev/column.h | 2 +- dev/functional/cxx_compiler_quirks.h | 10 +- dev/functional/fast_and.h | 2 +- dev/functional/tuple.h | 254 ++++++--- dev/functional/tuple_common.h | 21 + dev/functional/type_at.h | 12 +- dev/functional/unique_tuple.h | 212 +++++--- dev/tuple_helper/tuple_filter.h | 17 +- include/sqlite_orm/sqlite_orm.h | 510 ++++++++++++------ tests/backup_tests.cpp | 5 + tests/functional/tuple/cnstr.convert_copy.cpp | 92 ++++ tests/functional/tuple/cnstr.convert_move.cpp | 63 +++ tests/functional/tuple/cnstr.copy.cpp | 77 +++ tests/functional/tuple/cnstr.default.cpp | 144 +++++ tests/functional/tuple/cnstr.move.cpp | 82 +++ tests/functional/tuple/cnstr.nested.cpp | 23 + tests/functional/tuple/cnstr.trap.cpp | 87 +++ .../functional/tuple/cnstr.variadic_array.cpp | 17 + .../functional/tuple/cnstr.variadic_copy.cpp | 144 +++++ .../tuple/cnstr.variadic_forward.cpp | 98 ++++ tests/functional/tuple/empty_member.cpp | 16 + 21 files changed, 1535 insertions(+), 353 deletions(-) create mode 100644 dev/functional/tuple_common.h create mode 100644 tests/functional/tuple/cnstr.convert_copy.cpp create mode 100644 tests/functional/tuple/cnstr.convert_move.cpp create mode 100644 tests/functional/tuple/cnstr.copy.cpp create mode 100644 tests/functional/tuple/cnstr.default.cpp create mode 100644 tests/functional/tuple/cnstr.move.cpp create mode 100644 tests/functional/tuple/cnstr.nested.cpp create mode 100644 tests/functional/tuple/cnstr.trap.cpp create mode 100644 tests/functional/tuple/cnstr.variadic_array.cpp create mode 100644 tests/functional/tuple/cnstr.variadic_copy.cpp create mode 100644 tests/functional/tuple/cnstr.variadic_forward.cpp create mode 100644 tests/functional/tuple/empty_member.cpp diff --git a/dev/column.h b/dev/column.h index ed63e3ee9..f53cfc7b2 100644 --- a/dev/column.h +++ b/dev/column.h @@ -46,7 +46,7 @@ namespace sqlite_orm { * Member pointer used to read a field value. * If it is a object member pointer it is also used to write a field value. */ - const member_pointer_t member_pointer; + member_pointer_t member_pointer; /** * Setter member function to write a field value diff --git a/dev/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index 6bba37c11..a5a4c76b5 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -25,6 +25,10 @@ // Because we know what we are doing, we suppress the diagnostic message #define SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(...) SQLITE_ORM_CLANG_SUPPRESS("-Wmissing-braces", __VA_ARGS__) +#if defined(_MSC_VER) && (_MSC_VER < 1915) +#define SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 +#endif + #if defined(_MSC_VER) && (_MSC_VER < 1920) #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #define SQLITE_ORM_BROKEN_CONSTEXPR_DELEGATING_CTORS @@ -35,9 +39,3 @@ #else #define SQLITE_ORM_MSVC_EMPTYBASES #endif - -#ifndef SQLITE_ORM_BROKEN_CONSTEXPR_DELEGATING_CTORS -#define SQLITE_ORM_DELEGATING_CONSTEXPR constexpr -#else -#define SQLITE_ORM_DELEGATING_CONSTEXPR -#endif diff --git a/dev/functional/fast_and.h b/dev/functional/fast_and.h index 999efcadf..750f368f6 100644 --- a/dev/functional/fast_and.h +++ b/dev/functional/fast_and.h @@ -18,5 +18,5 @@ namespace sqlite_orm { #define SQLITE_ORM_FAST_AND(...) ::sqlite_orm::internal::fast_and<__VA_ARGS__::value...>::value #else -#define SQLITE_ORM_FAST_AND(...) polyfill::conjunction_v<__VA_ARGS__...> +#define SQLITE_ORM_FAST_AND(...) polyfill::conjunction<__VA_ARGS__...>::value #endif diff --git a/dev/functional/tuple.h b/dev/functional/tuple.h index ed0d0041a..d4d669e37 100644 --- a/dev/functional/tuple.h +++ b/dev/functional/tuple.h @@ -6,7 +6,6 @@ #include "cxx_universal.h" #include "cxx_type_traits_polyfill.h" #include "fast_and.h" -#include "pack.h" #include "type_at.h" namespace _sqlite_orm { @@ -15,105 +14,111 @@ namespace _sqlite_orm { // (as seen in boost hana) /* - * element of a tuple + * storage element of a tuple + */ + template::value && !std::is_final::value> + struct SQLITE_ORM_MSVC_EMPTYBASES tuplem : indexed_type { + X data; + + constexpr tuplem() : data() {} + + template + constexpr tuplem(Y&& y) : data(std::forward(y)) {} + }; + + /* + * storage element of a tuple, using EBO */ template - struct tuplem : indexed_type { - SQLITE_ORM_NOUNIQUEADDRESS X element; + struct SQLITE_ORM_MSVC_EMPTYBASES tuplem : X, indexed_type { constexpr tuplem() = default; template - constexpr tuplem(Y&& y) : element(std::forward(y)) {} + constexpr tuplem(Y&& y) : X(std::forward(y)) {} }; + + template + constexpr const X& ebo_get(const tuplem& elem) { + return (elem.data); + } + template + constexpr X& ebo_get(tuplem& elem) { + return (elem.data); + } + template + constexpr X&& ebo_get(tuplem&& elem) { + return std::forward(elem.data); + } + template + constexpr const X& ebo_get(const tuplem& elem) { + return elem; + } + template + constexpr X& ebo_get(tuplem& elem) { + return elem; + } + template + constexpr X&& ebo_get(tuplem&& elem) { + return std::forward(elem); + } } namespace sqlite_orm { namespace internal { namespace mpl { + using ::_sqlite_orm::ebo_get; using ::_sqlite_orm::tuplem; - struct from_variadic_t {}; - template struct basic_tuple; - template - struct basic_tuple, X...> : tuplem... { - constexpr basic_tuple() = default; - - template - constexpr basic_tuple(from_variadic_t, Y&&... y) : tuplem(std::forward(y))... {} - - // copy/move constructor - template - SQLITE_ORM_DELEGATING_CONSTEXPR basic_tuple(Other&& other) : - basic_tuple{from_variadic_t{}, std::get(std::forward(other))...} {} - }; - - /* - * tuple - */ template - struct SQLITE_ORM_MSVC_EMPTYBASES tuple final : basic_tuple, X...> { - private: - using base_type = basic_tuple, X...>; + struct tuple; - public: -#ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED - template...>, bool> = true> - constexpr explicit(!SQLITE_ORM_FAST_AND(std::is_default_constructible)) tuple() : base_type{} {} -#else - template...>, bool> = true> - constexpr tuple() : base_type{} {} -#endif + template + struct remove_rvalue_reference { + using type = T; + }; + template + struct remove_rvalue_reference { + using type = T; + }; + template + using remove_rvalue_reference_t = typename remove_rvalue_reference::type; - template), bool> = true> - SQLITE_ORM_DELEGATING_CONSTEXPR tuple(Y&&... y) : base_type{from_variadic_t{}, std::forward(y)...} {} + struct from_variadic_t {}; - template), bool> = true> - constexpr tuple(const tuple& other) : base_type{other} {} + template + struct enable_tuple_ctor; - template), bool> = true> - constexpr tuple(tuple&& other) : base_type{std::move(other)} {} + template + struct enable_tuple_ctor, Void...> + : std::enable_if), bool> {}; - // The two following constructors are required to make sure that - // the tuple(Y&&...) constructor is _not_ preferred over the copy - // constructor for unary tuples containing a type that is constructible - // from tuple<...>. + template + struct enable_tuple_ctor, Void...> + : std::enable_if), bool> {}; - template...>, - bool> = true> - constexpr tuple(const tuple& other) : base_type{other} {} + template + struct enable_tuple_variadic_ctor; - template< - class... Void, - std::enable_if_t...>, bool> = true> - constexpr tuple(tuple&& other) : base_type{std::move(other)} {} - }; + template + struct enable_tuple_variadic_ctor, Y...> + : std::enable_if), bool> {}; - template<> - struct tuple<> final { - constexpr tuple() = default; - }; + template + struct enable_tuple_nonconst_copy_ctor; - namespace adl { - template - constexpr auto make_tuple(X&&... x) { - return tuple...>{std::forward(x)...}; - } - } - using adl::make_tuple; +#ifdef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + template + struct enable_tuple_nonconst_copy_ctor, tuple, Void...> + : std::enable_if), bool> {}; - template - struct type_at> { - using indexed_t = decltype(get_indexed_type(std::declval>())); - using type = typename indexed_t::type; - }; + template + struct enable_tuple_nonconst_copy_ctor, const tuple, Void...> + : std::enable_if), bool> {}; +#endif } } @@ -126,24 +131,21 @@ namespace std { struct tuple_size> : integral_constant {}; template - decltype(auto) get(const sqlite_orm::mpl::tuple& tpl) noexcept { + constexpr decltype(auto) get(const sqlite_orm::mpl::tuple& tpl) noexcept { using namespace sqlite_orm::mpl; - const tuplem>>& elem = tpl; - return (elem.element); + return ebo_get(tpl); } template - decltype(auto) get(sqlite_orm::mpl::tuple& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::tuple& tpl) noexcept { using namespace sqlite_orm::mpl; - tuplem>>& elem = tpl; - return (elem.element); + return ebo_get(tpl); } template - decltype(auto) get(sqlite_orm::mpl::tuple&& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::tuple&& tpl) noexcept { using namespace sqlite_orm::mpl; - tuplem>>& elem = tpl; - return std::move(elem.element); + return ebo_get(std::move(tpl)); } template @@ -155,3 +157,93 @@ namespace std { template decltype(auto) get(sqlite_orm::mpl::tuple&&) noexcept = delete; } + +namespace sqlite_orm { + namespace internal { + namespace mpl { + + template + struct SQLITE_ORM_MSVC_EMPTYBASES basic_tuple, X...> : tuplem... { + constexpr basic_tuple() = default; + + // variadic constructor + template + constexpr basic_tuple(from_variadic_t, Y&&... y) : tuplem(std::forward(y))... {} + + // converting copy/move constructor + template + constexpr basic_tuple(Other&& other) : tuplem(std::get(std::forward(other)))... {} + + constexpr basic_tuple(const basic_tuple&) = default; + constexpr basic_tuple(basic_tuple&&) = default; + }; + + template<> + struct tuple<> final { + constexpr tuple() = default; + }; + + /* + * tuple + */ + template + struct tuple final : basic_tuple, X...> { + private: + using base_type = basic_tuple, X...>; + + public: + // default constructor + template::type = true> + constexpr tuple() : base_type{} {} + + // direct constructor + template::type = true> + constexpr tuple(const X&... x) : base_type{from_variadic_t{}, x...} {} + + // converting constructor + template::type = true> + constexpr tuple(Y&&... y) : base_type{from_variadic_t{}, std::forward(y)...} {} + + // converting copy constructor + template), bool> = true> + constexpr tuple(const tuple& other) : base_type{other} {} + + // converting move constructor + template), bool> = true> + constexpr tuple(tuple&& other) : base_type{std::move(other)} {} + +#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + constexpr tuple(const tuple&) = default; + constexpr tuple(tuple&&) = default; + + // non-const copy constructor. + // The non-const copy constructor is required to make sure that + // the converting tuple(Y&&...) constructor is _not_ preferred over the copy + // constructor for unary tuples containing a type that is constructible from tuple<...>. + constexpr tuple(tuple& other) : base_type{const_cast(other)} {} +#else + template::type = true> + constexpr tuple(Other& other) : base_type{const_cast(other)} {} +#endif + }; + + namespace adl { + template + constexpr auto make_tuple(X&&... x) { + return tuple...>{std::forward(x)...}; + } + } + using adl::make_tuple; + + // implementation note: we could derive from `type_at` but leverage the fact that `tuple` is derived from `indexed_type` + template + struct type_at> { + // implementation note: we could use `get_indexed_type()`, but `ebo_get` is readily available. + using forwarded_t = decltype(ebo_get(std::declval>())); + using type = remove_rvalue_reference_t; + }; + } + } +} diff --git a/dev/functional/tuple_common.h b/dev/functional/tuple_common.h new file mode 100644 index 000000000..602ae53d8 --- /dev/null +++ b/dev/functional/tuple_common.h @@ -0,0 +1,21 @@ +#pragma once + +#include // std::enable_if, std::is_constructible + +#include "fast_and.h" + +namespace sqlite_orm { + namespace internal { + namespace mpl { + + template + struct enable_tuple_variadic_ctor {}; + + template + struct enable_tuple_variadic_ctor, Y...> + : std::enable_if), bool> {}; + } + } + + namespace mpl = mpl; +} diff --git a/dev/functional/type_at.h b/dev/functional/type_at.h index dde4ad7bc..b35823fc7 100644 --- a/dev/functional/type_at.h +++ b/dev/functional/type_at.h @@ -11,13 +11,11 @@ namespace sqlite_orm { namespace mpl { #ifndef SQLITE_ORM_HAS_TYPE_PACK_ELEMENT_INTRINSIC - namespace td { - template - struct indexer; + template + struct indexer; - template - struct indexer, T...> : indexed_type... {}; - } + template + struct indexer, T...> : indexed_type... {}; #endif template @@ -25,7 +23,7 @@ namespace sqlite_orm { #ifdef SQLITE_ORM_HAS_TYPE_PACK_ELEMENT_INTRINSIC using type = __type_pack_element; #else - using Indexer = td::indexer, T...>; + using Indexer = indexer, T...>; // implementation note: needs to be aliased on its own [SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION] using indexed_t = decltype(get_indexed_type(Indexer{})); using type = typename indexed_t::type; diff --git a/dev/functional/unique_tuple.h b/dev/functional/unique_tuple.h index 5c105712e..e17a83613 100644 --- a/dev/functional/unique_tuple.h +++ b/dev/functional/unique_tuple.h @@ -14,77 +14,95 @@ namespace _sqlite_orm { // (as seen in boost hana) /* - * element of a unique tuple + * storage element of a unique tuple */ - template + template::value && !std::is_final::value> struct uplem { - SQLITE_ORM_NOUNIQUEADDRESS X element; + X data; + + constexpr uplem() : data() {} + + template + constexpr uplem(Y&& y) : data(std::forward(y)) {} + }; + + /* + * storage element of a unique tuple, using EBO + */ + template + struct uplem : X { constexpr uplem() = default; template - constexpr uplem(Y&& y) : element(std::forward(y)) {} + constexpr uplem(Y&& y) : X(std::forward(y)) {} }; + + template + constexpr const X& ebo_get(const uplem& elem) { + return (elem.data); + } + template + constexpr X& ebo_get(uplem& elem) { + return (elem.data); + } + template + constexpr X&& ebo_get(uplem&& elem) { + return std::forward(elem.data); + } + template + constexpr const X& ebo_get(const uplem& elem) { + return elem; + } + template + constexpr X& ebo_get(uplem& elem) { + return elem; + } + template + constexpr X&& ebo_get(uplem&& elem) { + return std::forward(elem); + } } namespace sqlite_orm { namespace internal { namespace mpl { + using ::_sqlite_orm::ebo_get; using ::_sqlite_orm::uplem; - /* - * unique tuple, which allows only distinct types. - */ template - struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { -#ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED - template...>, bool> = true> - constexpr explicit(!SQLITE_ORM_FAST_AND(std::is_default_constructible)) uple() {} -#else - template), bool> = true> - constexpr uple() {} -#endif + struct uple; - template), bool> = true> - constexpr uple(Y&&... y) : uplem(std::forward(y))... {} + template + struct enable_tuple_ctor; - template), bool> = true> - constexpr uple(const uple& other) : uplem(std::get(other))... {} + template + struct enable_tuple_ctor, Void...> + : std::enable_if), bool> {}; - template), bool> = true> - constexpr uple(uple&& other) : uplem(std::get(std::move(other)))... {} + template + struct enable_tuple_ctor, Void...> + : std::enable_if), bool> {}; - // The two following constructors are required to make sure that - // the tuple(Y&&...) constructor is _not_ preferred over the copy - // constructor for unary tuples containing a type that is constructible - // from uple<...>. + template + struct enable_tuple_variadic_ctor; - template...>, - bool> = true> - constexpr uple(const uple& other) : uplem(std::get(other))... {} + template + struct enable_tuple_variadic_ctor, Y...> + : std::enable_if), bool> {}; - template< - class... Void, - std::enable_if_t...>, bool> = true> - constexpr uple(uple&& other) : uplem(std::get(std::move(other)))... {} - }; + template + struct enable_tuple_nonconst_copy_ctor; - template<> - struct uple<> final { - constexpr uple() = default; - }; - - template - constexpr auto make_unique_tuple(X&&... x) { - return uple...>{std::forward(x)...}; - } +#ifdef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + template + struct enable_tuple_nonconst_copy_ctor, uple, Void...> + : std::enable_if), bool> {}; - template - struct type_at> : type_at {}; + template + struct enable_tuple_nonconst_copy_ctor, const uple, Void...> + : std::enable_if), bool> {}; +#endif } } @@ -97,44 +115,106 @@ namespace std { struct tuple_size> : integral_constant {}; template - decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { + constexpr decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { using namespace sqlite_orm::mpl; - const uplem>& elem = tpl; - return (elem.element); + using uplem_t = uplem>; + return ebo_get(static_cast(tpl)); } template - decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { using namespace sqlite_orm::mpl; - uplem>& elem = tpl; - return (elem.element); + using uplem_t = uplem>; + return ebo_get(static_cast(tpl)); } template - decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { using namespace sqlite_orm::mpl; - uplem>& elem = tpl; - return std::move(elem.element); + using uplem_t = uplem>; + return ebo_get(static_cast(tpl)); } template - decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { + constexpr decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { using sqlite_orm::mpl::uplem; - const uplem& elem = tpl; - return (elem.element); + using uplem_t = uplem; + return ebo_get(static_cast(tpl)); } template - decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { using sqlite_orm::mpl::uplem; - uplem& elem = tpl; - return (elem.element); + using uplem_t = uplem; + return ebo_get(static_cast(tpl)); } template - decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { using sqlite_orm::mpl::uplem; - uplem& elem = tpl; - return std::move(elem.element); + using uplem_t = uplem; + return ebo_get(static_cast(tpl)); + } +} + +namespace sqlite_orm { + namespace internal { + namespace mpl { + + template<> + struct uple<> final { + constexpr uple() = default; + }; + + /* + * unique tuple, which allows only distinct types. + */ + template + struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { + // default constructor + template::type = true> + constexpr uple() {} + + // direct constructor + template::type = true> + constexpr uple(const X&... x) : uplem(x)... {} + + // converting constructor + template::type = true> + constexpr uple(Y&&... y) : uplem(std::forward(y))... {} + + // converting copy constructor + template), bool> = true> + constexpr uple(const uple& other) : uplem(std::get(other))... {} + + // converting move constructor + template), bool> = true> + constexpr uple(uple&& other) : uplem(std::get(std::move(other)))... {} + +#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + constexpr uple(const uple&) = default; + constexpr uple(uple&&) = default; + + // non-const copy constructor. + // The non-const copy constructor is required to make sure that + // the converting uple(Y&&...) constructor is _not_ preferred over the copy + // constructor for unary tuples containing a type that is constructible from uple<...>. + constexpr uple(uple& other) : uplem(std::get(const_cast(other)))... {} +#else + template::type = true> + constexpr uple(Other& other) : uplem(std::get(const_cast(other)))... {} +#endif + }; + + template + constexpr auto make_unique_tuple(X&&... x) { + return uple...>{std::forward(x)...}; + } + + template + struct type_at> : type_at {}; + } } } diff --git a/dev/tuple_helper/tuple_filter.h b/dev/tuple_helper/tuple_filter.h index 89b6396aa..beb136c00 100644 --- a/dev/tuple_helper/tuple_filter.h +++ b/dev/tuple_helper/tuple_filter.h @@ -1,7 +1,6 @@ #pragma once #include // std::integral_constant, std::index_sequence, std::make_index_sequence, std::conditional, std::declval -#include // std::tuple #include "../functional/cxx_universal.h" #include "../functional/type_at.h" @@ -26,19 +25,9 @@ namespace sqlite_orm { template struct tuple_from_index_sequence; - template - struct tuple_from_index_sequence, std::index_sequence> { - using type = std::tuple>...>; - }; - - template - struct tuple_from_index_sequence, std::index_sequence> { - using type = mpl::uple>...>; - }; - - template - struct tuple_from_index_sequence, std::index_sequence> { - using type = mpl::tuple>...>; + template class Tuple, class... T, size_t... Idx> + struct tuple_from_index_sequence, std::index_sequence> { + using type = Tuple>...>; }; template diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 5142ff90a..a578dbc8b 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -143,6 +143,10 @@ using std::nullptr_t; // Because we know what we are doing, we suppress the diagnostic message #define SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(...) SQLITE_ORM_CLANG_SUPPRESS("-Wmissing-braces", __VA_ARGS__) +#if defined(_MSC_VER) && (_MSC_VER < 1915) +#define SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 +#endif + #if defined(_MSC_VER) && (_MSC_VER < 1920) #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #define SQLITE_ORM_BROKEN_CONSTEXPR_DELEGATING_CTORS @@ -154,12 +158,6 @@ using std::nullptr_t; #define SQLITE_ORM_MSVC_EMPTYBASES #endif -#ifndef SQLITE_ORM_BROKEN_CONSTEXPR_DELEGATING_CTORS -#define SQLITE_ORM_DELEGATING_CONSTEXPR constexpr -#else -#define SQLITE_ORM_DELEGATING_CONSTEXPR -#endif - namespace sqlite_orm { namespace internal { namespace polyfill { @@ -1048,7 +1046,7 @@ namespace sqlite_orm { #define SQLITE_ORM_FAST_AND(...) ::sqlite_orm::internal::fast_and<__VA_ARGS__::value...>::value #else -#define SQLITE_ORM_FAST_AND(...) polyfill::conjunction_v<__VA_ARGS__...> +#define SQLITE_ORM_FAST_AND(...) polyfill::conjunction<__VA_ARGS__...>::value #endif // #include "type_at.h" @@ -1099,13 +1097,11 @@ namespace sqlite_orm { namespace mpl { #ifndef SQLITE_ORM_HAS_TYPE_PACK_ELEMENT_INTRINSIC - namespace td { - template - struct indexer; + template + struct indexer; - template - struct indexer, T...> : indexed_type... {}; - } + template + struct indexer, T...> : indexed_type... {}; #endif template @@ -1113,7 +1109,7 @@ namespace sqlite_orm { #ifdef SQLITE_ORM_HAS_TYPE_PACK_ELEMENT_INTRINSIC using type = __type_pack_element; #else - using Indexer = td::indexer, T...>; + using Indexer = indexer, T...>; // implementation note: needs to be aliased on its own [SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION] using indexed_t = decltype(get_indexed_type(Indexer{})); using type = typename indexed_t::type; @@ -1152,77 +1148,95 @@ namespace _sqlite_orm { // (as seen in boost hana) /* - * element of a unique tuple + * storage element of a unique tuple */ - template + template::value && !std::is_final::value> struct uplem { - SQLITE_ORM_NOUNIQUEADDRESS X element; + X data; + + constexpr uplem() : data() {} + + template + constexpr uplem(Y&& y) : data(std::forward(y)) {} + }; + + /* + * storage element of a unique tuple, using EBO + */ + template + struct uplem : X { constexpr uplem() = default; template - constexpr uplem(Y&& y) : element(std::forward(y)) {} + constexpr uplem(Y&& y) : X(std::forward(y)) {} }; + + template + constexpr const X& ebo_get(const uplem& elem) { + return (elem.data); + } + template + constexpr X& ebo_get(uplem& elem) { + return (elem.data); + } + template + constexpr X&& ebo_get(uplem&& elem) { + return std::forward(elem.data); + } + template + constexpr const X& ebo_get(const uplem& elem) { + return elem; + } + template + constexpr X& ebo_get(uplem& elem) { + return elem; + } + template + constexpr X&& ebo_get(uplem&& elem) { + return std::forward(elem); + } } namespace sqlite_orm { namespace internal { namespace mpl { + using ::_sqlite_orm::ebo_get; using ::_sqlite_orm::uplem; - /* - * unique tuple, which allows only distinct types. - */ template - struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { -#ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED - template...>, bool> = true> - constexpr explicit(!SQLITE_ORM_FAST_AND(std::is_default_constructible)) uple() {} -#else - template), bool> = true> - constexpr uple() {} -#endif + struct uple; - template), bool> = true> - constexpr uple(Y&&... y) : uplem(std::forward(y))... {} + template + struct enable_tuple_ctor; - template), bool> = true> - constexpr uple(const uple& other) : uplem(std::get(other))... {} + template + struct enable_tuple_ctor, Void...> + : std::enable_if), bool> {}; - template), bool> = true> - constexpr uple(uple&& other) : uplem(std::get(std::move(other)))... {} + template + struct enable_tuple_ctor, Void...> + : std::enable_if), bool> {}; - // The two following constructors are required to make sure that - // the tuple(Y&&...) constructor is _not_ preferred over the copy - // constructor for unary tuples containing a type that is constructible - // from uple<...>. + template + struct enable_tuple_variadic_ctor; - template...>, - bool> = true> - constexpr uple(const uple& other) : uplem(std::get(other))... {} + template + struct enable_tuple_variadic_ctor, Y...> + : std::enable_if), bool> {}; - template< - class... Void, - std::enable_if_t...>, bool> = true> - constexpr uple(uple&& other) : uplem(std::get(std::move(other)))... {} - }; + template + struct enable_tuple_nonconst_copy_ctor; - template<> - struct uple<> final { - constexpr uple() = default; - }; - - template - constexpr auto make_unique_tuple(X&&... x) { - return uple...>{std::forward(x)...}; - } +#ifdef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + template + struct enable_tuple_nonconst_copy_ctor, uple, Void...> + : std::enable_if), bool> {}; - template - struct type_at> : type_at {}; + template + struct enable_tuple_nonconst_copy_ctor, const uple, Void...> + : std::enable_if), bool> {}; +#endif } } @@ -1235,45 +1249,107 @@ namespace std { struct tuple_size> : integral_constant {}; template - decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { + constexpr decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { using namespace sqlite_orm::mpl; - const uplem>& elem = tpl; - return (elem.element); + using uplem_t = uplem>; + return ebo_get(static_cast(tpl)); } template - decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { using namespace sqlite_orm::mpl; - uplem>& elem = tpl; - return (elem.element); + using uplem_t = uplem>; + return ebo_get(static_cast(tpl)); } template - decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { using namespace sqlite_orm::mpl; - uplem>& elem = tpl; - return std::move(elem.element); + using uplem_t = uplem>; + return ebo_get(static_cast(tpl)); } template - decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { + constexpr decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { using sqlite_orm::mpl::uplem; - const uplem& elem = tpl; - return (elem.element); + using uplem_t = uplem; + return ebo_get(static_cast(tpl)); } template - decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { using sqlite_orm::mpl::uplem; - uplem& elem = tpl; - return (elem.element); + using uplem_t = uplem; + return ebo_get(static_cast(tpl)); } template - decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { using sqlite_orm::mpl::uplem; - uplem& elem = tpl; - return std::move(elem.element); + using uplem_t = uplem; + return ebo_get(static_cast(tpl)); + } +} + +namespace sqlite_orm { + namespace internal { + namespace mpl { + + template<> + struct uple<> final { + constexpr uple() = default; + }; + + /* + * unique tuple, which allows only distinct types. + */ + template + struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { + // default constructor + template::type = true> + constexpr uple() {} + + // direct constructor + template::type = true> + constexpr uple(const X&... x) : uplem(x)... {} + + // converting constructor + template::type = true> + constexpr uple(Y&&... y) : uplem(std::forward(y))... {} + + // converting copy constructor + template), bool> = true> + constexpr uple(const uple& other) : uplem(std::get(other))... {} + + // converting move constructor + template), bool> = true> + constexpr uple(uple&& other) : uplem(std::get(std::move(other)))... {} + +#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + constexpr uple(const uple&) = default; + constexpr uple(uple&&) = default; + + // non-const copy constructor. + // The non-const copy constructor is required to make sure that + // the converting uple(Y&&...) constructor is _not_ preferred over the copy + // constructor for unary tuples containing a type that is constructible from uple<...>. + constexpr uple(uple& other) : uplem(std::get(const_cast(other)))... {} +#else + template::type = true> + constexpr uple(Other& other) : uplem(std::get(const_cast(other)))... {} +#endif + }; + + template + constexpr auto make_unique_tuple(X&&... x) { + return uple...>{std::forward(x)...}; + } + + template + struct type_at> : type_at {}; + } } } @@ -1288,8 +1364,6 @@ namespace std { // #include "fast_and.h" -// #include "pack.h" - // #include "type_at.h" namespace _sqlite_orm { @@ -1298,105 +1372,111 @@ namespace _sqlite_orm { // (as seen in boost hana) /* - * element of a tuple + * storage element of a tuple + */ + template::value && !std::is_final::value> + struct SQLITE_ORM_MSVC_EMPTYBASES tuplem : indexed_type { + X data; + + constexpr tuplem() : data() {} + + template + constexpr tuplem(Y&& y) : data(std::forward(y)) {} + }; + + /* + * storage element of a tuple, using EBO */ template - struct tuplem : indexed_type { - SQLITE_ORM_NOUNIQUEADDRESS X element; + struct SQLITE_ORM_MSVC_EMPTYBASES tuplem : X, indexed_type { constexpr tuplem() = default; template - constexpr tuplem(Y&& y) : element(std::forward(y)) {} + constexpr tuplem(Y&& y) : X(std::forward(y)) {} }; + + template + constexpr const X& ebo_get(const tuplem& elem) { + return (elem.data); + } + template + constexpr X& ebo_get(tuplem& elem) { + return (elem.data); + } + template + constexpr X&& ebo_get(tuplem&& elem) { + return std::forward(elem.data); + } + template + constexpr const X& ebo_get(const tuplem& elem) { + return elem; + } + template + constexpr X& ebo_get(tuplem& elem) { + return elem; + } + template + constexpr X&& ebo_get(tuplem&& elem) { + return std::forward(elem); + } } namespace sqlite_orm { namespace internal { namespace mpl { + using ::_sqlite_orm::ebo_get; using ::_sqlite_orm::tuplem; - struct from_variadic_t {}; - template struct basic_tuple; - template - struct basic_tuple, X...> : tuplem... { - constexpr basic_tuple() = default; - - template - constexpr basic_tuple(from_variadic_t, Y&&... y) : tuplem(std::forward(y))... {} - - // copy/move constructor - template - SQLITE_ORM_DELEGATING_CONSTEXPR basic_tuple(Other&& other) : - basic_tuple{from_variadic_t{}, std::get(std::forward(other))...} {} - }; - - /* - * tuple - */ template - struct SQLITE_ORM_MSVC_EMPTYBASES tuple final : basic_tuple, X...> { - private: - using base_type = basic_tuple, X...>; + struct tuple; - public: -#ifdef SQLITE_ORM_CONDITIONAL_EXPLICIT_SUPPORTED - template...>, bool> = true> - constexpr explicit(!SQLITE_ORM_FAST_AND(std::is_default_constructible)) tuple() : base_type{} {} -#else - template...>, bool> = true> - constexpr tuple() : base_type{} {} -#endif + template + struct remove_rvalue_reference { + using type = T; + }; + template + struct remove_rvalue_reference { + using type = T; + }; + template + using remove_rvalue_reference_t = typename remove_rvalue_reference::type; - template), bool> = true> - SQLITE_ORM_DELEGATING_CONSTEXPR tuple(Y&&... y) : base_type{from_variadic_t{}, std::forward(y)...} {} + struct from_variadic_t {}; - template), bool> = true> - constexpr tuple(const tuple& other) : base_type{other} {} + template + struct enable_tuple_ctor; - template), bool> = true> - constexpr tuple(tuple&& other) : base_type{std::move(other)} {} + template + struct enable_tuple_ctor, Void...> + : std::enable_if), bool> {}; - // The two following constructors are required to make sure that - // the tuple(Y&&...) constructor is _not_ preferred over the copy - // constructor for unary tuples containing a type that is constructible - // from tuple<...>. + template + struct enable_tuple_ctor, Void...> + : std::enable_if), bool> {}; - template...>, - bool> = true> - constexpr tuple(const tuple& other) : base_type{other} {} + template + struct enable_tuple_variadic_ctor; - template< - class... Void, - std::enable_if_t...>, bool> = true> - constexpr tuple(tuple&& other) : base_type{std::move(other)} {} - }; + template + struct enable_tuple_variadic_ctor, Y...> + : std::enable_if), bool> {}; - template<> - struct tuple<> final { - constexpr tuple() = default; - }; + template + struct enable_tuple_nonconst_copy_ctor; - namespace adl { - template - constexpr auto make_tuple(X&&... x) { - return tuple...>{std::forward(x)...}; - } - } - using adl::make_tuple; +#ifdef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + template + struct enable_tuple_nonconst_copy_ctor, tuple, Void...> + : std::enable_if), bool> {}; - template - struct type_at> { - using indexed_t = decltype(get_indexed_type(std::declval>())); - using type = typename indexed_t::type; - }; + template + struct enable_tuple_nonconst_copy_ctor, const tuple, Void...> + : std::enable_if), bool> {}; +#endif } } @@ -1409,24 +1489,21 @@ namespace std { struct tuple_size> : integral_constant {}; template - decltype(auto) get(const sqlite_orm::mpl::tuple& tpl) noexcept { + constexpr decltype(auto) get(const sqlite_orm::mpl::tuple& tpl) noexcept { using namespace sqlite_orm::mpl; - const tuplem>>& elem = tpl; - return (elem.element); + return ebo_get(tpl); } template - decltype(auto) get(sqlite_orm::mpl::tuple& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::tuple& tpl) noexcept { using namespace sqlite_orm::mpl; - tuplem>>& elem = tpl; - return (elem.element); + return ebo_get(tpl); } template - decltype(auto) get(sqlite_orm::mpl::tuple&& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::tuple&& tpl) noexcept { using namespace sqlite_orm::mpl; - tuplem>>& elem = tpl; - return std::move(elem.element); + return ebo_get(std::move(tpl)); } template @@ -1439,6 +1516,96 @@ namespace std { decltype(auto) get(sqlite_orm::mpl::tuple&&) noexcept = delete; } +namespace sqlite_orm { + namespace internal { + namespace mpl { + + template + struct SQLITE_ORM_MSVC_EMPTYBASES basic_tuple, X...> : tuplem... { + constexpr basic_tuple() = default; + + // variadic constructor + template + constexpr basic_tuple(from_variadic_t, Y&&... y) : tuplem(std::forward(y))... {} + + // converting copy/move constructor + template + constexpr basic_tuple(Other&& other) : tuplem(std::get(std::forward(other)))... {} + + constexpr basic_tuple(const basic_tuple&) = default; + constexpr basic_tuple(basic_tuple&&) = default; + }; + + template<> + struct tuple<> final { + constexpr tuple() = default; + }; + + /* + * tuple + */ + template + struct tuple final : basic_tuple, X...> { + private: + using base_type = basic_tuple, X...>; + + public: + // default constructor + template::type = true> + constexpr tuple() : base_type{} {} + + // direct constructor + template::type = true> + constexpr tuple(const X&... x) : base_type{from_variadic_t{}, x...} {} + + // converting constructor + template::type = true> + constexpr tuple(Y&&... y) : base_type{from_variadic_t{}, std::forward(y)...} {} + + // converting copy constructor + template), bool> = true> + constexpr tuple(const tuple& other) : base_type{other} {} + + // converting move constructor + template), bool> = true> + constexpr tuple(tuple&& other) : base_type{std::move(other)} {} + +#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + constexpr tuple(const tuple&) = default; + constexpr tuple(tuple&&) = default; + + // non-const copy constructor. + // The non-const copy constructor is required to make sure that + // the converting tuple(Y&&...) constructor is _not_ preferred over the copy + // constructor for unary tuples containing a type that is constructible from tuple<...>. + constexpr tuple(tuple& other) : base_type{const_cast(other)} {} +#else + template::type = true> + constexpr tuple(Other& other) : base_type{const_cast(other)} {} +#endif + }; + + namespace adl { + template + constexpr auto make_tuple(X&&... x) { + return tuple...>{std::forward(x)...}; + } + } + using adl::make_tuple; + + // implementation note: we could derive from `type_at` but leverage the fact that `tuple` is derived from `indexed_type` + template + struct type_at> { + // implementation note: we could use `get_indexed_type()`, but `ebo_get` is readily available. + using forwarded_t = decltype(ebo_get(std::declval>())); + using type = remove_rvalue_reference_t; + }; + } + } +} + namespace sqlite_orm { namespace internal { /* @@ -1494,7 +1661,6 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_filter.h" #include // std::integral_constant, std::index_sequence, std::make_index_sequence, std::conditional, std::declval -#include // std::tuple // #include "../functional/cxx_universal.h" @@ -1523,19 +1689,9 @@ namespace sqlite_orm { template struct tuple_from_index_sequence; - template - struct tuple_from_index_sequence, std::index_sequence> { - using type = std::tuple>...>; - }; - - template - struct tuple_from_index_sequence, std::index_sequence> { - using type = mpl::uple>...>; - }; - - template - struct tuple_from_index_sequence, std::index_sequence> { - using type = mpl::tuple>...>; + template class Tuple, class... T, size_t... Idx> + struct tuple_from_index_sequence, std::index_sequence> { + using type = Tuple>...>; }; template @@ -2631,7 +2787,7 @@ namespace sqlite_orm { * Member pointer used to read a field value. * If it is a object member pointer it is also used to write a field value. */ - const member_pointer_t member_pointer; + member_pointer_t member_pointer; /** * Setter member function to write a field value diff --git a/tests/backup_tests.cpp b/tests/backup_tests.cpp index 7db85cb8c..b8aa55d0a 100644 --- a/tests/backup_tests.cpp +++ b/tests/backup_tests.cpp @@ -26,6 +26,11 @@ namespace { }; auto initStorageMarvel(const std::string& path) { + auto table = make_table("marvel", + make_column("id", &MarvelHero::id, primary_key()), + make_column("name", &MarvelHero::name), + make_column("abilities", &MarvelHero::abilities)); + auto table2 = table; auto storage = make_storage(path, make_table("marvel", make_column("id", &MarvelHero::id, primary_key()), diff --git a/tests/functional/tuple/cnstr.convert_copy.cpp b/tests/functional/tuple/cnstr.convert_copy.cpp new file mode 100644 index 000000000..970339b70 --- /dev/null +++ b/tests/functional/tuple/cnstr.convert_copy.cpp @@ -0,0 +1,92 @@ +#include +#include + +using namespace sqlite_orm; + +namespace { + struct A { + int id_; + constexpr A(int i) : id_(i) {} + friend constexpr bool operator==(const A& x, const A& y) { + return x.id_ == y.id_; + } + }; + + struct B { + int id_; + explicit B(int i) : id_(i) {} + }; + + struct C { + int id_; + constexpr explicit C(int i) : id_(i) {} + friend constexpr bool operator==(const C& x, const C& y) { + return x.id_ == y.id_; + } + }; + + struct D : B { + explicit D(int i) : B(i) {} + }; +} + +TEST_CASE("tuple - convert copyable") { + { + using T0 = mpl::tuple; + using T1 = mpl::tuple; + T0 t0(2.5); + T1 t1 = t0; + REQUIRE(std::get<0>(t1) == 2); + } + { + using T0 = mpl::tuple; + using T1 = mpl::tuple; + constexpr T0 t0(2.5); + constexpr T1 t1 = t0; + STATIC_REQUIRE(std::get<0>(t1) == 2); + } + { + using T0 = mpl::tuple; + using T1 = mpl::tuple; + constexpr T0 t0(2); + constexpr T1 t1{t0}; + STATIC_REQUIRE(std::get<0>(t1) == C(2)); + } + { + using T0 = mpl::tuple; + using T1 = mpl::tuple; + T0 t0(2.5, 'a'); + T1 t1 = t0; + REQUIRE(std::get<0>(t1) == 2); + REQUIRE(std::get<1>(t1) == int('a')); + } + { + using T0 = mpl::tuple; + using T1 = mpl::tuple; + T0 t0(2.5, 'a', D(3)); + T1 t1 = t0; + REQUIRE(std::get<0>(t1) == 2); + REQUIRE(std::get<1>(t1) == int('a')); + REQUIRE(std::get<2>(t1).id_ == 3); + } + { + D d(3); + using T0 = mpl::tuple; + using T1 = mpl::tuple; + T0 t0(2.5, 'a', d); + T1 t1 = t0; + d.id_ = 2; + REQUIRE(std::get<0>(t1) == 2); + REQUIRE(std::get<1>(t1) == int('a')); + REQUIRE(std::get<2>(t1).id_ == 2); + } + { + using T0 = mpl::tuple; + using T1 = mpl::tuple; + T0 t0(2.5, 'a', 3); + T1 t1(t0); + REQUIRE(std::get<0>(t1) == 2); + REQUIRE(std::get<1>(t1) == int('a')); + REQUIRE(std::get<2>(t1).id_ == 3); + } +} diff --git a/tests/functional/tuple/cnstr.convert_move.cpp b/tests/functional/tuple/cnstr.convert_move.cpp new file mode 100644 index 000000000..909af5f5c --- /dev/null +++ b/tests/functional/tuple/cnstr.convert_move.cpp @@ -0,0 +1,63 @@ +#include +#include + +using namespace sqlite_orm; + +namespace { + struct B { + int id_; + explicit B(int i) : id_(i) {} + virtual ~B() {} + }; + + struct D : B { + explicit D(int i) : B(i) {} + }; +} + +TEST_CASE("tuple - convert movable") { + { + using T0 = mpl::tuple; + using T1 = mpl::tuple; + T0 t0(2.5); + T1 t1 = std::move(t0); + REQUIRE(std::get<0>(t1) == 2); + } + { + using T0 = mpl::tuple; + using T1 = mpl::tuple; + T0 t0(2.5, 'a'); + T1 t1 = std::move(t0); + REQUIRE(std::get<0>(t1) == 2); + REQUIRE(std::get<1>(t1) == int('a')); + } + { + using T0 = mpl::tuple; + using T1 = mpl::tuple; + T0 t0(2.5, 'a', D(3)); + T1 t1 = std::move(t0); + REQUIRE(std::get<0>(t1) == 2); + REQUIRE(std::get<1>(t1) == int('a')); + REQUIRE(std::get<2>(t1).id_ == 3); + } + { + D d(3); + using T0 = mpl::tuple; + using T1 = mpl::tuple; + T0 t0(2.5, 'a', d); + T1 t1 = std::move(t0); + d.id_ = 2; + REQUIRE(std::get<0>(t1) == 2); + REQUIRE(std::get<1>(t1) == int('a')); + REQUIRE(std::get<2>(t1).id_ == 2); + } + { + using T0 = mpl::tuple>; + using T1 = mpl::tuple>; + T0 t0(2.5, 'a', std::unique_ptr(new D(3))); + T1 t1 = std::move(t0); + REQUIRE(std::get<0>(t1) == 2); + REQUIRE(std::get<1>(t1) == int('a')); + REQUIRE(std::get<2>(t1)->id_ == 3); + } +} diff --git a/tests/functional/tuple/cnstr.copy.cpp b/tests/functional/tuple/cnstr.copy.cpp new file mode 100644 index 000000000..672c91098 --- /dev/null +++ b/tests/functional/tuple/cnstr.copy.cpp @@ -0,0 +1,77 @@ +#include +#include + +using namespace sqlite_orm; + +namespace { + struct Empty {}; +} + +template class Tuple> +static void template_template_test_case() { + { + using T = Tuple<>; + T t0; + T t_implicit = t0; + T t_explicit(t0); + + (void)t_explicit; + (void)t_implicit; + } + { + using T = Tuple; + T t0(2); + T t = t0; + REQUIRE(std::get<0>(t) == 2); + } + { + using T = Tuple; + T t0(2, 'a'); + T t = t0; + REQUIRE(std::get<0>(t) == 2); + REQUIRE(std::get<1>(t) == 'a'); + } + { + using T = Tuple; + const T t0(2, 'a', "some text"); + T t = t0; + REQUIRE(std::get<0>(t) == 2); + REQUIRE(std::get<1>(t) == 'a'); + REQUIRE(std::get<2>(t) == "some text"); + } + { + using T = Tuple; + constexpr T t0(2); + constexpr T t = t0; + static_assert(std::get<0>(t) == 2, ""); + } + { + using T = Tuple; + constexpr T t0; + constexpr T t = t0; + constexpr Empty e = std::get<0>(t0); + (void)e; + } + { + struct T {}; + struct U {}; + + constexpr Tuple binary{}; + constexpr Tuple copy_implicit = binary; + constexpr Tuple copy_explicit(binary); + + (void)copy_implicit; + (void)copy_explicit; + } +} + +TEST_CASE("tuple - copy") { + { + INFO("mpl::tuple"); + template_template_test_case(); + } + { + INFO("mpl::uple"); + template_template_test_case(); + } +} diff --git a/tests/functional/tuple/cnstr.default.cpp b/tests/functional/tuple/cnstr.default.cpp new file mode 100644 index 000000000..5df669547 --- /dev/null +++ b/tests/functional/tuple/cnstr.default.cpp @@ -0,0 +1,144 @@ +#include +#include + +using namespace sqlite_orm; + +namespace { + struct DefaultOnly { + int data_; + DefaultOnly(DefaultOnly const&) = delete; + DefaultOnly& operator=(DefaultOnly const&) = delete; + + static int count; + + DefaultOnly() : data_(-1) { + ++count; + } + ~DefaultOnly() { + data_ = 0; + --count; + } + + friend bool operator==(DefaultOnly const& x, DefaultOnly const& y) { + return x.data_ == y.data_; + } + + friend bool operator<(DefaultOnly const& x, DefaultOnly const& y) { + return x.data_ < y.data_; + } + }; + + int DefaultOnly::count = 0; + + struct NoDefault { + NoDefault() = delete; + explicit NoDefault(int) {} + }; + + struct IllFormedDefault { + IllFormedDefault(int x) : value(x) {} + template + constexpr IllFormedDefault() { + static_assert(Pred, "The default constructor should not be instantiated"); + } + int value; + }; +} + +template class Tuple> +static void template_template_test_case() { + { + Tuple<> t; + (void)t; + } + { + Tuple t; + REQUIRE(std::get<0>(t) == 0); + } + { + Tuple t; + REQUIRE(std::get<0>(t) == 0); + REQUIRE(std::get<1>(t) == nullptr); + } + { + Tuple t; + REQUIRE(std::get<0>(t) == 0); + REQUIRE(std::get<1>(t) == nullptr); + REQUIRE(std::get<2>(t) == ""); + } + { + Tuple t; + REQUIRE(std::get<0>(t) == 0); + REQUIRE(std::get<1>(t) == nullptr); + REQUIRE(std::get<2>(t) == ""); + REQUIRE(std::get<3>(t) == DefaultOnly()); + } + { + // See LLVM bug #21157. + STATIC_REQUIRE(!std::is_default_constructible>()); + STATIC_REQUIRE(!std::is_default_constructible>()); + } + { + struct T {}; + struct U {}; + struct V {}; + + constexpr Tuple<> z0; + (void)z0; + constexpr Tuple z1; + (void)z1; + constexpr Tuple z2; + (void)z2; + constexpr Tuple z3; + (void)z3; + } + { + constexpr Tuple t; + REQUIRE(std::get<0>(t) == 0); + } + { + constexpr Tuple t; + REQUIRE(std::get<0>(t) == 0); + REQUIRE(std::get<1>(t) == nullptr); + } + + // Make sure we can hold non default-constructible elements, and that + // it does not trigger an error in the default constructor. + { + IllFormedDefault v(0); + Tuple t1(v); + Tuple t2{v}; + Tuple t3 = {v}; + (void)t1; + (void)t2; + (void)t3; + } + { + Tuple t1(0); + Tuple t2{0}; + Tuple t3 = {0}; + (void)t1; + (void)t2; + (void)t3; + } + { + NoDefault v(0); + Tuple t1(v); + Tuple t2{v}; + Tuple t3 = {v}; + (void)t1; + (void)t2; + (void)t3; + } +} + +TEST_CASE("tuple - default") { + { + INFO("mpl::tuple"); + template_template_test_case(); + } + { + INFO("mpl::uple"); + template_template_test_case(); + } +} diff --git a/tests/functional/tuple/cnstr.move.cpp b/tests/functional/tuple/cnstr.move.cpp new file mode 100644 index 000000000..7f804ef7a --- /dev/null +++ b/tests/functional/tuple/cnstr.move.cpp @@ -0,0 +1,82 @@ +#include +#include + +using namespace sqlite_orm; + +namespace { + template + struct MoveOnly { + int data_; + MoveOnly(MoveOnly const&) = delete; + MoveOnly& operator=(MoveOnly const&) = delete; + MoveOnly(int data = 1) : data_(data) {} + MoveOnly(MoveOnly&& x) : data_(x.data_) { + x.data_ = 0; + } + + MoveOnly& operator=(MoveOnly&& x) { + data_ = x.data_; + x.data_ = 0; + return *this; + } + + int get() const { + return data_; + } + bool operator==(const MoveOnly& x) const { + return data_ == x.data_; + } + bool operator<(const MoveOnly& x) const { + return data_ < x.data_; + } + }; + + using MoveOnly1 = MoveOnly<1>; + using MoveOnly2 = MoveOnly<2>; +} + +template class Tuple> +static void template_template_test_case() { + { + using T = mpl::tuple<>; + T t0; + T t = std::move(t0); + (void)t; + } + { + using T = mpl::tuple; + T t0(MoveOnly1(0)); + T t = std::move(t0); + (void)t; + REQUIRE(std::get<0>(t) == 0); + } + { + using T = mpl::tuple; + T t0(MoveOnly1(0), MoveOnly2(1)); + T t = std::move(t0); + (void)t; + REQUIRE(std::get<0>(t) == 0); + REQUIRE(std::get<1>(t) == 1); + } + { + // Check for SFINAE-friendliness + STATIC_REQUIRE(!std::is_constructible, MoveOnly1 const&>{}); + + STATIC_REQUIRE(!std::is_constructible, MoveOnly1&>{}); + + STATIC_REQUIRE(std::is_constructible, MoveOnly1>{}); + + STATIC_REQUIRE(std::is_constructible, MoveOnly2&&>{}); + } +} + +TEST_CASE("tuple - move") { + { + INFO("mpl::tuple"); + template_template_test_case(); + } + { + INFO("mpl::uple"); + template_template_test_case(); + } +} diff --git a/tests/functional/tuple/cnstr.nested.cpp b/tests/functional/tuple/cnstr.nested.cpp new file mode 100644 index 000000000..f50c714a6 --- /dev/null +++ b/tests/functional/tuple/cnstr.nested.cpp @@ -0,0 +1,23 @@ +#include +#include + +using namespace sqlite_orm; + +// See this bug: https://llvm.org/bugs/show_bug.cgi?id=24173 + +namespace { + template + constexpr mpl::tuple...> f(X&&... xs) { + return mpl::tuple...>{std::forward(xs)...}; + } + + template + constexpr mpl::uple...> g(X&&... xs) { + return mpl::uple...>{std::forward(xs)...}; + } +} + +TEST_CASE("tuple - nested") { + f(f(f(f(f(f(f(f(f(f(f(f(1)))))))))))); + g(g(g(g(g(g(g(g(g(g(g(g(1)))))))))))); +} diff --git a/tests/functional/tuple/cnstr.trap.cpp b/tests/functional/tuple/cnstr.trap.cpp new file mode 100644 index 000000000..6854905cb --- /dev/null +++ b/tests/functional/tuple/cnstr.trap.cpp @@ -0,0 +1,87 @@ +#include +#include + +using namespace sqlite_orm; + +// Make sure that the tuple(Yn&&...) is not preferred over copy constructors +// in single-element cases and other similar cases. + +namespace { + struct Trap1 { + Trap1() = default; + Trap1(Trap1 const&) = default; +#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + Trap1(Trap1&) = default; +#endif + Trap1(Trap1&&) = default; + + template + Trap1(X&&) { + static_assert(sizeof(X) && false, "this constructor must not be instantiated"); + } + }; + + struct Trap2 { + Trap2() = default; + Trap2(Trap2 const&) = default; +#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + Trap2(Trap2&) = default; +#endif + Trap2(Trap2&&) = default; + + template + Trap2(X) { // not by reference + static_assert(sizeof(X) && false, "this constructor must not be instantiated"); + } + }; + + struct Trap3 { + Trap3() = default; + Trap3(Trap3 const&) = default; +#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + Trap3(Trap3&) = default; +#endif + Trap3(Trap3&&) = default; + + template + constexpr explicit Trap3(X&&) { // explicit, and constexpr + static_assert(sizeof(X) && false, "this constructor must not be instantiated"); + } + }; + + struct Trap4 { + Trap4() = default; + template + constexpr explicit Trap4(Args&&) { + static_assert(sizeof(Args) && false, "must never be instantiated"); + } + + Trap4(Trap4 const&) = default; + Trap4(Trap4&&) = default; + }; +} + +TEMPLATE_PRODUCT_TEST_CASE("tuple - constructors trap", + "[tuple][trap]", + (mpl::tuple, mpl::uple), + (Trap1, Trap2, Trap3)) { + TestType tuple{}; + TestType implicit_copy = tuple; + TestType explicit_copy(tuple); + TestType implicit_move = std::move(tuple); + TestType explicit_move(std::move(tuple)); + + (void)implicit_copy; + (void)explicit_copy; + (void)implicit_move; + (void)explicit_move; +} + +TEMPLATE_PRODUCT_TEST_CASE("tuple - element constructor trap", "[tuple]", (mpl::tuple, mpl::uple), (Trap4)) { + struct Foo { + Foo() = default; + Foo(Foo const&) = default; + Foo(Foo&&) = default; + TestType t; + }; +} diff --git a/tests/functional/tuple/cnstr.variadic_array.cpp b/tests/functional/tuple/cnstr.variadic_array.cpp new file mode 100644 index 000000000..31a011d5a --- /dev/null +++ b/tests/functional/tuple/cnstr.variadic_array.cpp @@ -0,0 +1,17 @@ +#include +#include +#include + +using namespace sqlite_orm; + +// +// This test checks that we can NOT construct a tuple holding array members, +// per the standard. +// + +TEST_CASE("tuple - array elements") { + STATIC_REQUIRE(!std::is_constructible, int[3]>{}); + STATIC_REQUIRE(!std::is_constructible, int[3], float[4]>{}); + STATIC_REQUIRE(!std::is_constructible, int[3]>{}); + STATIC_REQUIRE(!std::is_constructible, int[3], float[4]>{}); +} diff --git a/tests/functional/tuple/cnstr.variadic_copy.cpp b/tests/functional/tuple/cnstr.variadic_copy.cpp new file mode 100644 index 000000000..7460b4a06 --- /dev/null +++ b/tests/functional/tuple/cnstr.variadic_copy.cpp @@ -0,0 +1,144 @@ +#include +#include + +using namespace sqlite_orm; + +namespace { + template + struct never { + static constexpr bool value = false; + }; + + struct NoValueCtor { + NoValueCtor() : id(++count) {} + NoValueCtor(NoValueCtor const& other) : id(other.id) { + ++count; + } + + // The constexpr is required to make is_constructible instantiate this + // template. The explicit is needed to test-around a similar bug with + // is_convertible. + template + constexpr explicit NoValueCtor(T) { + static_assert(never::value, "This should not be instantiated"); + } + + static int count; + int id; + }; + + int NoValueCtor::count = 0; + + struct NoValueCtorEmpty { + NoValueCtorEmpty() {} + NoValueCtorEmpty(NoValueCtorEmpty const&) {} + + template + constexpr explicit NoValueCtorEmpty(T) { + static_assert(never::value, "This should not be instantiated"); + } + }; +} + +template class Tuple> +static void template_template_test_case() { + { + Tuple t(2); + REQUIRE(std::get<0>(t) == 2); + } + { + constexpr Tuple t(2); + STATIC_REQUIRE(std::get<0>(t) == 2); + } + { + constexpr Tuple t; + STATIC_REQUIRE(std::get<0>(t) == 0); + } + { + constexpr Tuple t(2, nullptr); + STATIC_REQUIRE(std::get<0>(t) == 2); + STATIC_REQUIRE(std::get<1>(t) == nullptr); + } + { + Tuple t(2, nullptr); + REQUIRE(std::get<0>(t) == 2); + REQUIRE(std::get<1>(t) == nullptr); + } + { + Tuple t(2, nullptr, "text"); + REQUIRE(std::get<0>(t) == 2); + REQUIRE(std::get<1>(t) == nullptr); + REQUIRE(std::get<2>(t) == "text"); + } + { + Tuple t(1, NoValueCtor(), 2, 3); + REQUIRE(std::get<0>(t) == 1); + REQUIRE(std::get<1>(t).id == NoValueCtor::count - 1); + REQUIRE(std::get<2>(t) == 2); + REQUIRE(std::get<3>(t) == 3); + } + { + Tuple t(1, NoValueCtorEmpty(), 2, 3); + REQUIRE(std::get<0>(t) == 1); + REQUIRE(std::get<2>(t) == 2); + REQUIRE(std::get<3>(t) == 3); + } + { + struct T {}; + struct U {}; + struct V {}; + + constexpr T t{}; + constexpr U u{}; + constexpr V v{}; + + constexpr Tuple x1{t}; + (void)x1; + constexpr Tuple x2{t, u}; + (void)x2; + constexpr Tuple x3{t, u, v}; + (void)x3; + } + { + struct T {}; + struct U {}; + struct V {}; + + // Check for SFINAE-friendliness + STATIC_REQUIRE(!std::is_constructible, T>{}); + + STATIC_REQUIRE(!std::is_constructible, U, T>{}); + + STATIC_REQUIRE(!std::is_constructible, T, U, V>{}); + } + + // Make sure we can initialize elements with the brace-init syntax. + { + struct Member {}; + struct Element { + Member member; + }; + struct Element2 { + Member member; + }; + struct Element3 { + Member member; + }; + + Tuple xs{{Member()}, {Member()}, {Member()}}; + Tuple ys = {{Member()}, {Member()}, {Member()}}; + (void)xs; + (void)ys; + } +} + +TEST_CASE("tuple - variadic copy") { + { + INFO("mpl::tuple"); + template_template_test_case(); + } + { + INFO("mpl::uple"); + template_template_test_case(); + } +} diff --git a/tests/functional/tuple/cnstr.variadic_forward.cpp b/tests/functional/tuple/cnstr.variadic_forward.cpp new file mode 100644 index 000000000..24b3025e9 --- /dev/null +++ b/tests/functional/tuple/cnstr.variadic_forward.cpp @@ -0,0 +1,98 @@ +#include +#include + +using namespace sqlite_orm; + +namespace { + struct MoveOnly { + int data_; + MoveOnly(MoveOnly const&) = delete; + MoveOnly& operator=(MoveOnly const&) = delete; + MoveOnly(int data = 1) : data_(data) {} + MoveOnly(MoveOnly&& x) : data_(x.data_) { + x.data_ = 0; + } + + MoveOnly& operator=(MoveOnly&& x) { + data_ = x.data_; + x.data_ = 0; + return *this; + } + + int get() const { + return data_; + } + bool operator==(const MoveOnly& x) const { + return data_ == x.data_; + } + bool operator<(const MoveOnly& x) const { + return data_ < x.data_; + } + }; + + struct Empty {}; + struct A { + int id_; + explicit constexpr A(int i) : id_(i) {} + }; + + struct NoDefault { + NoDefault() = delete; + }; +} + +TEST_CASE("tuple - variadic forward") { + { + mpl::tuple t(MoveOnly(0)); + REQUIRE(std::get<0>(t) == 0); + } + { + mpl::tuple t(MoveOnly(0), MoveOnly(1)); + REQUIRE(std::get<0>(t) == 0); + REQUIRE(std::get<1>(t) == 1); + } + { + mpl::tuple t(MoveOnly(0), MoveOnly(1), MoveOnly(2)); + REQUIRE(std::get<0>(t) == 0); + REQUIRE(std::get<1>(t) == 1); + REQUIRE(std::get<2>(t) == 2); + } + { + constexpr mpl::tuple t0{Empty()}; + (void)t0; + } + { + constexpr mpl::tuple t(3, 2); + STATIC_REQUIRE(std::get<0>(t).id_ == 3); + } + { + typedef mpl::tuple Tuple; + + STATIC_REQUIRE(!std::is_constructible::value); + + STATIC_REQUIRE(std::is_constructible::value); + } + { + typedef mpl::tuple Tuple; + + STATIC_REQUIRE(!std::is_constructible::value); + + STATIC_REQUIRE(std::is_constructible::value); + } + { + typedef mpl::tuple Tuple; + typedef mpl::tuple NestedTuple; + + STATIC_REQUIRE(!std::is_constructible::value); + + STATIC_REQUIRE(std::is_constructible::value); + } + { + typedef mpl::tuple Tuple; + typedef mpl::tuple NestedTuple; + + STATIC_REQUIRE(!std::is_constructible::value); + + STATIC_REQUIRE(std::is_constructible::value); + } +} diff --git a/tests/functional/tuple/empty_member.cpp b/tests/functional/tuple/empty_member.cpp new file mode 100644 index 000000000..e2bec6af3 --- /dev/null +++ b/tests/functional/tuple/empty_member.cpp @@ -0,0 +1,16 @@ +#include +#include + +using namespace sqlite_orm; + +namespace { + struct A {}; + struct B {}; +} + +TEMPLATE_PRODUCT_TEST_CASE("tuple - empty member", + "[tuple]", + (mpl::tuple, mpl::uple), + ((int, A), (A, int), (A, int, B), (A, B, int), (int, A, B))) { + STATIC_REQUIRE(sizeof(TestType) == sizeof(int)); +} From 89f0f57fe937a9a6df753a997cddaea86c9d1327 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Sat, 11 Jun 2022 23:31:03 +0300 Subject: [PATCH 06/16] More internal usage of custom tuple --- dev/ast/group_by.h | 9 ++-- dev/column.h | 2 +- dev/conditions.h | 13 ++--- dev/core_functions.h | 8 +-- dev/expression.h | 5 +- dev/functional/pack.h | 11 ++++ dev/functional/tuple.h | 9 ++++ dev/functional/type_at.h | 6 --- dev/functional/unique_tuple.h | 8 +++ dev/prepared_statement.h | 2 +- dev/row_extractor.h | 2 +- dev/serializing_util.h | 80 +++++++++++++++--------------- dev/statement_serializer.h | 2 +- dev/storage.h | 14 ++---- dev/table.h | 1 - dev/triggers.h | 13 +++-- dev/tuple_helper/tuple_iteration.h | 1 - dev/tuple_helper/tuple_traits.h | 15 +----- dev/values.h | 4 +- dev/values_to_tuple.h | 1 - dev/view.h | 1 - 21 files changed, 104 insertions(+), 103 deletions(-) diff --git a/dev/ast/group_by.h b/dev/ast/group_by.h index c2deeb54c..7a6b3ff62 100644 --- a/dev/ast/group_by.h +++ b/dev/ast/group_by.h @@ -1,17 +1,16 @@ #pragma once -#include // std::tuple, std::make_tuple -#include // std::true_type, std::false_type #include // std::forward, std::move #include "../functional/cxx_type_traits_polyfill.h" +#include "../functional/tuple.h" namespace sqlite_orm { namespace internal { template struct group_by_with_having { - using args_type = std::tuple; + using args_type = mpl::tuple; using expression_type = T; args_type args; @@ -23,7 +22,7 @@ namespace sqlite_orm { */ template struct group_by_t { - using args_type = std::tuple; + using args_type = mpl::tuple; args_type args; @@ -58,7 +57,7 @@ namespace sqlite_orm { */ template internal::group_by_t group_by(Args&&... args) { - return {std::make_tuple(std::forward(args)...)}; + return {mpl::make_tuple(std::forward(args)...)}; } /** diff --git a/dev/column.h b/dev/column.h index f53cfc7b2..fbf519eb9 100644 --- a/dev/column.h +++ b/dev/column.h @@ -1,12 +1,12 @@ #pragma once -#include // std::tuple #include // std::string #include // std::unique_ptr #include // std::is_same, std::is_member_object_pointer #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" +#include "functional/unique_tuple.h" #include "tuple_helper/tuple_traits.h" #include "tuple_helper/tuple_filter.h" #include "type_traits.h" diff --git a/dev/conditions.h b/dev/conditions.h index 873776481..ad1bc46b5 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -3,11 +3,12 @@ #include // std::string #include // std::enable_if, std::is_same #include // std::vector -#include // std::tuple, std::tuple_size #include // std::stringstream +#include // std::move #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" +#include "functional/tuple.h" #include "type_traits.h" #include "collate_argument.h" #include "constraints.h" @@ -376,7 +377,7 @@ namespace sqlite_orm { template struct in_t : condition_t, in_base, negatable_t { L left; - std::tuple argument; + mpl::tuple argument; in_t(L left_, decltype(argument) argument_, bool negative_) : in_base{negative_}, left(std::move(left_)), argument(std::move(argument_)) {} @@ -497,7 +498,7 @@ namespace sqlite_orm { */ template struct multi_order_by_t : order_by_string { - using args_type = std::tuple; + using args_type = mpl::tuple; args_type args; @@ -796,7 +797,7 @@ namespace sqlite_orm { template struct from_t { - using tuple_type = std::tuple; + using tuple_type = mpl::tuple; }; template @@ -809,7 +810,7 @@ namespace sqlite_orm { */ template internal::from_t from() { - static_assert(std::tuple_size>::value > 0, ""); + static_assert(sizeof...(Args) > 0, ""); return {}; } @@ -1196,7 +1197,7 @@ namespace sqlite_orm { */ template internal::multi_order_by_t multi_order_by(Args&&... args) { - return {std::make_tuple(std::forward(args)...)}; + return {mpl::make_tuple(std::forward(args)...)}; } /** diff --git a/dev/core_functions.h b/dev/core_functions.h index 1c4a896d9..a58cd1b3c 100644 --- a/dev/core_functions.h +++ b/dev/core_functions.h @@ -1965,7 +1965,7 @@ namespace sqlite_orm { template internal::built_in_function_t json_insert(X x, Args... args) { - static_assert(std::tuple_size>::value % 2 == 0, + static_assert(sizeof...(Args) % 2 == 0, "number of arguments in json_insert must be odd"); return {std::tuple{std::forward(x), std::forward(args)...}}; } @@ -1973,21 +1973,21 @@ namespace sqlite_orm { template internal::built_in_function_t json_replace(X x, Args... args) { - static_assert(std::tuple_size>::value % 2 == 0, + static_assert(sizeof...(Args) % 2 == 0, "number of arguments in json_replace must be odd"); return {std::tuple{std::forward(x), std::forward(args)...}}; } template internal::built_in_function_t json_set(X x, Args... args) { - static_assert(std::tuple_size>::value % 2 == 0, + static_assert(sizeof...(Args) % 2 == 0, "number of arguments in json_set must be odd"); return {std::tuple{std::forward(x), std::forward(args)...}}; } template internal::built_in_function_t json_object(Args... args) { - static_assert(std::tuple_size>::value % 2 == 0, + static_assert(sizeof...(Args) % 2 == 0, "number of arguments in json_object must be even"); return {std::tuple{std::forward(args)...}}; } diff --git a/dev/expression.h b/dev/expression.h index b92fb0030..65297ab08 100644 --- a/dev/expression.h +++ b/dev/expression.h @@ -5,6 +5,7 @@ #include "functional/cxx_optional.h" #include "functional/cxx_universal.h" +#include "functional/tuple.h" // make_tuple #include "operators.h" namespace sqlite_orm { @@ -41,12 +42,12 @@ namespace sqlite_orm { #endif template in_t in(Args... args) const { - return {this->value, std::make_tuple(std::forward(args)...), false}; + return {this->value, mpl::make_tuple(std::forward(args)...), false}; } template in_t not_in(Args... args) const { - return {this->value, std::make_tuple(std::forward(args)...), true}; + return {this->value, mpl::make_tuple(std::forward(args)...), true}; } template diff --git a/dev/functional/pack.h b/dev/functional/pack.h index 0b258f62e..120e52036 100644 --- a/dev/functional/pack.h +++ b/dev/functional/pack.h @@ -1,5 +1,7 @@ #pragma once +#include // std::integral_constant + #include "cxx_universal.h" namespace _sqlite_orm { @@ -33,3 +35,12 @@ namespace sqlite_orm { namespace mpl = internal::mpl; } + +// retain stl tuple interface for `tuple` +namespace std { + template + struct tuple_size; + + template + struct tuple_size> : integral_constant {}; +} diff --git a/dev/functional/tuple.h b/dev/functional/tuple.h index d4d669e37..e7fd810cf 100644 --- a/dev/functional/tuple.h +++ b/dev/functional/tuple.h @@ -127,6 +127,9 @@ namespace sqlite_orm { // retain stl tuple interface for `tuple` namespace std { + template + struct tuple_size; + template struct tuple_size> : integral_constant {}; @@ -234,7 +237,13 @@ namespace sqlite_orm { constexpr auto make_tuple(X&&... x) { return tuple...>{std::forward(x)...}; } + + template + constexpr tuple forward_as_tuple(X&&... args) noexcept { + return tuple(_STD forward(args)...); + } } + using adl::forward_as_tuple; using adl::make_tuple; // implementation note: we could derive from `type_at` but leverage the fact that `tuple` is derived from `indexed_type` diff --git a/dev/functional/type_at.h b/dev/functional/type_at.h index b35823fc7..e08ac8418 100644 --- a/dev/functional/type_at.h +++ b/dev/functional/type_at.h @@ -49,9 +49,3 @@ namespace sqlite_orm { namespace mpl = internal::mpl; } - -// retain stl tuple interface for `tuple` -namespace std { - template - struct tuple_size> : integral_constant {}; -} diff --git a/dev/functional/unique_tuple.h b/dev/functional/unique_tuple.h index e17a83613..c66d3e197 100644 --- a/dev/functional/unique_tuple.h +++ b/dev/functional/unique_tuple.h @@ -111,6 +111,9 @@ namespace sqlite_orm { // retain stl tuple interface for `uple` namespace std { + template + struct tuple_size; + template struct tuple_size> : integral_constant {}; @@ -213,6 +216,11 @@ namespace sqlite_orm { return uple...>{std::forward(x)...}; } + template + constexpr uple forward_as_unique_tuple(X&&... args) noexcept { + return uple(_STD forward(args)...); + } + template struct type_at> : type_at {}; } diff --git a/dev/prepared_statement.h b/dev/prepared_statement.h index 0d88ba513..775771c04 100644 --- a/dev/prepared_statement.h +++ b/dev/prepared_statement.h @@ -373,7 +373,7 @@ namespace sqlite_orm { */ template internal::insert_raw_t insert(Args... args) { - using args_tuple = mpl::tuple; + using args_tuple = mpl::pack; using internal::count_tuple; using internal::is_columns; using internal::is_insert_constraint; diff --git a/dev/row_extractor.h b/dev/row_extractor.h index ed60e596a..f6e6759a3 100644 --- a/dev/row_extractor.h +++ b/dev/row_extractor.h @@ -13,7 +13,7 @@ #include #include // std::copy #include // std::back_inserter -#include // std::tuple, std::tuple_size, std::tuple_element +#include // std::tuple #include "functional/cxx_universal.h" #include "arithmetic_tag.h" diff --git a/dev/serializing_util.h b/dev/serializing_util.h index 178d4a1a9..98660a1ac 100644 --- a/dev/serializing_util.h +++ b/dev/serializing_util.h @@ -125,7 +125,7 @@ namespace sqlite_orm { struct streaming { template auto operator()(const Ts&... ts) const { - return std::forward_as_tuple(*this, ts...); + return mpl::forward_as_tuple(*this, ts...); } template @@ -151,9 +151,9 @@ namespace sqlite_orm { // space + space-separated template std::ostream& operator<<(std::ostream& ss, - std::tuple&, T, Ctx> tpl) { - const auto& conditions = get<1>(tpl); - auto& context = get<2>(tpl); + mpl::tuple&, T, Ctx> tpl) { + const auto& conditions = std::get<1>(tpl); + auto& context = std::get<2>(tpl); iterate_tuple(conditions, [&ss, &context](auto& c) { ss << " " << serialize(c, context); @@ -164,9 +164,9 @@ namespace sqlite_orm { // serialize and stream a tuple of action expressions; // space-separated template - std::ostream& operator<<(std::ostream& ss, std::tuple&, T, Ctx> tpl) { - const auto& actions = get<1>(tpl); - auto& context = get<2>(tpl); + std::ostream& operator<<(std::ostream& ss, mpl::tuple&, T, Ctx> tpl) { + const auto& actions = std::get<1>(tpl); + auto& context = std::get<2>(tpl); iterate_tuple(actions, [&ss, &context, first = true](auto& action) mutable { constexpr std::array sep = {" ", ""}; @@ -179,9 +179,9 @@ namespace sqlite_orm { // comma-separated template std::ostream& operator<<(std::ostream& ss, - std::tuple&, T, Ctx> tpl) { - const auto& args = get<1>(tpl); - auto& context = get<2>(tpl); + mpl::tuple&, T, Ctx> tpl) { + const auto& args = std::get<1>(tpl); + auto& context = std::get<2>(tpl); iterate_tuple(args, [&ss, &context, first = true](auto& arg) mutable { constexpr std::array sep = {", ", ""}; @@ -195,9 +195,9 @@ namespace sqlite_orm { template std::ostream& operator<<( std::ostream& ss, - std::tuple&, const std::tuple...>&, Ctx> tpl) { - const auto& args = get<1>(tpl); - auto& context = get<2>(tpl); + mpl::tuple&, const std::tuple...>&, Ctx> tpl) { + const auto& args = std::get<1>(tpl); + auto& context = std::get<2>(tpl); iterate_tuple(args, [&ss, &context, first = true](auto& arg) mutable { constexpr std::array sep = {", ", ""}; @@ -210,9 +210,9 @@ namespace sqlite_orm { // comma-separated template std::ostream& operator<<(std::ostream& ss, - std::tuple&, C, Ctx> tpl) { - const auto& args = get<1>(tpl); - auto& context = get<2>(tpl); + mpl::tuple&, C, Ctx> tpl) { + const auto& args = std::get<1>(tpl); + auto& context = std::get<2>(tpl); constexpr std::array sep = {", ", ""}; for(size_t i = 0, first = true; i < args.size(); ++i) { @@ -224,8 +224,8 @@ namespace sqlite_orm { // stream a vector of already serialized strings; // comma-separated template - std::ostream& operator<<(std::ostream& ss, std::tuple&, C> tpl) { - const auto& strings = get<1>(tpl); + std::ostream& operator<<(std::ostream& ss, mpl::tuple&, C> tpl) { + const auto& strings = std::get<1>(tpl); constexpr std::array sep = {", ", ""}; for(size_t i = 0, first = true; i < strings.size(); ++i) { @@ -240,7 +240,7 @@ namespace sqlite_orm { // 3. qualifier, identifier, alias template std::ostream& operator<<(std::ostream& ss, - std::tuple&, Strings...> tpl) { + mpl::tuple&, Strings...> tpl) { stream_identifier(ss, tpl, streaming_identifier.offset_index(std::index_sequence_for{})); return ss; } @@ -253,8 +253,8 @@ namespace sqlite_orm { // // comma-separated template - std::ostream& operator<<(std::ostream& ss, std::tuple&, C> tpl) { - const auto& identifiers = get<1>(tpl); + std::ostream& operator<<(std::ostream& ss, mpl::tuple&, C> tpl) { + const auto& identifiers = std::get<1>(tpl); constexpr std::array sep = {", ", ""}; bool first = true; @@ -268,9 +268,9 @@ namespace sqlite_orm { // stream placeholders as part of a values clause template std::ostream& operator<<(std::ostream& ss, - std::tuple&, Ts...> tpl) { - const size_t& columnsCount = get<1>(tpl); - const ptrdiff_t& valuesCount = get<2>(tpl); + mpl::tuple&, Ts...> tpl) { + const size_t& columnsCount = std::get<1>(tpl); + const ptrdiff_t& valuesCount = std::get<2>(tpl); if(!valuesCount || !columnsCount) { return ss; @@ -297,9 +297,9 @@ namespace sqlite_orm { // comma-separated template std::ostream& operator<<(std::ostream& ss, - std::tuple&, Table, const bool&> tpl) { - const auto& table = get<1>(tpl); - const bool& qualified = get<2>(tpl); + mpl::tuple&, Table, const bool&> tpl) { + const auto& table = std::get<1>(tpl); + const bool& qualified = std::get<2>(tpl); table.for_each_column([&ss, &tableName = qualified ? table.name : std::string{}, first = true]( const column_identifier& column) mutable { @@ -314,8 +314,8 @@ namespace sqlite_orm { // comma-separated template std::ostream& operator<<(std::ostream& ss, - std::tuple&, Table> tpl) { - const auto& table = get<1>(tpl); + mpl::tuple&, Table> tpl) { + const auto& table = std::get<1>(tpl); table.template for_each_column_excluding( [&ss, first = true](const column_identifier& column) mutable { @@ -331,11 +331,11 @@ namespace sqlite_orm { template std::ostream& operator<<(std::ostream& ss, - std::tuple&, PredFnCls, L, Ctx, Obj> tpl) { + mpl::tuple&, PredFnCls, L, Ctx, Obj> tpl) { using check_if_excluded = polyfill::remove_cvref_t>; - auto& excluded = get<2>(tpl); - auto& context = get<3>(tpl); - auto& object = get<4>(tpl); + auto& excluded = std::get<2>(tpl); + auto& context = std::get<3>(tpl); + auto& object = std::get<4>(tpl); using object_type = polyfill::remove_cvref_t; auto& table = pick_table(context.db_objects); @@ -356,9 +356,9 @@ namespace sqlite_orm { // comma-separated template std::ostream& operator<<(std::ostream& ss, - std::tuple&, T, Ctx> tpl) { - const auto& columns = get<1>(tpl); - auto& context = get<2>(tpl); + mpl::tuple&, T, Ctx> tpl) { + const auto& columns = std::get<1>(tpl); + auto& context = std::get<2>(tpl); iterate_tuple(columns, [&ss, &context, first = true](auto& colRef) mutable { const std::string* columnName = find_column_name(context.db_objects, colRef); @@ -375,13 +375,13 @@ namespace sqlite_orm { template std::ostream& operator<<(std::ostream& ss, - std::tuple&, + mpl::tuple&, const column_constraints&, const bool&, Ctx> tpl) { - const auto& column = get<1>(tpl); - const bool& isNotNull = get<2>(tpl); - auto& context = get<3>(tpl); + const auto& column = std::get<1>(tpl); + const bool& isNotNull = std::get<2>(tpl); + auto& context = std::get<3>(tpl); using constraints_type = constraints_type_t>; constexpr size_t constraintsCount = std::tuple_size::value; diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 5254c9357..6d0c06431 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -963,7 +963,7 @@ namespace sqlite_orm { template std::string operator()(const statement_type& ins, const Ctx& context) const { - constexpr size_t colsCount = std::tuple_size>::value; + constexpr size_t colsCount = sizeof...(Cols); static_assert(colsCount > 0, "Use insert or replace with 1 argument instead"); using expression_type = std::decay_t; using object_type = typename expression_object_type::type; diff --git a/dev/storage.h b/dev/storage.h index 29e310ea9..d1467bb9e 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -9,7 +9,6 @@ #include // std::stringstream #include // std::map #include // std::vector -#include // std::tuple_size, std::tuple, std::make_tuple, std::tie #include // std::forward, std::pair #include // std::for_each, std::ranges::for_each #include "functional/cxx_optional.h" @@ -173,8 +172,8 @@ namespace sqlite_orm { template void assert_mapped_type() const { - using mapped_types_tuple = std::tuple; - static_assert(mpl::invoke_t, mapped_types_tuple>::value, + using mapped_types_pack = mpl::pack; + static_assert(mpl::invoke_t, mapped_types_pack>::value, "type is not mapped to a storage"); } @@ -458,11 +457,7 @@ namespace sqlite_orm { * @param m is a class member pointer (the same you passed into make_column). * @return group_concat query result. */ - template, - std::enable_if_t::value >= 1, bool> = true> + template= 1, bool> = true> std::string group_concat(F O::*m, Args&&... args) { return this->group_concat_internal(m, {}, std::forward(args)...); } @@ -567,8 +562,7 @@ namespace sqlite_orm { */ template> std::vector select(T m, Args... args) { - static_assert(!is_base_of_template_v || - std::tuple_size>::value == 0, + static_assert(!is_base_of_template_v || sizeof...(Args) == 0, "Cannot use args with a compound operator"); auto statement = this->prepare(sqlite_orm::select(std::move(m), std::forward(args)...)); return this->execute(statement); diff --git a/dev/table.h b/dev/table.h index f3301c2ea..fc340efdc 100644 --- a/dev/table.h +++ b/dev/table.h @@ -3,7 +3,6 @@ #include // std::string #include // std::remove_reference, std::is_same, std::decay #include // std::vector -#include // std::tuple_size, std::tuple_element #include // std::forward, std::move #include "functional/cxx_universal.h" diff --git a/dev/triggers.h b/dev/triggers.h index 20b18fef1..671539a8e 100644 --- a/dev/triggers.h +++ b/dev/triggers.h @@ -1,11 +1,10 @@ #pragma once -#include -#include #include -#include +#include // std::move, std::forward #include "functional/cxx_universal.h" +#include "functional/tuple.h" #include "optional_container.h" // NOTE Idea : Maybe also implement a custom trigger system to call a c++ callback when a trigger triggers ? @@ -26,7 +25,7 @@ namespace sqlite_orm { */ template struct partial_trigger_t { - using statements_type = std::tuple; + using statements_type = mpl::tuple; /** * Base of the trigger (contains its type, timing and associated table) @@ -38,7 +37,7 @@ namespace sqlite_orm { statements_type statements; partial_trigger_t(T trigger_base, S... statements) : - base{std::move(trigger_base)}, statements{std::make_tuple(std::forward(statements)...)} {} + base{std::move(trigger_base)}, statements{mpl::make_tuple(std::forward(statements)...)} {} partial_trigger_t &end() { return *this; @@ -156,7 +155,7 @@ namespace sqlite_orm { */ template struct trigger_update_type_t : trigger_type_base_t { - using columns_type = std::tuple; + using columns_type = mpl::tuple; /** * Contains the columns the trigger is watching. Will only @@ -165,7 +164,7 @@ namespace sqlite_orm { columns_type columns; trigger_update_type_t(trigger_timing timing, trigger_type type, Cs... columns) : - trigger_type_base_t(timing, type), columns(std::make_tuple(std::forward(columns)...)) {} + trigger_type_base_t(timing, type), columns(mpl::make_tuple(std::forward(columns)...)) {} template trigger_base_t> on() { diff --git a/dev/tuple_helper/tuple_iteration.h b/dev/tuple_helper/tuple_iteration.h index 1dd297499..b5f06148f 100644 --- a/dev/tuple_helper/tuple_iteration.h +++ b/dev/tuple_helper/tuple_iteration.h @@ -1,6 +1,5 @@ #pragma once -#include // std::tuple, std::get, std::tuple_element, std::tuple_size #include // std::index_sequence, std::make_index_sequence #include // std::forward, std::move diff --git a/dev/tuple_helper/tuple_traits.h b/dev/tuple_helper/tuple_traits.h index 4a9e0dfe1..56f3ac064 100644 --- a/dev/tuple_helper/tuple_traits.h +++ b/dev/tuple_helper/tuple_traits.h @@ -1,12 +1,7 @@ #pragma once -#include // std::is_same -#include - #include "../functional/cxx_type_traits_polyfill.h" #include "../functional/mpl.h" -#include "../functional/unique_tuple.h" -#include "../functional/tuple.h" namespace sqlite_orm { namespace internal { @@ -16,14 +11,8 @@ namespace sqlite_orm { template class TraitFn, class Tuple> struct tuple_has {}; - template class TraitFn, class... Types> - struct tuple_has> : polyfill::disjunction...> {}; - - template class TraitFn, class... Types> - struct tuple_has> : polyfill::disjunction...> {}; - - template class TraitFn, class... Types> - struct tuple_has> : polyfill::disjunction...> {}; + template class TraitFn, template class Tuple, class... Types> + struct tuple_has> : polyfill::disjunction...> {}; /* * Trait metafunction class that checks whether a tuple contains a type with given trait. diff --git a/dev/values.h b/dev/values.h index a42b52e68..ced45afa7 100644 --- a/dev/values.h +++ b/dev/values.h @@ -1,11 +1,11 @@ #pragma once #include // std::vector -#include // std::tuple #include // std::forward #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" +#include "functional/tuple.h" namespace sqlite_orm { @@ -13,7 +13,7 @@ namespace sqlite_orm { template struct values_t { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; args_tuple tuple; }; diff --git a/dev/values_to_tuple.h b/dev/values_to_tuple.h index fb392799d..4dfbb89b8 100644 --- a/dev/values_to_tuple.h +++ b/dev/values_to_tuple.h @@ -2,7 +2,6 @@ #include #include // std::index_sequence, std::make_index_sequence -#include // std::tuple, std::tuple_size, std::get #include "functional/cxx_universal.h" #include "functional/tuple.h" diff --git a/dev/view.h b/dev/view.h index e062df98b..78eaa41c2 100644 --- a/dev/view.h +++ b/dev/view.h @@ -3,7 +3,6 @@ #include #include // std::string #include // std::forward, std::move -#include // std::tuple, std::make_tuple #include "row_extractor.h" #include "error_code.h" From 3d5d75e647a39455fdb49a926422b19b6765fa49 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 15 Jun 2022 12:57:24 +0300 Subject: [PATCH 07/16] Replaced many more occurrences of std tuple --- dev/ast/upsert_clause.h | 21 +- dev/ast_iterator.h | 4 +- dev/constraints.h | 32 +- dev/core_functions.h | 266 ++-- dev/expression.h | 2 +- dev/function.h | 2 +- dev/functional/cxx_compiler_quirks.h | 4 +- dev/functional/cxx_core_features.h | 5 +- dev/functional/indexed_type.h | 23 + dev/functional/pack.h | 16 - dev/functional/tuple.h | 163 +- dev/functional/tuple_common.h | 34 +- dev/functional/type_at.h | 8 +- dev/functional/unique_tuple.h | 151 +- dev/node_tuple.h | 2 +- dev/select_constraints.h | 27 +- dev/serializing_util.h | 3 +- dev/statement_serializer.h | 25 +- dev/tuple_helper/index_sequence_util.h | 4 +- include/sqlite_orm/sqlite_orm.h | 1405 ++++++++++------- .../functional/tuple/assign.convert_copy.cpp | 69 + .../functional/tuple/assign.convert_move.cpp | 79 + tests/functional/tuple/assign.copy.cpp | 49 + tests/functional/tuple/assign.move.cpp | 72 + tests/functional/tuple/cnstr.convert_copy.cpp | 42 +- tests/functional/tuple/cnstr.convert_move.cpp | 34 +- tests/functional/tuple/cnstr.copy.cpp | 2 +- tests/functional/tuple/cnstr.default.cpp | 2 +- tests/functional/tuple/cnstr.move.cpp | 2 +- 29 files changed, 1606 insertions(+), 942 deletions(-) create mode 100644 dev/functional/indexed_type.h create mode 100644 tests/functional/tuple/assign.convert_copy.cpp create mode 100644 tests/functional/tuple/assign.convert_move.cpp create mode 100644 tests/functional/tuple/assign.copy.cpp create mode 100644 tests/functional/tuple/assign.move.cpp diff --git a/dev/ast/upsert_clause.h b/dev/ast/upsert_clause.h index f46a293b6..ab190d110 100644 --- a/dev/ast/upsert_clause.h +++ b/dev/ast/upsert_clause.h @@ -1,10 +1,9 @@ #pragma once -#include // std::tuple, std::make_tuple -#include // std::false_type, std::true_type #include // std::forward, std::move #include "../functional/cxx_type_traits_polyfill.h" +#include "../functional/tuple.h" namespace sqlite_orm { namespace internal { @@ -14,24 +13,24 @@ namespace sqlite_orm { template struct conflict_target { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; args_tuple args; - upsert_clause> do_nothing() { - return {move(this->args), {}}; + upsert_clause> do_nothing() { + return {std::move(this->args), {}}; } template - upsert_clause> do_update(ActionsArgs... actions) { - return {move(this->args), {std::make_tuple(std::forward(actions)...)}}; + upsert_clause> do_update(ActionsArgs... actions) { + return {std::move(this->args), {std::forward(actions)...}}; } }; template - struct upsert_clause, std::tuple> { - using target_args_tuple = std::tuple; - using actions_tuple = std::tuple; + struct upsert_clause, mpl::tuple> { + using target_args_tuple = mpl::tuple; + using actions_tuple = mpl::tuple; target_args_tuple target_args; @@ -56,7 +55,7 @@ namespace sqlite_orm { */ template internal::conflict_target on_conflict(Args... args) { - return {std::tuple(std::forward(args)...)}; + return {{std::forward(args)...}}; } #endif } diff --git a/dev/ast_iterator.h b/dev/ast_iterator.h index f66f29de6..4981ec3ef 100644 --- a/dev/ast_iterator.h +++ b/dev/ast_iterator.h @@ -96,8 +96,8 @@ namespace sqlite_orm { }; template - struct ast_iterator, std::tuple>, void> { - using node_type = upsert_clause, std::tuple>; + struct ast_iterator, mpl::tuple>, void> { + using node_type = upsert_clause, mpl::tuple>; template void operator()(const node_type& expression, L& lambda) const { diff --git a/dev/constraints.h b/dev/constraints.h index d377f4a9e..237b5e506 100644 --- a/dev/constraints.h +++ b/dev/constraints.h @@ -3,12 +3,12 @@ #include // std::system_error #include // std::ostream #include // std::string -#include // std::tuple, std::make_tuple -#include // std::is_base_of, std::false_type, std::true_type +#include // std::is_base_of, std::false_type #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" #include "functional/mpl.h" +#include "functional/tuple.h" #include "tuple_helper/same_or_void.h" #include "tuple_helper/tuple_traits.h" #include "tuple_helper/tuple_filter.h" @@ -60,11 +60,11 @@ namespace sqlite_orm { template struct primary_key_t : primary_key_base { using order_by = primary_key_base::order_by; - using columns_tuple = std::tuple; + using columns_tuple = mpl::tuple; columns_tuple columns; - primary_key_t(decltype(columns) c) : columns(move(c)) {} + primary_key_t(decltype(columns) c) : columns(std::move(c)) {} primary_key_t asc() const { auto res = *this; @@ -90,11 +90,11 @@ namespace sqlite_orm { */ template struct unique_t : unique_base { - using columns_tuple = std::tuple; + using columns_tuple = mpl::tuple; columns_tuple columns; - unique_t(columns_tuple columns_) : columns(move(columns_)) {} + unique_t(columns_tuple columns_) : columns(std::move(columns_)) {} }; /** @@ -243,9 +243,9 @@ namespace sqlite_orm { } template - struct foreign_key_t, std::tuple> { - using columns_type = std::tuple; - using references_type = std::tuple; + struct foreign_key_t, mpl::tuple> { + using columns_type = mpl::tuple; + using references_type = mpl::tuple; using self = foreign_key_t; /** @@ -269,7 +269,7 @@ namespace sqlite_orm { static_assert(!std::is_same::value, "All references must have the same type"); foreign_key_t(columns_type columns_, references_type references_) : - columns(move(columns_)), references(move(references_)), + columns(std::move(columns_)), references(std::move(references_)), on_update(*this, true, foreign_key_action::none), on_delete(*this, false, foreign_key_action::none) {} foreign_key_t(const self& other) : @@ -298,13 +298,13 @@ namespace sqlite_orm { */ template struct foreign_key_intermediate_t { - using tuple_type = std::tuple; + using tuple_type = mpl::tuple; tuple_type columns; template - foreign_key_t, std::tuple> references(Rs... refs) { - return {std::move(this->columns), std::make_tuple(std::forward(refs)...)}; + foreign_key_t, mpl::tuple> references(Rs... refs) { + return {std::move(this->columns), mpl::make_tuple(std::forward(refs)...)}; } }; #endif @@ -449,7 +449,7 @@ namespace sqlite_orm { */ template internal::foreign_key_intermediate_t foreign_key(Cs... columns) { - return {std::make_tuple(std::forward(columns)...)}; + return {mpl::make_tuple(std::forward(columns)...)}; } #endif @@ -458,7 +458,7 @@ namespace sqlite_orm { */ template internal::unique_t unique(Args... args) { - return {std::make_tuple(std::forward(args)...)}; + return {mpl::make_tuple(std::forward(args)...)}; } inline internal::unique_t<> unique() { @@ -471,7 +471,7 @@ namespace sqlite_orm { template internal::primary_key_t primary_key(Cs... cs) { - return {std::make_tuple(std::forward(cs)...)}; + return {mpl::make_tuple(std::forward(cs)...)}; } inline internal::primary_key_t<> primary_key() { diff --git a/dev/core_functions.h b/dev/core_functions.h index a58cd1b3c..4db212115 100644 --- a/dev/core_functions.h +++ b/dev/core_functions.h @@ -1,12 +1,12 @@ #pragma once #include // std::string -#include // std::make_tuple, std::tuple_size #include // std::forward, std::is_base_of, std::enable_if #include // std::unique_ptr #include // std::vector #include "functional/cxx_type_traits_polyfill.h" +#include "functional/tuple.h" #include "conditions.h" #include "is_base_of_template.h" #include "tuple_helper/tuple_filter.h" @@ -34,7 +34,7 @@ namespace sqlite_orm { struct built_in_function_t : S, arithmetic_t { using return_type = R; using string_type = S; - using args_type = std::tuple; + using args_type = mpl::tuple; static constexpr size_t args_size = std::tuple_size::value; @@ -662,7 +662,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t acos(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -678,7 +678,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t acos(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -690,7 +690,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t acosh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -706,7 +706,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t acosh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -718,7 +718,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t asin(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -734,7 +734,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t asin(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -746,7 +746,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t asinh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -762,7 +762,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t asinh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -774,7 +774,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t atan(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -790,7 +790,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t atan(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -802,7 +802,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t atan2(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -818,7 +818,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t atan2(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -830,7 +830,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t atanh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -846,7 +846,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t atanh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -858,7 +858,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ceil(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -874,7 +874,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ceil(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -886,7 +886,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ceiling(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -902,7 +902,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ceiling(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -914,7 +914,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t cos(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -930,7 +930,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t cos(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -942,7 +942,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t cosh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -958,7 +958,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t cosh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -970,7 +970,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t degrees(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -986,7 +986,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t degrees(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -998,7 +998,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t exp(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1014,7 +1014,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t exp(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1026,7 +1026,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t floor(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1042,7 +1042,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t floor(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1054,7 +1054,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ln(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1070,7 +1070,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ln(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1082,7 +1082,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1098,7 +1098,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1110,7 +1110,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log10(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1126,7 +1126,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log10(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1138,7 +1138,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log(B b, X x) { - return {std::tuple{std::forward(b), std::forward(x)}}; + return {{std::forward(b), std::forward(x)}}; } /** @@ -1154,7 +1154,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log(B b, X x) { - return {std::tuple{std::forward(b), std::forward(x)}}; + return {{std::forward(b), std::forward(x)}}; } /** @@ -1166,7 +1166,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log2(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1182,7 +1182,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log2(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1194,7 +1194,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t mod_f(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -1210,7 +1210,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t mod_f(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -1249,7 +1249,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t pow(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -1265,7 +1265,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t pow(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -1277,7 +1277,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t power(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -1293,7 +1293,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t power(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -1305,7 +1305,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t radians(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1321,7 +1321,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t radians(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1333,7 +1333,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t sin(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1349,7 +1349,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t sin(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1361,7 +1361,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t sinh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1377,7 +1377,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t sinh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1389,7 +1389,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t sqrt(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1405,7 +1405,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t sqrt(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1417,7 +1417,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t tan(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1433,7 +1433,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t tan(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1445,7 +1445,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t tanh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1461,7 +1461,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t tanh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1473,7 +1473,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t trunc(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1489,7 +1489,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t trunc(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } #endif // SQLITE_ENABLE_MATH_FUNCTIONS /** @@ -1497,7 +1497,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t typeof_(T t) { - return {std::tuple{std::forward(t)}}; + return {{std::forward(t)}}; } /** @@ -1505,7 +1505,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t unicode(T t) { - return {std::tuple{std::forward(t)}}; + return {{std::forward(t)}}; } /** @@ -1513,7 +1513,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t length(T t) { - return {std::tuple{std::forward(t)}}; + return {{std::forward(t)}}; } /** @@ -1521,7 +1521,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t, internal::abs_string, T> abs(T t) { - return {std::tuple{std::forward(t)}}; + return {{std::forward(t)}}; } /** @@ -1529,7 +1529,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t lower(T t) { - return {std::tuple{std::forward(t)}}; + return {{std::forward(t)}}; } /** @@ -1537,7 +1537,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t upper(T t) { - return {std::tuple{std::forward(t)}}; + return {{std::forward(t)}}; } /** @@ -1566,7 +1566,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t trim(T t) { - return {std::tuple{std::forward(t)}}; + return {{std::forward(t)}}; } /** @@ -1574,7 +1574,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t trim(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -1582,7 +1582,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ltrim(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1590,7 +1590,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ltrim(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -1598,7 +1598,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t rtrim(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1606,7 +1606,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t rtrim(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -1614,7 +1614,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t hex(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1622,7 +1622,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t quote(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1630,7 +1630,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t, internal::randomblob_string, X> randomblob(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1638,7 +1638,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t instr(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -1647,9 +1647,9 @@ namespace sqlite_orm { template, internal::is_into>::value == 0, bool> = true> + std::enable_if_t, internal::is_into>::value == 0, bool> = true> internal::built_in_function_t replace(X x, Y y, Z z) { - return {std::tuple{std::forward(x), std::forward(y), std::forward(z)}}; + return {{std::forward(x), std::forward(y), std::forward(z)}}; } /** @@ -1657,7 +1657,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t round(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1665,7 +1665,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t round(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } #if SQLITE_VERSION_NUMBER >= 3007016 @@ -1675,7 +1675,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t char_(Args... args) { - return {std::make_tuple(std::forward(args)...)}; + return {{std::forward(args)...}}; } /** @@ -1698,7 +1698,7 @@ namespace sqlite_orm { polyfill::type_identity>::type, internal::coalesce_string, Args...> { - return {std::make_tuple(std::forward(args)...)}; + return {{std::forward(args)...}}; } /** @@ -1713,7 +1713,7 @@ namespace sqlite_orm { internal::ifnull_string, X, Y> { - return {std::make_tuple(std::move(x), std::move(y))}; + return {{std::move(x), std::move(y)}}; } /** @@ -1739,17 +1739,17 @@ namespace sqlite_orm { X, Y>; - return F{std::make_tuple(std::move(x), std::move(y))}; + return F{{std::move(x), std::move(y)}}; } else { using F = internal::built_in_function_t; - return F{std::make_tuple(std::move(x), std::move(y))}; + return F{{std::move(x), std::move(y)}}; } } #else template internal::built_in_function_t nullif(X x, Y y) { - return {std::make_tuple(std::move(x), std::move(y))}; + return {{std::move(x), std::move(y)}}; } #endif @@ -1758,7 +1758,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t date(Args... args) { - return {std::tuple{std::forward(args)...}}; + return {{std::forward(args)...}}; } /** @@ -1766,7 +1766,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t time(Args... args) { - return {std::tuple{std::forward(args)...}}; + return {{std::forward(args)...}}; } /** @@ -1774,7 +1774,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t datetime(Args... args) { - return {std::tuple{std::forward(args)...}}; + return {{std::forward(args)...}}; } /** @@ -1782,7 +1782,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t julianday(Args... args) { - return {std::tuple{std::forward(args)...}}; + return {{std::forward(args)...}}; } /** @@ -1790,7 +1790,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t strftime(Args... args) { - return {std::tuple{std::forward(args)...}}; + return {{std::forward(args)...}}; } /** @@ -1798,7 +1798,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t, internal::zeroblob_string, N> zeroblob(N n) { - return {std::tuple{std::forward(n)}}; + return {{std::forward(n)}}; } /** @@ -1806,7 +1806,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t substr(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -1814,7 +1814,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t substr(X x, Y y, Z z) { - return {std::tuple{std::forward(x), std::forward(y), std::forward(z)}}; + return {{std::forward(x), std::forward(y), std::forward(z)}}; } #ifdef SQLITE_SOUNDEX @@ -1823,7 +1823,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t soundex(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } #endif @@ -1832,7 +1832,7 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t total(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1840,7 +1840,7 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t, internal::sum_string, X> sum(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1848,7 +1848,7 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t count(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1872,7 +1872,7 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t avg(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1880,7 +1880,7 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t, internal::max_string, X> max(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1888,7 +1888,7 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t, internal::min_string, X> min(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1898,7 +1898,7 @@ namespace sqlite_orm { template internal::built_in_function_t, internal::max_string, X, Y, Rest...> max(X x, Y y, Rest... rest) { - return {std::tuple{std::forward(x), std::forward(y), std::forward(rest)...}}; + return {{std::forward(x), std::forward(y), std::forward(rest)...}}; } /** @@ -1908,7 +1908,7 @@ namespace sqlite_orm { template internal::built_in_function_t, internal::min_string, X, Y, Rest...> min(X x, Y y, Rest... rest) { - return {std::tuple{std::forward(x), std::forward(y), std::forward(rest)...}}; + return {{std::forward(x), std::forward(y), std::forward(rest)...}}; } /** @@ -1916,7 +1916,7 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t group_concat(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -1924,128 +1924,124 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t group_concat(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } #ifdef SQLITE_ENABLE_JSON1 template internal::built_in_function_t json(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_array(Args... args) { - return {std::tuple{std::forward(args)...}}; + return {{std::forward(args)...}}; } template internal::built_in_function_t json_array_length(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_array_length(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_array_length(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } template internal::built_in_function_t json_array_length(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } template internal::built_in_function_t json_extract(X x, Args... args) { - return {std::tuple{std::forward(x), std::forward(args)...}}; + return {{std::forward(x), std::forward(args)...}}; } template internal::built_in_function_t json_insert(X x, Args... args) { - static_assert(sizeof...(Args) % 2 == 0, - "number of arguments in json_insert must be odd"); - return {std::tuple{std::forward(x), std::forward(args)...}}; + static_assert(sizeof...(Args) % 2 == 0, "number of arguments in json_insert must be odd"); + return {{std::forward(x), std::forward(args)...}}; } template internal::built_in_function_t json_replace(X x, Args... args) { - static_assert(sizeof...(Args) % 2 == 0, - "number of arguments in json_replace must be odd"); - return {std::tuple{std::forward(x), std::forward(args)...}}; + static_assert(sizeof...(Args) % 2 == 0, "number of arguments in json_replace must be odd"); + return {{std::forward(x), std::forward(args)...}}; } template internal::built_in_function_t json_set(X x, Args... args) { - static_assert(sizeof...(Args) % 2 == 0, - "number of arguments in json_set must be odd"); - return {std::tuple{std::forward(x), std::forward(args)...}}; + static_assert(sizeof...(Args) % 2 == 0, "number of arguments in json_set must be odd"); + return {{std::forward(x), std::forward(args)...}}; } template internal::built_in_function_t json_object(Args... args) { - static_assert(sizeof...(Args) % 2 == 0, - "number of arguments in json_object must be even"); - return {std::tuple{std::forward(args)...}}; + static_assert(sizeof...(Args) % 2 == 0, "number of arguments in json_object must be even"); + return {{std::forward(args)...}}; } template internal::built_in_function_t json_patch(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } template internal::built_in_function_t json_remove(X x, Args... args) { - return {std::tuple{std::forward(x), std::forward(args)...}}; + return {{std::forward(x), std::forward(args)...}}; } template internal::built_in_function_t json_remove(X x, Args... args) { - return {std::tuple{std::forward(x), std::forward(args)...}}; + return {{std::forward(x), std::forward(args)...}}; } template internal::built_in_function_t json_type(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_type(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_type(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } template internal::built_in_function_t json_type(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } template internal::built_in_function_t json_valid(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_quote(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_group_array(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_group_object(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } #endif // SQLITE_ENABLE_JSON1 diff --git a/dev/expression.h b/dev/expression.h index 65297ab08..5c0fe105b 100644 --- a/dev/expression.h +++ b/dev/expression.h @@ -5,7 +5,7 @@ #include "functional/cxx_optional.h" #include "functional/cxx_universal.h" -#include "functional/tuple.h" // make_tuple +#include "functional/tuple.h" // make_tuple #include "operators.h" namespace sqlite_orm { diff --git a/dev/function.h b/dev/function.h index cfa7797a1..a6c2452ad 100644 --- a/dev/function.h +++ b/dev/function.h @@ -207,7 +207,7 @@ namespace sqlite_orm { using func_arg_t = mpl::element_at_t; using passed_arg_t = unpacked_arg_t>; -#ifdef SQLITE_ORM_RELAXED_CONSTEXPR +#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED constexpr bool valid = validate_pointer_value_type, unpacked_arg_t>>( diff --git a/dev/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index a5a4c76b5..5273be5a4 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -25,9 +25,11 @@ // Because we know what we are doing, we suppress the diagnostic message #define SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(...) SQLITE_ORM_CLANG_SUPPRESS("-Wmissing-braces", __VA_ARGS__) -#if defined(_MSC_VER) && (_MSC_VER < 1915) +#if defined(_MSC_VER) && !defined(__clang__) // MSVC +#if __cplusplus < 202002L #define SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 #endif +#endif #if defined(_MSC_VER) && (_MSC_VER < 1920) #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION diff --git a/dev/functional/cxx_core_features.h b/dev/functional/cxx_core_features.h index b54641916..68bbc3e0c 100644 --- a/dev/functional/cxx_core_features.h +++ b/dev/functional/cxx_core_features.h @@ -24,7 +24,10 @@ #endif #if __cpp_constexpr >= 201304L -#define SQLITE_ORM_RELAXED_CONSTEXPR +#define SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED +#define SQLITE_ORM_NONCONST_CONSTEXPR constexpr +#else +#define SQLITE_ORM_NONCONST_CONSTEXPR #endif #if __cpp_noexcept_function_type >= 201510L diff --git a/dev/functional/indexed_type.h b/dev/functional/indexed_type.h new file mode 100644 index 000000000..3f0503104 --- /dev/null +++ b/dev/functional/indexed_type.h @@ -0,0 +1,23 @@ +#pragma once + +#include "cxx_universal.h" + +namespace _sqlite_orm { + // short names defined in a short namespace to reduce symbol lengths, + // since those types are used as a building block; + // (as seen in boost hana) + + template + struct indexed_type { + using type = T; + }; +} + +namespace sqlite_orm { + namespace internal { + namespace mpl { + + using _sqlite_orm::indexed_type; + } + } +} diff --git a/dev/functional/pack.h b/dev/functional/pack.h index 120e52036..a8b0c51ec 100644 --- a/dev/functional/pack.h +++ b/dev/functional/pack.h @@ -4,26 +4,10 @@ #include "cxx_universal.h" -namespace _sqlite_orm { - // short names defined in a short namespace to reduce symbol lengths, - // since those types are used as a building block; - // (as seen in boost hana) - - template - struct indexed_type { - using type = T; - }; -} - namespace sqlite_orm { namespace internal { namespace mpl { - using _sqlite_orm::indexed_type; - - template - indexed_type get_indexed_type(const indexed_type&); - template struct pack { static constexpr size_t size() { diff --git a/dev/functional/tuple.h b/dev/functional/tuple.h index e7fd810cf..75be2d01d 100644 --- a/dev/functional/tuple.h +++ b/dev/functional/tuple.h @@ -1,12 +1,14 @@ #pragma once -#include // std::integral_constant, std::decay, std::is_constructible, std::is_default_constructible, std::enable_if +#include // std::integral_constant, std::decay, std::is_constructible, std::is_default_constructible, std::enable_if, std::declval #include // std::move, std::forward #include "cxx_universal.h" #include "cxx_type_traits_polyfill.h" #include "fast_and.h" +#include "indexed_type.h" #include "type_at.h" +#include "tuple_common.h" namespace _sqlite_orm { // short names defined in a short namespace to reduce symbol lengths, @@ -16,8 +18,8 @@ namespace _sqlite_orm { /* * storage element of a tuple */ - template::value && !std::is_final::value> - struct SQLITE_ORM_MSVC_EMPTYBASES tuplem : indexed_type { + template::value && !std::is_final::value> + struct SQLITE_ORM_MSVC_EMPTYBASES tuplem : indexed_type { X data; constexpr tuplem() : data() {} @@ -29,8 +31,8 @@ namespace _sqlite_orm { /* * storage element of a tuple, using EBO */ - template - struct SQLITE_ORM_MSVC_EMPTYBASES tuplem : X, indexed_type { + template + struct SQLITE_ORM_MSVC_EMPTYBASES tuplem : X, indexed_type { constexpr tuplem() = default; @@ -38,28 +40,28 @@ namespace _sqlite_orm { constexpr tuplem(Y&& y) : X(std::forward(y)) {} }; - template - constexpr const X& ebo_get(const tuplem& elem) { + template + constexpr const X& ebo_get(const tuplem& elem) { return (elem.data); } - template - constexpr X& ebo_get(tuplem& elem) { + template + constexpr X& ebo_get(tuplem& elem) { return (elem.data); } - template - constexpr X&& ebo_get(tuplem&& elem) { + template + constexpr X&& ebo_get(tuplem&& elem) { return std::forward(elem.data); } - template - constexpr const X& ebo_get(const tuplem& elem) { + template + constexpr const X& ebo_get(const tuplem& elem) { return elem; } - template - constexpr X& ebo_get(tuplem& elem) { + template + constexpr X& ebo_get(tuplem& elem) { return elem; } - template - constexpr X&& ebo_get(tuplem&& elem) { + template + constexpr X&& ebo_get(tuplem&& elem) { return std::forward(elem); } } @@ -76,22 +78,6 @@ namespace sqlite_orm { template struct tuple; - template - struct remove_rvalue_reference { - using type = T; - }; - template - struct remove_rvalue_reference { - using type = T; - }; - template - using remove_rvalue_reference_t = typename remove_rvalue_reference::type; - - struct from_variadic_t {}; - - template - struct enable_tuple_ctor; - template struct enable_tuple_ctor, Void...> : std::enable_if), bool> {}; @@ -100,16 +86,10 @@ namespace sqlite_orm { struct enable_tuple_ctor, Void...> : std::enable_if), bool> {}; - template - struct enable_tuple_variadic_ctor; - template struct enable_tuple_variadic_ctor, Y...> : std::enable_if), bool> {}; - template - struct enable_tuple_nonconst_copy_ctor; - #ifdef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 template struct enable_tuple_nonconst_copy_ctor, tuple, Void...> @@ -122,7 +102,7 @@ namespace sqlite_orm { } } - namespace mpl = mpl; + namespace mpl = internal::mpl; } // retain stl tuple interface for `tuple` @@ -130,9 +110,16 @@ namespace std { template struct tuple_size; + template + struct tuple_element; + template struct tuple_size> : integral_constant {}; + template + struct tuple_element> : sqlite_orm::mpl::type_at> { + }; + template constexpr decltype(auto) get(const sqlite_orm::mpl::tuple& tpl) noexcept { using namespace sqlite_orm::mpl; @@ -165,20 +152,34 @@ namespace sqlite_orm { namespace internal { namespace mpl { - template - struct SQLITE_ORM_MSVC_EMPTYBASES basic_tuple, X...> : tuplem... { + template + struct SQLITE_ORM_MSVC_EMPTYBASES basic_tuple, X...> : tuplem... { constexpr basic_tuple() = default; // variadic constructor template - constexpr basic_tuple(from_variadic_t, Y&&... y) : tuplem(std::forward(y))... {} + constexpr basic_tuple(from_variadic_t, Y&&... y) : tuplem(std::forward(y))... {} // converting copy/move constructor template - constexpr basic_tuple(Other&& other) : tuplem(std::get(std::forward(other)))... {} + constexpr basic_tuple(Other&& other) : tuplem(ebo_get(std::forward(other)))... {} + // default copy constructor constexpr basic_tuple(const basic_tuple&) = default; + // default move constructor constexpr basic_tuple(basic_tuple&&) = default; + + // converting copy/move assignment + template + SQLITE_ORM_NONCONST_CONSTEXPR void operator=(Other&& other) { + int poormansfold[] = {(ebo_get(*this) = ebo_get(std::forward(other)), int{})...}; + (void)poormansfold; + } + + // default copy assignment + SQLITE_ORM_NONCONST_CONSTEXPR basic_tuple& operator=(const basic_tuple&) = default; + // default move assignment + SQLITE_ORM_NONCONST_CONSTEXPR basic_tuple& operator=(basic_tuple&&) = default; }; template<> @@ -191,10 +192,8 @@ namespace sqlite_orm { */ template struct tuple final : basic_tuple, X...> { - private: using base_type = basic_tuple, X...>; - public: // default constructor template::type = true> constexpr tuple() : base_type{} {} @@ -217,19 +216,41 @@ namespace sqlite_orm { template), bool> = true> constexpr tuple(tuple&& other) : base_type{std::move(other)} {} -#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + // default copy constructor constexpr tuple(const tuple&) = default; + // default move constructor constexpr tuple(tuple&&) = default; // non-const copy constructor. // The non-const copy constructor is required to make sure that // the converting tuple(Y&&...) constructor is _not_ preferred over the copy // constructor for unary tuples containing a type that is constructible from tuple<...>. +#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 constexpr tuple(tuple& other) : base_type{const_cast(other)} {} #else template::type = true> constexpr tuple(Other& other) : base_type{const_cast(other)} {} #endif + + // converting copy assignment + template), bool> = true> + SQLITE_ORM_NONCONST_CONSTEXPR tuple& operator=(const tuple& other) { + base_type::operator=(other); + return *this; + } + + // converting move assignment + template), bool> = true> + SQLITE_ORM_NONCONST_CONSTEXPR tuple& operator=(tuple&& other) { + base_type::operator=(std::move(other)); + return *this; + } + + // default copy assignment + SQLITE_ORM_NONCONST_CONSTEXPR tuple& operator=(const tuple&) = default; + // default move assignment + SQLITE_ORM_NONCONST_CONSTEXPR tuple& operator=(tuple&&) = default; }; namespace adl { @@ -240,11 +261,25 @@ namespace sqlite_orm { template constexpr tuple forward_as_tuple(X&&... args) noexcept { - return tuple(_STD forward(args)...); + return tuple{std::forward(args)...}; + } + + template + constexpr tuple tie(X&... args) noexcept { + return tuple{args...}; } } using adl::forward_as_tuple; using adl::make_tuple; + using adl::tie; + } + } +} + +// ops +namespace sqlite_orm { + namespace internal { + namespace mpl { // implementation note: we could derive from `type_at` but leverage the fact that `tuple` is derived from `indexed_type` template @@ -253,6 +288,38 @@ namespace sqlite_orm { using forwarded_t = decltype(ebo_get(std::declval>())); using type = remove_rvalue_reference_t; }; + +#ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED + template + constexpr bool equal_indexable([[maybe_unused]] const tuple& left, + [[maybe_unused]] const tuple& right, + std::index_sequence) { + return ((ebo_get(left) == ebo_get(right)) && ...); + } +#else + template + constexpr bool equal_indexable(const tuple&, const tuple&, std::index_sequence<>) { + return true; + } + template + constexpr bool + equal_indexable(const tuple& left, const tuple& right, std::index_sequence) { + return (ebo_get(left) == ebo_get(right)) && + equal_indexable(left, right, std::index_sequence{}); + } +#endif + + template + constexpr bool operator==(const tuple& left, const tuple& right) { + static_assert(sizeof...(X) == sizeof...(Y), "cannot compare tuples of different sizes"); + return equal_indexable(left, right, std::make_index_sequence{}); + } + + template + constexpr bool operator!=(const tuple& left, const tuple& right) { + static_assert(sizeof...(X) == sizeof...(Y), "cannot compare tuples of different sizes"); + return !equal_indexable(left, right, std::make_index_sequence{}); + } } } } diff --git a/dev/functional/tuple_common.h b/dev/functional/tuple_common.h index 602ae53d8..5dfc7e91e 100644 --- a/dev/functional/tuple_common.h +++ b/dev/functional/tuple_common.h @@ -1,21 +1,39 @@ #pragma once +#include // std::is_empty, std::is_final -#include // std::enable_if, std::is_constructible - -#include "fast_and.h" +namespace _sqlite_orm { + template + constexpr bool is_ebo_able_v = std::is_empty::value && !std::is_final::value; +} namespace sqlite_orm { namespace internal { namespace mpl { + using _sqlite_orm::is_ebo_able_v; template - struct enable_tuple_variadic_ctor {}; + struct enable_tuple_variadic_ctor; + + template + struct enable_tuple_ctor; + + template + struct enable_tuple_nonconst_copy_ctor; + + struct from_variadic_t {}; - template - struct enable_tuple_variadic_ctor, Y...> - : std::enable_if), bool> {}; + template + struct remove_rvalue_reference { + using type = T; + }; + template + struct remove_rvalue_reference { + using type = T; + }; + template + using remove_rvalue_reference_t = typename remove_rvalue_reference::type; } } - namespace mpl = mpl; + namespace mpl = internal::mpl; } diff --git a/dev/functional/type_at.h b/dev/functional/type_at.h index e08ac8418..56c8fa95a 100644 --- a/dev/functional/type_at.h +++ b/dev/functional/type_at.h @@ -4,6 +4,7 @@ #include #include "cxx_universal.h" +#include "indexed_type.h" #include "pack.h" namespace sqlite_orm { @@ -14,8 +15,11 @@ namespace sqlite_orm { template struct indexer; - template - struct indexer, T...> : indexed_type... {}; + template + struct indexer, T...> : indexed_type... {}; + + template + indexed_type get_indexed_type(const indexed_type&); #endif template diff --git a/dev/functional/unique_tuple.h b/dev/functional/unique_tuple.h index c66d3e197..25965e830 100644 --- a/dev/functional/unique_tuple.h +++ b/dev/functional/unique_tuple.h @@ -7,6 +7,7 @@ #include "cxx_type_traits_polyfill.h" #include "fast_and.h" #include "type_at.h" +#include "tuple_common.h" namespace _sqlite_orm { // short names defined in a short namespace to reduce symbol lengths, @@ -16,7 +17,7 @@ namespace _sqlite_orm { /* * storage element of a unique tuple */ - template::value && !std::is_final::value> + template> struct uplem { X data; @@ -38,27 +39,27 @@ namespace _sqlite_orm { constexpr uplem(Y&& y) : X(std::forward(y)) {} }; - template + template>> constexpr const X& ebo_get(const uplem& elem) { return (elem.data); } - template + template, bool> = true> constexpr X& ebo_get(uplem& elem) { return (elem.data); } - template + template, bool> = true> constexpr X&& ebo_get(uplem&& elem) { return std::forward(elem.data); } - template + template, bool> = true> constexpr const X& ebo_get(const uplem& elem) { return elem; } - template + template, bool> = true> constexpr X& ebo_get(uplem& elem) { return elem; } - template + template, bool> = true> constexpr X&& ebo_get(uplem&& elem) { return std::forward(elem); } @@ -73,9 +74,6 @@ namespace sqlite_orm { template struct uple; - template - struct enable_tuple_ctor; - template struct enable_tuple_ctor, Void...> : std::enable_if), bool> {}; @@ -84,16 +82,10 @@ namespace sqlite_orm { struct enable_tuple_ctor, Void...> : std::enable_if), bool> {}; - template - struct enable_tuple_variadic_ctor; - - template + template struct enable_tuple_variadic_ctor, Y...> : std::enable_if), bool> {}; - template - struct enable_tuple_nonconst_copy_ctor; - #ifdef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 template struct enable_tuple_nonconst_copy_ctor, uple, Void...> @@ -106,7 +98,7 @@ namespace sqlite_orm { } } - namespace mpl = mpl; + namespace mpl = internal::mpl; } // retain stl tuple interface for `uple` @@ -114,49 +106,52 @@ namespace std { template struct tuple_size; + template + struct tuple_element; + template struct tuple_size> : integral_constant {}; + template + struct tuple_element> : sqlite_orm::mpl::type_at> {}; + template constexpr decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { using namespace sqlite_orm::mpl; - using uplem_t = uplem>; - return ebo_get(static_cast(tpl)); + using type = type_at_t; + return ebo_get(static_cast&>(tpl)); } template constexpr decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { using namespace sqlite_orm::mpl; - using uplem_t = uplem>; - return ebo_get(static_cast(tpl)); + using type = type_at_t; + return ebo_get(static_cast&>(tpl)); } template constexpr decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { using namespace sqlite_orm::mpl; - using uplem_t = uplem>; - return ebo_get(static_cast(tpl)); + using type = type_at_t; + return ebo_get(static_cast&&>(tpl)); } template constexpr decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { - using sqlite_orm::mpl::uplem; - using uplem_t = uplem; - return ebo_get(static_cast(tpl)); + using namespace sqlite_orm::mpl; + return ebo_get(static_cast&>(tpl)); } template constexpr decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { - using sqlite_orm::mpl::uplem; - using uplem_t = uplem; - return ebo_get(static_cast(tpl)); + using namespace sqlite_orm::mpl; + return ebo_get(static_cast&>(tpl)); } template constexpr decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { - using sqlite_orm::mpl::uplem; - using uplem_t = uplem; - return ebo_get(static_cast(tpl)); + using namespace sqlite_orm::mpl; + return ebo_get(static_cast&&>(tpl)); } } @@ -190,25 +185,49 @@ namespace sqlite_orm { // converting copy constructor template), bool> = true> - constexpr uple(const uple& other) : uplem(std::get(other))... {} + constexpr uple(const uple& other) : uplem(ebo_get(other))... {} // converting move constructor template), bool> = true> - constexpr uple(uple&& other) : uplem(std::get(std::move(other)))... {} + constexpr uple(uple&& other) : uplem(ebo_get(std::move(other)))... {} -#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + // default copy constructor constexpr uple(const uple&) = default; + // default move constructor constexpr uple(uple&&) = default; // non-const copy constructor. // The non-const copy constructor is required to make sure that // the converting uple(Y&&...) constructor is _not_ preferred over the copy // constructor for unary tuples containing a type that is constructible from uple<...>. - constexpr uple(uple& other) : uplem(std::get(const_cast(other)))... {} +#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + constexpr uple(uple& other) : uplem(ebo_get(const_cast(other)))... {} #else template::type = true> - constexpr uple(Other& other) : uplem(std::get(const_cast(other)))... {} + constexpr uple(Other& other) : uplem(ebo_get(const_cast(other)))... {} #endif + + // converting copy assignment + template), bool> = true> + SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(const uple& other) { + int poormansfold[] = {(ebo_get(*this) = ebo_get(other), int{})...}; + (void)poormansfold; + return *this; + } + + // converting move assignment + template), bool> = true> + SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(uple&& other) { + int poormansfold[] = {(ebo_get(*this) = ebo_get(std::move(other)), int{})...}; + (void)poormansfold; + return *this; + } + + // default copy assignment + SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(const uple&) = default; + // default move assignment + SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(uple&&) = default; }; template @@ -218,11 +237,63 @@ namespace sqlite_orm { template constexpr uple forward_as_unique_tuple(X&&... args) noexcept { - return uple(_STD forward(args)...); + return uple{std::forward(args)...}; } - template + template + constexpr uple tie_unique(X&... args) noexcept { + return uple{args...}; + } + } + } +} + +// ops +namespace sqlite_orm { + namespace internal { + namespace mpl { + + template struct type_at> : type_at {}; + +#ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED + template = true> + constexpr bool equal_indexable([[maybe_unused]] const uple& left, + [[maybe_unused]] const uple& right, + std::index_sequence) { + return ((ebo_get(left) == ebo_get(right)) && ...); + } + + template = true> + constexpr bool equal_indexable([[maybe_unused]] const uple& left, + [[maybe_unused]] const uple& right, + std::index_sequence) { + return ((std::get(left) == std::get(right)) && ...); + } +#else + template + constexpr bool equal_indexable(const uple&, const uple&, std::index_sequence<>) { + return true; + } + template + constexpr bool + equal_indexable(const uple& left, const uple& right, std::index_sequence) { + return (std::get(left) == std::get(right)) && + equal_indexable(left, right, std::index_sequence{}); + } +#endif + + template + constexpr bool operator==(const uple& left, const uple& right) { + static_assert(sizeof...(X) == sizeof...(Y), "cannot compare tuples of different sizes"); + return equal_indexable(left, right, std::make_index_sequence{}); + } + + template + constexpr bool operator!=(const uple& left, const uple& right) { + static_assert(sizeof...(X) == sizeof...(Y), "cannot compare tuples of different sizes"); + return !equal_indexable(left, right, std::make_index_sequence{}); + } } } } diff --git a/dev/node_tuple.h b/dev/node_tuple.h index 33bcfacc3..7f34c021e 100644 --- a/dev/node_tuple.h +++ b/dev/node_tuple.h @@ -55,7 +55,7 @@ namespace sqlite_orm { }; template - struct node_tuple, std::tuple>, void> + struct node_tuple, mpl::tuple>, void> : node_tuple> {}; template diff --git a/dev/select_constraints.h b/dev/select_constraints.h index 8f31e467a..91cc54a28 100644 --- a/dev/select_constraints.h +++ b/dev/select_constraints.h @@ -7,6 +7,7 @@ #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" +#include "functional/tuple.h" #include "is_base_of_template.h" #include "tuple_helper/tuple_filter.h" #include "optional_container.h" @@ -62,7 +63,7 @@ namespace sqlite_orm { template struct columns_t { - using columns_type = std::tuple; + using columns_type = mpl::tuple; columns_type columns; bool distinct = false; @@ -70,7 +71,7 @@ namespace sqlite_orm { static constexpr int count = std::tuple_size::value; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - columns_t(columns_type columns) : columns{move(columns)} {} + columns_t(columns_type columns) : columns{std::move(columns)} {} #endif }; @@ -82,7 +83,7 @@ namespace sqlite_orm { template struct set_t { - using assigns_type = std::tuple; + using assigns_type = mpl::tuple; assigns_type assigns; }; @@ -136,14 +137,15 @@ namespace sqlite_orm { template struct select_t { using return_type = T; - using conditions_type = std::tuple; + using conditions_type = mpl::tuple; return_type col; conditions_type conditions; bool highest_level = false; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - select_t(return_type col, conditions_type conditions) : col{std::move(col)}, conditions{move(conditions)} {} + select_t(return_type col, conditions_type conditions) : + col{std::move(col)}, conditions{std::move(conditions)} {} #endif }; @@ -297,8 +299,7 @@ namespace sqlite_orm { simple_case_builder> when(W w, then_t t) { using result_args_type = std::tuple>; std::pair newPair{std::move(w), std::move(t.expression)}; - result_args_type result_args = - std::tuple_cat(std::move(this->args), std::move(std::make_tuple(newPair))); + result_args_type result_args = std::tuple_cat(std::move(this->args), std::make_tuple(newPair)); std::get::value - 1>(result_args) = std::move(newPair); return {std::move(this->case_expression), std::move(result_args), std::move(this->else_expression)}; } @@ -366,16 +367,16 @@ namespace sqlite_orm { */ template internal::set_t set(Args... args) { - using arg_tuple = std::tuple; - static_assert(std::tuple_size::value == - internal::count_tuple::value, + using args_pack = mpl::pack; + static_assert(std::tuple_size::value == + internal::count_tuple::value, "set function accepts assign operators only"); - return {std::make_tuple(std::forward(args)...)}; + return {mpl::make_tuple(std::forward(args)...)}; } template internal::columns_t columns(Args... args) { - return {std::make_tuple(std::forward(args)...)}; + return {mpl::make_tuple(std::forward(args)...)}; } /** @@ -395,7 +396,7 @@ namespace sqlite_orm { internal::select_t select(T t, Args... args) { using args_tuple = std::tuple; internal::validate_conditions(); - return {std::move(t), std::make_tuple(std::forward(args)...)}; + return {std::move(t), mpl::make_tuple(std::forward(args)...)}; } /** diff --git a/dev/serializing_util.h b/dev/serializing_util.h index 98660a1ac..fc8a4e83f 100644 --- a/dev/serializing_util.h +++ b/dev/serializing_util.h @@ -13,6 +13,7 @@ #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" +#include "functional/tuple.h" #include "functional/type_at.h" #include "tuple_helper/tuple_iteration.h" #include "error_code.h" @@ -195,7 +196,7 @@ namespace sqlite_orm { template std::ostream& operator<<( std::ostream& ss, - mpl::tuple&, const std::tuple...>&, Ctx> tpl) { + mpl::tuple&, const mpl::tuple...>&, Ctx> tpl) { const auto& args = std::get<1>(tpl); auto& context = std::get<2>(tpl); diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 6d0c06431..e59046a87 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -15,6 +15,7 @@ #include "functional/cxx_universal.h" #include "functional/cxx_functional_polyfill.h" #include "functional/mpl.h" +#include "functional/pack.h" #include "functional/type_at.h" #include "tuple_helper/tuple_filter.h" #include "ast/upsert_clause.h" @@ -212,9 +213,9 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, std::tuple>, void> { - using statement_type = upsert_clause, std::tuple>; + template + struct statement_serializer> { + using statement_type = T; template std::string operator()(const statement_type& statement, const Ctx& context) const { @@ -836,9 +837,9 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, std::tuple>, void> { - using statement_type = foreign_key_t, std::tuple>; + template + struct statement_serializer> { + using statement_type = FK; template std::string operator()(const statement_type& fk, const Ctx& context) const { @@ -1436,7 +1437,7 @@ namespace sqlite_orm { table_name_collector collector([&context](const std::type_index& ti) { return find_table_name(context.db_objects, ti); }); - constexpr bool explicitFromItemsCount = count_tuple, is_from>::value; + constexpr bool explicitFromItemsCount = count_tuple, is_from>::value; if(!explicitFromItemsCount) { iterate_ast(sel.col, collector); iterate_ast(sel.conditions, collector); @@ -1528,17 +1529,15 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, void> { - using statement_type = from_t; + template + struct statement_serializer> { + using statement_type = T; template std::string operator()(const statement_type&, const Ctx& context) const { - using tuple = std::tuple; - std::stringstream ss; ss << "FROM "; - iterate_tuple([&context, &ss, first = true](auto* item) mutable { + iterate_tuple([&context, &ss, first = true](auto* item) mutable { using from_type = std::remove_pointer_t; constexpr std::array sep = {", ", ""}; diff --git a/dev/tuple_helper/index_sequence_util.h b/dev/tuple_helper/index_sequence_util.h index 34341bac8..556c21142 100644 --- a/dev/tuple_helper/index_sequence_util.h +++ b/dev/tuple_helper/index_sequence_util.h @@ -3,7 +3,7 @@ #include // std::index_sequence, std::make_index_sequence #include "../functional/cxx_universal.h" -#ifdef SQLITE_ORM_RELAXED_CONSTEXPR +#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED #include #endif @@ -17,7 +17,7 @@ namespace sqlite_orm { return I; } -#ifdef SQLITE_ORM_RELAXED_CONSTEXPR +#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED /** * Reorder the values of an index_sequence according to the positions from a second sequence. */ diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index a578dbc8b..bd390af22 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -58,7 +58,10 @@ using std::nullptr_t; #endif #if __cpp_constexpr >= 201304L -#define SQLITE_ORM_RELAXED_CONSTEXPR +#define SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED +#define SQLITE_ORM_NONCONST_CONSTEXPR constexpr +#else +#define SQLITE_ORM_NONCONST_CONSTEXPR #endif #if __cpp_noexcept_function_type >= 201510L @@ -143,9 +146,11 @@ using std::nullptr_t; // Because we know what we are doing, we suppress the diagnostic message #define SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(...) SQLITE_ORM_CLANG_SUPPRESS("-Wmissing-braces", __VA_ARGS__) -#if defined(_MSC_VER) && (_MSC_VER < 1915) +#if defined(_MSC_VER) && !defined(__clang__) // MSVC +#if __cplusplus < 202002L #define SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 #endif +#endif #if defined(_MSC_VER) && (_MSC_VER < 1920) #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION @@ -662,8 +667,7 @@ namespace sqlite_orm { #include // std::system_error #include // std::ostream #include // std::string -#include // std::tuple, std::make_tuple -#include // std::is_base_of, std::false_type, std::true_type +#include // std::is_base_of, std::false_type // #include "functional/cxx_universal.h" @@ -977,47 +981,9 @@ namespace sqlite_orm { } } -// #include "tuple_helper/same_or_void.h" - -namespace sqlite_orm { - namespace internal { - - /** - * Accepts any number of arguments and evaluates `type` alias as T if all arguments are the same or void otherwise - */ - template - struct same_or_void { - using type = void; - }; - - template - struct same_or_void { - using type = A; - }; - - template - struct same_or_void { - using type = A; - }; - - template - struct same_or_void : same_or_void {}; - - } -} - -// #include "tuple_helper/tuple_traits.h" - -#include // std::is_same -#include - -// #include "../functional/cxx_type_traits_polyfill.h" - -// #include "../functional/mpl.h" - -// #include "../functional/unique_tuple.h" +// #include "functional/tuple.h" -#include // std::integral_constant, std::decay, std::is_constructible, std::is_default_constructible, std::enable_if +#include // std::integral_constant, std::decay, std::is_constructible, std::is_default_constructible, std::enable_if, std::declval #include // std::move, std::forward // #include "cxx_universal.h" @@ -1049,14 +1015,7 @@ namespace sqlite_orm { #define SQLITE_ORM_FAST_AND(...) polyfill::conjunction<__VA_ARGS__...>::value #endif -// #include "type_at.h" - -#include // std::integral_constant, std::index_sequence, std::make_index_sequence -#include - -// #include "cxx_universal.h" - -// #include "pack.h" +// #include "indexed_type.h" // #include "cxx_universal.h" @@ -1076,9 +1035,28 @@ namespace sqlite_orm { namespace mpl { using _sqlite_orm::indexed_type; + } + } +} - template - indexed_type get_indexed_type(const indexed_type&); +// #include "type_at.h" + +#include // std::integral_constant, std::index_sequence, std::make_index_sequence +#include + +// #include "cxx_universal.h" + +// #include "indexed_type.h" + +// #include "pack.h" + +#include // std::integral_constant + +// #include "cxx_universal.h" + +namespace sqlite_orm { + namespace internal { + namespace mpl { template struct pack { @@ -1092,6 +1070,15 @@ namespace sqlite_orm { namespace mpl = internal::mpl; } +// retain stl tuple interface for `tuple` +namespace std { + template + struct tuple_size; + + template + struct tuple_size> : integral_constant {}; +} + namespace sqlite_orm { namespace internal { namespace mpl { @@ -1100,8 +1087,11 @@ namespace sqlite_orm { template struct indexer; - template - struct indexer, T...> : indexed_type... {}; + template + struct indexer, T...> : indexed_type... {}; + + template + indexed_type get_indexed_type(const indexed_type&); #endif template @@ -1136,10 +1126,45 @@ namespace sqlite_orm { namespace mpl = internal::mpl; } -// retain stl tuple interface for `tuple` -namespace std { - template - struct tuple_size> : integral_constant {}; +// #include "tuple_common.h" + +#include // std::is_empty, std::is_final + +namespace _sqlite_orm { + template + constexpr bool is_ebo_able_v = std::is_empty::value && !std::is_final::value; +} + +namespace sqlite_orm { + namespace internal { + namespace mpl { + using _sqlite_orm::is_ebo_able_v; + + template + struct enable_tuple_variadic_ctor; + + template + struct enable_tuple_ctor; + + template + struct enable_tuple_nonconst_copy_ctor; + + struct from_variadic_t {}; + + template + struct remove_rvalue_reference { + using type = T; + }; + template + struct remove_rvalue_reference { + using type = T; + }; + template + using remove_rvalue_reference_t = typename remove_rvalue_reference::type; + } + } + + namespace mpl = internal::mpl; } namespace _sqlite_orm { @@ -1148,52 +1173,52 @@ namespace _sqlite_orm { // (as seen in boost hana) /* - * storage element of a unique tuple + * storage element of a tuple */ - template::value && !std::is_final::value> - struct uplem { + template::value && !std::is_final::value> + struct SQLITE_ORM_MSVC_EMPTYBASES tuplem : indexed_type { X data; - constexpr uplem() : data() {} + constexpr tuplem() : data() {} template - constexpr uplem(Y&& y) : data(std::forward(y)) {} + constexpr tuplem(Y&& y) : data(std::forward(y)) {} }; /* - * storage element of a unique tuple, using EBO + * storage element of a tuple, using EBO */ - template - struct uplem : X { + template + struct SQLITE_ORM_MSVC_EMPTYBASES tuplem : X, indexed_type { - constexpr uplem() = default; + constexpr tuplem() = default; template - constexpr uplem(Y&& y) : X(std::forward(y)) {} + constexpr tuplem(Y&& y) : X(std::forward(y)) {} }; - template - constexpr const X& ebo_get(const uplem& elem) { + template + constexpr const X& ebo_get(const tuplem& elem) { return (elem.data); } - template - constexpr X& ebo_get(uplem& elem) { + template + constexpr X& ebo_get(tuplem& elem) { return (elem.data); } - template - constexpr X&& ebo_get(uplem&& elem) { + template + constexpr X&& ebo_get(tuplem&& elem) { return std::forward(elem.data); } - template - constexpr const X& ebo_get(const uplem& elem) { + template + constexpr const X& ebo_get(const tuplem& elem) { return elem; } - template - constexpr X& ebo_get(uplem& elem) { + template + constexpr X& ebo_get(tuplem& elem) { return elem; } - template - constexpr X&& ebo_get(uplem&& elem) { + template + constexpr X&& ebo_get(tuplem&& elem) { return std::forward(elem); } } @@ -1202,158 +1227,352 @@ namespace sqlite_orm { namespace internal { namespace mpl { using ::_sqlite_orm::ebo_get; - using ::_sqlite_orm::uplem; + using ::_sqlite_orm::tuplem; - template - struct uple; + template + struct basic_tuple; - template - struct enable_tuple_ctor; + template + struct tuple; template - struct enable_tuple_ctor, Void...> + struct enable_tuple_ctor, Void...> : std::enable_if), bool> {}; template - struct enable_tuple_ctor, Void...> + struct enable_tuple_ctor, Void...> : std::enable_if), bool> {}; - template - struct enable_tuple_variadic_ctor; - - template - struct enable_tuple_variadic_ctor, Y...> + template + struct enable_tuple_variadic_ctor, Y...> : std::enable_if), bool> {}; - template - struct enable_tuple_nonconst_copy_ctor; - #ifdef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 template - struct enable_tuple_nonconst_copy_ctor, uple, Void...> + struct enable_tuple_nonconst_copy_ctor, tuple, Void...> : std::enable_if), bool> {}; template - struct enable_tuple_nonconst_copy_ctor, const uple, Void...> + struct enable_tuple_nonconst_copy_ctor, const tuple, Void...> : std::enable_if), bool> {}; #endif } } - namespace mpl = mpl; + namespace mpl = internal::mpl; } -// retain stl tuple interface for `uple` +// retain stl tuple interface for `tuple` namespace std { + template + struct tuple_size; + + template + struct tuple_element; + template - struct tuple_size> : integral_constant {}; + struct tuple_size> : integral_constant {}; template - constexpr decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { + struct tuple_element> : sqlite_orm::mpl::type_at> { + }; + + template + constexpr decltype(auto) get(const sqlite_orm::mpl::tuple& tpl) noexcept { using namespace sqlite_orm::mpl; - using uplem_t = uplem>; - return ebo_get(static_cast(tpl)); + return ebo_get(tpl); } template - constexpr decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::tuple& tpl) noexcept { using namespace sqlite_orm::mpl; - using uplem_t = uplem>; - return ebo_get(static_cast(tpl)); + return ebo_get(tpl); } template - constexpr decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::tuple&& tpl) noexcept { using namespace sqlite_orm::mpl; - using uplem_t = uplem>; - return ebo_get(static_cast(tpl)); + return ebo_get(std::move(tpl)); } template - constexpr decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { - using sqlite_orm::mpl::uplem; - using uplem_t = uplem; - return ebo_get(static_cast(tpl)); - } + decltype(auto) get(const sqlite_orm::mpl::tuple&) noexcept = delete; template - constexpr decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { - using sqlite_orm::mpl::uplem; - using uplem_t = uplem; - return ebo_get(static_cast(tpl)); - } + decltype(auto) get(sqlite_orm::mpl::tuple&) noexcept = delete; template - constexpr decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { - using sqlite_orm::mpl::uplem; - using uplem_t = uplem; - return ebo_get(static_cast(tpl)); - } + decltype(auto) get(sqlite_orm::mpl::tuple&&) noexcept = delete; } namespace sqlite_orm { namespace internal { namespace mpl { + template + struct SQLITE_ORM_MSVC_EMPTYBASES basic_tuple, X...> : tuplem... { + constexpr basic_tuple() = default; + + // variadic constructor + template + constexpr basic_tuple(from_variadic_t, Y&&... y) : tuplem(std::forward(y))... {} + + // converting copy/move constructor + template + constexpr basic_tuple(Other&& other) : tuplem(ebo_get(std::forward(other)))... {} + + // default copy constructor + constexpr basic_tuple(const basic_tuple&) = default; + // default move constructor + constexpr basic_tuple(basic_tuple&&) = default; + + // converting copy/move assignment + template + SQLITE_ORM_NONCONST_CONSTEXPR void operator=(Other&& other) { + int poormansfold[] = {(ebo_get(*this) = ebo_get(std::forward(other)), int{})...}; + (void)poormansfold; + } + + // default copy assignment + SQLITE_ORM_NONCONST_CONSTEXPR basic_tuple& operator=(const basic_tuple&) = default; + // default move assignment + SQLITE_ORM_NONCONST_CONSTEXPR basic_tuple& operator=(basic_tuple&&) = default; + }; + template<> - struct uple<> final { - constexpr uple() = default; + struct tuple<> final { + constexpr tuple() = default; }; /* - * unique tuple, which allows only distinct types. + * tuple */ template - struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { + struct tuple final : basic_tuple, X...> { + using base_type = basic_tuple, X...>; + // default constructor - template::type = true> - constexpr uple() {} + template::type = true> + constexpr tuple() : base_type{} {} // direct constructor - template::type = true> - constexpr uple(const X&... x) : uplem(x)... {} + template::type = true> + constexpr tuple(const X&... x) : base_type{from_variadic_t{}, x...} {} // converting constructor template::type = true> - constexpr uple(Y&&... y) : uplem(std::forward(y))... {} + typename enable_tuple_variadic_ctor::type = true> + constexpr tuple(Y&&... y) : base_type{from_variadic_t{}, std::forward(y)...} {} // converting copy constructor template), bool> = true> - constexpr uple(const uple& other) : uplem(std::get(other))... {} + constexpr tuple(const tuple& other) : base_type{other} {} // converting move constructor template), bool> = true> - constexpr uple(uple&& other) : uplem(std::get(std::move(other)))... {} + constexpr tuple(tuple&& other) : base_type{std::move(other)} {} -#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 - constexpr uple(const uple&) = default; - constexpr uple(uple&&) = default; + // default copy constructor + constexpr tuple(const tuple&) = default; + // default move constructor + constexpr tuple(tuple&&) = default; // non-const copy constructor. // The non-const copy constructor is required to make sure that - // the converting uple(Y&&...) constructor is _not_ preferred over the copy - // constructor for unary tuples containing a type that is constructible from uple<...>. - constexpr uple(uple& other) : uplem(std::get(const_cast(other)))... {} + // the converting tuple(Y&&...) constructor is _not_ preferred over the copy + // constructor for unary tuples containing a type that is constructible from tuple<...>. +#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + constexpr tuple(tuple& other) : base_type{const_cast(other)} {} #else - template::type = true> - constexpr uple(Other& other) : uplem(std::get(const_cast(other)))... {} + template::type = true> + constexpr tuple(Other& other) : base_type{const_cast(other)} {} #endif + + // converting copy assignment + template), bool> = true> + SQLITE_ORM_NONCONST_CONSTEXPR tuple& operator=(const tuple& other) { + base_type::operator=(other); + return *this; + } + + // converting move assignment + template), bool> = true> + SQLITE_ORM_NONCONST_CONSTEXPR tuple& operator=(tuple&& other) { + base_type::operator=(std::move(other)); + return *this; + } + + // default copy assignment + SQLITE_ORM_NONCONST_CONSTEXPR tuple& operator=(const tuple&) = default; + // default move assignment + SQLITE_ORM_NONCONST_CONSTEXPR tuple& operator=(tuple&&) = default; }; - template - constexpr auto make_unique_tuple(X&&... x) { - return uple...>{std::forward(x)...}; + namespace adl { + template + constexpr auto make_tuple(X&&... x) { + return tuple...>{std::forward(x)...}; + } + + template + constexpr tuple forward_as_tuple(X&&... args) noexcept { + return tuple{std::forward(args)...}; + } + + template + constexpr tuple tie(X&... args) noexcept { + return tuple{args...}; + } } + using adl::forward_as_tuple; + using adl::make_tuple; + using adl::tie; + } + } +} - template - struct type_at> : type_at {}; +// ops +namespace sqlite_orm { + namespace internal { + namespace mpl { + + // implementation note: we could derive from `type_at` but leverage the fact that `tuple` is derived from `indexed_type` + template + struct type_at> { + // implementation note: we could use `get_indexed_type()`, but `ebo_get` is readily available. + using forwarded_t = decltype(ebo_get(std::declval>())); + using type = remove_rvalue_reference_t; + }; + +#ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED + template + constexpr bool equal_indexable([[maybe_unused]] const tuple& left, + [[maybe_unused]] const tuple& right, + std::index_sequence) { + return ((ebo_get(left) == ebo_get(right)) && ...); + } +#else + template + constexpr bool equal_indexable(const tuple&, const tuple&, std::index_sequence<>) { + return true; + } + template + constexpr bool + equal_indexable(const tuple& left, const tuple& right, std::index_sequence) { + return (ebo_get(left) == ebo_get(right)) && + equal_indexable(left, right, std::index_sequence{}); + } +#endif + + template + constexpr bool operator==(const tuple& left, const tuple& right) { + static_assert(sizeof...(X) == sizeof...(Y), "cannot compare tuples of different sizes"); + return equal_indexable(left, right, std::make_index_sequence{}); + } + + template + constexpr bool operator!=(const tuple& left, const tuple& right) { + static_assert(sizeof...(X) == sizeof...(Y), "cannot compare tuples of different sizes"); + return !equal_indexable(left, right, std::make_index_sequence{}); + } } } } -// #include "../functional/tuple.h" +// #include "tuple_helper/same_or_void.h" + +namespace sqlite_orm { + namespace internal { + + /** + * Accepts any number of arguments and evaluates `type` alias as T if all arguments are the same or void otherwise + */ + template + struct same_or_void { + using type = void; + }; + + template + struct same_or_void { + using type = A; + }; + + template + struct same_or_void { + using type = A; + }; + + template + struct same_or_void : same_or_void {}; + + } +} + +// #include "tuple_helper/tuple_traits.h" + +// #include "../functional/cxx_type_traits_polyfill.h" + +// #include "../functional/mpl.h" + +namespace sqlite_orm { + namespace internal { + /* + * Higher-order trait metafunction that checks whether a tuple contains a type with given trait. + */ + template class TraitFn, class Tuple> + struct tuple_has {}; + + template class TraitFn, template class Tuple, class... Types> + struct tuple_has> : polyfill::disjunction...> {}; + + /* + * Trait metafunction class that checks whether a tuple contains a type with given trait. + */ + template class TraitFn> + using check_if_tuple_has = mpl::bind_front_higherorder_fn; + + /* + * Trait metafunction class that checks whether a tuple doesn't contain a type with given trait. + */ + template class TraitFn> + using check_if_tuple_has_not = mpl::not_>; + + /* + * Metafunction class that checks whether a tuple contains given type. + */ + template + using check_if_tuple_has_type = mpl::bind_front_higherorder_fn::template fn>; + + /* + * Metafunction class that checks whether a tuple contains a given template. + * + * Note: we are using 2 small tricks: + * 1. A template template parameter can be treated like a metafunction, so we can just "quote" a 'primary' + * template into the MPL system (e.g. `std::vector`). + * 2. This metafunction class does the opposite of the trait function `is_specialization`: + * `is_specialization` tries to instantiate the primary template template parameter using the + * template parameters of a template type, then compares both instantiated types. + * Here instead, `pass_extracted_fn_to` extracts the template template parameter from a template type, + * then compares the resulting template template parameters. + */ + template class Primary> + using check_if_tuple_has_template = + mpl::bind_front_higherorder_fn::template fn>; + } +} +// #include "tuple_helper/tuple_filter.h" + +#include // std::integral_constant, std::index_sequence, std::make_index_sequence, std::conditional, std::declval + +// #include "../functional/cxx_universal.h" + +// #include "../functional/type_at.h" + +// #include "../functional/pack.h" + +// #include "../functional/unique_tuple.h" #include // std::integral_constant, std::decay, std::is_constructible, std::is_default_constructible, std::enable_if #include // std::move, std::forward @@ -1366,309 +1585,296 @@ namespace sqlite_orm { // #include "type_at.h" +// #include "tuple_common.h" + namespace _sqlite_orm { // short names defined in a short namespace to reduce symbol lengths, // since those types are used as a building block; // (as seen in boost hana) /* - * storage element of a tuple + * storage element of a unique tuple */ - template::value && !std::is_final::value> - struct SQLITE_ORM_MSVC_EMPTYBASES tuplem : indexed_type { + template> + struct uplem { X data; - constexpr tuplem() : data() {} + constexpr uplem() : data() {} template - constexpr tuplem(Y&& y) : data(std::forward(y)) {} + constexpr uplem(Y&& y) : data(std::forward(y)) {} }; /* - * storage element of a tuple, using EBO + * storage element of a unique tuple, using EBO */ - template - struct SQLITE_ORM_MSVC_EMPTYBASES tuplem : X, indexed_type { + template + struct uplem : X { - constexpr tuplem() = default; + constexpr uplem() = default; template - constexpr tuplem(Y&& y) : X(std::forward(y)) {} + constexpr uplem(Y&& y) : X(std::forward(y)) {} }; - template - constexpr const X& ebo_get(const tuplem& elem) { + template>> + constexpr const X& ebo_get(const uplem& elem) { return (elem.data); } - template - constexpr X& ebo_get(tuplem& elem) { + template, bool> = true> + constexpr X& ebo_get(uplem& elem) { return (elem.data); } - template - constexpr X&& ebo_get(tuplem&& elem) { + template, bool> = true> + constexpr X&& ebo_get(uplem&& elem) { return std::forward(elem.data); } - template - constexpr const X& ebo_get(const tuplem& elem) { + template, bool> = true> + constexpr const X& ebo_get(const uplem& elem) { return elem; } - template - constexpr X& ebo_get(tuplem& elem) { + template, bool> = true> + constexpr X& ebo_get(uplem& elem) { return elem; } - template - constexpr X&& ebo_get(tuplem&& elem) { + template, bool> = true> + constexpr X&& ebo_get(uplem&& elem) { return std::forward(elem); } } namespace sqlite_orm { - namespace internal { - namespace mpl { - using ::_sqlite_orm::ebo_get; - using ::_sqlite_orm::tuplem; - - template - struct basic_tuple; - - template - struct tuple; - - template - struct remove_rvalue_reference { - using type = T; - }; - template - struct remove_rvalue_reference { - using type = T; - }; - template - using remove_rvalue_reference_t = typename remove_rvalue_reference::type; - - struct from_variadic_t {}; + namespace internal { + namespace mpl { + using ::_sqlite_orm::ebo_get; + using ::_sqlite_orm::uplem; - template - struct enable_tuple_ctor; + template + struct uple; template - struct enable_tuple_ctor, Void...> + struct enable_tuple_ctor, Void...> : std::enable_if), bool> {}; template - struct enable_tuple_ctor, Void...> + struct enable_tuple_ctor, Void...> : std::enable_if), bool> {}; - template - struct enable_tuple_variadic_ctor; - template - struct enable_tuple_variadic_ctor, Y...> + struct enable_tuple_variadic_ctor, Y...> : std::enable_if), bool> {}; - template - struct enable_tuple_nonconst_copy_ctor; - #ifdef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 template - struct enable_tuple_nonconst_copy_ctor, tuple, Void...> + struct enable_tuple_nonconst_copy_ctor, uple, Void...> : std::enable_if), bool> {}; template - struct enable_tuple_nonconst_copy_ctor, const tuple, Void...> + struct enable_tuple_nonconst_copy_ctor, const uple, Void...> : std::enable_if), bool> {}; #endif } } - namespace mpl = mpl; + namespace mpl = internal::mpl; } -// retain stl tuple interface for `tuple` +// retain stl tuple interface for `uple` namespace std { + template + struct tuple_size; + + template + struct tuple_element; + template - struct tuple_size> : integral_constant {}; + struct tuple_size> : integral_constant {}; template - constexpr decltype(auto) get(const sqlite_orm::mpl::tuple& tpl) noexcept { + struct tuple_element> : sqlite_orm::mpl::type_at> {}; + + template + constexpr decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { using namespace sqlite_orm::mpl; - return ebo_get(tpl); + using type = type_at_t; + return ebo_get(static_cast&>(tpl)); } template - constexpr decltype(auto) get(sqlite_orm::mpl::tuple& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { using namespace sqlite_orm::mpl; - return ebo_get(tpl); + using type = type_at_t; + return ebo_get(static_cast&>(tpl)); } template - constexpr decltype(auto) get(sqlite_orm::mpl::tuple&& tpl) noexcept { + constexpr decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { using namespace sqlite_orm::mpl; - return ebo_get(std::move(tpl)); + using type = type_at_t; + return ebo_get(static_cast&&>(tpl)); } template - decltype(auto) get(const sqlite_orm::mpl::tuple&) noexcept = delete; + constexpr decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { + using namespace sqlite_orm::mpl; + return ebo_get(static_cast&>(tpl)); + } template - decltype(auto) get(sqlite_orm::mpl::tuple&) noexcept = delete; + constexpr decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { + using namespace sqlite_orm::mpl; + return ebo_get(static_cast&>(tpl)); + } template - decltype(auto) get(sqlite_orm::mpl::tuple&&) noexcept = delete; + constexpr decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { + using namespace sqlite_orm::mpl; + return ebo_get(static_cast&&>(tpl)); + } } namespace sqlite_orm { namespace internal { namespace mpl { - template - struct SQLITE_ORM_MSVC_EMPTYBASES basic_tuple, X...> : tuplem... { - constexpr basic_tuple() = default; - - // variadic constructor - template - constexpr basic_tuple(from_variadic_t, Y&&... y) : tuplem(std::forward(y))... {} - - // converting copy/move constructor - template - constexpr basic_tuple(Other&& other) : tuplem(std::get(std::forward(other)))... {} - - constexpr basic_tuple(const basic_tuple&) = default; - constexpr basic_tuple(basic_tuple&&) = default; - }; - template<> - struct tuple<> final { - constexpr tuple() = default; + struct uple<> final { + constexpr uple() = default; }; /* - * tuple + * unique tuple, which allows only distinct types. */ template - struct tuple final : basic_tuple, X...> { - private: - using base_type = basic_tuple, X...>; - - public: + struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { // default constructor - template::type = true> - constexpr tuple() : base_type{} {} + template::type = true> + constexpr uple() {} // direct constructor - template::type = true> - constexpr tuple(const X&... x) : base_type{from_variadic_t{}, x...} {} + template::type = true> + constexpr uple(const X&... x) : uplem(x)... {} // converting constructor template::type = true> - constexpr tuple(Y&&... y) : base_type{from_variadic_t{}, std::forward(y)...} {} + typename enable_tuple_variadic_ctor::type = true> + constexpr uple(Y&&... y) : uplem(std::forward(y))... {} // converting copy constructor template), bool> = true> - constexpr tuple(const tuple& other) : base_type{other} {} + constexpr uple(const uple& other) : uplem(ebo_get(other))... {} // converting move constructor template), bool> = true> - constexpr tuple(tuple&& other) : base_type{std::move(other)} {} + constexpr uple(uple&& other) : uplem(ebo_get(std::move(other)))... {} -#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 - constexpr tuple(const tuple&) = default; - constexpr tuple(tuple&&) = default; + // default copy constructor + constexpr uple(const uple&) = default; + // default move constructor + constexpr uple(uple&&) = default; // non-const copy constructor. // The non-const copy constructor is required to make sure that - // the converting tuple(Y&&...) constructor is _not_ preferred over the copy - // constructor for unary tuples containing a type that is constructible from tuple<...>. - constexpr tuple(tuple& other) : base_type{const_cast(other)} {} + // the converting uple(Y&&...) constructor is _not_ preferred over the copy + // constructor for unary tuples containing a type that is constructible from uple<...>. +#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + constexpr uple(uple& other) : uplem(ebo_get(const_cast(other)))... {} #else - template::type = true> - constexpr tuple(Other& other) : base_type{const_cast(other)} {} + template::type = true> + constexpr uple(Other& other) : uplem(ebo_get(const_cast(other)))... {} #endif - }; - namespace adl { - template - constexpr auto make_tuple(X&&... x) { - return tuple...>{std::forward(x)...}; + // converting copy assignment + template), bool> = true> + SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(const uple& other) { + int poormansfold[] = {(ebo_get(*this) = ebo_get(other), int{})...}; + (void)poormansfold; + return *this; } - } - using adl::make_tuple; - // implementation note: we could derive from `type_at` but leverage the fact that `tuple` is derived from `indexed_type` - template - struct type_at> { - // implementation note: we could use `get_indexed_type()`, but `ebo_get` is readily available. - using forwarded_t = decltype(ebo_get(std::declval>())); - using type = remove_rvalue_reference_t; + // converting move assignment + template), bool> = true> + SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(uple&& other) { + int poormansfold[] = {(ebo_get(*this) = ebo_get(std::move(other)), int{})...}; + (void)poormansfold; + return *this; + } + + // default copy assignment + SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(const uple&) = default; + // default move assignment + SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(uple&&) = default; }; + + template + constexpr auto make_unique_tuple(X&&... x) { + return uple...>{std::forward(x)...}; + } + + template + constexpr uple forward_as_unique_tuple(X&&... args) noexcept { + return uple{std::forward(args)...}; + } + + template + constexpr uple tie_unique(X&... args) noexcept { + return uple{args...}; + } } } } +// ops namespace sqlite_orm { namespace internal { - /* - * Higher-order trait metafunction that checks whether a tuple contains a type with given trait. - */ - template class TraitFn, class Tuple> - struct tuple_has {}; - - template class TraitFn, class... Types> - struct tuple_has> : polyfill::disjunction...> {}; - - template class TraitFn, class... Types> - struct tuple_has> : polyfill::disjunction...> {}; + namespace mpl { - template class TraitFn, class... Types> - struct tuple_has> : polyfill::disjunction...> {}; + template + struct type_at> : type_at {}; - /* - * Trait metafunction class that checks whether a tuple contains a type with given trait. - */ - template class TraitFn> - using check_if_tuple_has = mpl::bind_front_higherorder_fn; +#ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED + template = true> + constexpr bool equal_indexable([[maybe_unused]] const uple& left, + [[maybe_unused]] const uple& right, + std::index_sequence) { + return ((ebo_get(left) == ebo_get(right)) && ...); + } - /* - * Trait metafunction class that checks whether a tuple doesn't contain a type with given trait. - */ - template class TraitFn> - using check_if_tuple_has_not = mpl::not_>; + template = true> + constexpr bool equal_indexable([[maybe_unused]] const uple& left, + [[maybe_unused]] const uple& right, + std::index_sequence) { + return ((std::get(left) == std::get(right)) && ...); + } +#else + template + constexpr bool equal_indexable(const uple&, const uple&, std::index_sequence<>) { + return true; + } + template + constexpr bool + equal_indexable(const uple& left, const uple& right, std::index_sequence) { + return (std::get(left) == std::get(right)) && + equal_indexable(left, right, std::index_sequence{}); + } +#endif - /* - * Metafunction class that checks whether a tuple contains given type. - */ - template - using check_if_tuple_has_type = mpl::bind_front_higherorder_fn::template fn>; + template + constexpr bool operator==(const uple& left, const uple& right) { + static_assert(sizeof...(X) == sizeof...(Y), "cannot compare tuples of different sizes"); + return equal_indexable(left, right, std::make_index_sequence{}); + } - /* - * Metafunction class that checks whether a tuple contains a given template. - * - * Note: we are using 2 small tricks: - * 1. A template template parameter can be treated like a metafunction, so we can just "quote" a 'primary' - * template into the MPL system (e.g. `std::vector`). - * 2. This metafunction class does the opposite of the trait function `is_specialization`: - * `is_specialization` tries to instantiate the primary template template parameter using the - * template parameters of a template type, then compares both instantiated types. - * Here instead, `pass_extracted_fn_to` extracts the template template parameter from a template type, - * then compares the resulting template template parameters. - */ - template class Primary> - using check_if_tuple_has_template = - mpl::bind_front_higherorder_fn::template fn>; + template + constexpr bool operator!=(const uple& left, const uple& right) { + static_assert(sizeof...(X) == sizeof...(Y), "cannot compare tuples of different sizes"); + return !equal_indexable(left, right, std::make_index_sequence{}); + } + } } } -// #include "tuple_helper/tuple_filter.h" - -#include // std::integral_constant, std::index_sequence, std::make_index_sequence, std::conditional, std::declval - -// #include "../functional/cxx_universal.h" - -// #include "../functional/type_at.h" - -// #include "../functional/pack.h" - -// #include "../functional/unique_tuple.h" // #include "../functional/tuple.h" @@ -1858,11 +2064,11 @@ namespace sqlite_orm { template struct primary_key_t : primary_key_base { using order_by = primary_key_base::order_by; - using columns_tuple = std::tuple; + using columns_tuple = mpl::tuple; columns_tuple columns; - primary_key_t(decltype(columns) c) : columns(move(c)) {} + primary_key_t(decltype(columns) c) : columns(std::move(c)) {} primary_key_t asc() const { auto res = *this; @@ -1888,11 +2094,11 @@ namespace sqlite_orm { */ template struct unique_t : unique_base { - using columns_tuple = std::tuple; + using columns_tuple = mpl::tuple; columns_tuple columns; - unique_t(columns_tuple columns_) : columns(move(columns_)) {} + unique_t(columns_tuple columns_) : columns(std::move(columns_)) {} }; /** @@ -2041,9 +2247,9 @@ namespace sqlite_orm { } template - struct foreign_key_t, std::tuple> { - using columns_type = std::tuple; - using references_type = std::tuple; + struct foreign_key_t, mpl::tuple> { + using columns_type = mpl::tuple; + using references_type = mpl::tuple; using self = foreign_key_t; /** @@ -2067,7 +2273,7 @@ namespace sqlite_orm { static_assert(!std::is_same::value, "All references must have the same type"); foreign_key_t(columns_type columns_, references_type references_) : - columns(move(columns_)), references(move(references_)), + columns(std::move(columns_)), references(std::move(references_)), on_update(*this, true, foreign_key_action::none), on_delete(*this, false, foreign_key_action::none) {} foreign_key_t(const self& other) : @@ -2096,13 +2302,13 @@ namespace sqlite_orm { */ template struct foreign_key_intermediate_t { - using tuple_type = std::tuple; + using tuple_type = mpl::tuple; tuple_type columns; template - foreign_key_t, std::tuple> references(Rs... refs) { - return {std::move(this->columns), std::make_tuple(std::forward(refs)...)}; + foreign_key_t, mpl::tuple> references(Rs... refs) { + return {std::move(this->columns), mpl::make_tuple(std::forward(refs)...)}; } }; #endif @@ -2247,7 +2453,7 @@ namespace sqlite_orm { */ template internal::foreign_key_intermediate_t foreign_key(Cs... columns) { - return {std::make_tuple(std::forward(columns)...)}; + return {mpl::make_tuple(std::forward(columns)...)}; } #endif @@ -2256,7 +2462,7 @@ namespace sqlite_orm { */ template internal::unique_t unique(Args... args) { - return {std::make_tuple(std::forward(args)...)}; + return {mpl::make_tuple(std::forward(args)...)}; } inline internal::unique_t<> unique() { @@ -2269,7 +2475,7 @@ namespace sqlite_orm { template internal::primary_key_t primary_key(Cs... cs) { - return {std::make_tuple(std::forward(cs)...)}; + return {mpl::make_tuple(std::forward(cs)...)}; } inline internal::primary_key_t<> primary_key() { @@ -2641,7 +2847,6 @@ namespace sqlite_orm { } #pragma once -#include // std::tuple #include // std::string #include // std::unique_ptr #include // std::is_same, std::is_member_object_pointer @@ -2650,6 +2855,8 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" +// #include "functional/unique_tuple.h" + // #include "tuple_helper/tuple_traits.h" // #include "tuple_helper/tuple_filter.h" @@ -3087,13 +3294,15 @@ namespace sqlite_orm { #include // std::string #include // std::enable_if, std::is_same #include // std::vector -#include // std::tuple, std::tuple_size #include // std::stringstream +#include // std::move // #include "functional/cxx_universal.h" // #include "functional/cxx_type_traits_polyfill.h" +// #include "functional/tuple.h" + // #include "type_traits.h" // #include "collate_argument.h" @@ -3183,6 +3392,8 @@ namespace sqlite_orm { // #include "functional/cxx_universal.h" +// #include "functional/tuple.h" +// make_tuple // #include "operators.h" namespace sqlite_orm { @@ -3219,12 +3430,12 @@ namespace sqlite_orm { #endif template in_t in(Args... args) const { - return {this->value, std::make_tuple(std::forward(args)...), false}; + return {this->value, mpl::make_tuple(std::forward(args)...), false}; } template in_t not_in(Args... args) const { - return {this->value, std::make_tuple(std::forward(args)...), true}; + return {this->value, mpl::make_tuple(std::forward(args)...), true}; } template @@ -3637,7 +3848,7 @@ namespace sqlite_orm { template struct in_t : condition_t, in_base, negatable_t { L left; - std::tuple argument; + mpl::tuple argument; in_t(L left_, decltype(argument) argument_, bool negative_) : in_base{negative_}, left(std::move(left_)), argument(std::move(argument_)) {} @@ -3758,7 +3969,7 @@ namespace sqlite_orm { */ template struct multi_order_by_t : order_by_string { - using args_type = std::tuple; + using args_type = mpl::tuple; args_type args; @@ -4057,7 +4268,7 @@ namespace sqlite_orm { template struct from_t { - using tuple_type = std::tuple; + using tuple_type = mpl::tuple; }; template @@ -4070,7 +4281,7 @@ namespace sqlite_orm { */ template internal::from_t from() { - static_assert(std::tuple_size>::value > 0, ""); + static_assert(sizeof...(Args) > 0, ""); return {}; } @@ -4457,7 +4668,7 @@ namespace sqlite_orm { */ template internal::multi_order_by_t multi_order_by(Args&&... args) { - return {std::make_tuple(std::forward(args)...)}; + return {mpl::make_tuple(std::forward(args)...)}; } /** @@ -4801,13 +5012,14 @@ namespace sqlite_orm { #pragma once #include // std::string -#include // std::make_tuple, std::tuple_size #include // std::forward, std::is_base_of, std::enable_if #include // std::unique_ptr #include // std::vector // #include "functional/cxx_type_traits_polyfill.h" +// #include "functional/tuple.h" + // #include "conditions.h" // #include "is_base_of_template.h" @@ -4897,7 +5109,7 @@ namespace sqlite_orm { struct built_in_function_t : S, arithmetic_t { using return_type = R; using string_type = S; - using args_type = std::tuple; + using args_type = mpl::tuple; static constexpr size_t args_size = std::tuple_size::value; @@ -5525,7 +5737,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t acos(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5541,7 +5753,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t acos(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5553,7 +5765,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t acosh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5569,7 +5781,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t acosh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5581,7 +5793,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t asin(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5597,7 +5809,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t asin(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5609,7 +5821,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t asinh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5625,7 +5837,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t asinh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5637,7 +5849,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t atan(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5653,7 +5865,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t atan(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5665,7 +5877,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t atan2(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -5681,7 +5893,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t atan2(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -5693,7 +5905,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t atanh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5709,7 +5921,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t atanh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5721,7 +5933,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ceil(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5737,7 +5949,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ceil(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5749,7 +5961,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ceiling(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5765,7 +5977,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ceiling(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5777,7 +5989,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t cos(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5793,7 +6005,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t cos(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5805,7 +6017,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t cosh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5821,7 +6033,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t cosh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5833,7 +6045,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t degrees(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5849,7 +6061,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t degrees(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5861,7 +6073,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t exp(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5877,7 +6089,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t exp(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5889,7 +6101,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t floor(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5905,7 +6117,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t floor(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5917,7 +6129,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ln(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5933,7 +6145,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ln(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5945,7 +6157,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5961,7 +6173,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5973,7 +6185,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log10(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -5989,7 +6201,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log10(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6001,7 +6213,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log(B b, X x) { - return {std::tuple{std::forward(b), std::forward(x)}}; + return {{std::forward(b), std::forward(x)}}; } /** @@ -6017,7 +6229,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log(B b, X x) { - return {std::tuple{std::forward(b), std::forward(x)}}; + return {{std::forward(b), std::forward(x)}}; } /** @@ -6029,7 +6241,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log2(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6045,7 +6257,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t log2(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6057,7 +6269,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t mod_f(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -6073,7 +6285,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t mod_f(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -6112,7 +6324,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t pow(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -6128,7 +6340,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t pow(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -6140,7 +6352,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t power(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -6156,7 +6368,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t power(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -6168,7 +6380,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t radians(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6184,7 +6396,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t radians(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6196,7 +6408,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t sin(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6212,7 +6424,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t sin(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6224,7 +6436,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t sinh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6240,7 +6452,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t sinh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6252,7 +6464,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t sqrt(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6268,7 +6480,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t sqrt(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6280,7 +6492,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t tan(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6296,7 +6508,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t tan(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6308,7 +6520,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t tanh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6324,7 +6536,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t tanh(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6336,7 +6548,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t trunc(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6352,7 +6564,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t trunc(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } #endif // SQLITE_ENABLE_MATH_FUNCTIONS /** @@ -6360,7 +6572,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t typeof_(T t) { - return {std::tuple{std::forward(t)}}; + return {{std::forward(t)}}; } /** @@ -6368,7 +6580,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t unicode(T t) { - return {std::tuple{std::forward(t)}}; + return {{std::forward(t)}}; } /** @@ -6376,7 +6588,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t length(T t) { - return {std::tuple{std::forward(t)}}; + return {{std::forward(t)}}; } /** @@ -6384,7 +6596,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t, internal::abs_string, T> abs(T t) { - return {std::tuple{std::forward(t)}}; + return {{std::forward(t)}}; } /** @@ -6392,7 +6604,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t lower(T t) { - return {std::tuple{std::forward(t)}}; + return {{std::forward(t)}}; } /** @@ -6400,7 +6612,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t upper(T t) { - return {std::tuple{std::forward(t)}}; + return {{std::forward(t)}}; } /** @@ -6429,7 +6641,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t trim(T t) { - return {std::tuple{std::forward(t)}}; + return {{std::forward(t)}}; } /** @@ -6437,7 +6649,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t trim(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -6445,7 +6657,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ltrim(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6453,7 +6665,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t ltrim(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -6461,7 +6673,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t rtrim(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6469,7 +6681,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t rtrim(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -6477,7 +6689,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t hex(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6485,7 +6697,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t quote(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6493,7 +6705,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t, internal::randomblob_string, X> randomblob(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6501,7 +6713,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t instr(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -6510,9 +6722,9 @@ namespace sqlite_orm { template, internal::is_into>::value == 0, bool> = true> + std::enable_if_t, internal::is_into>::value == 0, bool> = true> internal::built_in_function_t replace(X x, Y y, Z z) { - return {std::tuple{std::forward(x), std::forward(y), std::forward(z)}}; + return {{std::forward(x), std::forward(y), std::forward(z)}}; } /** @@ -6520,7 +6732,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t round(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6528,7 +6740,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t round(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } #if SQLITE_VERSION_NUMBER >= 3007016 @@ -6538,7 +6750,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t char_(Args... args) { - return {std::make_tuple(std::forward(args)...)}; + return {{std::forward(args)...}}; } /** @@ -6561,7 +6773,7 @@ namespace sqlite_orm { polyfill::type_identity>::type, internal::coalesce_string, Args...> { - return {std::make_tuple(std::forward(args)...)}; + return {{std::forward(args)...}}; } /** @@ -6576,7 +6788,7 @@ namespace sqlite_orm { internal::ifnull_string, X, Y> { - return {std::make_tuple(std::move(x), std::move(y))}; + return {{std::move(x), std::move(y)}}; } /** @@ -6602,17 +6814,17 @@ namespace sqlite_orm { X, Y>; - return F{std::make_tuple(std::move(x), std::move(y))}; + return F{{std::move(x), std::move(y)}}; } else { using F = internal::built_in_function_t; - return F{std::make_tuple(std::move(x), std::move(y))}; + return F{{std::move(x), std::move(y)}}; } } #else template internal::built_in_function_t nullif(X x, Y y) { - return {std::make_tuple(std::move(x), std::move(y))}; + return {{std::move(x), std::move(y)}}; } #endif @@ -6621,7 +6833,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t date(Args... args) { - return {std::tuple{std::forward(args)...}}; + return {{std::forward(args)...}}; } /** @@ -6629,7 +6841,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t time(Args... args) { - return {std::tuple{std::forward(args)...}}; + return {{std::forward(args)...}}; } /** @@ -6637,7 +6849,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t datetime(Args... args) { - return {std::tuple{std::forward(args)...}}; + return {{std::forward(args)...}}; } /** @@ -6645,7 +6857,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t julianday(Args... args) { - return {std::tuple{std::forward(args)...}}; + return {{std::forward(args)...}}; } /** @@ -6653,7 +6865,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t strftime(Args... args) { - return {std::tuple{std::forward(args)...}}; + return {{std::forward(args)...}}; } /** @@ -6661,7 +6873,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t, internal::zeroblob_string, N> zeroblob(N n) { - return {std::tuple{std::forward(n)}}; + return {{std::forward(n)}}; } /** @@ -6669,7 +6881,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t substr(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } /** @@ -6677,7 +6889,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t substr(X x, Y y, Z z) { - return {std::tuple{std::forward(x), std::forward(y), std::forward(z)}}; + return {{std::forward(x), std::forward(y), std::forward(z)}}; } #ifdef SQLITE_SOUNDEX @@ -6686,7 +6898,7 @@ namespace sqlite_orm { */ template internal::built_in_function_t soundex(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } #endif @@ -6695,7 +6907,7 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t total(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6703,7 +6915,7 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t, internal::sum_string, X> sum(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6711,7 +6923,7 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t count(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6735,7 +6947,7 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t avg(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6743,7 +6955,7 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t, internal::max_string, X> max(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6751,7 +6963,7 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t, internal::min_string, X> min(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6761,7 +6973,7 @@ namespace sqlite_orm { template internal::built_in_function_t, internal::max_string, X, Y, Rest...> max(X x, Y y, Rest... rest) { - return {std::tuple{std::forward(x), std::forward(y), std::forward(rest)...}}; + return {{std::forward(x), std::forward(y), std::forward(rest)...}}; } /** @@ -6771,7 +6983,7 @@ namespace sqlite_orm { template internal::built_in_function_t, internal::min_string, X, Y, Rest...> min(X x, Y y, Rest... rest) { - return {std::tuple{std::forward(x), std::forward(y), std::forward(rest)...}}; + return {{std::forward(x), std::forward(y), std::forward(rest)...}}; } /** @@ -6779,7 +6991,7 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t group_concat(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } /** @@ -6787,128 +6999,124 @@ namespace sqlite_orm { */ template internal::built_in_aggregate_function_t group_concat(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } #ifdef SQLITE_ENABLE_JSON1 template internal::built_in_function_t json(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_array(Args... args) { - return {std::tuple{std::forward(args)...}}; + return {{std::forward(args)...}}; } template internal::built_in_function_t json_array_length(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_array_length(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_array_length(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } template internal::built_in_function_t json_array_length(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } template internal::built_in_function_t json_extract(X x, Args... args) { - return {std::tuple{std::forward(x), std::forward(args)...}}; + return {{std::forward(x), std::forward(args)...}}; } template internal::built_in_function_t json_insert(X x, Args... args) { - static_assert(std::tuple_size>::value % 2 == 0, - "number of arguments in json_insert must be odd"); - return {std::tuple{std::forward(x), std::forward(args)...}}; + static_assert(sizeof...(Args) % 2 == 0, "number of arguments in json_insert must be odd"); + return {{std::forward(x), std::forward(args)...}}; } template internal::built_in_function_t json_replace(X x, Args... args) { - static_assert(std::tuple_size>::value % 2 == 0, - "number of arguments in json_replace must be odd"); - return {std::tuple{std::forward(x), std::forward(args)...}}; + static_assert(sizeof...(Args) % 2 == 0, "number of arguments in json_replace must be odd"); + return {{std::forward(x), std::forward(args)...}}; } template internal::built_in_function_t json_set(X x, Args... args) { - static_assert(std::tuple_size>::value % 2 == 0, - "number of arguments in json_set must be odd"); - return {std::tuple{std::forward(x), std::forward(args)...}}; + static_assert(sizeof...(Args) % 2 == 0, "number of arguments in json_set must be odd"); + return {{std::forward(x), std::forward(args)...}}; } template internal::built_in_function_t json_object(Args... args) { - static_assert(std::tuple_size>::value % 2 == 0, - "number of arguments in json_object must be even"); - return {std::tuple{std::forward(args)...}}; + static_assert(sizeof...(Args) % 2 == 0, "number of arguments in json_object must be even"); + return {{std::forward(args)...}}; } template internal::built_in_function_t json_patch(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } template internal::built_in_function_t json_remove(X x, Args... args) { - return {std::tuple{std::forward(x), std::forward(args)...}}; + return {{std::forward(x), std::forward(args)...}}; } template internal::built_in_function_t json_remove(X x, Args... args) { - return {std::tuple{std::forward(x), std::forward(args)...}}; + return {{std::forward(x), std::forward(args)...}}; } template internal::built_in_function_t json_type(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_type(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_type(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } template internal::built_in_function_t json_type(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } template internal::built_in_function_t json_valid(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_quote(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_group_array(X x) { - return {std::tuple{std::forward(x)}}; + return {{std::forward(x)}}; } template internal::built_in_function_t json_group_object(X x, Y y) { - return {std::tuple{std::forward(x), std::forward(y)}}; + return {{std::forward(x), std::forward(y)}}; } #endif // SQLITE_ENABLE_JSON1 @@ -6984,6 +7192,8 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" +// #include "functional/tuple.h" + // #include "is_base_of_template.h" // #include "tuple_helper/tuple_filter.h" @@ -7048,18 +7258,18 @@ namespace sqlite_orm { // #include "ast/group_by.h" -#include // std::tuple, std::make_tuple -#include // std::true_type, std::false_type #include // std::forward, std::move // #include "../functional/cxx_type_traits_polyfill.h" +// #include "../functional/tuple.h" + namespace sqlite_orm { namespace internal { template struct group_by_with_having { - using args_type = std::tuple; + using args_type = mpl::tuple; using expression_type = T; args_type args; @@ -7071,7 +7281,7 @@ namespace sqlite_orm { */ template struct group_by_t { - using args_type = std::tuple; + using args_type = mpl::tuple; args_type args; @@ -7106,7 +7316,7 @@ namespace sqlite_orm { */ template internal::group_by_t group_by(Args&&... args) { - return {std::make_tuple(std::forward(args)...)}; + return {mpl::make_tuple(std::forward(args)...)}; } /** @@ -7171,7 +7381,7 @@ namespace sqlite_orm { template struct columns_t { - using columns_type = std::tuple; + using columns_type = mpl::tuple; columns_type columns; bool distinct = false; @@ -7179,7 +7389,7 @@ namespace sqlite_orm { static constexpr int count = std::tuple_size::value; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - columns_t(columns_type columns) : columns{move(columns)} {} + columns_t(columns_type columns) : columns{std::move(columns)} {} #endif }; @@ -7191,7 +7401,7 @@ namespace sqlite_orm { template struct set_t { - using assigns_type = std::tuple; + using assigns_type = mpl::tuple; assigns_type assigns; }; @@ -7245,14 +7455,15 @@ namespace sqlite_orm { template struct select_t { using return_type = T; - using conditions_type = std::tuple; + using conditions_type = mpl::tuple; return_type col; conditions_type conditions; bool highest_level = false; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - select_t(return_type col, conditions_type conditions) : col{std::move(col)}, conditions{move(conditions)} {} + select_t(return_type col, conditions_type conditions) : + col{std::move(col)}, conditions{std::move(conditions)} {} #endif }; @@ -7406,8 +7617,7 @@ namespace sqlite_orm { simple_case_builder> when(W w, then_t t) { using result_args_type = std::tuple>; std::pair newPair{std::move(w), std::move(t.expression)}; - result_args_type result_args = - std::tuple_cat(std::move(this->args), std::move(std::make_tuple(newPair))); + result_args_type result_args = std::tuple_cat(std::move(this->args), std::make_tuple(newPair)); std::get::value - 1>(result_args) = std::move(newPair); return {std::move(this->case_expression), std::move(result_args), std::move(this->else_expression)}; } @@ -7475,16 +7685,16 @@ namespace sqlite_orm { */ template internal::set_t set(Args... args) { - using arg_tuple = std::tuple; - static_assert(std::tuple_size::value == - internal::count_tuple::value, + using args_pack = mpl::pack; + static_assert(std::tuple_size::value == + internal::count_tuple::value, "set function accepts assign operators only"); - return {std::make_tuple(std::forward(args)...)}; + return {mpl::make_tuple(std::forward(args)...)}; } template internal::columns_t columns(Args... args) { - return {std::make_tuple(std::forward(args)...)}; + return {mpl::make_tuple(std::forward(args)...)}; } /** @@ -7504,7 +7714,7 @@ namespace sqlite_orm { internal::select_t select(T t, Args... args) { using args_tuple = std::tuple; internal::validate_conditions(); - return {std::move(t), std::make_tuple(std::forward(args)...)}; + return {std::move(t), mpl::make_tuple(std::forward(args)...)}; } /** @@ -7619,13 +7829,13 @@ namespace sqlite_orm { } #pragma once -#include -#include #include -#include +#include // std::move, std::forward // #include "functional/cxx_universal.h" +// #include "functional/tuple.h" + // #include "optional_container.h" // NOTE Idea : Maybe also implement a custom trigger system to call a c++ callback when a trigger triggers ? @@ -7646,7 +7856,7 @@ namespace sqlite_orm { */ template struct partial_trigger_t { - using statements_type = std::tuple; + using statements_type = mpl::tuple; /** * Base of the trigger (contains its type, timing and associated table) @@ -7658,7 +7868,7 @@ namespace sqlite_orm { statements_type statements; partial_trigger_t(T trigger_base, S... statements) : - base{std::move(trigger_base)}, statements{std::make_tuple(std::forward(statements)...)} {} + base{std::move(trigger_base)}, statements{mpl::make_tuple(std::forward(statements)...)} {} partial_trigger_t& end() { return *this; @@ -7776,7 +7986,7 @@ namespace sqlite_orm { */ template struct trigger_update_type_t : trigger_type_base_t { - using columns_type = std::tuple; + using columns_type = mpl::tuple; /** * Contains the columns the trigger is watching. Will only @@ -7785,7 +7995,7 @@ namespace sqlite_orm { columns_type columns; trigger_update_type_t(trigger_timing timing, trigger_type type, Cs... columns) : - trigger_type_base_t(timing, type), columns(std::make_tuple(std::forward(columns)...)) {} + trigger_type_base_t(timing, type), columns(mpl::make_tuple(std::forward(columns)...)) {} template trigger_base_t> on() { @@ -8819,7 +9029,7 @@ namespace sqlite_orm { #include #include // std::copy #include // std::back_inserter -#include // std::tuple, std::tuple_size, std::tuple_element +#include // std::tuple // #include "functional/cxx_universal.h" @@ -10082,7 +10292,7 @@ namespace sqlite_orm { using func_arg_t = mpl::element_at_t; using passed_arg_t = unpacked_arg_t>; -#ifdef SQLITE_ORM_RELAXED_CONSTEXPR +#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED constexpr bool valid = validate_pointer_value_type, unpacked_arg_t>>( @@ -10397,7 +10607,6 @@ namespace sqlite_orm { #include // std::string #include // std::remove_reference, std::is_same, std::decay #include // std::vector -#include // std::tuple_size, std::tuple_element #include // std::forward, std::move // #include "functional/cxx_universal.h" @@ -10494,7 +10703,7 @@ namespace sqlite_orm { // #include "../functional/cxx_universal.h" -#ifdef SQLITE_ORM_RELAXED_CONSTEXPR +#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED #include #endif @@ -10508,7 +10717,7 @@ namespace sqlite_orm { return I; } -#ifdef SQLITE_ORM_RELAXED_CONSTEXPR +#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED /** * Reorder the values of an index_sequence according to the positions from a second sequence. */ @@ -10547,7 +10756,6 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_iteration.h" -#include // std::tuple, std::get, std::tuple_element, std::tuple_size #include // std::index_sequence, std::make_index_sequence #include // std::forward, std::move @@ -11104,7 +11312,6 @@ namespace sqlite_orm { #include // std::stringstream #include // std::map #include // std::vector -#include // std::tuple_size, std::tuple, std::make_tuple, std::tie #include // std::forward, std::pair #include // std::for_each, std::ranges::for_each // #include "functional/cxx_optional.h" @@ -11270,7 +11477,6 @@ namespace sqlite_orm { #include #include // std::string #include // std::forward, std::move -#include // std::tuple, std::make_tuple // #include "row_extractor.h" @@ -11499,20 +11705,21 @@ namespace sqlite_orm { // #include "values.h" #include // std::vector -#include // std::tuple #include // std::forward // #include "functional/cxx_universal.h" // #include "functional/cxx_type_traits_polyfill.h" +// #include "functional/tuple.h" + namespace sqlite_orm { namespace internal { template struct values_t { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; args_tuple tuple; }; @@ -11544,12 +11751,12 @@ namespace sqlite_orm { // #include "ast/upsert_clause.h" -#include // std::tuple, std::make_tuple -#include // std::false_type, std::true_type #include // std::forward, std::move // #include "../functional/cxx_type_traits_polyfill.h" +// #include "../functional/tuple.h" + namespace sqlite_orm { namespace internal { #if SQLITE_VERSION_NUMBER >= 3024000 @@ -11558,24 +11765,24 @@ namespace sqlite_orm { template struct conflict_target { - using args_tuple = std::tuple; + using args_tuple = mpl::tuple; args_tuple args; - upsert_clause> do_nothing() { - return {move(this->args), {}}; + upsert_clause> do_nothing() { + return {std::move(this->args), {}}; } template - upsert_clause> do_update(ActionsArgs... actions) { - return {move(this->args), {std::make_tuple(std::forward(actions)...)}}; + upsert_clause> do_update(ActionsArgs... actions) { + return {std::move(this->args), {std::forward(actions)...}}; } }; template - struct upsert_clause, std::tuple> { - using target_args_tuple = std::tuple; - using actions_tuple = std::tuple; + struct upsert_clause, mpl::tuple> { + using target_args_tuple = mpl::tuple; + using actions_tuple = mpl::tuple; target_args_tuple target_args; @@ -11600,7 +11807,7 @@ namespace sqlite_orm { */ template internal::conflict_target on_conflict(Args... args) { - return {std::tuple(std::forward(args)...)}; + return {{std::forward(args)...}}; } #endif } @@ -11961,7 +12168,7 @@ namespace sqlite_orm { */ template internal::insert_raw_t insert(Args... args) { - using args_tuple = mpl::tuple; + using args_tuple = mpl::pack; using internal::count_tuple; using internal::is_columns; using internal::is_insert_constraint; @@ -12476,8 +12683,8 @@ namespace sqlite_orm { }; template - struct ast_iterator, std::tuple>, void> { - using node_type = upsert_clause, std::tuple>; + struct ast_iterator, mpl::tuple>, void> { + using node_type = upsert_clause, mpl::tuple>; template void operator()(const node_type& expression, L& lambda) const { @@ -13199,6 +13406,8 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" +// #include "functional/tuple.h" + // #include "functional/type_at.h" // #include "tuple_helper/tuple_iteration.h" @@ -13315,7 +13524,7 @@ namespace sqlite_orm { struct streaming { template auto operator()(const Ts&... ts) const { - return std::forward_as_tuple(*this, ts...); + return mpl::forward_as_tuple(*this, ts...); } template @@ -13341,9 +13550,9 @@ namespace sqlite_orm { // space + space-separated template std::ostream& operator<<(std::ostream& ss, - std::tuple&, T, Ctx> tpl) { - const auto& conditions = get<1>(tpl); - auto& context = get<2>(tpl); + mpl::tuple&, T, Ctx> tpl) { + const auto& conditions = std::get<1>(tpl); + auto& context = std::get<2>(tpl); iterate_tuple(conditions, [&ss, &context](auto& c) { ss << " " << serialize(c, context); @@ -13354,9 +13563,9 @@ namespace sqlite_orm { // serialize and stream a tuple of action expressions; // space-separated template - std::ostream& operator<<(std::ostream& ss, std::tuple&, T, Ctx> tpl) { - const auto& actions = get<1>(tpl); - auto& context = get<2>(tpl); + std::ostream& operator<<(std::ostream& ss, mpl::tuple&, T, Ctx> tpl) { + const auto& actions = std::get<1>(tpl); + auto& context = std::get<2>(tpl); iterate_tuple(actions, [&ss, &context, first = true](auto& action) mutable { constexpr std::array sep = {" ", ""}; @@ -13369,9 +13578,9 @@ namespace sqlite_orm { // comma-separated template std::ostream& operator<<(std::ostream& ss, - std::tuple&, T, Ctx> tpl) { - const auto& args = get<1>(tpl); - auto& context = get<2>(tpl); + mpl::tuple&, T, Ctx> tpl) { + const auto& args = std::get<1>(tpl); + auto& context = std::get<2>(tpl); iterate_tuple(args, [&ss, &context, first = true](auto& arg) mutable { constexpr std::array sep = {", ", ""}; @@ -13385,9 +13594,9 @@ namespace sqlite_orm { template std::ostream& operator<<( std::ostream& ss, - std::tuple&, const std::tuple...>&, Ctx> tpl) { - const auto& args = get<1>(tpl); - auto& context = get<2>(tpl); + mpl::tuple&, const mpl::tuple...>&, Ctx> tpl) { + const auto& args = std::get<1>(tpl); + auto& context = std::get<2>(tpl); iterate_tuple(args, [&ss, &context, first = true](auto& arg) mutable { constexpr std::array sep = {", ", ""}; @@ -13400,9 +13609,9 @@ namespace sqlite_orm { // comma-separated template std::ostream& operator<<(std::ostream& ss, - std::tuple&, C, Ctx> tpl) { - const auto& args = get<1>(tpl); - auto& context = get<2>(tpl); + mpl::tuple&, C, Ctx> tpl) { + const auto& args = std::get<1>(tpl); + auto& context = std::get<2>(tpl); constexpr std::array sep = {", ", ""}; for(size_t i = 0, first = true; i < args.size(); ++i) { @@ -13414,8 +13623,8 @@ namespace sqlite_orm { // stream a vector of already serialized strings; // comma-separated template - std::ostream& operator<<(std::ostream& ss, std::tuple&, C> tpl) { - const auto& strings = get<1>(tpl); + std::ostream& operator<<(std::ostream& ss, mpl::tuple&, C> tpl) { + const auto& strings = std::get<1>(tpl); constexpr std::array sep = {", ", ""}; for(size_t i = 0, first = true; i < strings.size(); ++i) { @@ -13430,7 +13639,7 @@ namespace sqlite_orm { // 3. qualifier, identifier, alias template std::ostream& operator<<(std::ostream& ss, - std::tuple&, Strings...> tpl) { + mpl::tuple&, Strings...> tpl) { stream_identifier(ss, tpl, streaming_identifier.offset_index(std::index_sequence_for{})); return ss; } @@ -13443,8 +13652,8 @@ namespace sqlite_orm { // // comma-separated template - std::ostream& operator<<(std::ostream& ss, std::tuple&, C> tpl) { - const auto& identifiers = get<1>(tpl); + std::ostream& operator<<(std::ostream& ss, mpl::tuple&, C> tpl) { + const auto& identifiers = std::get<1>(tpl); constexpr std::array sep = {", ", ""}; bool first = true; @@ -13458,9 +13667,9 @@ namespace sqlite_orm { // stream placeholders as part of a values clause template std::ostream& operator<<(std::ostream& ss, - std::tuple&, Ts...> tpl) { - const size_t& columnsCount = get<1>(tpl); - const ptrdiff_t& valuesCount = get<2>(tpl); + mpl::tuple&, Ts...> tpl) { + const size_t& columnsCount = std::get<1>(tpl); + const ptrdiff_t& valuesCount = std::get<2>(tpl); if(!valuesCount || !columnsCount) { return ss; @@ -13487,9 +13696,9 @@ namespace sqlite_orm { // comma-separated template std::ostream& operator<<(std::ostream& ss, - std::tuple&, Table, const bool&> tpl) { - const auto& table = get<1>(tpl); - const bool& qualified = get<2>(tpl); + mpl::tuple&, Table, const bool&> tpl) { + const auto& table = std::get<1>(tpl); + const bool& qualified = std::get<2>(tpl); table.for_each_column([&ss, &tableName = qualified ? table.name : std::string{}, first = true]( const column_identifier& column) mutable { @@ -13504,8 +13713,8 @@ namespace sqlite_orm { // comma-separated template std::ostream& operator<<(std::ostream& ss, - std::tuple&, Table> tpl) { - const auto& table = get<1>(tpl); + mpl::tuple&, Table> tpl) { + const auto& table = std::get<1>(tpl); table.template for_each_column_excluding( [&ss, first = true](const column_identifier& column) mutable { @@ -13521,11 +13730,11 @@ namespace sqlite_orm { template std::ostream& operator<<(std::ostream& ss, - std::tuple&, PredFnCls, L, Ctx, Obj> tpl) { + mpl::tuple&, PredFnCls, L, Ctx, Obj> tpl) { using check_if_excluded = polyfill::remove_cvref_t>; - auto& excluded = get<2>(tpl); - auto& context = get<3>(tpl); - auto& object = get<4>(tpl); + auto& excluded = std::get<2>(tpl); + auto& context = std::get<3>(tpl); + auto& object = std::get<4>(tpl); using object_type = polyfill::remove_cvref_t; auto& table = pick_table(context.db_objects); @@ -13546,9 +13755,9 @@ namespace sqlite_orm { // comma-separated template std::ostream& operator<<(std::ostream& ss, - std::tuple&, T, Ctx> tpl) { - const auto& columns = get<1>(tpl); - auto& context = get<2>(tpl); + mpl::tuple&, T, Ctx> tpl) { + const auto& columns = std::get<1>(tpl); + auto& context = std::get<2>(tpl); iterate_tuple(columns, [&ss, &context, first = true](auto& colRef) mutable { const std::string* columnName = find_column_name(context.db_objects, colRef); @@ -13565,13 +13774,13 @@ namespace sqlite_orm { template std::ostream& operator<<(std::ostream& ss, - std::tuple&, + mpl::tuple&, const column_constraints&, const bool&, Ctx> tpl) { - const auto& column = get<1>(tpl); - const bool& isNotNull = get<2>(tpl); - auto& context = get<3>(tpl); + const auto& column = std::get<1>(tpl); + const bool& isNotNull = std::get<2>(tpl); + auto& context = std::get<3>(tpl); using constraints_type = constraints_type_t>; constexpr size_t constraintsCount = std::tuple_size::value; @@ -14122,7 +14331,6 @@ namespace sqlite_orm { #include #include // std::index_sequence, std::make_index_sequence -#include // std::tuple, std::tuple_size, std::get // #include "functional/cxx_universal.h" @@ -15243,6 +15451,8 @@ namespace sqlite_orm { // #include "functional/mpl.h" +// #include "functional/pack.h" + // #include "functional/type_at.h" // #include "tuple_helper/tuple_filter.h" @@ -15744,9 +15954,9 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, std::tuple>, void> { - using statement_type = upsert_clause, std::tuple>; + template + struct statement_serializer> { + using statement_type = T; template std::string operator()(const statement_type& statement, const Ctx& context) const { @@ -16368,9 +16578,9 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, std::tuple>, void> { - using statement_type = foreign_key_t, std::tuple>; + template + struct statement_serializer> { + using statement_type = FK; template std::string operator()(const statement_type& fk, const Ctx& context) const { @@ -16495,7 +16705,7 @@ namespace sqlite_orm { template std::string operator()(const statement_type& ins, const Ctx& context) const { - constexpr size_t colsCount = std::tuple_size>::value; + constexpr size_t colsCount = sizeof...(Cols); static_assert(colsCount > 0, "Use insert or replace with 1 argument instead"); using expression_type = std::decay_t; using object_type = typename expression_object_type::type; @@ -16968,7 +17178,7 @@ namespace sqlite_orm { table_name_collector collector([&context](const std::type_index& ti) { return find_table_name(context.db_objects, ti); }); - constexpr bool explicitFromItemsCount = count_tuple, is_from>::value; + constexpr bool explicitFromItemsCount = count_tuple, is_from>::value; if(!explicitFromItemsCount) { iterate_ast(sel.col, collector); iterate_ast(sel.conditions, collector); @@ -17060,17 +17270,15 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, void> { - using statement_type = from_t; + template + struct statement_serializer> { + using statement_type = T; template std::string operator()(const statement_type&, const Ctx& context) const { - using tuple = std::tuple; - std::stringstream ss; ss << "FROM "; - iterate_tuple([&context, &ss, first = true](auto* item) mutable { + iterate_tuple([&context, &ss, first = true](auto* item) mutable { using from_type = std::remove_pointer_t; constexpr std::array sep = {", ", ""}; @@ -17678,8 +17886,8 @@ namespace sqlite_orm { template void assert_mapped_type() const { - using mapped_types_tuple = std::tuple; - static_assert(mpl::invoke_t, mapped_types_tuple>::value, + using mapped_types_pack = mpl::pack; + static_assert(mpl::invoke_t, mapped_types_pack>::value, "type is not mapped to a storage"); } @@ -17963,11 +18171,7 @@ namespace sqlite_orm { * @param m is a class member pointer (the same you passed into make_column). * @return group_concat query result. */ - template, - std::enable_if_t::value >= 1, bool> = true> + template= 1, bool> = true> std::string group_concat(F O::*m, Args&&... args) { return this->group_concat_internal(m, {}, std::forward(args)...); } @@ -18072,8 +18276,7 @@ namespace sqlite_orm { */ template> std::vector select(T m, Args... args) { - static_assert(!is_base_of_template_v || - std::tuple_size>::value == 0, + static_assert(!is_base_of_template_v || sizeof...(Args) == 0, "Cannot use args with a compound operator"); auto statement = this->prepare(sqlite_orm::select(std::move(m), std::forward(args)...)); return this->execute(statement); @@ -19056,7 +19259,7 @@ namespace sqlite_orm { }; template - struct node_tuple, std::tuple>, void> + struct node_tuple, mpl::tuple>, void> : node_tuple> {}; template diff --git a/tests/functional/tuple/assign.convert_copy.cpp b/tests/functional/tuple/assign.convert_copy.cpp new file mode 100644 index 000000000..a2b4cbf7e --- /dev/null +++ b/tests/functional/tuple/assign.convert_copy.cpp @@ -0,0 +1,69 @@ +#include +#include + +using namespace sqlite_orm; + +namespace { + struct B { + int id_; + explicit B(int i = 0) : id_(i) {} + }; + + struct D : B { + explicit D(int i = 0) : B(i) {} + }; +} + +template class Tuple> +static void template_template_test_case() { + { + using T0 = Tuple; + using T1 = Tuple; + T0 t0(2.5); + T1 t1; + t1 = t0; + REQUIRE(std::get<0>(t1) == 2); + } + { + using T0 = Tuple; + using T1 = Tuple; + T0 t0(2.5, 'a'); + T1 t1; + t1 = t0; + REQUIRE(std::get<0>(t1) == 2); + REQUIRE(std::get<1>(t1) == int('a')); + } + { + using T0 = Tuple; + using T1 = Tuple; + T0 t0(2.5, 'a', D(3)); + T1 t1; + t1 = t0; + REQUIRE(std::get<0>(t1) == 2); + REQUIRE(std::get<1>(t1) == int('a')); + REQUIRE(std::get<2>(t1).id_ == 3); + } + { + D d(3); + D d2(2); + using T0 = Tuple; + using T1 = Tuple; + T0 t0(2.5, 'a', d2); + T1 t1(1.5, 'b', d); + t1 = t0; + REQUIRE(std::get<0>(t1) == 2); + REQUIRE(std::get<1>(t1) == int('a')); + REQUIRE(std::get<2>(t1).id_ == 2); + } +} + +TEST_CASE("tuple - converting copy assignment") { + { + INFO("mpl::tuple"); + template_template_test_case(); + } + { + INFO("mpl::uple"); + template_template_test_case(); + } +} diff --git a/tests/functional/tuple/assign.convert_move.cpp b/tests/functional/tuple/assign.convert_move.cpp new file mode 100644 index 000000000..ff8ab5097 --- /dev/null +++ b/tests/functional/tuple/assign.convert_move.cpp @@ -0,0 +1,79 @@ +#include +#include + +using namespace sqlite_orm; + +namespace { + struct B { + int id_; + explicit B(int i = 0) : id_(i) {} + virtual ~B() {} + }; + + struct D : B { + explicit D(int i) : B(i) {} + }; +} + +template class Tuple> +static void template_template_test_case() { + { + using T0 = Tuple; + using T1 = Tuple; + T0 t0(2.5); + T1 t1; + t1 = std::move(t0); + REQUIRE(std::get<0>(t1) == 2); + } + { + using T0 = Tuple; + using T1 = Tuple; + T0 t0(2.5, 'a'); + T1 t1; + t1 = std::move(t0); + REQUIRE(std::get<0>(t1) == 2); + REQUIRE(std::get<1>(t1) == int('a')); + } + { + using T0 = Tuple; + using T1 = Tuple; + T0 t0(2.5, 'a', D(3)); + T1 t1; + t1 = std::move(t0); + REQUIRE(std::get<0>(t1) == 2); + REQUIRE(std::get<1>(t1) == int('a')); + REQUIRE(std::get<2>(t1).id_ == 3); + } + { + D d(3); + D d2(2); + using T0 = Tuple; + using T1 = Tuple; + T0 t0(2.5, 'a', d2); + T1 t1(1.5, 'b', d); + t1 = std::move(t0); + REQUIRE(std::get<0>(t1) == 2); + REQUIRE(std::get<1>(t1) == int('a')); + REQUIRE(std::get<2>(t1).id_ == 2); + } + { + using T0 = Tuple>; + using T1 = Tuple>; + T0 t0(2.5, 'a', std::unique_ptr(new D(3))); + T1 t1; + t1 = std::move(t0); + REQUIRE(std::get<0>(t1) == 2); + REQUIRE(std::get<1>(t1) == int('a')); + REQUIRE(std::get<2>(t1)->id_ == 3); + } +} + +TEST_CASE("tuple - converting move assignment") { + { + //INFO("mpl::tuple"); + //template_template_test_case(); + } { + INFO("mpl::uple"); + template_template_test_case(); + } +} diff --git a/tests/functional/tuple/assign.copy.cpp b/tests/functional/tuple/assign.copy.cpp new file mode 100644 index 000000000..06f082906 --- /dev/null +++ b/tests/functional/tuple/assign.copy.cpp @@ -0,0 +1,49 @@ +#include +#include + +using namespace sqlite_orm; + +template class Tuple> +static void template_template_test_case() { + { + using T = Tuple<>; + T t0; + T t; + t = t0; + } + { + using T = Tuple; + T t0(2); + T t; + t = t0; + REQUIRE(std::get<0>(t) == 2); + } + { + using T = Tuple; + T t0(2, 'a'); + T t; + t = t0; + REQUIRE(std::get<0>(t) == 2); + REQUIRE(std::get<1>(t) == 'a'); + } + { + using T = Tuple; + const T t0(2, 'a', "some text"); + T t; + t = t0; + REQUIRE(std::get<0>(t) == 2); + REQUIRE(std::get<1>(t) == 'a'); + REQUIRE(std::get<2>(t) == "some text"); + } +} + +TEST_CASE("tuple - copy assignment") { + { + INFO("mpl::tuple"); + template_template_test_case(); + } + { + INFO("mpl::uple"); + template_template_test_case(); + } +} diff --git a/tests/functional/tuple/assign.move.cpp b/tests/functional/tuple/assign.move.cpp new file mode 100644 index 000000000..ea5930de5 --- /dev/null +++ b/tests/functional/tuple/assign.move.cpp @@ -0,0 +1,72 @@ +#include +#include + +using namespace sqlite_orm; + +namespace { + template + struct MoveOnly { + int data_; + MoveOnly(MoveOnly const&) = delete; + MoveOnly& operator=(MoveOnly const&) = delete; + MoveOnly(int data = 1) : data_(data) {} + MoveOnly(MoveOnly&& x) : data_(x.data_) { + x.data_ = 0; + } + + MoveOnly& operator=(MoveOnly&& x) { + data_ = x.data_; + x.data_ = 0; + return *this; + } + + int get() const { + return data_; + } + bool operator==(const MoveOnly& x) const { + return data_ == x.data_; + } + bool operator<(const MoveOnly& x) const { + return data_ < x.data_; + } + }; + + using MoveOnly1 = MoveOnly<1>; + using MoveOnly2 = MoveOnly<2>; +} + +template class Tuple> +static void template_template_test_case() { + { + using T = Tuple<>; + T t0; + T t; + t = std::move(t0); + } + { + using T = Tuple; + T t0(MoveOnly1(0)); + T t; + t = std::move(t0); + REQUIRE(std::get<0>(t) == 0); + } + { + using T = Tuple; + T t0(MoveOnly1(0), MoveOnly2(1)); + T t; + t = std::move(t0); + REQUIRE(std::get<0>(t) == 0); + REQUIRE(std::get<1>(t) == 1); + } +} + +TEST_CASE("tuple - move assignment") { + { + INFO("mpl::tuple"); + template_template_test_case(); + } + { + INFO("mpl::uple"); + template_template_test_case(); + } +} diff --git a/tests/functional/tuple/cnstr.convert_copy.cpp b/tests/functional/tuple/cnstr.convert_copy.cpp index 970339b70..4335b4b07 100644 --- a/tests/functional/tuple/cnstr.convert_copy.cpp +++ b/tests/functional/tuple/cnstr.convert_copy.cpp @@ -30,39 +30,40 @@ namespace { }; } -TEST_CASE("tuple - convert copyable") { +template class Tuple> +static void template_template_test_case() { { - using T0 = mpl::tuple; - using T1 = mpl::tuple; + using T0 = Tuple; + using T1 = Tuple; T0 t0(2.5); T1 t1 = t0; REQUIRE(std::get<0>(t1) == 2); } { - using T0 = mpl::tuple; - using T1 = mpl::tuple; + using T0 = Tuple; + using T1 = Tuple; constexpr T0 t0(2.5); constexpr T1 t1 = t0; STATIC_REQUIRE(std::get<0>(t1) == 2); } { - using T0 = mpl::tuple; - using T1 = mpl::tuple; + using T0 = Tuple; + using T1 = Tuple; constexpr T0 t0(2); constexpr T1 t1{t0}; STATIC_REQUIRE(std::get<0>(t1) == C(2)); } { - using T0 = mpl::tuple; - using T1 = mpl::tuple; + using T0 = Tuple; + using T1 = Tuple; T0 t0(2.5, 'a'); T1 t1 = t0; REQUIRE(std::get<0>(t1) == 2); REQUIRE(std::get<1>(t1) == int('a')); } { - using T0 = mpl::tuple; - using T1 = mpl::tuple; + using T0 = Tuple; + using T1 = Tuple; T0 t0(2.5, 'a', D(3)); T1 t1 = t0; REQUIRE(std::get<0>(t1) == 2); @@ -71,8 +72,8 @@ TEST_CASE("tuple - convert copyable") { } { D d(3); - using T0 = mpl::tuple; - using T1 = mpl::tuple; + using T0 = Tuple; + using T1 = Tuple; T0 t0(2.5, 'a', d); T1 t1 = t0; d.id_ = 2; @@ -81,8 +82,8 @@ TEST_CASE("tuple - convert copyable") { REQUIRE(std::get<2>(t1).id_ == 2); } { - using T0 = mpl::tuple; - using T1 = mpl::tuple; + using T0 = Tuple; + using T1 = Tuple; T0 t0(2.5, 'a', 3); T1 t1(t0); REQUIRE(std::get<0>(t1) == 2); @@ -90,3 +91,14 @@ TEST_CASE("tuple - convert copyable") { REQUIRE(std::get<2>(t1).id_ == 3); } } + +TEST_CASE("tuple - converting copy construction") { + { + INFO("mpl::tuple"); + template_template_test_case(); + } + { + INFO("mpl::uple"); + template_template_test_case(); + } +} diff --git a/tests/functional/tuple/cnstr.convert_move.cpp b/tests/functional/tuple/cnstr.convert_move.cpp index 909af5f5c..ea4531102 100644 --- a/tests/functional/tuple/cnstr.convert_move.cpp +++ b/tests/functional/tuple/cnstr.convert_move.cpp @@ -15,25 +15,26 @@ namespace { }; } -TEST_CASE("tuple - convert movable") { +template class Tuple> +static void template_template_test_case() { { - using T0 = mpl::tuple; - using T1 = mpl::tuple; + using T0 = Tuple; + using T1 = Tuple; T0 t0(2.5); T1 t1 = std::move(t0); REQUIRE(std::get<0>(t1) == 2); } { - using T0 = mpl::tuple; - using T1 = mpl::tuple; + using T0 = Tuple; + using T1 = Tuple; T0 t0(2.5, 'a'); T1 t1 = std::move(t0); REQUIRE(std::get<0>(t1) == 2); REQUIRE(std::get<1>(t1) == int('a')); } { - using T0 = mpl::tuple; - using T1 = mpl::tuple; + using T0 = Tuple; + using T1 = Tuple; T0 t0(2.5, 'a', D(3)); T1 t1 = std::move(t0); REQUIRE(std::get<0>(t1) == 2); @@ -42,8 +43,8 @@ TEST_CASE("tuple - convert movable") { } { D d(3); - using T0 = mpl::tuple; - using T1 = mpl::tuple; + using T0 = Tuple; + using T1 = Tuple; T0 t0(2.5, 'a', d); T1 t1 = std::move(t0); d.id_ = 2; @@ -52,8 +53,8 @@ TEST_CASE("tuple - convert movable") { REQUIRE(std::get<2>(t1).id_ == 2); } { - using T0 = mpl::tuple>; - using T1 = mpl::tuple>; + using T0 = Tuple>; + using T1 = Tuple>; T0 t0(2.5, 'a', std::unique_ptr(new D(3))); T1 t1 = std::move(t0); REQUIRE(std::get<0>(t1) == 2); @@ -61,3 +62,14 @@ TEST_CASE("tuple - convert movable") { REQUIRE(std::get<2>(t1)->id_ == 3); } } + +TEST_CASE("tuple - converting move construction") { + { + INFO("mpl::tuple"); + template_template_test_case(); + } + { + INFO("mpl::uple"); + template_template_test_case(); + } +} diff --git a/tests/functional/tuple/cnstr.copy.cpp b/tests/functional/tuple/cnstr.copy.cpp index 672c91098..e0938bda6 100644 --- a/tests/functional/tuple/cnstr.copy.cpp +++ b/tests/functional/tuple/cnstr.copy.cpp @@ -65,7 +65,7 @@ static void template_template_test_case() { } } -TEST_CASE("tuple - copy") { +TEST_CASE("tuple - copy construction") { { INFO("mpl::tuple"); template_template_test_case(); diff --git a/tests/functional/tuple/cnstr.default.cpp b/tests/functional/tuple/cnstr.default.cpp index 5df669547..5770349da 100644 --- a/tests/functional/tuple/cnstr.default.cpp +++ b/tests/functional/tuple/cnstr.default.cpp @@ -132,7 +132,7 @@ static void template_template_test_case() { } } -TEST_CASE("tuple - default") { +TEST_CASE("tuple - default construction") { { INFO("mpl::tuple"); template_template_test_case(); diff --git a/tests/functional/tuple/cnstr.move.cpp b/tests/functional/tuple/cnstr.move.cpp index 7f804ef7a..ed35d3835 100644 --- a/tests/functional/tuple/cnstr.move.cpp +++ b/tests/functional/tuple/cnstr.move.cpp @@ -70,7 +70,7 @@ static void template_template_test_case() { } } -TEST_CASE("tuple - move") { +TEST_CASE("tuple - move construction") { { INFO("mpl::tuple"); template_template_test_case(); From 7a048e3cee434f8304eedea23adaba4358903fd0 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Jun 2022 00:04:15 +0300 Subject: [PATCH 08/16] Replaced std tuple of simple case builder --- dev/functional/cxx_type_traits_polyfill.h | 24 + dev/functional/index_sequence_util.h | 113 ++ dev/functional/indexed_type.h | 2 +- dev/functional/pack_util.h | 30 + dev/functional/tuple.h | 37 +- dev/functional/tuple_common.h | 7 + dev/functional/unique_tuple.h | 6 +- dev/implementations/column_definitions.h | 4 +- dev/select_constraints.h | 10 +- dev/table.h | 5 +- dev/tuple_helper/index_sequence_util.h | 51 - dev/tuple_helper/tuple_filter.h | 30 +- dev/tuple_helper/tuple_iteration.h | 4 +- include/sqlite_orm/sqlite_orm.h | 1197 +++++++++-------- tests/constraints/foreign_key.cpp | 4 +- tests/static_tests/foreign_key.cpp | 13 +- tests/static_tests/node_tuple.cpp | 8 +- .../static_tests_storage_traits.h | 6 +- 18 files changed, 910 insertions(+), 641 deletions(-) create mode 100644 dev/functional/index_sequence_util.h create mode 100644 dev/functional/pack_util.h delete mode 100644 dev/tuple_helper/index_sequence_util.h diff --git a/dev/functional/cxx_type_traits_polyfill.h b/dev/functional/cxx_type_traits_polyfill.h index 7c19451c5..996684220 100644 --- a/dev/functional/cxx_type_traits_polyfill.h +++ b/dev/functional/cxx_type_traits_polyfill.h @@ -74,6 +74,30 @@ namespace sqlite_orm { using type_identity_t = typename type_identity::type; #endif +#if __cpp_lib_unwrap_ref >= 201811L + using std::unwrap_ref_decay, std::unwrap_ref_decay_t; + using std::unwrap_reference, std::unwrap_reference_t; +#else + template + struct unwrap_reference { + using type = T; + }; + template + struct unwrap_reference> { + using type = T&; + }; + template + using unwrap_reference_t = typename unwrap_reference::type; + + template + using unwrap_ref_decay_t = unwrap_reference_t>; + + template + struct unwrap_ref_decay { + using type = unwrap_ref_decay_t; + }; +#endif + #if 0 // __cpp_lib_detect >= 0L // library fundamentals TS v2, [meta.detect] using std::nonesuch; using std::detector; diff --git a/dev/functional/index_sequence_util.h b/dev/functional/index_sequence_util.h new file mode 100644 index 000000000..ad96d2967 --- /dev/null +++ b/dev/functional/index_sequence_util.h @@ -0,0 +1,113 @@ +#pragma once + +#include // std::index_sequence, std::make_index_sequence + +#include "cxx_universal.h" +#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED +#include +#endif +#include "pack.h" + +namespace sqlite_orm { + namespace internal { + namespace mpl { + /** + * Get the first value of an index_sequence. + */ + template + SQLITE_ORM_CONSTEVAL size_t first_index_sequence_value(std::index_sequence) { + return I; + } + +#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED + /** + * Reorder the values of an index_sequence according to the positions from a second sequence. + */ + template + SQLITE_ORM_CONSTEVAL auto reorder_index_sequence(std::index_sequence, + std::index_sequence) { + constexpr std::array values{Value...}; + return std::index_sequence{}; + } + + template + SQLITE_ORM_CONSTEVAL std::index_sequence reorder_index_sequence(std::index_sequence, + std::index_sequence) { + return {}; + } + + inline SQLITE_ORM_CONSTEVAL std::index_sequence<> reorder_index_sequence(std::index_sequence<>, + std::index_sequence<>) { + return {}; + } + + /** + * Reverse the values of an index_sequence. + */ + template + SQLITE_ORM_CONSTEVAL auto reverse_index_sequence(std::index_sequence) { + return reorder_index_sequence(std::index_sequence{}, + std::make_index_sequence{}); + } +#endif + +#ifdef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + template + using comma_expression_helper = std::integral_constant; +#endif + + template + constexpr auto expand_n(std::index_sequence) { +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + using type = std::index_sequence<(Times, n)...>; +#else + using type = std::index_sequence::value...>; +#endif + return type{}; + } + + template + using expand_n_t = decltype(expand_n(Times{})); + +#ifdef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + template + struct spread_idxseq_helper { + using type = expand_n_t>; + }; +#endif + + template + constexpr auto spread_idxseq(std::index_sequence, std::index_sequence) { +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + using type = pack>...>; +#else + using type = pack::type...>; +#endif + return type{}; + } + + template + using spread_idxseq_t = decltype(spread_idxseq(std::declval(), std::declval())); + + template + struct flatten_idxseq { + using type = std::index_sequence<>; + }; + + template + struct flatten_idxseq> { + using type = std::index_sequence; + }; + + template + struct flatten_idxseq, std::index_sequence, Seq...> + : flatten_idxseq, Seq...> {}; + + template + struct flatten_idxseq> : flatten_idxseq {}; + + template + using flatten_idxseq_t = typename flatten_idxseq::type; + } + } +} diff --git a/dev/functional/indexed_type.h b/dev/functional/indexed_type.h index 3f0503104..c61701431 100644 --- a/dev/functional/indexed_type.h +++ b/dev/functional/indexed_type.h @@ -7,7 +7,7 @@ namespace _sqlite_orm { // since those types are used as a building block; // (as seen in boost hana) - template + template struct indexed_type { using type = T; }; diff --git a/dev/functional/pack_util.h b/dev/functional/pack_util.h new file mode 100644 index 000000000..8288d05ce --- /dev/null +++ b/dev/functional/pack_util.h @@ -0,0 +1,30 @@ +#pragma once + +namespace sqlite_orm { + namespace internal { + namespace mpl { + template class R, class... Pack> + struct flatten_types { + using type = R<>; + }; + + template class R, template class Pack1, class... X> + struct flatten_types> { + using type = R; + }; + + template class R, + template + class Pack1, + template + class Pack2, + class... X, + class... Y, + class... Pack> + struct flatten_types, Pack2, Pack...> : flatten_types, Pack...> {}; + + template class R, class... Pack> + using flatten_types_t = typename flatten_types::type; + } + } +} diff --git a/dev/functional/tuple.h b/dev/functional/tuple.h index 75be2d01d..48dd92007 100644 --- a/dev/functional/tuple.h +++ b/dev/functional/tuple.h @@ -1,12 +1,14 @@ #pragma once -#include // std::integral_constant, std::decay, std::is_constructible, std::is_default_constructible, std::enable_if, std::declval +#include // std::integral_constant, std::decay, std::remove_reference, std::is_constructible, std::is_default_constructible, std::enable_if, std::declval #include // std::move, std::forward #include "cxx_universal.h" #include "cxx_type_traits_polyfill.h" #include "fast_and.h" #include "indexed_type.h" +#include "index_sequence_util.h" +#include "pack_util.h" #include "type_at.h" #include "tuple_common.h" @@ -256,22 +258,49 @@ namespace sqlite_orm { namespace adl { template constexpr auto make_tuple(X&&... x) { - return tuple...>{std::forward(x)...}; + return tuple...>{std::forward(x)...}; } template constexpr tuple forward_as_tuple(X&&... args) noexcept { - return tuple{std::forward(args)...}; + return {std::forward(args)...}; } template constexpr tuple tie(X&... args) noexcept { - return tuple{args...}; + return {args...}; + } + + template + constexpr flatten_types_t...> + tuple_cat_helper(std::index_sequence, std::index_sequence, Tuples&&... tuples) { + return {ebo_get(std::get(adl::forward_as_tuple(std::forward(tuples)...)))...}; + } + + template + constexpr auto tuple_cat(Tuples&&... tuples) { + using tuples_seq = std::make_index_sequence; + // -> index_sequence + using sizes_seq = std::index_sequence>::value...>; + using inner = flatten_idxseq_t< + // -> pack, index_sequence, ...> + spread_idxseq_t>; + using outer = typename flatten_idxseq< +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + // index_sequence, ... + std::make_index_sequence>::value>... +#else + typename make_idxseq_helper>::type... +#endif + >::type; + + return tuple_cat_helper(inner{}, outer{}, std::forward(tuples)...); } } using adl::forward_as_tuple; using adl::make_tuple; using adl::tie; + using adl::tuple_cat; } } } diff --git a/dev/functional/tuple_common.h b/dev/functional/tuple_common.h index 5dfc7e91e..a966682d7 100644 --- a/dev/functional/tuple_common.h +++ b/dev/functional/tuple_common.h @@ -32,6 +32,13 @@ namespace sqlite_orm { }; template using remove_rvalue_reference_t = typename remove_rvalue_reference::type; + +#ifdef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + template + struct make_idxseq_helper { + using type = std::make_index_sequence::value>; + }; +#endif } } diff --git a/dev/functional/unique_tuple.h b/dev/functional/unique_tuple.h index 25965e830..4bed51b80 100644 --- a/dev/functional/unique_tuple.h +++ b/dev/functional/unique_tuple.h @@ -232,17 +232,17 @@ namespace sqlite_orm { template constexpr auto make_unique_tuple(X&&... x) { - return uple...>{std::forward(x)...}; + return uple...>{std::forward(x)...}; } template constexpr uple forward_as_unique_tuple(X&&... args) noexcept { - return uple{std::forward(args)...}; + return {std::forward(args)...}; } template constexpr uple tie_unique(X&... args) noexcept { - return uple{args...}; + return {args...}; } } } diff --git a/dev/implementations/column_definitions.h b/dev/implementations/column_definitions.h index b2c83fc61..585cc3959 100644 --- a/dev/implementations/column_definitions.h +++ b/dev/implementations/column_definitions.h @@ -8,7 +8,7 @@ #include "../functional/cxx_core_features.h" #include "../functional/static_magic.h" -#include "../tuple_helper/index_sequence_util.h" +#include "../functional/index_sequence_util.h" #include "../tuple_helper/tuple_filter.h" #include "../tuple_helper/tuple_traits.h" #include "../default_value_extractor.h" @@ -26,7 +26,7 @@ namespace sqlite_orm { call_if_constexpr( [&value](auto& constraints, auto op_index_sequence) { using default_op_index_sequence = decltype(op_index_sequence); - constexpr size_t opIndex = first_index_sequence_value(default_op_index_sequence{}); + constexpr size_t opIndex = mpl::first_index_sequence_value(default_op_index_sequence{}); value = std::make_unique(serialize_default_value(std::get(constraints))); }, this->constraints, diff --git a/dev/select_constraints.h b/dev/select_constraints.h index 91cc54a28..a9b79c9b0 100644 --- a/dev/select_constraints.h +++ b/dev/select_constraints.h @@ -271,7 +271,7 @@ namespace sqlite_orm { struct simple_case_t { using return_type = R; using case_expression_type = T; - using args_type = std::tuple; + using args_type = mpl::tuple; using else_expression_type = E; optional_container case_expression; @@ -288,7 +288,7 @@ namespace sqlite_orm { struct simple_case_builder { using return_type = R; using case_expression_type = T; - using args_type = std::tuple; + using args_type = mpl::tuple; using else_expression_type = E; optional_container case_expression; @@ -297,9 +297,9 @@ namespace sqlite_orm { template simple_case_builder> when(W w, then_t t) { - using result_args_type = std::tuple>; + using result_args_type = mpl::tuple>; std::pair newPair{std::move(w), std::move(t.expression)}; - result_args_type result_args = std::tuple_cat(std::move(this->args), std::make_tuple(newPair)); + result_args_type result_args = mpl::tuple_cat(std::move(this->args), mpl::make_tuple(newPair)); std::get::value - 1>(result_args) = std::move(newPair); return {std::move(this->case_expression), std::move(result_args), std::move(this->else_expression)}; } @@ -394,7 +394,7 @@ namespace sqlite_orm { */ template internal::select_t select(T t, Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::pack; internal::validate_conditions(); return {std::move(t), mpl::make_tuple(std::forward(args)...)}; } diff --git a/dev/table.h b/dev/table.h index fc340efdc..1d8ba1acc 100644 --- a/dev/table.h +++ b/dev/table.h @@ -11,9 +11,9 @@ #include "functional/static_magic.h" #include "functional/mpl.h" #include "functional/type_at.h" +#include "functional/index_sequence_util.h" #include "functional/tuple.h" #include "typed_comparator.h" -#include "tuple_helper/index_sequence_util.h" #include "tuple_helper/tuple_filter.h" #include "tuple_helper/tuple_traits.h" #include "tuple_helper/tuple_iteration.h" @@ -108,7 +108,8 @@ namespace sqlite_orm { using generated_op_index_sequence = filter_tuple_sequence_t, is_generated_always>; - constexpr size_t opIndex = first_index_sequence_value(generated_op_index_sequence{}); + constexpr size_t opIndex = + mpl::first_index_sequence_value(generated_op_index_sequence{}); result = &std::get(column.constraints).storage; }); #endif diff --git a/dev/tuple_helper/index_sequence_util.h b/dev/tuple_helper/index_sequence_util.h deleted file mode 100644 index 556c21142..000000000 --- a/dev/tuple_helper/index_sequence_util.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include // std::index_sequence, std::make_index_sequence - -#include "../functional/cxx_universal.h" -#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED -#include -#endif - -namespace sqlite_orm { - namespace internal { - /** - * Get the first value of an index_sequence. - */ - template - SQLITE_ORM_CONSTEVAL size_t first_index_sequence_value(std::index_sequence) { - return I; - } - -#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED - /** - * Reorder the values of an index_sequence according to the positions from a second sequence. - */ - template - SQLITE_ORM_CONSTEVAL auto reorder_index_sequence(std::index_sequence, - std::index_sequence) { - constexpr std::array values{Value...}; - return std::index_sequence{}; - } - - template - SQLITE_ORM_CONSTEVAL std::index_sequence reorder_index_sequence(std::index_sequence, - std::index_sequence) { - return {}; - } - - inline SQLITE_ORM_CONSTEVAL std::index_sequence<> reorder_index_sequence(std::index_sequence<>, - std::index_sequence<>) { - return {}; - } - - /** - * Reverse the values of an index_sequence. - */ - template - SQLITE_ORM_CONSTEVAL auto reverse_index_sequence(std::index_sequence) { - return reorder_index_sequence(std::index_sequence{}, std::make_index_sequence{}); - } -#endif - } -} diff --git a/dev/tuple_helper/tuple_filter.h b/dev/tuple_helper/tuple_filter.h index 4597d8daf..f91900a82 100644 --- a/dev/tuple_helper/tuple_filter.h +++ b/dev/tuple_helper/tuple_filter.h @@ -1,18 +1,16 @@ #pragma once #include // std::integral_constant, std::index_sequence, std::make_index_sequence, std::conditional, std::declval +#include #include "../functional/cxx_universal.h" -#include "../functional/type_at.h" -#include "../functional/pack.h" -#include "../functional/unique_tuple.h" -#include "../functional/tuple.h" +#include "../functional/index_sequence_util.h" namespace sqlite_orm { namespace internal { template - using tuple_cat_t = decltype(std::tuple_cat(std::declval()...)); + using tuple_cat_t = mpl::flatten_types_t; template struct conc_tuple { @@ -30,29 +28,15 @@ namespace sqlite_orm { template using tuple_from_index_sequence_t = typename tuple_from_index_sequence::type; - template - struct concat_idx_seq { - using type = std::index_sequence<>; - }; - - template - struct concat_idx_seq> { - using type = std::index_sequence; - }; - - template - struct concat_idx_seq, std::index_sequence, Seq...> - : concat_idx_seq, Seq...> {}; - template class Pred, template class Proj, class Seq> struct filter_tuple_sequence; #ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION template class Pred, template class Proj, size_t... Idx> struct filter_tuple_sequence> - : concat_idx_seq>>::value, - std::index_sequence, - std::index_sequence<>>...> {}; + : mpl::flatten_idxseq>>::value, + std::index_sequence, + std::index_sequence<>>...> {}; #else template class Pred, class SFINAE = void> struct tuple_seq_single { @@ -66,7 +50,7 @@ namespace sqlite_orm { template class Pred, template class Proj, size_t... Idx> struct filter_tuple_sequence> - : concat_idx_seq>, Pred>::type...> {}; + : mpl::flatten_idxseq>, Pred>::type...> {}; #endif template void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { if constexpr(reversed) { - iterate_tuple(tpl, reverse_index_sequence(std::index_sequence{}), std::forward(lambda)); + iterate_tuple(tpl, mpl::reverse_index_sequence(std::index_sequence{}), std::forward(lambda)); } else { (lambda(std::get(tpl)), ...); } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index f8b75b182..1f625b6e0 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -234,6 +234,30 @@ namespace sqlite_orm { using type_identity_t = typename type_identity::type; #endif +#if __cpp_lib_unwrap_ref >= 201811L + using std::unwrap_ref_decay, std::unwrap_ref_decay_t; + using std::unwrap_reference, std::unwrap_reference_t; +#else + template + struct unwrap_reference { + using type = T; + }; + template + struct unwrap_reference> { + using type = T&; + }; + template + using unwrap_reference_t = typename unwrap_reference::type; + + template + using unwrap_ref_decay_t = unwrap_reference_t>; + + template + struct unwrap_ref_decay { + using type = unwrap_ref_decay_t; + }; +#endif + #if 0 // __cpp_lib_detect >= 0L // library fundamentals TS v2, [meta.detect] using std::nonesuch; using std::detector; @@ -983,7 +1007,7 @@ namespace sqlite_orm { // #include "functional/tuple.h" -#include // std::integral_constant, std::decay, std::is_constructible, std::is_default_constructible, std::enable_if, std::declval +#include // std::integral_constant, std::decay, std::remove_reference, std::is_constructible, std::is_default_constructible, std::enable_if, std::declval #include // std::move, std::forward // #include "cxx_universal.h" @@ -1024,7 +1048,7 @@ namespace _sqlite_orm { // since those types are used as a building block; // (as seen in boost hana) - template + template struct indexed_type { using type = T; }; @@ -1039,15 +1063,15 @@ namespace sqlite_orm { } } -// #include "type_at.h" +// #include "index_sequence_util.h" -#include // std::integral_constant, std::index_sequence, std::make_index_sequence -#include +#include // std::index_sequence, std::make_index_sequence // #include "cxx_universal.h" -// #include "indexed_type.h" - +#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED +#include +#endif // #include "pack.h" #include // std::integral_constant @@ -1079,6 +1103,152 @@ namespace std { struct tuple_size> : integral_constant {}; } +namespace sqlite_orm { + namespace internal { + namespace mpl { + /** + * Get the first value of an index_sequence. + */ + template + SQLITE_ORM_CONSTEVAL size_t first_index_sequence_value(std::index_sequence) { + return I; + } + +#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED + /** + * Reorder the values of an index_sequence according to the positions from a second sequence. + */ + template + SQLITE_ORM_CONSTEVAL auto reorder_index_sequence(std::index_sequence, + std::index_sequence) { + constexpr std::array values{Value...}; + return std::index_sequence{}; + } + + template + SQLITE_ORM_CONSTEVAL std::index_sequence reorder_index_sequence(std::index_sequence, + std::index_sequence) { + return {}; + } + + inline SQLITE_ORM_CONSTEVAL std::index_sequence<> reorder_index_sequence(std::index_sequence<>, + std::index_sequence<>) { + return {}; + } + + /** + * Reverse the values of an index_sequence. + */ + template + SQLITE_ORM_CONSTEVAL auto reverse_index_sequence(std::index_sequence) { + return reorder_index_sequence(std::index_sequence{}, + std::make_index_sequence{}); + } +#endif + +#ifdef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + template + using comma_expression_helper = std::integral_constant; +#endif + + template + constexpr auto expand_n(std::index_sequence) { +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + using type = std::index_sequence<(Times, n)...>; +#else + using type = std::index_sequence::value...>; +#endif + return type{}; + } + + template + using expand_n_t = decltype(expand_n(Times{})); + +#ifdef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + template + struct spread_idxseq_helper { + using type = expand_n_t>; + }; +#endif + + template + constexpr auto spread_idxseq(std::index_sequence, std::index_sequence) { +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + using type = pack>...>; +#else + using type = pack::type...>; +#endif + return type{}; + } + + template + using spread_idxseq_t = decltype(spread_idxseq(std::declval(), std::declval())); + + template + struct flatten_idxseq { + using type = std::index_sequence<>; + }; + + template + struct flatten_idxseq> { + using type = std::index_sequence; + }; + + template + struct flatten_idxseq, std::index_sequence, Seq...> + : flatten_idxseq, Seq...> {}; + + template + struct flatten_idxseq> : flatten_idxseq {}; + + template + using flatten_idxseq_t = typename flatten_idxseq::type; + } + } +} + +// #include "pack_util.h" + +namespace sqlite_orm { + namespace internal { + namespace mpl { + template class R, class... Pack> + struct flatten_types { + using type = R<>; + }; + + template class R, template class Pack1, class... X> + struct flatten_types> { + using type = R; + }; + + template class R, + template + class Pack1, + template + class Pack2, + class... X, + class... Y, + class... Pack> + struct flatten_types, Pack2, Pack...> : flatten_types, Pack...> {}; + + template class R, class... Pack> + using flatten_types_t = typename flatten_types::type; + } + } +} + +// #include "type_at.h" + +#include // std::integral_constant, std::index_sequence, std::make_index_sequence +#include + +// #include "cxx_universal.h" + +// #include "indexed_type.h" + +// #include "pack.h" + namespace sqlite_orm { namespace internal { namespace mpl { @@ -1161,6 +1331,13 @@ namespace sqlite_orm { }; template using remove_rvalue_reference_t = typename remove_rvalue_reference::type; + +#ifdef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + template + struct make_idxseq_helper { + using type = std::make_index_sequence::value>; + }; +#endif } } @@ -1413,22 +1590,49 @@ namespace sqlite_orm { namespace adl { template constexpr auto make_tuple(X&&... x) { - return tuple...>{std::forward(x)...}; + return tuple...>{std::forward(x)...}; } template constexpr tuple forward_as_tuple(X&&... args) noexcept { - return tuple{std::forward(args)...}; + return {std::forward(args)...}; } template constexpr tuple tie(X&... args) noexcept { - return tuple{args...}; + return {args...}; + } + + template + constexpr flatten_types_t...> + tuple_cat_helper(std::index_sequence, std::index_sequence, Tuples&&... tuples) { + return {ebo_get(std::get(adl::forward_as_tuple(std::forward(tuples)...)))...}; + } + + template + constexpr auto tuple_cat(Tuples&&... tuples) { + using tuples_seq = std::make_index_sequence; + // -> index_sequence + using sizes_seq = std::index_sequence>::value...>; + using inner = flatten_idxseq_t< + // -> pack, index_sequence, ...> + spread_idxseq_t>; + using outer = typename flatten_idxseq< +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + // index_sequence, ... + std::make_index_sequence>::value>... +#else + typename make_idxseq_helper>::type... +#endif + >::type; + + return tuple_cat_helper(inner{}, outer{}, std::forward(tuples)...); } } using adl::forward_as_tuple; using adl::make_tuple; using adl::tie; + using adl::tuple_cat; } } } @@ -1565,425 +1769,104 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_filter.h" #include // std::integral_constant, std::index_sequence, std::make_index_sequence, std::conditional, std::declval +#include // #include "../functional/cxx_universal.h" -// #include "../functional/type_at.h" - -// #include "../functional/pack.h" +// #include "../functional/index_sequence_util.h" -// #include "../functional/unique_tuple.h" - -#include // std::integral_constant, std::decay, std::is_constructible, std::is_default_constructible, std::enable_if -#include // std::move, std::forward +namespace sqlite_orm { + namespace internal { -// #include "cxx_universal.h" + template + using tuple_cat_t = mpl::flatten_types_t; -// #include "cxx_type_traits_polyfill.h" + template + struct conc_tuple { + using type = tuple_cat_t; + }; -// #include "fast_and.h" + template + struct tuple_from_index_sequence; -// #include "type_at.h" + template class Tuple, class... T, size_t... Idx> + struct tuple_from_index_sequence, std::index_sequence> { + using type = Tuple>...>; + }; -// #include "tuple_common.h" + template + using tuple_from_index_sequence_t = typename tuple_from_index_sequence::type; -namespace _sqlite_orm { - // short names defined in a short namespace to reduce symbol lengths, - // since those types are used as a building block; - // (as seen in boost hana) + template class Pred, template class Proj, class Seq> + struct filter_tuple_sequence; - /* - * storage element of a unique tuple - */ - template> - struct uplem { - X data; +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence> + : mpl::flatten_idxseq>>::value, + std::index_sequence, + std::index_sequence<>>...> {}; +#else + template class Pred, class SFINAE = void> + struct tuple_seq_single { + using type = std::index_sequence<>; + }; - constexpr uplem() : data() {} + template class Pred> + struct tuple_seq_single::value>> { + using type = std::index_sequence; + }; - template - constexpr uplem(Y&& y) : data(std::forward(y)) {} - }; + template class Pred, template class Proj, size_t... Idx> + struct filter_tuple_sequence> + : mpl::flatten_idxseq>, Pred>::type...> {}; +#endif - /* - * storage element of a unique tuple, using EBO - */ - template - struct uplem : X { + template + class Pred, + template class Proj = polyfill::type_identity_t, + class Seq = std::make_index_sequence::value>> + using filter_tuple_sequence_t = typename filter_tuple_sequence::type; - constexpr uplem() = default; + template + class Pred, + template class FilterProj = polyfill::type_identity_t, + class Seq = std::make_index_sequence::value>> + using filter_tuple_t = tuple_from_index_sequence_t>; - template - constexpr uplem(Y&& y) : X(std::forward(y)) {} - }; + template + class Pred, + template class FilterProj = polyfill::type_identity_t> + struct count_tuple : std::integral_constant::size()> {}; - template>> - constexpr const X& ebo_get(const uplem& elem) { - return (elem.data); - } - template, bool> = true> - constexpr X& ebo_get(uplem& elem) { - return (elem.data); - } - template, bool> = true> - constexpr X&& ebo_get(uplem&& elem) { - return std::forward(elem.data); - } - template, bool> = true> - constexpr const X& ebo_get(const uplem& elem) { - return elem; - } - template, bool> = true> - constexpr X& ebo_get(uplem& elem) { - return elem; - } - template, bool> = true> - constexpr X&& ebo_get(uplem&& elem) { - return std::forward(elem); + /* + * Count a tuple, picking only those elements specified in the index sequence. + * + * Implementation note: must be distinct from `count_tuple` because legacy compilers have problems + * with a default Sequence in function template parameters [SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION]. + */ + template + class Pred, + class Seq, + template class FilterProj = polyfill::type_identity_t> + struct count_filtered_tuple + : std::integral_constant::size()> {}; } } -namespace sqlite_orm { - namespace internal { - namespace mpl { - using ::_sqlite_orm::ebo_get; - using ::_sqlite_orm::uplem; +// #include "type_traits.h" - template - struct uple; +// #include "collate_argument.h" - template - struct enable_tuple_ctor, Void...> - : std::enable_if), bool> {}; +// #include "error_code.h" - template - struct enable_tuple_ctor, Void...> - : std::enable_if), bool> {}; +// #include "table_type_of.h" - template - struct enable_tuple_variadic_ctor, Y...> - : std::enable_if), bool> {}; - -#ifdef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 - template - struct enable_tuple_nonconst_copy_ctor, uple, Void...> - : std::enable_if), bool> {}; - - template - struct enable_tuple_nonconst_copy_ctor, const uple, Void...> - : std::enable_if), bool> {}; -#endif - } - } - - namespace mpl = internal::mpl; -} - -// retain stl tuple interface for `uple` -namespace std { - template - struct tuple_size; - - template - struct tuple_element; - - template - struct tuple_size> : integral_constant {}; - - template - struct tuple_element> : sqlite_orm::mpl::type_at> {}; - - template - constexpr decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { - using namespace sqlite_orm::mpl; - using type = type_at_t; - return ebo_get(static_cast&>(tpl)); - } - - template - constexpr decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { - using namespace sqlite_orm::mpl; - using type = type_at_t; - return ebo_get(static_cast&>(tpl)); - } - - template - constexpr decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { - using namespace sqlite_orm::mpl; - using type = type_at_t; - return ebo_get(static_cast&&>(tpl)); - } - - template - constexpr decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { - using namespace sqlite_orm::mpl; - return ebo_get(static_cast&>(tpl)); - } - - template - constexpr decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { - using namespace sqlite_orm::mpl; - return ebo_get(static_cast&>(tpl)); - } - - template - constexpr decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { - using namespace sqlite_orm::mpl; - return ebo_get(static_cast&&>(tpl)); - } -} - -namespace sqlite_orm { - namespace internal { - namespace mpl { - - template<> - struct uple<> final { - constexpr uple() = default; - }; - - /* - * unique tuple, which allows only distinct types. - */ - template - struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { - // default constructor - template::type = true> - constexpr uple() {} - - // direct constructor - template::type = true> - constexpr uple(const X&... x) : uplem(x)... {} - - // converting constructor - template::type = true> - constexpr uple(Y&&... y) : uplem(std::forward(y))... {} - - // converting copy constructor - template), bool> = true> - constexpr uple(const uple& other) : uplem(ebo_get(other))... {} - - // converting move constructor - template), bool> = true> - constexpr uple(uple&& other) : uplem(ebo_get(std::move(other)))... {} - - // default copy constructor - constexpr uple(const uple&) = default; - // default move constructor - constexpr uple(uple&&) = default; - - // non-const copy constructor. - // The non-const copy constructor is required to make sure that - // the converting uple(Y&&...) constructor is _not_ preferred over the copy - // constructor for unary tuples containing a type that is constructible from uple<...>. -#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 - constexpr uple(uple& other) : uplem(ebo_get(const_cast(other)))... {} -#else - template::type = true> - constexpr uple(Other& other) : uplem(ebo_get(const_cast(other)))... {} -#endif - - // converting copy assignment - template), bool> = true> - SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(const uple& other) { - int poormansfold[] = {(ebo_get(*this) = ebo_get(other), int{})...}; - (void)poormansfold; - return *this; - } - - // converting move assignment - template), bool> = true> - SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(uple&& other) { - int poormansfold[] = {(ebo_get(*this) = ebo_get(std::move(other)), int{})...}; - (void)poormansfold; - return *this; - } - - // default copy assignment - SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(const uple&) = default; - // default move assignment - SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(uple&&) = default; - }; - - template - constexpr auto make_unique_tuple(X&&... x) { - return uple...>{std::forward(x)...}; - } - - template - constexpr uple forward_as_unique_tuple(X&&... args) noexcept { - return uple{std::forward(args)...}; - } - - template - constexpr uple tie_unique(X&... args) noexcept { - return uple{args...}; - } - } - } -} - -// ops -namespace sqlite_orm { - namespace internal { - namespace mpl { - - template - struct type_at> : type_at {}; - -#ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED - template = true> - constexpr bool equal_indexable([[maybe_unused]] const uple& left, - [[maybe_unused]] const uple& right, - std::index_sequence) { - return ((ebo_get(left) == ebo_get(right)) && ...); - } - - template = true> - constexpr bool equal_indexable([[maybe_unused]] const uple& left, - [[maybe_unused]] const uple& right, - std::index_sequence) { - return ((std::get(left) == std::get(right)) && ...); - } -#else - template - constexpr bool equal_indexable(const uple&, const uple&, std::index_sequence<>) { - return true; - } - template - constexpr bool - equal_indexable(const uple& left, const uple& right, std::index_sequence) { - return (std::get(left) == std::get(right)) && - equal_indexable(left, right, std::index_sequence{}); - } -#endif - - template - constexpr bool operator==(const uple& left, const uple& right) { - static_assert(sizeof...(X) == sizeof...(Y), "cannot compare tuples of different sizes"); - return equal_indexable(left, right, std::make_index_sequence{}); - } - - template - constexpr bool operator!=(const uple& left, const uple& right) { - static_assert(sizeof...(X) == sizeof...(Y), "cannot compare tuples of different sizes"); - return !equal_indexable(left, right, std::make_index_sequence{}); - } - } - } -} - -// #include "../functional/tuple.h" - -namespace sqlite_orm { - namespace internal { - - template - using tuple_cat_t = decltype(std::tuple_cat(std::declval()...)); - - template - struct conc_tuple { - using type = tuple_cat_t; - }; - - template - struct tuple_from_index_sequence; - - template class Tuple, class... T, size_t... Idx> - struct tuple_from_index_sequence, std::index_sequence> { - using type = Tuple>...>; - }; - - template - using tuple_from_index_sequence_t = typename tuple_from_index_sequence::type; - - template - struct concat_idx_seq { - using type = std::index_sequence<>; - }; - - template - struct concat_idx_seq> { - using type = std::index_sequence; - }; - - template - struct concat_idx_seq, std::index_sequence, Seq...> - : concat_idx_seq, Seq...> {}; - - template class Pred, template class Proj, class Seq> - struct filter_tuple_sequence; - -#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence> - : concat_idx_seq>>::value, - std::index_sequence, - std::index_sequence<>>...> {}; -#else - template class Pred, class SFINAE = void> - struct tuple_seq_single { - using type = std::index_sequence<>; - }; - - template class Pred> - struct tuple_seq_single::value>> { - using type = std::index_sequence; - }; - - template class Pred, template class Proj, size_t... Idx> - struct filter_tuple_sequence> - : concat_idx_seq>, Pred>::type...> {}; -#endif - - template - class Pred, - template class Proj = polyfill::type_identity_t, - class Seq = std::make_index_sequence::value>> - using filter_tuple_sequence_t = typename filter_tuple_sequence::type; - - template - class Pred, - template class FilterProj = polyfill::type_identity_t, - class Seq = std::make_index_sequence::value>> - using filter_tuple_t = tuple_from_index_sequence_t>; - - template - class Pred, - template class FilterProj = polyfill::type_identity_t> - struct count_tuple : std::integral_constant::size()> {}; - - /* - * Count a tuple, picking only those elements specified in the index sequence. - * - * Implementation note: must be distinct from `count_tuple` because legacy compilers have problems - * with a default Sequence in function template parameters [SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION]. - */ - template - class Pred, - class Seq, - template class FilterProj = polyfill::type_identity_t> - struct count_filtered_tuple - : std::integral_constant::size()> {}; - } -} - -// #include "type_traits.h" - -// #include "collate_argument.h" - -// #include "error_code.h" - -// #include "table_type_of.h" - -namespace sqlite_orm { +namespace sqlite_orm { namespace internal { @@ -2769,90 +2652,392 @@ namespace sqlite_orm { return {std::move(l), std::move(r)}; } - /** - * Public interface for + operator. Example: `select(add(&User::age, 100));` => SELECT age + 100 FROM users - */ - template - internal::add_t add(L l, R r) { - return {std::move(l), std::move(r)}; + /** + * Public interface for + operator. Example: `select(add(&User::age, 100));` => SELECT age + 100 FROM users + */ + template + internal::add_t add(L l, R r) { + return {std::move(l), std::move(r)}; + } + + /** + * Public interface for - operator. Example: `select(sub(&User::age, 1));` => SELECT age - 1 FROM users + */ + template + internal::sub_t sub(L l, R r) { + return {std::move(l), std::move(r)}; + } + + /** + * Public interface for * operator. Example: `select(mul(&User::salary, 2));` => SELECT salary * 2 FROM users + */ + template + internal::mul_t mul(L l, R r) { + return {std::move(l), std::move(r)}; + } + + /** + * Public interface for / operator. Example: `select(div(&User::salary, 3));` => SELECT salary / 3 FROM users + * @note Please notice that ::div function already exists in pure C standard library inside header. + * If you use `using namespace sqlite_orm` directive you an specify which `div` you call explicitly using `::div` or `sqlite_orm::div` statements. + */ + template + internal::div_t div(L l, R r) { + return {std::move(l), std::move(r)}; + } + + /** + * Public interface for % operator. Example: `select(mod(&User::age, 5));` => SELECT age % 5 FROM users + */ + template + internal::mod_t mod(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::bitwise_shift_left_t bitwise_shift_left(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::bitwise_shift_right_t bitwise_shift_right(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::bitwise_and_t bitwise_and(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::bitwise_or_t bitwise_or(L l, R r) { + return {std::move(l), std::move(r)}; + } + + template + internal::bitwise_not_t bitwise_not(T t) { + return {std::move(t)}; + } + + template + internal::assign_t assign(L l, R r) { + return {std::move(l), std::move(r)}; + } + +} +#pragma once + +#include // std::string +#include // std::unique_ptr +#include // std::is_same, std::is_member_object_pointer + +// #include "functional/cxx_universal.h" + +// #include "functional/cxx_type_traits_polyfill.h" + +// #include "functional/unique_tuple.h" + +#include // std::integral_constant, std::decay, std::is_constructible, std::is_default_constructible, std::enable_if +#include // std::move, std::forward + +// #include "cxx_universal.h" + +// #include "cxx_type_traits_polyfill.h" + +// #include "fast_and.h" + +// #include "type_at.h" + +// #include "tuple_common.h" + +namespace _sqlite_orm { + // short names defined in a short namespace to reduce symbol lengths, + // since those types are used as a building block; + // (as seen in boost hana) + + /* + * storage element of a unique tuple + */ + template> + struct uplem { + X data; + + constexpr uplem() : data() {} + + template + constexpr uplem(Y&& y) : data(std::forward(y)) {} + }; + + /* + * storage element of a unique tuple, using EBO + */ + template + struct uplem : X { + + constexpr uplem() = default; + + template + constexpr uplem(Y&& y) : X(std::forward(y)) {} + }; + + template>> + constexpr const X& ebo_get(const uplem& elem) { + return (elem.data); + } + template, bool> = true> + constexpr X& ebo_get(uplem& elem) { + return (elem.data); + } + template, bool> = true> + constexpr X&& ebo_get(uplem&& elem) { + return std::forward(elem.data); + } + template, bool> = true> + constexpr const X& ebo_get(const uplem& elem) { + return elem; + } + template, bool> = true> + constexpr X& ebo_get(uplem& elem) { + return elem; + } + template, bool> = true> + constexpr X&& ebo_get(uplem&& elem) { + return std::forward(elem); + } +} + +namespace sqlite_orm { + namespace internal { + namespace mpl { + using ::_sqlite_orm::ebo_get; + using ::_sqlite_orm::uplem; + + template + struct uple; + + template + struct enable_tuple_ctor, Void...> + : std::enable_if), bool> {}; + + template + struct enable_tuple_ctor, Void...> + : std::enable_if), bool> {}; + + template + struct enable_tuple_variadic_ctor, Y...> + : std::enable_if), bool> {}; + +#ifdef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + template + struct enable_tuple_nonconst_copy_ctor, uple, Void...> + : std::enable_if), bool> {}; + + template + struct enable_tuple_nonconst_copy_ctor, const uple, Void...> + : std::enable_if), bool> {}; +#endif + } + } + + namespace mpl = internal::mpl; +} + +// retain stl tuple interface for `uple` +namespace std { + template + struct tuple_size; + + template + struct tuple_element; + + template + struct tuple_size> : integral_constant {}; + + template + struct tuple_element> : sqlite_orm::mpl::type_at> {}; + + template + constexpr decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { + using namespace sqlite_orm::mpl; + using type = type_at_t; + return ebo_get(static_cast&>(tpl)); + } + + template + constexpr decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { + using namespace sqlite_orm::mpl; + using type = type_at_t; + return ebo_get(static_cast&>(tpl)); } - /** - * Public interface for - operator. Example: `select(sub(&User::age, 1));` => SELECT age - 1 FROM users - */ - template - internal::sub_t sub(L l, R r) { - return {std::move(l), std::move(r)}; + template + constexpr decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { + using namespace sqlite_orm::mpl; + using type = type_at_t; + return ebo_get(static_cast&&>(tpl)); } - /** - * Public interface for * operator. Example: `select(mul(&User::salary, 2));` => SELECT salary * 2 FROM users - */ - template - internal::mul_t mul(L l, R r) { - return {std::move(l), std::move(r)}; + template + constexpr decltype(auto) get(const sqlite_orm::mpl::uple& tpl) noexcept { + using namespace sqlite_orm::mpl; + return ebo_get(static_cast&>(tpl)); } - /** - * Public interface for / operator. Example: `select(div(&User::salary, 3));` => SELECT salary / 3 FROM users - * @note Please notice that ::div function already exists in pure C standard library inside header. - * If you use `using namespace sqlite_orm` directive you an specify which `div` you call explicitly using `::div` or `sqlite_orm::div` statements. - */ - template - internal::div_t div(L l, R r) { - return {std::move(l), std::move(r)}; + template + constexpr decltype(auto) get(sqlite_orm::mpl::uple& tpl) noexcept { + using namespace sqlite_orm::mpl; + return ebo_get(static_cast&>(tpl)); } - /** - * Public interface for % operator. Example: `select(mod(&User::age, 5));` => SELECT age % 5 FROM users - */ - template - internal::mod_t mod(L l, R r) { - return {std::move(l), std::move(r)}; + template + constexpr decltype(auto) get(sqlite_orm::mpl::uple&& tpl) noexcept { + using namespace sqlite_orm::mpl; + return ebo_get(static_cast&&>(tpl)); } +} - template - internal::bitwise_shift_left_t bitwise_shift_left(L l, R r) { - return {std::move(l), std::move(r)}; - } +namespace sqlite_orm { + namespace internal { + namespace mpl { - template - internal::bitwise_shift_right_t bitwise_shift_right(L l, R r) { - return {std::move(l), std::move(r)}; - } + template<> + struct uple<> final { + constexpr uple() = default; + }; - template - internal::bitwise_and_t bitwise_and(L l, R r) { - return {std::move(l), std::move(r)}; - } + /* + * unique tuple, which allows only distinct types. + */ + template + struct SQLITE_ORM_MSVC_EMPTYBASES uple final : uplem... { + // default constructor + template::type = true> + constexpr uple() {} - template - internal::bitwise_or_t bitwise_or(L l, R r) { - return {std::move(l), std::move(r)}; - } + // direct constructor + template::type = true> + constexpr uple(const X&... x) : uplem(x)... {} - template - internal::bitwise_not_t bitwise_not(T t) { - return {std::move(t)}; - } + // converting constructor + template::type = true> + constexpr uple(Y&&... y) : uplem(std::forward(y))... {} - template - internal::assign_t assign(L l, R r) { - return {std::move(l), std::move(r)}; - } + // converting copy constructor + template), bool> = true> + constexpr uple(const uple& other) : uplem(ebo_get(other))... {} + + // converting move constructor + template), bool> = true> + constexpr uple(uple&& other) : uplem(ebo_get(std::move(other)))... {} + + // default copy constructor + constexpr uple(const uple&) = default; + // default move constructor + constexpr uple(uple&&) = default; + + // non-const copy constructor. + // The non-const copy constructor is required to make sure that + // the converting uple(Y&&...) constructor is _not_ preferred over the copy + // constructor for unary tuples containing a type that is constructible from uple<...>. +#ifndef SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 + constexpr uple(uple& other) : uplem(ebo_get(const_cast(other)))... {} +#else + template::type = true> + constexpr uple(Other& other) : uplem(ebo_get(const_cast(other)))... {} +#endif + // converting copy assignment + template), bool> = true> + SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(const uple& other) { + int poormansfold[] = {(ebo_get(*this) = ebo_get(other), int{})...}; + (void)poormansfold; + return *this; + } + + // converting move assignment + template), bool> = true> + SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(uple&& other) { + int poormansfold[] = {(ebo_get(*this) = ebo_get(std::move(other)), int{})...}; + (void)poormansfold; + return *this; + } + + // default copy assignment + SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(const uple&) = default; + // default move assignment + SQLITE_ORM_NONCONST_CONSTEXPR uple& operator=(uple&&) = default; + }; + + template + constexpr auto make_unique_tuple(X&&... x) { + return uple...>{std::forward(x)...}; + } + + template + constexpr uple forward_as_unique_tuple(X&&... args) noexcept { + return {std::forward(args)...}; + } + + template + constexpr uple tie_unique(X&... args) noexcept { + return {args...}; + } + } + } } -#pragma once -#include // std::string -#include // std::unique_ptr -#include // std::is_same, std::is_member_object_pointer +// ops +namespace sqlite_orm { + namespace internal { + namespace mpl { -// #include "functional/cxx_universal.h" + template + struct type_at> : type_at {}; -// #include "functional/cxx_type_traits_polyfill.h" +#ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED + template = true> + constexpr bool equal_indexable([[maybe_unused]] const uple& left, + [[maybe_unused]] const uple& right, + std::index_sequence) { + return ((ebo_get(left) == ebo_get(right)) && ...); + } -// #include "functional/unique_tuple.h" + template = true> + constexpr bool equal_indexable([[maybe_unused]] const uple& left, + [[maybe_unused]] const uple& right, + std::index_sequence) { + return ((std::get(left) == std::get(right)) && ...); + } +#else + template + constexpr bool equal_indexable(const uple&, const uple&, std::index_sequence<>) { + return true; + } + template + constexpr bool + equal_indexable(const uple& left, const uple& right, std::index_sequence) { + return (std::get(left) == std::get(right)) && + equal_indexable(left, right, std::index_sequence{}); + } +#endif + + template + constexpr bool operator==(const uple& left, const uple& right) { + static_assert(sizeof...(X) == sizeof...(Y), "cannot compare tuples of different sizes"); + return equal_indexable(left, right, std::make_index_sequence{}); + } + + template + constexpr bool operator!=(const uple& left, const uple& right) { + static_assert(sizeof...(X) == sizeof...(Y), "cannot compare tuples of different sizes"); + return !equal_indexable(left, right, std::make_index_sequence{}); + } + } + } +} // #include "tuple_helper/tuple_traits.h" @@ -7586,7 +7771,7 @@ namespace sqlite_orm { struct simple_case_t { using return_type = R; using case_expression_type = T; - using args_type = std::tuple; + using args_type = mpl::tuple; using else_expression_type = E; optional_container case_expression; @@ -7603,7 +7788,7 @@ namespace sqlite_orm { struct simple_case_builder { using return_type = R; using case_expression_type = T; - using args_type = std::tuple; + using args_type = mpl::tuple; using else_expression_type = E; optional_container case_expression; @@ -7612,9 +7797,9 @@ namespace sqlite_orm { template simple_case_builder> when(W w, then_t t) { - using result_args_type = std::tuple>; + using result_args_type = mpl::tuple>; std::pair newPair{std::move(w), std::move(t.expression)}; - result_args_type result_args = std::tuple_cat(std::move(this->args), std::make_tuple(newPair)); + result_args_type result_args = mpl::tuple_cat(std::move(this->args), mpl::make_tuple(newPair)); std::get::value - 1>(result_args) = std::move(newPair); return {std::move(this->case_expression), std::move(result_args), std::move(this->else_expression)}; } @@ -7709,7 +7894,7 @@ namespace sqlite_orm { */ template internal::select_t select(T t, Args... args) { - using args_tuple = std::tuple; + using args_tuple = mpl::pack; internal::validate_conditions(); return {std::move(t), mpl::make_tuple(std::forward(args)...)}; } @@ -10690,63 +10875,12 @@ namespace sqlite_orm { // #include "functional/type_at.h" +// #include "functional/index_sequence_util.h" + // #include "functional/tuple.h" // #include "typed_comparator.h" -// #include "tuple_helper/index_sequence_util.h" - -#include // std::index_sequence, std::make_index_sequence - -// #include "../functional/cxx_universal.h" - -#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED -#include -#endif - -namespace sqlite_orm { - namespace internal { - /** - * Get the first value of an index_sequence. - */ - template - SQLITE_ORM_CONSTEVAL size_t first_index_sequence_value(std::index_sequence) { - return I; - } - -#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED - /** - * Reorder the values of an index_sequence according to the positions from a second sequence. - */ - template - SQLITE_ORM_CONSTEVAL auto reorder_index_sequence(std::index_sequence, - std::index_sequence) { - constexpr std::array values{Value...}; - return std::index_sequence{}; - } - - template - SQLITE_ORM_CONSTEVAL std::index_sequence reorder_index_sequence(std::index_sequence, - std::index_sequence) { - return {}; - } - - inline SQLITE_ORM_CONSTEVAL std::index_sequence<> reorder_index_sequence(std::index_sequence<>, - std::index_sequence<>) { - return {}; - } - - /** - * Reverse the values of an index_sequence. - */ - template - SQLITE_ORM_CONSTEVAL auto reverse_index_sequence(std::index_sequence) { - return reorder_index_sequence(std::index_sequence{}, std::make_index_sequence{}); - } -#endif - } -} - // #include "tuple_helper/tuple_filter.h" // #include "tuple_helper/tuple_traits.h" @@ -10762,7 +10896,7 @@ namespace sqlite_orm { // #include "../functional/cxx_functional_polyfill.h" -// #include "index_sequence_util.h" +// #include "../functional/index_sequence_util.h" namespace sqlite_orm { namespace internal { @@ -10788,7 +10922,7 @@ namespace sqlite_orm { template void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { if constexpr(reversed) { - iterate_tuple(tpl, reverse_index_sequence(std::index_sequence{}), std::forward(lambda)); + iterate_tuple(tpl, mpl::reverse_index_sequence(std::index_sequence{}), std::forward(lambda)); } else { (lambda(std::get(tpl)), ...); } @@ -10976,7 +11110,8 @@ namespace sqlite_orm { using generated_op_index_sequence = filter_tuple_sequence_t, is_generated_always>; - constexpr size_t opIndex = first_index_sequence_value(generated_op_index_sequence{}); + constexpr size_t opIndex = + mpl::first_index_sequence_value(generated_op_index_sequence{}); result = &std::get(column.constraints).storage; }); #endif @@ -19832,7 +19967,7 @@ namespace sqlite_orm { // #include "../functional/static_magic.h" -// #include "../tuple_helper/index_sequence_util.h" +// #include "../functional/index_sequence_util.h" // #include "../tuple_helper/tuple_filter.h" @@ -19854,7 +19989,7 @@ namespace sqlite_orm { call_if_constexpr( [&value](auto& constraints, auto op_index_sequence) { using default_op_index_sequence = decltype(op_index_sequence); - constexpr size_t opIndex = first_index_sequence_value(default_op_index_sequence{}); + constexpr size_t opIndex = mpl::first_index_sequence_value(default_op_index_sequence{}); value = std::make_unique(serialize_default_value(std::get(constraints))); }, this->constraints, diff --git a/tests/constraints/foreign_key.cpp b/tests/constraints/foreign_key.cpp index 794a7f28e..b1343507a 100644 --- a/tests/constraints/foreign_key.cpp +++ b/tests/constraints/foreign_key.cpp @@ -48,10 +48,10 @@ TEST_CASE("Foreign key") { STATIC_REQUIRE(storage_foreign_keys_count::value == 0); using LocationFks = storage_fk_references::type; - STATIC_REQUIRE(std::is_same>::value); + STATIC_REQUIRE(std::is_same>::value); using VisitFks = storage_fk_references::type; - STATIC_REQUIRE(std::is_same>::value); + STATIC_REQUIRE(std::is_same>::value); } storage.sync_schema(); diff --git a/tests/static_tests/foreign_key.cpp b/tests/static_tests/foreign_key.cpp index a5fdc8956..f7a9149ea 100644 --- a/tests/static_tests/foreign_key.cpp +++ b/tests/static_tests/foreign_key.cpp @@ -3,7 +3,6 @@ #include // std::is_same #include // std::string -#include // std::is_same #include "static_tests_storage_traits.h" @@ -106,32 +105,32 @@ TEST_CASE("foreign key static") { using namespace sqlite_orm::internal::storage_traits; { using FkTuple = storage_fk_references::type; - using Expected = std::tuple<>; + using Expected = mpl::tuple<>; STATIC_REQUIRE(std::is_same::value); } { using FkTuple = storage_fk_references::type; - using Expected = std::tuple; + using Expected = mpl::tuple; STATIC_REQUIRE(std::is_same::value); } { using FkTuple = storage_fk_references::type; - using Expected = std::tuple<>; + using Expected = mpl::tuple<>; STATIC_REQUIRE(std::is_same::value); } { using FkTuple = storage_fk_references::type; - using Expected = std::tuple<>; + using Expected = mpl::tuple<>; STATIC_REQUIRE(std::is_same::value); } { using FkTuple = storage_fk_references::type; - using Expected = std::tuple<>; + using Expected = mpl::tuple<>; STATIC_REQUIRE(std::is_same::value); } { using FkTuple = storage_fk_references::type; - using Expected = std::tuple; + using Expected = mpl::tuple; STATIC_REQUIRE(std::is_same::value); } } diff --git a/tests/static_tests/node_tuple.cpp b/tests/static_tests/node_tuple.cpp index c0dca0a4b..2a7ab2032 100644 --- a/tests/static_tests/node_tuple.cpp +++ b/tests/static_tests/node_tuple.cpp @@ -14,7 +14,7 @@ template struct is_tuple : std::false_type {}; template -struct is_tuple> : std::true_type {}; +struct is_tuple> : std::true_type {}; TEST_CASE("Node tuple") { using internal::bindable_filter_t; @@ -869,8 +869,8 @@ TEST_CASE("Node tuple") { using CaseExpressionTuple = node_tuple::type; STATIC_REQUIRE(is_same>::value); - STATIC_REQUIRE(is_tuple>::value); - STATIC_REQUIRE(is_tuple>::value); + STATIC_REQUIRE(is_tuple>::value); + STATIC_REQUIRE(is_tuple>::value); STATIC_REQUIRE(!is_tuple::value); STATIC_REQUIRE(is_pair>::value); STATIC_REQUIRE(!is_pair::value); @@ -885,7 +885,7 @@ TEST_CASE("Node tuple") { STATIC_REQUIRE(is_same::value); using Arg0Second = Arg0::second_type; STATIC_REQUIRE(is_same::value); - STATIC_REQUIRE(is_same>>::value); + STATIC_REQUIRE(is_same>>::value); using ElseExpressionTuple = node_tuple::type; STATIC_REQUIRE(is_same>::value); diff --git a/tests/static_tests/static_tests_storage_traits.h b/tests/static_tests/static_tests_storage_traits.h index b5247aae6..032398ebb 100644 --- a/tests/static_tests/static_tests_storage_traits.h +++ b/tests/static_tests/static_tests_storage_traits.h @@ -7,8 +7,6 @@ #include // std::integral_constant -#include - namespace sqlite_orm { namespace internal { @@ -103,11 +101,11 @@ namespace sqlite_orm { template struct storage_fk_references_impl, Lookup> - : conc_tuple::type...> {}; + : mpl::flatten_types::type...> {}; template struct storage_foreign_keys_impl, Lookup> - : conc_tuple...> {}; + : mpl::flatten_types...> {}; /** * S - storage class From 1aebf2c5ae6be7c3fe9fa6d737fbb0fc0bdd09fc Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Jun 2022 00:57:01 +0300 Subject: [PATCH 09/16] Implemented `iterate_tuple()` in terms of a 'poor man's fold` --- dev/tuple_helper/tuple_iteration.h | 15 ++++++--------- include/sqlite_orm/sqlite_orm.h | 15 ++++++--------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/dev/tuple_helper/tuple_iteration.h b/dev/tuple_helper/tuple_iteration.h index 93449c46e..aab3fd1df 100644 --- a/dev/tuple_helper/tuple_iteration.h +++ b/dev/tuple_helper/tuple_iteration.h @@ -51,8 +51,8 @@ namespace sqlite_orm { iterate_tuple(tpl, std::index_sequence{}, std::forward(lambda)); lambda(std::get(tpl)); } else { - lambda(std::get(tpl)); - iterate_tuple(tpl, std::index_sequence{}, std::forward(lambda)); + int poormansfold[] = {(lambda(std::get(tpl)), int{}), (lambda(std::get(tpl)), int{})...}; + (void)poormansfold; } } #endif @@ -69,13 +69,10 @@ namespace sqlite_orm { (lambda((mpl::element_at_t*)nullptr), ...); } #else - template - void iterate_tuple(std::index_sequence<>, L&& /*lambda*/) {} - - template - void iterate_tuple(std::index_sequence, L&& lambda) { - lambda((mpl::element_at_t*)nullptr); - iterate_tuple(std::index_sequence{}, std::forward(lambda)); + template + void iterate_tuple(std::index_sequence, L&& lambda) { + int poormansfold[] = {int{}, (lambda((mpl::element_at_t*)nullptr), int{})...}; + (void)poormansfold; } #endif template diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 1f625b6e0..972ed4e82 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -10941,8 +10941,8 @@ namespace sqlite_orm { iterate_tuple(tpl, std::index_sequence{}, std::forward(lambda)); lambda(std::get(tpl)); } else { - lambda(std::get(tpl)); - iterate_tuple(tpl, std::index_sequence{}, std::forward(lambda)); + int poormansfold[] = {(lambda(std::get(tpl)), int{}), (lambda(std::get(tpl)), int{})...}; + (void)poormansfold; } } #endif @@ -10959,13 +10959,10 @@ namespace sqlite_orm { (lambda((mpl::element_at_t*)nullptr), ...); } #else - template - void iterate_tuple(std::index_sequence<>, L&& /*lambda*/) {} - - template - void iterate_tuple(std::index_sequence, L&& lambda) { - lambda((mpl::element_at_t*)nullptr); - iterate_tuple(std::index_sequence{}, std::forward(lambda)); + template + void iterate_tuple(std::index_sequence, L&& lambda) { + int poormansfold[] = {int{}, (lambda((mpl::element_at_t*)nullptr), int{})...}; + (void)poormansfold; } #endif template From b9d3746793b4a7dd24990e0d37b582edb7c1d860 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Jun 2022 01:20:35 +0300 Subject: [PATCH 10/16] Replaced last remaining occurrences of std tuple --- dev/node_tuple.h | 4 +- dev/tuple_helper/tuple_filter.h | 11 +++-- include/sqlite_orm/sqlite_orm.h | 17 +++---- tests/static_tests/functional/tuple_conc.cpp | 47 ++++++++++---------- tests/static_tests/node_tuple.cpp | 4 +- 5 files changed, 42 insertions(+), 41 deletions(-) diff --git a/dev/node_tuple.h b/dev/node_tuple.h index f8ea52f96..e6ae56e69 100644 --- a/dev/node_tuple.h +++ b/dev/node_tuple.h @@ -27,7 +27,7 @@ namespace sqlite_orm { template struct node_tuple { - using type = std::tuple; + using type = mpl::tuple; }; template @@ -35,7 +35,7 @@ namespace sqlite_orm { template<> struct node_tuple { - using type = std::tuple<>; + using type = mpl::tuple<>; }; #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template diff --git a/dev/tuple_helper/tuple_filter.h b/dev/tuple_helper/tuple_filter.h index f91900a82..0ec7b2f44 100644 --- a/dev/tuple_helper/tuple_filter.h +++ b/dev/tuple_helper/tuple_filter.h @@ -1,21 +1,20 @@ #pragma once #include // std::integral_constant, std::index_sequence, std::make_index_sequence, std::conditional, std::declval -#include #include "../functional/cxx_universal.h" #include "../functional/index_sequence_util.h" +#include "../functional/pack_util.h" +#include "../functional/tuple.h" namespace sqlite_orm { namespace internal { - template - using tuple_cat_t = mpl::flatten_types_t; + template + using tuple_cat_t = mpl::flatten_types_t; template - struct conc_tuple { - using type = tuple_cat_t; - }; + struct conc_tuple : mpl::flatten_types {}; template struct tuple_from_index_sequence; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 972ed4e82..eba9fe29b 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -1769,22 +1769,23 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_filter.h" #include // std::integral_constant, std::index_sequence, std::make_index_sequence, std::conditional, std::declval -#include // #include "../functional/cxx_universal.h" // #include "../functional/index_sequence_util.h" +// #include "../functional/pack_util.h" + +// #include "../functional/tuple.h" + namespace sqlite_orm { namespace internal { - template - using tuple_cat_t = mpl::flatten_types_t; + template + using tuple_cat_t = mpl::flatten_types_t; template - struct conc_tuple { - using type = tuple_cat_t; - }; + struct conc_tuple : mpl::flatten_types {}; template struct tuple_from_index_sequence; @@ -19360,7 +19361,7 @@ namespace sqlite_orm { template struct node_tuple { - using type = std::tuple; + using type = mpl::tuple; }; template @@ -19368,7 +19369,7 @@ namespace sqlite_orm { template<> struct node_tuple { - using type = std::tuple<>; + using type = mpl::tuple<>; }; #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template diff --git a/tests/static_tests/functional/tuple_conc.cpp b/tests/static_tests/functional/tuple_conc.cpp index f55f5bea4..2855e5870 100644 --- a/tests/static_tests/functional/tuple_conc.cpp +++ b/tests/static_tests/functional/tuple_conc.cpp @@ -4,56 +4,57 @@ #include // std::is_same using namespace sqlite_orm; +using mpl::tuple; TEST_CASE("Tuple conc") { using namespace internal; { - using TupleL = std::tuple; - using TupleR = std::tuple; + using TupleL = tuple; + using TupleR = tuple; using IntStringTuple = tuple_cat_t; - STATIC_REQUIRE(std::is_same>::value); + STATIC_REQUIRE(std::is_same>::value); } { - using TupleL = std::tuple; - using TupleR = std::tuple; + using TupleL = tuple; + using TupleR = tuple; using IntFloatTuple = tuple_cat_t; - STATIC_REQUIRE(std::is_same>::value); + STATIC_REQUIRE(std::is_same>::value); } { using TupleL = std::tuple<>; - using TupleR = std::tuple; + using TupleR = tuple; using NoneFloatTuple = tuple_cat_t; - STATIC_REQUIRE(std::is_same>::value); + STATIC_REQUIRE(std::is_same>::value); } { - using TupleL = std::tuple<>; - using TupleR = std::tuple<>; + using TupleL = tuple<>; + using TupleR = tuple<>; using NoneNoneTuple = tuple_cat_t; - STATIC_REQUIRE(std::is_same>::value); + STATIC_REQUIRE(std::is_same>::value); } { - using TupleL = std::tuple; - using TupleR = std::tuple; + using TupleL = tuple; + using TupleR = tuple; using IntFloatDoubleTuple = tuple_cat_t; - STATIC_REQUIRE(std::is_same>::value); + STATIC_REQUIRE(std::is_same>::value); } { - using Arg = std::tuple; + using Arg = tuple; using SingleArgTuple = tuple_cat_t; STATIC_REQUIRE(std::is_same::value); } { - using Arg1 = std::tuple; - using Arg2 = std::tuple; - using Arg3 = std::tuple; + using Arg1 = tuple; + using Arg2 = tuple; + using Arg3 = tuple; using IntFloatStringTuple = tuple_cat_t; - STATIC_REQUIRE(std::is_same>::value); + STATIC_REQUIRE(std::is_same>::value); } { - using Arg1 = std::tuple; - using Arg2 = std::tuple; - using Arg3 = std::tuple<>; + using Arg1 = tuple; + using Arg2 = tuple; + using Arg3 = tuple<>; using IntFloatEmptyTuple = tuple_cat_t; - STATIC_REQUIRE(std::is_same>::value); + STATIC_REQUIRE(std::is_same>::value); } } diff --git a/tests/static_tests/node_tuple.cpp b/tests/static_tests/node_tuple.cpp index 2a7ab2032..34557ad18 100644 --- a/tests/static_tests/node_tuple.cpp +++ b/tests/static_tests/node_tuple.cpp @@ -20,8 +20,8 @@ TEST_CASE("Node tuple") { using internal::bindable_filter_t; using internal::node_tuple; using internal::node_tuple_t; + using mpl::tuple; using std::is_same; - using std::tuple; struct User { int id = 0; @@ -463,7 +463,7 @@ TEST_CASE("Node tuple") { where(greater_or_equal(&User::id, 10) and lesser_or_equal(&User::id, 20))); using Sel = decltype(sel); using Tuple = node_tuple_t; - using Expected = std:: + using Expected = tuple; static_assert(is_same::value, "select(columns(&User::id, &User::name), where(greater_or_equal(&User::id, 10) and " From f2e110d70fa5553cf1220c006e2502045ceb5f45 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Jun 2022 21:26:28 +0300 Subject: [PATCH 11/16] Replaced last remnants of std tuple internally --- dev/column.h | 7 +- dev/conditions.h | 3 +- dev/functional/index_sequence_util.h | 28 +- dev/functional/pack.h | 5 +- dev/functional/pack_util.h | 41 ++- dev/functional/tuple.h | 42 ++- dev/functional/type_at.h | 7 - dev/functional/unique_tuple.h | 6 +- dev/get_prepared_statement.h | 32 +-- dev/prepared_statement.h | 1 + dev/statement_serializer.h | 2 +- dev/tuple_helper/tuple_iteration.h | 56 ++-- dev/tuple_helper/tuple_transformer.h | 17 +- include/sqlite_orm/sqlite_orm.h | 252 +++++++++++------- .../statement_serializer_tests/bindables.cpp | 80 +++--- tests/static_tests/bindable_filter.cpp | 74 ++--- tests/static_tests/functional/tuple_conc.cpp | 2 +- .../static_tests/functional/tuple_filter.cpp | 18 +- .../static_tests/functional/tuple_traits.cpp | 4 +- .../is_column_with_insertable_primary_key.cpp | 6 +- tests/tuple_iteration.cpp | 16 +- 21 files changed, 409 insertions(+), 290 deletions(-) diff --git a/dev/column.h b/dev/column.h index fbf519eb9..bdc8c7c1e 100644 --- a/dev/column.h +++ b/dev/column.h @@ -6,6 +6,7 @@ #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" +#include "functional/fast_and.h" #include "functional/unique_tuple.h" #include "tuple_helper/tuple_traits.h" #include "tuple_helper/tuple_filter.h" @@ -140,7 +141,7 @@ namespace sqlite_orm { */ template = true> internal::column_t make_column(std::string name, M m, Op... constraints) { - static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); + static_assert(SQLITE_ORM_FAST_AND(internal::is_constraint), "Incorrect constraints pack"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), m, {}, mpl::make_unique_tuple(constraints...)}); } @@ -156,7 +157,7 @@ namespace sqlite_orm { internal::column_t make_column(std::string name, S setter, G getter, Op... constraints) { static_assert(std::is_same, internal::getter_field_type_t>::value, "Getter and setter must get and set same data type"); - static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); + static_assert(SQLITE_ORM_FAST_AND(internal::is_constraint), "Incorrect constraints pack"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( return {move(name), getter, setter, mpl::make_unique_tuple(constraints...)}); @@ -174,7 +175,7 @@ namespace sqlite_orm { internal::column_t make_column(std::string name, G getter, S setter, Op... constraints) { static_assert(std::is_same, internal::getter_field_type_t>::value, "Getter and setter must get and set same data type"); - static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); + static_assert(SQLITE_ORM_FAST_AND(internal::is_constraint), "Incorrect constraints pack"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( return {move(name), getter, setter, mpl::make_unique_tuple(constraints...)}); diff --git a/dev/conditions.h b/dev/conditions.h index ad1bc46b5..bc16fe1c5 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -8,6 +8,7 @@ #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" +#include "functional/pack.h" #include "functional/tuple.h" #include "type_traits.h" #include "collate_argument.h" @@ -797,7 +798,7 @@ namespace sqlite_orm { template struct from_t { - using tuple_type = mpl::tuple; + using pack_type = mpl::pack; }; template diff --git a/dev/functional/index_sequence_util.h b/dev/functional/index_sequence_util.h index ad96d2967..931a022e4 100644 --- a/dev/functional/index_sequence_util.h +++ b/dev/functional/index_sequence_util.h @@ -14,8 +14,8 @@ namespace sqlite_orm { /** * Get the first value of an index_sequence. */ - template - SQLITE_ORM_CONSTEVAL size_t first_index_sequence_value(std::index_sequence) { + template + SQLITE_ORM_CONSTEVAL size_t first_index_sequence_value(std::index_sequence) { return I; } @@ -44,10 +44,9 @@ namespace sqlite_orm { /** * Reverse the values of an index_sequence. */ - template - SQLITE_ORM_CONSTEVAL auto reverse_index_sequence(std::index_sequence) { - return reorder_index_sequence(std::index_sequence{}, - std::make_index_sequence{}); + template + SQLITE_ORM_CONSTEVAL auto reverse_index_sequence(std::index_sequence) { + return reorder_index_sequence(std::index_sequence{}, std::make_index_sequence{}); } #endif @@ -56,12 +55,15 @@ namespace sqlite_orm { using comma_expression_helper = std::integral_constant; #endif - template - constexpr auto expand_n(std::index_sequence) { + /* + * Duplicate specified number x times into an index sequence (using the size of the variadic argument x) + */ + template + constexpr auto expand_n(std::index_sequence) { #ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION - using type = std::index_sequence<(Times, n)...>; + using type = std::index_sequence<(x, n)...>; #else - using type = std::index_sequence::value...>; + using type = std::index_sequence::value...>; #endif return type{}; } @@ -94,9 +96,9 @@ namespace sqlite_orm { using type = std::index_sequence<>; }; - template - struct flatten_idxseq> { - using type = std::index_sequence; + template + struct flatten_idxseq> { + using type = std::index_sequence; }; template diff --git a/dev/functional/pack.h b/dev/functional/pack.h index a8b0c51ec..37a3d6cd2 100644 --- a/dev/functional/pack.h +++ b/dev/functional/pack.h @@ -8,6 +8,9 @@ namespace sqlite_orm { namespace internal { namespace mpl { + /* + * Type list + */ template struct pack { static constexpr size_t size() { @@ -20,7 +23,7 @@ namespace sqlite_orm { namespace mpl = internal::mpl; } -// retain stl tuple interface for `tuple` +// retain stl tuple interface for `pack` namespace std { template struct tuple_size; diff --git a/dev/functional/pack_util.h b/dev/functional/pack_util.h index 8288d05ce..a429e73a2 100644 --- a/dev/functional/pack_util.h +++ b/dev/functional/pack_util.h @@ -1,30 +1,53 @@ #pragma once +#include "pack.h" +#include "mpl.h" + namespace sqlite_orm { namespace internal { namespace mpl { - template class R, class... Pack> + + /* + * Flatten specified type lists into specified result type list + */ + template class R, class... List> struct flatten_types { using type = R<>; }; - template class R, template class Pack1, class... X> - struct flatten_types> { + template class R, template class List1, class... X> + struct flatten_types> { using type = R; }; template class R, template - class Pack1, + class List1, template - class Pack2, + class List2, class... X, class... Y, - class... Pack> - struct flatten_types, Pack2, Pack...> : flatten_types, Pack...> {}; + class... List> + struct flatten_types, List2, List...> : flatten_types, List...> {}; + + template class R, class... List> + using flatten_types_t = typename flatten_types::type; + + template class R, class List, template class Op> + struct transform_types; + + template class R, template class List, class... X, template class Op> + struct transform_types, Op> { + using type = R...>; + }; - template class R, class... Pack> - using flatten_types_t = typename flatten_types::type; + /* + * Transform specified type list. + * + * `Op` is a metafunction operation. + */ + template class R, class List, template class Op> + using transform_types_t = typename transform_types::type; } } } diff --git a/dev/functional/tuple.h b/dev/functional/tuple.h index 48dd92007..58ee23470 100644 --- a/dev/functional/tuple.h +++ b/dev/functional/tuple.h @@ -2,6 +2,7 @@ #include // std::integral_constant, std::decay, std::remove_reference, std::is_constructible, std::is_default_constructible, std::enable_if, std::declval #include // std::move, std::forward +#include // std::equal_to #include "cxx_universal.h" #include "cxx_type_traits_polyfill.h" @@ -274,20 +275,46 @@ namespace sqlite_orm { template constexpr flatten_types_t...> tuple_cat_helper(std::index_sequence, std::index_sequence, Tuples&&... tuples) { + // Note that for each element in a tuple we have a coordinate pair (i, j), + // that is, the length of the lists containing the Is and the Js must be equal: + static_assert(sizeof...(Ix) == sizeof...(Jx), ""); + // It then explodes the tuple of tuples into the return type using the coordinates (i, j) for each element: return {ebo_get(std::get(adl::forward_as_tuple(std::forward(tuples)...)))...}; } + /* + * This implementation of `tuple_cat` takes advantage of treating the specified tuples and + * their elements as a two-dimensional array. + * In order for this to work, the number of all elements combined (Jx) has to match + * a sequence of numbers produced using the number of specified tuples (Ix). + * Hence, each index in the sequence of tuples is duplicated by the number of elements of each respective tuple. + * + * Example, using 3 tuples: + * tuple0 + * tuple1 + * tuple0 + * + * outer sequence Jx (denoting which element to access): + * for tuple0: <0, 1, 2> + * for tuple1: <0> + * for tuple2: <0, 1> + * flattened -> <0, 1, 2, 0, 0, 1> + * + * inner sequence Ix (denoting which tuple to access): + * tuples as index sequence: <0, 1, 2> + * sizes as number sequence: <3, 1, 2> + * for tuple0: <0, 0, 0> + * for tuple1: <1> + * for tuple2: <2, 2> + * flattened -> <0, 0, 0, 1, 2, 2> + */ template constexpr auto tuple_cat(Tuples&&... tuples) { using tuples_seq = std::make_index_sequence; - // -> index_sequence using sizes_seq = std::index_sequence>::value...>; - using inner = flatten_idxseq_t< - // -> pack, index_sequence, ...> - spread_idxseq_t>; + using inner = flatten_idxseq_t>; using outer = typename flatten_idxseq< #ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION - // index_sequence, ... std::make_index_sequence>::value>... #else typename make_idxseq_helper>::type... @@ -323,7 +350,8 @@ namespace sqlite_orm { constexpr bool equal_indexable([[maybe_unused]] const tuple& left, [[maybe_unused]] const tuple& right, std::index_sequence) { - return ((ebo_get(left) == ebo_get(right)) && ...); + constexpr std::equal_to<> predicate = {}; + return (predicate(ebo_get(left), ebo_get(right)) && ...); } #else template @@ -333,7 +361,7 @@ namespace sqlite_orm { template constexpr bool equal_indexable(const tuple& left, const tuple& right, std::index_sequence) { - return (ebo_get(left) == ebo_get(right)) && + return std::equal_to<>{}(ebo_get(left), ebo_get(right)) && equal_indexable(left, right, std::index_sequence{}); } #endif diff --git a/dev/functional/type_at.h b/dev/functional/type_at.h index 56c8fa95a..a72b7775a 100644 --- a/dev/functional/type_at.h +++ b/dev/functional/type_at.h @@ -1,7 +1,6 @@ #pragma once #include // std::integral_constant, std::index_sequence, std::make_index_sequence -#include #include "cxx_universal.h" #include "indexed_type.h" @@ -34,9 +33,6 @@ namespace sqlite_orm { #endif }; - template - struct type_at> : type_at {}; - template struct type_at> : type_at {}; @@ -45,9 +41,6 @@ namespace sqlite_orm { template using element_at_t = typename type_at::type; - - template - struct pack> : pack {}; } } diff --git a/dev/functional/unique_tuple.h b/dev/functional/unique_tuple.h index 4bed51b80..01042b40e 100644 --- a/dev/functional/unique_tuple.h +++ b/dev/functional/unique_tuple.h @@ -2,6 +2,7 @@ #include // std::integral_constant, std::decay, std::is_constructible, std::is_default_constructible, std::enable_if #include // std::move, std::forward +#include // std::equal_to #include "cxx_universal.h" #include "cxx_type_traits_polyfill.h" @@ -268,7 +269,8 @@ namespace sqlite_orm { constexpr bool equal_indexable([[maybe_unused]] const uple& left, [[maybe_unused]] const uple& right, std::index_sequence) { - return ((std::get(left) == std::get(right)) && ...); + constexpr std::equal_to<> predicate = {}; + return (predicate(std::get(left), std::get(right)) && ...); } #else template @@ -278,7 +280,7 @@ namespace sqlite_orm { template constexpr bool equal_indexable(const uple& left, const uple& right, std::index_sequence) { - return (std::get(left) == std::get(right)) && + return std::equal_to<>{}(std::get(left), std::get(right)) && equal_indexable(left, right, std::index_sequence{}); } #endif diff --git a/dev/get_prepared_statement.h b/dev/get_prepared_statement.h index 976d00630..4129ac662 100644 --- a/dev/get_prepared_statement.h +++ b/dev/get_prepared_statement.h @@ -132,14 +132,14 @@ namespace sqlite_orm { using node_type = std::decay_t; if(internal::is_bindable_v) { ++index; - } - if(index == N) { - internal::call_if_constexpr::value>( - [](auto& r, auto& n) { - r = &n; - }, - result, - node); + if(index == N) { + internal::call_if_constexpr::value>( + [](auto& r, auto& n) { + r = &n; + }, + result, + node); + } } }); return internal::get_ref(*result); @@ -158,14 +158,14 @@ namespace sqlite_orm { using node_type = std::decay_t; if(internal::is_bindable_v) { ++index; - } - if(index == N) { - internal::call_if_constexpr::value>( - [](auto& r, auto& n) { - r = const_cast>(&n); - }, - result, - node); + if(index == N) { + internal::call_if_constexpr::value>( + [](auto& r, auto& n) { + r = const_cast>(&n); + }, + result, + node); + } } }); return internal::get_ref(*result); diff --git a/dev/prepared_statement.h b/dev/prepared_statement.h index 775771c04..8bac07971 100644 --- a/dev/prepared_statement.h +++ b/dev/prepared_statement.h @@ -10,6 +10,7 @@ #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" #include "functional/cxx_functional_polyfill.h" +#include "functional/pack.h" #include "functional/tuple.h" #include "tuple_helper/tuple_filter.h" #include "connection_holder.h" diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index e59046a87..17dce0aff 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -1537,7 +1537,7 @@ namespace sqlite_orm { std::string operator()(const statement_type&, const Ctx& context) const { std::stringstream ss; ss << "FROM "; - iterate_tuple([&context, &ss, first = true](auto* item) mutable { + iterate_pack(typename statement_type::pack_type{}, [&context, &ss, first = true](auto* item) mutable { using from_type = std::remove_pointer_t; constexpr std::array sep = {", ", ""}; diff --git a/dev/tuple_helper/tuple_iteration.h b/dev/tuple_helper/tuple_iteration.h index aab3fd1df..19bc483a2 100644 --- a/dev/tuple_helper/tuple_iteration.h +++ b/dev/tuple_helper/tuple_iteration.h @@ -10,6 +10,13 @@ namespace sqlite_orm { namespace internal { + namespace mpl { + template + struct pack; + + template + struct uple; + } // got it form here https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer template @@ -29,29 +36,29 @@ namespace sqlite_orm { } #if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) && defined(SQLITE_ORM_IF_CONSTEXPR_SUPPORTED) - template - void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { + template + void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { if constexpr(reversed) { - iterate_tuple(tpl, mpl::reverse_index_sequence(std::index_sequence{}), std::forward(lambda)); + iterate_tuple(tpl, mpl::reverse_index_sequence(std::index_sequence{}), std::forward(lambda)); } else { - (lambda(std::get(tpl)), ...); + (lambda(std::get(tpl)), ...); } } #else template void iterate_tuple(const Tpl& /*tpl*/, std::index_sequence<>, L&& /*lambda*/) {} - template - void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { + template + void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { #ifdef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED if constexpr(reversed) { #else if(reversed) { #endif - iterate_tuple(tpl, std::index_sequence{}, std::forward(lambda)); + iterate_tuple(tpl, std::index_sequence{}, std::forward(lambda)); lambda(std::get(tpl)); } else { - int poormansfold[] = {(lambda(std::get(tpl)), int{}), (lambda(std::get(tpl)), int{})...}; + int poormansfold[] = {(lambda(std::get(tpl)), int{}), (lambda(std::get(tpl)), int{})...}; (void)poormansfold; } } @@ -64,25 +71,34 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED - template - void iterate_tuple(std::index_sequence, L&& lambda) { - (lambda((mpl::element_at_t*)nullptr), ...); + template + void iterate_tuple(const mpl::uple& tpl, L&& lambda) { + (lambda(std::get(tpl)), ...); } #else - template - void iterate_tuple(std::index_sequence, L&& lambda) { - int poormansfold[] = {int{}, (lambda((mpl::element_at_t*)nullptr), int{})...}; + template + void iterate_tuple(const mpl::uple& tpl, L&& lambda) { + int poormansfold[] = {int{}, (lambda(std::get(tpl)), int{})...}; (void)poormansfold; } #endif - template - void iterate_tuple(L&& lambda) { - iterate_tuple(std::make_index_sequence::value>{}, std::forward(lambda)); + +#ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED + template + void iterate_pack(mpl::pack, L&& lambda) { + (lambda((X*)nullptr), ...); } +#else + template + void iterate_pack(mpl::pack, L&& lambda) { + int poormansfold[] = {int{}, (lambda((X*)nullptr), int{})...}; + (void)poormansfold; + } +#endif - template - R create_from_tuple(Tpl&& tpl, std::index_sequence, Projection project = {}) { - return R{polyfill::invoke(project, std::get(std::forward(tpl)))...}; + template + R create_from_tuple(Tpl&& tpl, std::index_sequence, Projection project = {}) { + return R{polyfill::invoke(project, std::get(std::forward(tpl)))...}; } template diff --git a/dev/tuple_helper/tuple_transformer.h b/dev/tuple_helper/tuple_transformer.h index 87ca254d8..46ecf01df 100644 --- a/dev/tuple_helper/tuple_transformer.h +++ b/dev/tuple_helper/tuple_transformer.h @@ -2,24 +2,13 @@ #include // std::tuple -#include "../functional/mpl.h" -#include "../functional/tuple.h" +#include "../functional/pack_util.h" namespace sqlite_orm { namespace internal { template class Op> - struct tuple_transformer; - - template class Op> - struct tuple_transformer, Op> { - using type = std::tuple...>; - }; - - template class Op> - struct tuple_transformer, Op> { - using type = std::tuple...>; - }; + struct tuple_transformer : mpl::transform_types {}; /* * Transform specified tuple. @@ -27,6 +16,6 @@ namespace sqlite_orm { * `Op` is a metafunction operation. */ template class Op> - using transform_tuple_t = typename tuple_transformer::type; + using transform_tuple_t = mpl::transform_types_t; } } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index eba9fe29b..724b1e3e6 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -1009,6 +1009,7 @@ namespace sqlite_orm { #include // std::integral_constant, std::decay, std::remove_reference, std::is_constructible, std::is_default_constructible, std::enable_if, std::declval #include // std::move, std::forward +#include // std::equal_to // #include "cxx_universal.h" @@ -1082,6 +1083,9 @@ namespace sqlite_orm { namespace internal { namespace mpl { + /* + * Type list + */ template struct pack { static constexpr size_t size() { @@ -1094,7 +1098,7 @@ namespace sqlite_orm { namespace mpl = internal::mpl; } -// retain stl tuple interface for `tuple` +// retain stl tuple interface for `pack` namespace std { template struct tuple_size; @@ -1109,8 +1113,8 @@ namespace sqlite_orm { /** * Get the first value of an index_sequence. */ - template - SQLITE_ORM_CONSTEVAL size_t first_index_sequence_value(std::index_sequence) { + template + SQLITE_ORM_CONSTEVAL size_t first_index_sequence_value(std::index_sequence) { return I; } @@ -1139,10 +1143,9 @@ namespace sqlite_orm { /** * Reverse the values of an index_sequence. */ - template - SQLITE_ORM_CONSTEVAL auto reverse_index_sequence(std::index_sequence) { - return reorder_index_sequence(std::index_sequence{}, - std::make_index_sequence{}); + template + SQLITE_ORM_CONSTEVAL auto reverse_index_sequence(std::index_sequence) { + return reorder_index_sequence(std::index_sequence{}, std::make_index_sequence{}); } #endif @@ -1151,12 +1154,15 @@ namespace sqlite_orm { using comma_expression_helper = std::integral_constant; #endif - template - constexpr auto expand_n(std::index_sequence) { + /* + * Duplicate specified number x times into an index sequence (using the size of the variadic argument x) + */ + template + constexpr auto expand_n(std::index_sequence) { #ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION - using type = std::index_sequence<(Times, n)...>; + using type = std::index_sequence<(x, n)...>; #else - using type = std::index_sequence::value...>; + using type = std::index_sequence::value...>; #endif return type{}; } @@ -1189,9 +1195,9 @@ namespace sqlite_orm { using type = std::index_sequence<>; }; - template - struct flatten_idxseq> { - using type = std::index_sequence; + template + struct flatten_idxseq> { + using type = std::index_sequence; }; template @@ -1209,31 +1215,55 @@ namespace sqlite_orm { // #include "pack_util.h" +// #include "pack.h" + +// #include "mpl.h" + namespace sqlite_orm { namespace internal { namespace mpl { - template class R, class... Pack> + + /* + * Flatten specified type lists into specified result type list + */ + template class R, class... List> struct flatten_types { using type = R<>; }; - template class R, template class Pack1, class... X> - struct flatten_types> { + template class R, template class List1, class... X> + struct flatten_types> { using type = R; }; template class R, template - class Pack1, + class List1, template - class Pack2, + class List2, class... X, class... Y, - class... Pack> - struct flatten_types, Pack2, Pack...> : flatten_types, Pack...> {}; + class... List> + struct flatten_types, List2, List...> : flatten_types, List...> {}; + + template class R, class... List> + using flatten_types_t = typename flatten_types::type; + + template class R, class List, template class Op> + struct transform_types; - template class R, class... Pack> - using flatten_types_t = typename flatten_types::type; + template class R, template class List, class... X, template class Op> + struct transform_types, Op> { + using type = R...>; + }; + + /* + * Transform specified type list. + * + * `Op` is a metafunction operation. + */ + template class R, class List, template class Op> + using transform_types_t = typename transform_types::type; } } } @@ -1241,7 +1271,6 @@ namespace sqlite_orm { // #include "type_at.h" #include // std::integral_constant, std::index_sequence, std::make_index_sequence -#include // #include "cxx_universal.h" @@ -1276,9 +1305,6 @@ namespace sqlite_orm { #endif }; - template - struct type_at> : type_at {}; - template struct type_at> : type_at {}; @@ -1287,9 +1313,6 @@ namespace sqlite_orm { template using element_at_t = typename type_at::type; - - template - struct pack> : pack {}; } } @@ -1606,20 +1629,46 @@ namespace sqlite_orm { template constexpr flatten_types_t...> tuple_cat_helper(std::index_sequence, std::index_sequence, Tuples&&... tuples) { + // Note that for each element in a tuple we have a coordinate pair (i, j), + // that is, the length of the lists containing the Is and the Js must be equal: + static_assert(sizeof...(Ix) == sizeof...(Jx), ""); + // It then explodes the tuple of tuples into the return type using the coordinates (i, j) for each element: return {ebo_get(std::get(adl::forward_as_tuple(std::forward(tuples)...)))...}; } + /* + * This implementation of `tuple_cat` takes advantage of treating the specified tuples and + * their elements as a two-dimensional array. + * In order for this to work, the number of all elements combined (Jx) has to match + * a sequence of numbers produced using the number of specified tuples (Ix). + * Hence, each index in the sequence of tuples is duplicated by the number of elements of each respective tuple. + * + * Example, using 3 tuples: + * tuple0 + * tuple1 + * tuple0 + * + * outer sequence Jx (denoting which element to access): + * for tuple0: <0, 1, 2> + * for tuple1: <0> + * for tuple2: <0, 1> + * flattened -> <0, 1, 2, 0, 0, 1> + * + * inner sequence Ix (denoting which tuple to access): + * tuples as index sequence: <0, 1, 2> + * sizes as number sequence: <3, 1, 2> + * for tuple0: <0, 0, 0> + * for tuple1: <1> + * for tuple2: <2, 2> + * flattened -> <0, 0, 0, 1, 2, 2> + */ template constexpr auto tuple_cat(Tuples&&... tuples) { using tuples_seq = std::make_index_sequence; - // -> index_sequence using sizes_seq = std::index_sequence>::value...>; - using inner = flatten_idxseq_t< - // -> pack, index_sequence, ...> - spread_idxseq_t>; + using inner = flatten_idxseq_t>; using outer = typename flatten_idxseq< #ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION - // index_sequence, ... std::make_index_sequence>::value>... #else typename make_idxseq_helper>::type... @@ -1655,7 +1704,8 @@ namespace sqlite_orm { constexpr bool equal_indexable([[maybe_unused]] const tuple& left, [[maybe_unused]] const tuple& right, std::index_sequence) { - return ((ebo_get(left) == ebo_get(right)) && ...); + constexpr std::equal_to<> predicate = {}; + return (predicate(ebo_get(left), ebo_get(right)) && ...); } #else template @@ -1665,7 +1715,7 @@ namespace sqlite_orm { template constexpr bool equal_indexable(const tuple& left, const tuple& right, std::index_sequence) { - return (ebo_get(left) == ebo_get(right)) && + return std::equal_to<>{}(ebo_get(left), ebo_get(right)) && equal_indexable(left, right, std::index_sequence{}); } #endif @@ -2736,10 +2786,13 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" +// #include "functional/fast_and.h" + // #include "functional/unique_tuple.h" #include // std::integral_constant, std::decay, std::is_constructible, std::is_default_constructible, std::enable_if #include // std::move, std::forward +#include // std::equal_to // #include "cxx_universal.h" @@ -3010,7 +3063,8 @@ namespace sqlite_orm { constexpr bool equal_indexable([[maybe_unused]] const uple& left, [[maybe_unused]] const uple& right, std::index_sequence) { - return ((std::get(left) == std::get(right)) && ...); + constexpr std::equal_to<> predicate = {}; + return (predicate(std::get(left), std::get(right)) && ...); } #else template @@ -3020,7 +3074,7 @@ namespace sqlite_orm { template constexpr bool equal_indexable(const uple& left, const uple& right, std::index_sequence) { - return (std::get(left) == std::get(right)) && + return std::equal_to<>{}(std::get(left), std::get(right)) && equal_indexable(left, right, std::index_sequence{}); } #endif @@ -3271,7 +3325,7 @@ namespace sqlite_orm { */ template = true> internal::column_t make_column(std::string name, M m, Op... constraints) { - static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); + static_assert(SQLITE_ORM_FAST_AND(internal::is_constraint), "Incorrect constraints pack"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), m, {}, mpl::make_unique_tuple(constraints...)}); } @@ -3287,7 +3341,7 @@ namespace sqlite_orm { internal::column_t make_column(std::string name, S setter, G getter, Op... constraints) { static_assert(std::is_same, internal::getter_field_type_t>::value, "Getter and setter must get and set same data type"); - static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); + static_assert(SQLITE_ORM_FAST_AND(internal::is_constraint), "Incorrect constraints pack"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( return {move(name), getter, setter, mpl::make_unique_tuple(constraints...)}); @@ -3305,7 +3359,7 @@ namespace sqlite_orm { internal::column_t make_column(std::string name, G getter, S setter, Op... constraints) { static_assert(std::is_same, internal::getter_field_type_t>::value, "Getter and setter must get and set same data type"); - static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); + static_assert(SQLITE_ORM_FAST_AND(internal::is_constraint), "Incorrect constraints pack"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( return {move(name), getter, setter, mpl::make_unique_tuple(constraints...)}); @@ -3484,6 +3538,8 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" +// #include "functional/pack.h" + // #include "functional/tuple.h" // #include "type_traits.h" @@ -4451,7 +4507,7 @@ namespace sqlite_orm { template struct from_t { - using tuple_type = mpl::tuple; + using pack_type = mpl::pack; }; template @@ -10065,25 +10121,13 @@ namespace sqlite_orm { #include // std::tuple -// #include "../functional/mpl.h" - -// #include "../functional/tuple.h" +// #include "../functional/pack_util.h" namespace sqlite_orm { namespace internal { template class Op> - struct tuple_transformer; - - template class Op> - struct tuple_transformer, Op> { - using type = std::tuple...>; - }; - - template class Op> - struct tuple_transformer, Op> { - using type = std::tuple...>; - }; + struct tuple_transformer : mpl::transform_types {}; /* * Transform specified tuple. @@ -10091,7 +10135,7 @@ namespace sqlite_orm { * `Op` is a metafunction operation. */ template class Op> - using transform_tuple_t = typename tuple_transformer::type; + using transform_tuple_t = mpl::transform_types_t; } } @@ -10901,6 +10945,13 @@ namespace sqlite_orm { namespace sqlite_orm { namespace internal { + namespace mpl { + template + struct pack; + + template + struct uple; + } // got it form here https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer template @@ -10920,29 +10971,29 @@ namespace sqlite_orm { } #if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) && defined(SQLITE_ORM_IF_CONSTEXPR_SUPPORTED) - template - void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { + template + void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { if constexpr(reversed) { - iterate_tuple(tpl, mpl::reverse_index_sequence(std::index_sequence{}), std::forward(lambda)); + iterate_tuple(tpl, mpl::reverse_index_sequence(std::index_sequence{}), std::forward(lambda)); } else { - (lambda(std::get(tpl)), ...); + (lambda(std::get(tpl)), ...); } } #else template void iterate_tuple(const Tpl& /*tpl*/, std::index_sequence<>, L&& /*lambda*/) {} - template - void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { + template + void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { #ifdef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED if constexpr(reversed) { #else if(reversed) { #endif - iterate_tuple(tpl, std::index_sequence{}, std::forward(lambda)); + iterate_tuple(tpl, std::index_sequence{}, std::forward(lambda)); lambda(std::get(tpl)); } else { - int poormansfold[] = {(lambda(std::get(tpl)), int{}), (lambda(std::get(tpl)), int{})...}; + int poormansfold[] = {(lambda(std::get(tpl)), int{}), (lambda(std::get(tpl)), int{})...}; (void)poormansfold; } } @@ -10955,25 +11006,34 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED - template - void iterate_tuple(std::index_sequence, L&& lambda) { - (lambda((mpl::element_at_t*)nullptr), ...); + template + void iterate_tuple(const mpl::uple& tpl, L&& lambda) { + (lambda(std::get(tpl)), ...); } #else - template - void iterate_tuple(std::index_sequence, L&& lambda) { - int poormansfold[] = {int{}, (lambda((mpl::element_at_t*)nullptr), int{})...}; + template + void iterate_tuple(const mpl::uple& tpl, L&& lambda) { + int poormansfold[] = {int{}, (lambda(std::get(tpl)), int{})...}; (void)poormansfold; } #endif - template - void iterate_tuple(L&& lambda) { - iterate_tuple(std::make_index_sequence::value>{}, std::forward(lambda)); + +#ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED + template + void iterate_pack(mpl::pack, L&& lambda) { + (lambda((X*)nullptr), ...); } +#else + template + void iterate_pack(mpl::pack, L&& lambda) { + int poormansfold[] = {int{}, (lambda((X*)nullptr), int{})...}; + (void)poormansfold; + } +#endif - template - R create_from_tuple(Tpl&& tpl, std::index_sequence, Projection project = {}) { - return R{polyfill::invoke(project, std::get(std::forward(tpl)))...}; + template + R create_from_tuple(Tpl&& tpl, std::index_sequence, Projection project = {}) { + return R{polyfill::invoke(project, std::get(std::forward(tpl)))...}; } template @@ -11749,6 +11809,8 @@ namespace sqlite_orm { // #include "functional/cxx_functional_polyfill.h" +// #include "functional/pack.h" + // #include "functional/tuple.h" // #include "tuple_helper/tuple_filter.h" @@ -17408,7 +17470,7 @@ namespace sqlite_orm { std::string operator()(const statement_type&, const Ctx& context) const { std::stringstream ss; ss << "FROM "; - iterate_tuple([&context, &ss, first = true](auto* item) mutable { + iterate_pack(typename statement_type::pack_type{}, [&context, &ss, first = true](auto* item) mutable { using from_type = std::remove_pointer_t; constexpr std::array sep = {", ", ""}; @@ -19790,14 +19852,14 @@ namespace sqlite_orm { using node_type = std::decay_t; if(internal::is_bindable_v) { ++index; - } - if(index == N) { - internal::call_if_constexpr::value>( - [](auto& r, auto& n) { - r = &n; - }, - result, - node); + if(index == N) { + internal::call_if_constexpr::value>( + [](auto& r, auto& n) { + r = &n; + }, + result, + node); + } } }); return internal::get_ref(*result); @@ -19816,14 +19878,14 @@ namespace sqlite_orm { using node_type = std::decay_t; if(internal::is_bindable_v) { ++index; - } - if(index == N) { - internal::call_if_constexpr::value>( - [](auto& r, auto& n) { - r = const_cast>(&n); - }, - result, - node); + if(index == N) { + internal::call_if_constexpr::value>( + [](auto& r, auto& n) { + r = const_cast>(&n); + }, + result, + node); + } } }); return internal::get_ref(*result); diff --git a/tests/statement_serializer_tests/bindables.cpp b/tests/statement_serializer_tests/bindables.cpp index 2f4f59e43..8f6b4d6fd 100644 --- a/tests/statement_serializer_tests/bindables.cpp +++ b/tests/statement_serializer_tests/bindables.cpp @@ -1,6 +1,5 @@ #include #include -#include #include // std::fill_n #include #include @@ -12,7 +11,6 @@ using std::make_index_sequence; using std::nullptr_t; using std::shared_ptr; using std::string; -using std::tuple; using std::tuple_element_t; using std::tuple_size; using std::unique_ptr; @@ -91,8 +89,8 @@ void require_strings(const array& values, } template -void test_tuple(const tuple& t, const Ctx& ctx, const array& expected) { - require_strings({internal::serialize(get(t), ctx)...}, expected, index_sequence_for{}); +void test_tuple(const mpl::uple& t, const Ctx& ctx, const array& expected) { + require_strings({internal::serialize(std::get(t), ctx)...}, expected, index_sequence_for{}); } namespace { @@ -126,32 +124,32 @@ TEST_CASE("bindables") { context_t context{dbObjects}; SECTION("bindable_builtin_types") { - using Tuple = tuple; + >; constexpr Tuple tpl = make_default_tuple(); @@ -192,33 +190,33 @@ TEST_CASE("bindables") { } SECTION("non-bindable literals") { context.replace_bindable_with_question = true; - constexpr auto t = make_default_tuple>(); + constexpr auto t = make_default_tuple>(); test_tuple(t, context, e); } } SECTION("bindable_types") { - using Tuple = tuple, + wstring, + StringVeneer, #endif - unique_ptr, - shared_ptr, - vector, + unique_ptr, + shared_ptr, + vector, #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - std::optional, - std::optional, + std::optional, + std::optional, #endif #ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED - std::string_view, + std::string_view, #ifndef SQLITE_ORM_OMITS_CODECVT - std::wstring_view, + std::wstring_view, #endif #endif - StringVeneer, - Custom, - unique_ptr>; + StringVeneer, + Custom, + unique_ptr>; Tuple tpl = make_default_tuple(); @@ -254,7 +252,7 @@ TEST_CASE("bindables") { } SECTION("non-bindable literals") { context.replace_bindable_with_question = true; - auto t = make_default_tuple>(); + auto t = make_default_tuple>(); test_tuple(t, context, e); } } diff --git a/tests/static_tests/bindable_filter.cpp b/tests/static_tests/bindable_filter.cpp index a58676f02..c2995c4bc 100644 --- a/tests/static_tests/bindable_filter.cpp +++ b/tests/static_tests/bindable_filter.cpp @@ -27,62 +27,62 @@ TEST_CASE("bindable_filter") { using internal::bindable_filter_t; using std::is_same; { - using Tuple = std::tuple, + using Tuple = mpl::uple, #ifndef SQLITE_ORM_OMITS_CODECVT - const wchar_t*, - std::wstring, - StringVeneer, + const wchar_t*, + std::wstring, + StringVeneer, #endif - std::vector, - std::nullptr_t, + std::vector, + std::nullptr_t, #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - std::nullopt_t, - std::optional, - std::optional, + std::nullopt_t, + std::optional, + std::optional, #endif #ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED - std::string_view, + std::string_view, #ifndef SQLITE_ORM_OMITS_CODECVT - std::wstring_view, + std::wstring_view, #endif #endif - std::unique_ptr, - std::shared_ptr, + std::unique_ptr, + std::shared_ptr, #ifdef SQLITE_ORM_INLINE_VARIABLES_SUPPORTED - static_pointer_binding, + static_pointer_binding, #endif - Custom, - std::unique_ptr>; + Custom, + std::unique_ptr>; using Res = bindable_filter_t; STATIC_REQUIRE(is_same::value); } { - using Tuple = std::tuple; + using Tuple = mpl::uple; using Res = bindable_filter_t; - using Expected = std::tuple; + using Expected = mpl::uple; STATIC_REQUIRE(is_same::value); } { - using Tuple = std::tuple; + using Tuple = mpl::uple; using Res = bindable_filter_t; - using Expected = std::tuple; + using Expected = mpl::uple; STATIC_REQUIRE(is_same::value); } } diff --git a/tests/static_tests/functional/tuple_conc.cpp b/tests/static_tests/functional/tuple_conc.cpp index 2855e5870..076e3ef49 100644 --- a/tests/static_tests/functional/tuple_conc.cpp +++ b/tests/static_tests/functional/tuple_conc.cpp @@ -21,7 +21,7 @@ TEST_CASE("Tuple conc") { STATIC_REQUIRE(std::is_same>::value); } { - using TupleL = std::tuple<>; + using TupleL = tuple<>; using TupleR = tuple; using NoneFloatTuple = tuple_cat_t; STATIC_REQUIRE(std::is_same>::value); diff --git a/tests/static_tests/functional/tuple_filter.cpp b/tests/static_tests/functional/tuple_filter.cpp index 615ce823e..956ab6639 100644 --- a/tests/static_tests/functional/tuple_filter.cpp +++ b/tests/static_tests/functional/tuple_filter.cpp @@ -14,8 +14,8 @@ namespace { TEST_CASE("tuple_filter") { using internal::filter_tuple_t; SECTION("is_bindable") { - using Arg = std::tuple, internal::order_by_t>; - using Expected = std::tuple; + using Arg = mpl::tuple, internal::order_by_t>; + using Expected = mpl::tuple; using ResultType = filter_tuple_t; STATIC_REQUIRE(std::is_same::value); } @@ -24,8 +24,8 @@ TEST_CASE("tuple_filter") { using Column = decltype(column); using OrderBy = internal::order_by_t; using Unique = decltype(unique(&User::id)); - using Arg = std::tuple; - using Expected = std::tuple; + using Arg = mpl::tuple; + using Expected = mpl::tuple; using ResultType = filter_tuple_t; STATIC_REQUIRE(std::is_same::value); } @@ -34,7 +34,7 @@ TEST_CASE("tuple_filter") { TEST_CASE("count_tuple") { using internal::count_tuple; { - auto t = std::make_tuple(where(is_equal(&User::id, 5)), limit(5), order_by(&User::name)); + auto t = mpl::make_tuple(where(is_equal(&User::id, 5)), limit(5), order_by(&User::name)); using T = decltype(t); STATIC_REQUIRE(count_tuple::value == 1); STATIC_REQUIRE(count_tuple::value == 0); @@ -42,7 +42,7 @@ TEST_CASE("count_tuple") { STATIC_REQUIRE(count_tuple::value == 1); } { - auto t = std::make_tuple(where(lesser_than(&User::id, 10)), + auto t = mpl::make_tuple(where(lesser_than(&User::id, 10)), where(greater_than(&User::id, 5)), group_by(&User::name)); using T = decltype(t); @@ -52,7 +52,7 @@ TEST_CASE("count_tuple") { STATIC_REQUIRE(count_tuple::value == 0); } { - auto t = std::make_tuple(group_by(&User::name), limit(10, offset(5))); + auto t = mpl::make_tuple(group_by(&User::name), limit(10, offset(5))); using T = decltype(t); STATIC_REQUIRE(count_tuple::value == 0); STATIC_REQUIRE(count_tuple::value == 1); @@ -61,7 +61,7 @@ TEST_CASE("count_tuple") { } { auto t = - std::make_tuple(where(is_null(&User::name)), order_by(&User::id), multi_order_by(order_by(&User::name))); + mpl::make_tuple(where(is_null(&User::name)), order_by(&User::id), multi_order_by(order_by(&User::name))); using T = decltype(t); STATIC_REQUIRE(count_tuple::value == 1); STATIC_REQUIRE(count_tuple::value == 0); @@ -69,7 +69,7 @@ TEST_CASE("count_tuple") { STATIC_REQUIRE(count_tuple::value == 0); } { - auto t = std::make_tuple(dynamic_order_by(make_storage(""))); + auto t = mpl::make_tuple(dynamic_order_by(make_storage(""))); using T = decltype(t); STATIC_REQUIRE(count_tuple::value == 0); STATIC_REQUIRE(count_tuple::value == 0); diff --git a/tests/static_tests/functional/tuple_traits.cpp b/tests/static_tests/functional/tuple_traits.cpp index f8690170b..9c82d1d12 100644 --- a/tests/static_tests/functional/tuple_traits.cpp +++ b/tests/static_tests/functional/tuple_traits.cpp @@ -10,8 +10,8 @@ using internal::is_primary_key; using internal::primary_key_t; TEST_CASE("tuple traits") { - using empty_tuple_type = std::tuple<>; - using tuple_type = std::tuple, primary_key_t<>, std::string>; + using empty_tuple_type = mpl::tuple<>; + using tuple_type = mpl::tuple, primary_key_t<>, std::string>; STATIC_REQUIRE(mpl::invoke_t, tuple_type>::value); STATIC_REQUIRE(mpl::invoke_t, tuple_type>::value); diff --git a/tests/static_tests/is_column_with_insertable_primary_key.cpp b/tests/static_tests/is_column_with_insertable_primary_key.cpp index 9f0b15f27..050e63881 100644 --- a/tests/static_tests/is_column_with_insertable_primary_key.cpp +++ b/tests/static_tests/is_column_with_insertable_primary_key.cpp @@ -23,17 +23,17 @@ TEST_CASE("is_column_with_insertable_primary_key") { bool isActive; }; - auto insertable = std::make_tuple( /// + auto insertable = mpl::make_tuple( /// make_column("", &User::id, primary_key()), make_column("", &User::username, primary_key(), default_value("Clint Eastwood")), make_column("", &User::username, primary_key(), default_value(std::vector{})), make_column("", &User::username, primary_key(), autoincrement())); - auto noninsertable = std::make_tuple( /// + auto noninsertable = mpl::make_tuple( /// make_column("", &User::username, primary_key()), make_column("", &User::password, primary_key())); - auto outside = std::make_tuple( /// + auto outside = mpl::make_tuple( /// make_column("", &User::id), ///< not a primary key std::make_shared() ///< not a column ); diff --git a/tests/tuple_iteration.cpp b/tests/tuple_iteration.cpp index aa8be2866..6a1859e2b 100644 --- a/tests/tuple_iteration.cpp +++ b/tests/tuple_iteration.cpp @@ -16,22 +16,22 @@ TEST_CASE("tuple iteration") { types.emplace_back(typeid(item)); }; SECTION("empty") { - std::tuple<> tuple; + mpl::tuple<> tuple; iterate_tuple(tuple, lambda); } SECTION("int") { - std::tuple tuple; + mpl::tuple tuple; iterate_tuple(tuple, lambda); expected = {typeid(int)}; } SECTION("std::string, long") { - std::tuple tuple; + mpl::tuple tuple; iterate_tuple(tuple, lambda); expected = {typeid(std::string), typeid(long)}; } SECTION("index selection") { constexpr size_t selectedIdx = 1; - std::tuple tuple; + mpl::tuple tuple; iterate_tuple(tuple, std::index_sequence{}, lambda); expected = {typeid(long)}; } @@ -42,14 +42,14 @@ TEST_CASE("tuple iteration") { types.emplace_back(typeid(Item)); }; SECTION("empty") { - iterate_tuple>(lambda); + iterate_pack(mpl::pack<>{}, lambda); } SECTION("int") { - iterate_tuple>(lambda); + iterate_pack(mpl::pack{}, lambda); expected = {typeid(int)}; } SECTION("std::string, long") { - iterate_tuple>(lambda); + iterate_pack(mpl::pack{}, lambda); expected = {typeid(std::string), typeid(long)}; } } @@ -60,7 +60,7 @@ TEST_CASE("creation from tuple") { using namespace internal; using Catch::Matchers::Equals; - std::tuple tpl{"abc", "xyz"}; + mpl::tuple tpl{"abc", "xyz"}; SECTION("identity") { std::vector expected{get<0>(tpl), get<1>(tpl)}; auto strings = create_from_tuple>(tpl); From b513eddd1d8114b39100f64a40011c1d3341a7c1 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Jun 2022 21:28:15 +0300 Subject: [PATCH 12/16] Replaced std::decay with simpler type traits where possible --- dev/get_prepared_statement.h | 9 ++-- dev/implementations/table_definitions.h | 4 +- dev/prepared_statement.h | 2 +- dev/serializing_util.h | 4 +- dev/statement_serializer.h | 32 +++++------- dev/storage.h | 14 ++--- dev/storage_impl.h | 2 +- include/sqlite_orm/sqlite_orm.h | 68 ++++++++++++------------- 8 files changed, 65 insertions(+), 70 deletions(-) diff --git a/dev/get_prepared_statement.h b/dev/get_prepared_statement.h index 4129ac662..6ab15e8a9 100644 --- a/dev/get_prepared_statement.h +++ b/dev/get_prepared_statement.h @@ -3,6 +3,7 @@ #include // std::is_same, std::decay, std::remove_reference #include "functional/static_magic.h" +#include "functional/cxx_type_traits_polyfill.h" #include "functional/type_at.h" #include "prepared_statement.h" #include "ast_iterator.h" @@ -122,14 +123,14 @@ namespace sqlite_orm { template const auto& get(const internal::prepared_statement_t& statement) { - using statement_type = std::decay_t; + using statement_type = std::remove_reference_t; using expression_type = typename statement_type::expression_type; using node_tuple = internal::node_tuple_t; using bind_tuple = internal::bindable_filter_t; using result_type = mpl::element_at_t(N), bind_tuple>; const result_type* result = nullptr; internal::iterate_ast(statement.expression, [&result, index = -1](auto& node) mutable { - using node_type = std::decay_t; + using node_type = polyfill::remove_cvref_t; if(internal::is_bindable_v) { ++index; if(index == N) { @@ -147,7 +148,7 @@ namespace sqlite_orm { template auto& get(internal::prepared_statement_t& statement) { - using statement_type = std::decay_t; + using statement_type = std::remove_reference_t; using expression_type = typename statement_type::expression_type; using node_tuple = internal::node_tuple_t; using bind_tuple = internal::bindable_filter_t; @@ -155,7 +156,7 @@ namespace sqlite_orm { result_type* result = nullptr; internal::iterate_ast(statement.expression, [&result, index = -1](auto& node) mutable { - using node_type = std::decay_t; + using node_type = polyfill::remove_cvref_t; if(internal::is_bindable_v) { ++index; if(index == N) { diff --git a/dev/implementations/table_definitions.h b/dev/implementations/table_definitions.h index 30a2dcabc..b53d619bf 100644 --- a/dev/implementations/table_definitions.h +++ b/dev/implementations/table_definitions.h @@ -3,7 +3,7 @@ * this file is also used to provide definitions of interface methods 'hitting the database'. */ #pragma once -#include // std::decay_t +#include // std::remove_reference #include // std::move #include // std::find_if, std::ranges::find @@ -19,7 +19,7 @@ namespace sqlite_orm { std::vector res; res.reserve(size_t(filter_tuple_sequence_t::size())); this->for_each_column([&res](auto& column) { - using field_type = field_type_t>; + using field_type = field_type_t>; std::string dft; if(auto d = column.default_value()) { dft = move(*d); diff --git a/dev/prepared_statement.h b/dev/prepared_statement.h index 8bac07971..efcc12da9 100644 --- a/dev/prepared_statement.h +++ b/dev/prepared_statement.h @@ -4,7 +4,7 @@ #include // std::unique_ptr #include // std::iterator_traits #include // std::string -#include // std::integral_constant, std::declval +#include // std::integral_constant, std::declval, std::decay #include // std::pair #include "functional/cxx_universal.h" diff --git a/dev/serializing_util.h b/dev/serializing_util.h index fc8a4e83f..1b69d15be 100644 --- a/dev/serializing_util.h +++ b/dev/serializing_util.h @@ -1,6 +1,6 @@ #pragma once -#include // std::index_sequence +#include // std::index_sequence, std::remove_reference #include #include #include @@ -395,7 +395,7 @@ namespace sqlite_orm { iterate_tuple(column.constraints, [&constraintsStrings, &primaryKeyIndex, &autoincrementIndex, &tupleIndex, &context]( auto& constraint) { - using constraint_type = std::decay_t; + using constraint_type = polyfill::remove_cvref_t; constraintsStrings.push_back(serialize(constraint, context)); if(is_primary_key_v) { primaryKeyIndex = tupleIndex; diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 17dce0aff..9b0b29760 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -222,7 +222,7 @@ namespace sqlite_orm { std::stringstream ss; ss << "ON CONFLICT"; iterate_tuple(statement.target_args, [&ss, &context](auto& value) { - using value_type = std::decay_t; + using value_type = std::remove_reference_t; auto needParenthesis = std::is_member_pointer::value; ss << ' '; if(needParenthesis) { @@ -846,7 +846,7 @@ namespace sqlite_orm { std::stringstream ss; ss << "FOREIGN KEY(" << streaming_mapped_columns_expressions(fk.columns, context) << ") REFERENCES "; { - using references_type_t = typename std::decay_t::references_type; + using references_type_t = typename std::remove_reference_t::references_type; using first_reference_t = mpl::element_at_t<0, references_type_t>; using first_reference_mapped_type = table_type_of_t; auto refTableName = lookup_table_name(context.db_objects); @@ -942,8 +942,7 @@ namespace sqlite_orm { template std::string operator()(const statement_type& statement, const Ctx& context) const { - using expression_type = std::decay_t; - using object_type = typename expression_object_type::type; + using object_type = typename expression_object_type::type; auto& table = pick_table(context.db_objects); std::stringstream ss; ss << "REPLACE INTO " << streaming_identifier(table.name) << " (" @@ -966,8 +965,7 @@ namespace sqlite_orm { std::string operator()(const statement_type& ins, const Ctx& context) const { constexpr size_t colsCount = sizeof...(Cols); static_assert(colsCount > 0, "Use insert or replace with 1 argument instead"); - using expression_type = std::decay_t; - using object_type = typename expression_object_type::type; + using object_type = typename expression_object_type::type; auto& table = pick_table(context.db_objects); std::stringstream ss; ss << "INSERT INTO " << streaming_identifier(table.name) << " "; @@ -975,7 +973,7 @@ namespace sqlite_orm { << "VALUES ("; iterate_tuple(ins.columns.columns, [&ss, &context, &object = get_ref(ins.obj), first = true](auto& memberPointer) mutable { - using member_pointer_type = std::decay_t; + using member_pointer_type = polyfill::remove_cvref_t; static_assert(!is_setter_v, "Unable to use setter within insert explicit"); @@ -994,8 +992,7 @@ namespace sqlite_orm { template std::string operator()(const statement_type& statement, const Ctx& context) const { - using expression_type = std::decay_t; - using object_type = typename expression_object_type::type; + using object_type = typename expression_object_type::type; auto& table = pick_table(context.db_objects); std::stringstream ss; @@ -1087,7 +1084,7 @@ namespace sqlite_orm { std::string operator()(const statement_type& statement, const Ctx& context) const { using object_type = typename expression_object_type::type; auto& table = pick_table(context.db_objects); - using is_without_rowid = typename std::decay_t::is_without_rowid; + using is_without_rowid = typename std::remove_reference_t::is_without_rowid; std::vector> columnNames; table.template for_each_column_excluding< @@ -1172,7 +1169,7 @@ namespace sqlite_orm { ss << "REPLACE"; } iterate_tuple(statement.args, [&context, &ss](auto& value) { - using value_type = std::decay_t; + using value_type = polyfill::remove_cvref_t; ss << ' '; if(is_columns_v) { auto newContext = context; @@ -1226,8 +1223,7 @@ namespace sqlite_orm { template std::string operator()(const statement_type& rep, const Ctx& context) const { - using expression_type = std::decay_t; - using object_type = typename expression_object_type::type; + using object_type = typename expression_object_type::type; auto& table = pick_table(context.db_objects); std::stringstream ss; @@ -1248,7 +1244,7 @@ namespace sqlite_orm { std::string operator()(const statement_type& statement, const Ctx& context) const { using object_type = typename expression_object_type::type; auto& table = pick_table(context.db_objects); - using is_without_rowid = typename std::decay_t::is_without_rowid; + using is_without_rowid = typename std::remove_reference_t::is_without_rowid; std::vector> columnNames; table.template for_each_column_excluding< @@ -1442,7 +1438,7 @@ namespace sqlite_orm { iterate_ast(sel.col, collector); iterate_ast(sel.conditions, collector); join_iterator()([&collector, &context](const auto& c) { - using original_join_type = typename std::decay_t::join_type::type; + using original_join_type = typename std::remove_reference_t::join_type::type; using cross_join_type = mapped_type_proxy_t; auto crossJoinedTableName = lookup_table_name(context.db_objects); auto tableAliasString = alias_extractor::get(); @@ -1502,7 +1498,7 @@ namespace sqlite_orm { if(statement.unique) { ss << "UNIQUE "; } - using elements_type = typename std::decay_t::elements_type; + using elements_type = typename std::remove_reference_t::elements_type; using head_t = typename mpl::element_at_t<0, elements_type>::column_type; using indexed_type = table_type_of_t; ss << "INDEX IF NOT EXISTS " << streaming_identifier(statement.name) << " ON " @@ -1510,7 +1506,7 @@ namespace sqlite_orm { std::vector columnNames; std::string whereString; iterate_tuple(statement.elements, [&columnNames, &context, &whereString](auto& value) { - using value_type = std::decay_t; + using value_type = polyfill::remove_cvref_t; if(!is_where_v) { auto newContext = context; newContext.use_parentheses = false; @@ -1698,7 +1694,7 @@ namespace sqlite_orm { << serialize(statement.base, context); ss << " BEGIN "; iterate_tuple(statement.elements, [&ss, &context](auto& element) { - using element_type = std::decay_t; + using element_type = polyfill::remove_cvref_t; if(is_select_v) { auto newContext = context; newContext.use_parentheses = false; diff --git a/dev/storage.h b/dev/storage.h index d1467bb9e..032b8473c 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -101,7 +101,7 @@ namespace sqlite_orm { template void create_table(sqlite3* db, const std::string& tableName, const Table& table) { - using table_type = std::decay_t; + using table_type = std::remove_reference_t; using context_t = serializer_context; std::stringstream ss; @@ -605,7 +605,7 @@ namespace sqlite_orm { std::stringstream ss; ss << "{ "; table.for_each_column([&ss, &object, first = true](auto& column) mutable { - using column_type = std::decay_t; + using column_type = std::remove_reference_t; using field_type = typename column_type::field_type; constexpr std::array sep = {", ", ""}; @@ -1128,7 +1128,7 @@ namespace sqlite_orm { template int64 execute(const prepared_statement_t>& statement) { - using statement_type = std::decay_t; + using statement_type = std::remove_reference_t; using expression_type = typename statement_type::expression_type; using object_type = typename expression_object_type::type; @@ -1146,7 +1146,7 @@ namespace sqlite_orm { template, is_replace_range>, bool> = true> void execute(const prepared_statement_t& statement) { - using statement_type = std::decay_t; + using statement_type = std::remove_reference_t; using expression_type = typename statement_type::expression_type; using object_type = typename expression_object_type::type; @@ -1187,7 +1187,7 @@ namespace sqlite_orm { template, is_insert_range>, bool> = true> int64 execute(const prepared_statement_t& statement) { - using statement_type = std::decay_t; + using statement_type = std::remove_reference_t; using expression_type = typename statement_type::expression_type; using object_type = typename expression_object_type::type; @@ -1195,7 +1195,7 @@ namespace sqlite_orm { auto processObject = [&table = this->get_table(), bind_value = field_value_binder{stmt}](auto& object) mutable { - using is_without_rowid = typename std::decay_t::is_without_rowid; + using is_without_rowid = typename std::remove_reference_t::is_without_rowid; table.template for_each_column_excluding< mpl::conjunction>, mpl::disjunction_fn>>( @@ -1241,7 +1241,7 @@ namespace sqlite_orm { template void execute(const prepared_statement_t>& statement) { - using statement_type = std::decay_t; + using statement_type = std::remove_reference_t; using expression_type = typename statement_type::expression_type; using object_type = typename expression_object_type::type; diff --git a/dev/storage_impl.h b/dev/storage_impl.h index 701ffa43c..37dc2998a 100644 --- a/dev/storage_impl.h +++ b/dev/storage_impl.h @@ -41,7 +41,7 @@ namespace sqlite_orm { std::string find_table_name(const DBOs& dbObjects, const std::type_index& ti) { std::string res; iterate_tuple(dbObjects, tables_index_sequence{}, [&ti, &res](const auto& table) { - using table_type = std::decay_t; + using table_type = std::remove_reference_t; if(ti == typeid(object_type_t)) { res = table.name; } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 724b1e3e6..416f27b58 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -11416,7 +11416,7 @@ namespace sqlite_orm { std::string find_table_name(const DBOs& dbObjects, const std::type_index& ti) { std::string res; iterate_tuple(dbObjects, tables_index_sequence{}, [&ti, &res](const auto& table) { - using table_type = std::decay_t; + using table_type = std::remove_reference_t; if(ti == typeid(object_type_t)) { res = table.name; } @@ -11800,7 +11800,7 @@ namespace sqlite_orm { #include // std::unique_ptr #include // std::iterator_traits #include // std::string -#include // std::integral_constant, std::declval +#include // std::integral_constant, std::declval, std::decay #include // std::pair // #include "functional/cxx_universal.h" @@ -13583,7 +13583,7 @@ namespace sqlite_orm { // #include "serializing_util.h" -#include // std::index_sequence +#include // std::index_sequence, std::remove_reference #include #include #include @@ -13985,7 +13985,7 @@ namespace sqlite_orm { iterate_tuple(column.constraints, [&constraintsStrings, &primaryKeyIndex, &autoincrementIndex, &tupleIndex, &context]( auto& constraint) { - using constraint_type = std::decay_t; + using constraint_type = polyfill::remove_cvref_t; constraintsStrings.push_back(serialize(constraint, context)); if(is_primary_key_v) { primaryKeyIndex = tupleIndex; @@ -16155,7 +16155,7 @@ namespace sqlite_orm { std::stringstream ss; ss << "ON CONFLICT"; iterate_tuple(statement.target_args, [&ss, &context](auto& value) { - using value_type = std::decay_t; + using value_type = std::remove_reference_t; auto needParenthesis = std::is_member_pointer::value; ss << ' '; if(needParenthesis) { @@ -16779,7 +16779,7 @@ namespace sqlite_orm { std::stringstream ss; ss << "FOREIGN KEY(" << streaming_mapped_columns_expressions(fk.columns, context) << ") REFERENCES "; { - using references_type_t = typename std::decay_t::references_type; + using references_type_t = typename std::remove_reference_t::references_type; using first_reference_t = mpl::element_at_t<0, references_type_t>; using first_reference_mapped_type = table_type_of_t; auto refTableName = lookup_table_name(context.db_objects); @@ -16875,8 +16875,7 @@ namespace sqlite_orm { template std::string operator()(const statement_type& statement, const Ctx& context) const { - using expression_type = std::decay_t; - using object_type = typename expression_object_type::type; + using object_type = typename expression_object_type::type; auto& table = pick_table(context.db_objects); std::stringstream ss; ss << "REPLACE INTO " << streaming_identifier(table.name) << " (" @@ -16899,8 +16898,7 @@ namespace sqlite_orm { std::string operator()(const statement_type& ins, const Ctx& context) const { constexpr size_t colsCount = sizeof...(Cols); static_assert(colsCount > 0, "Use insert or replace with 1 argument instead"); - using expression_type = std::decay_t; - using object_type = typename expression_object_type::type; + using object_type = typename expression_object_type::type; auto& table = pick_table(context.db_objects); std::stringstream ss; ss << "INSERT INTO " << streaming_identifier(table.name) << " "; @@ -16908,7 +16906,7 @@ namespace sqlite_orm { << "VALUES ("; iterate_tuple(ins.columns.columns, [&ss, &context, &object = get_ref(ins.obj), first = true](auto& memberPointer) mutable { - using member_pointer_type = std::decay_t; + using member_pointer_type = polyfill::remove_cvref_t; static_assert(!is_setter_v, "Unable to use setter within insert explicit"); @@ -16927,8 +16925,7 @@ namespace sqlite_orm { template std::string operator()(const statement_type& statement, const Ctx& context) const { - using expression_type = std::decay_t; - using object_type = typename expression_object_type::type; + using object_type = typename expression_object_type::type; auto& table = pick_table(context.db_objects); std::stringstream ss; @@ -17020,7 +17017,7 @@ namespace sqlite_orm { std::string operator()(const statement_type& statement, const Ctx& context) const { using object_type = typename expression_object_type::type; auto& table = pick_table(context.db_objects); - using is_without_rowid = typename std::decay_t::is_without_rowid; + using is_without_rowid = typename std::remove_reference_t::is_without_rowid; std::vector> columnNames; table.template for_each_column_excluding< @@ -17105,7 +17102,7 @@ namespace sqlite_orm { ss << "REPLACE"; } iterate_tuple(statement.args, [&context, &ss](auto& value) { - using value_type = std::decay_t; + using value_type = polyfill::remove_cvref_t; ss << ' '; if(is_columns_v) { auto newContext = context; @@ -17159,8 +17156,7 @@ namespace sqlite_orm { template std::string operator()(const statement_type& rep, const Ctx& context) const { - using expression_type = std::decay_t; - using object_type = typename expression_object_type::type; + using object_type = typename expression_object_type::type; auto& table = pick_table(context.db_objects); std::stringstream ss; @@ -17181,7 +17177,7 @@ namespace sqlite_orm { std::string operator()(const statement_type& statement, const Ctx& context) const { using object_type = typename expression_object_type::type; auto& table = pick_table(context.db_objects); - using is_without_rowid = typename std::decay_t::is_without_rowid; + using is_without_rowid = typename std::remove_reference_t::is_without_rowid; std::vector> columnNames; table.template for_each_column_excluding< @@ -17375,7 +17371,7 @@ namespace sqlite_orm { iterate_ast(sel.col, collector); iterate_ast(sel.conditions, collector); join_iterator()([&collector, &context](const auto& c) { - using original_join_type = typename std::decay_t::join_type::type; + using original_join_type = typename std::remove_reference_t::join_type::type; using cross_join_type = mapped_type_proxy_t; auto crossJoinedTableName = lookup_table_name(context.db_objects); auto tableAliasString = alias_extractor::get(); @@ -17435,7 +17431,7 @@ namespace sqlite_orm { if(statement.unique) { ss << "UNIQUE "; } - using elements_type = typename std::decay_t::elements_type; + using elements_type = typename std::remove_reference_t::elements_type; using head_t = typename mpl::element_at_t<0, elements_type>::column_type; using indexed_type = table_type_of_t; ss << "INDEX IF NOT EXISTS " << streaming_identifier(statement.name) << " ON " @@ -17443,7 +17439,7 @@ namespace sqlite_orm { std::vector columnNames; std::string whereString; iterate_tuple(statement.elements, [&columnNames, &context, &whereString](auto& value) { - using value_type = std::decay_t; + using value_type = polyfill::remove_cvref_t; if(!is_where_v) { auto newContext = context; newContext.use_parentheses = false; @@ -17631,7 +17627,7 @@ namespace sqlite_orm { << serialize(statement.base, context); ss << " BEGIN "; iterate_tuple(statement.elements, [&ss, &context](auto& element) { - using element_type = std::decay_t; + using element_type = polyfill::remove_cvref_t; if(is_select_v) { auto newContext = context; newContext.use_parentheses = false; @@ -18007,7 +18003,7 @@ namespace sqlite_orm { template void create_table(sqlite3* db, const std::string& tableName, const Table& table) { - using table_type = std::decay_t; + using table_type = std::remove_reference_t; using context_t = serializer_context; std::stringstream ss; @@ -18511,7 +18507,7 @@ namespace sqlite_orm { std::stringstream ss; ss << "{ "; table.for_each_column([&ss, &object, first = true](auto& column) mutable { - using column_type = std::decay_t; + using column_type = std::remove_reference_t; using field_type = typename column_type::field_type; constexpr std::array sep = {", ", ""}; @@ -19034,7 +19030,7 @@ namespace sqlite_orm { template int64 execute(const prepared_statement_t>& statement) { - using statement_type = std::decay_t; + using statement_type = std::remove_reference_t; using expression_type = typename statement_type::expression_type; using object_type = typename expression_object_type::type; @@ -19052,7 +19048,7 @@ namespace sqlite_orm { template, is_replace_range>, bool> = true> void execute(const prepared_statement_t& statement) { - using statement_type = std::decay_t; + using statement_type = std::remove_reference_t; using expression_type = typename statement_type::expression_type; using object_type = typename expression_object_type::type; @@ -19093,7 +19089,7 @@ namespace sqlite_orm { template, is_insert_range>, bool> = true> int64 execute(const prepared_statement_t& statement) { - using statement_type = std::decay_t; + using statement_type = std::remove_reference_t; using expression_type = typename statement_type::expression_type; using object_type = typename expression_object_type::type; @@ -19101,7 +19097,7 @@ namespace sqlite_orm { auto processObject = [&table = this->get_table(), bind_value = field_value_binder{stmt}](auto& object) mutable { - using is_without_rowid = typename std::decay_t::is_without_rowid; + using is_without_rowid = typename std::remove_reference_t::is_without_rowid; table.template for_each_column_excluding< mpl::conjunction>, mpl::disjunction_fn>>( @@ -19147,7 +19143,7 @@ namespace sqlite_orm { template void execute(const prepared_statement_t>& statement) { - using statement_type = std::decay_t; + using statement_type = std::remove_reference_t; using expression_type = typename statement_type::expression_type; using object_type = typename expression_object_type::type; @@ -19720,6 +19716,8 @@ namespace sqlite_orm { // #include "functional/static_magic.h" +// #include "functional/cxx_type_traits_polyfill.h" + // #include "functional/type_at.h" // #include "prepared_statement.h" @@ -19842,14 +19840,14 @@ namespace sqlite_orm { template const auto& get(const internal::prepared_statement_t& statement) { - using statement_type = std::decay_t; + using statement_type = std::remove_reference_t; using expression_type = typename statement_type::expression_type; using node_tuple = internal::node_tuple_t; using bind_tuple = internal::bindable_filter_t; using result_type = mpl::element_at_t(N), bind_tuple>; const result_type* result = nullptr; internal::iterate_ast(statement.expression, [&result, index = -1](auto& node) mutable { - using node_type = std::decay_t; + using node_type = polyfill::remove_cvref_t; if(internal::is_bindable_v) { ++index; if(index == N) { @@ -19867,7 +19865,7 @@ namespace sqlite_orm { template auto& get(internal::prepared_statement_t& statement) { - using statement_type = std::decay_t; + using statement_type = std::remove_reference_t; using expression_type = typename statement_type::expression_type; using node_tuple = internal::node_tuple_t; using bind_tuple = internal::bindable_filter_t; @@ -19875,7 +19873,7 @@ namespace sqlite_orm { result_type* result = nullptr; internal::iterate_ast(statement.expression, [&result, index = -1](auto& node) mutable { - using node_type = std::decay_t; + using node_type = polyfill::remove_cvref_t; if(internal::is_bindable_v) { ++index; if(index == N) { @@ -20066,7 +20064,7 @@ namespace sqlite_orm { * this file is also used to provide definitions of interface methods 'hitting the database'. */ -#include // std::decay_t +#include // std::remove_reference #include // std::move #include // std::find_if, std::ranges::find @@ -20084,7 +20082,7 @@ namespace sqlite_orm { std::vector res; res.reserve(size_t(filter_tuple_sequence_t::size())); this->for_each_column([&res](auto& column) { - using field_type = field_type_t>; + using field_type = field_type_t>; std::string dft; if(auto d = column.default_value()) { dft = move(*d); From a6af8926a8e40e31cb424b92643892e62e66a35d Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Jun 2022 22:02:18 +0300 Subject: [PATCH 13/16] Temporarily disabled fast-fail for appveyor builds --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 69743a6b8..7486bcee1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -77,8 +77,8 @@ environment: platform: x86 SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_20=ON" -matrix: - fast_finish: true +#matrix: + #fast_finish: true for: - From 99af00505d4050034d3867f6415ee45913b588cc Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Jun 2022 23:12:31 +0300 Subject: [PATCH 14/16] Workaround gcc < 11.3 compiler bug --- dev/functional/cxx_compiler_quirks.h | 26 +++++++++++++++++----- dev/functional/index_sequence_util.h | 7 +++--- include/sqlite_orm/sqlite_orm.h | 33 ++++++++++++++++++++-------- 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/dev/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index 5273be5a4..4f6d46d9e 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -26,18 +26,32 @@ #define SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(...) SQLITE_ORM_CLANG_SUPPRESS("-Wmissing-braces", __VA_ARGS__) #if defined(_MSC_VER) && !defined(__clang__) // MSVC +#define SQLITE_ORM_MSVC_EMPTYBASES __declspec(empty_bases) +#else +#define SQLITE_ORM_MSVC_EMPTYBASES +#endif + +#if defined(_MSC_VER) && !defined(__clang__) // MSVC + #if __cplusplus < 202002L #define SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 #endif -#endif -#if defined(_MSC_VER) && (_MSC_VER < 1920) +#if _MSC_VER < 1920 #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #define SQLITE_ORM_BROKEN_CONSTEXPR_DELEGATING_CTORS #endif -#if defined(_MSC_VER) && !defined(__clang__) // MSVC -#define SQLITE_ORM_MSVC_EMPTYBASES __declspec(empty_bases) -#else -#define SQLITE_ORM_MSVC_EMPTYBASES +#elif defined(__clang__) && defined(_MSC_VER) // Clang-cl (Clang for Windows) + +#elif defined(__clang__) // genuine Clang + +#elif defined(__clang__) && defined(__apple_build_version__) // Apple's Clang + +#elif defined(__GNUC__) // GCC + +#if __GNUC__ < 11 || (__GNUC__ == 11 && __GNUC_MINOR__ < 3) +#define SQLITE_ORM_BROKEN_GCC_ALIAS_TARGS_84785 +#endif + #endif diff --git a/dev/functional/index_sequence_util.h b/dev/functional/index_sequence_util.h index 931a022e4..017990bf7 100644 --- a/dev/functional/index_sequence_util.h +++ b/dev/functional/index_sequence_util.h @@ -1,6 +1,7 @@ #pragma once -#include // std::index_sequence, std::make_index_sequence +#include // std::integral_constant, std::declval +#include // std::index_sequence, std::make_index_sequence #include "cxx_universal.h" #ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED @@ -71,7 +72,7 @@ namespace sqlite_orm { template using expand_n_t = decltype(expand_n(Times{})); -#ifdef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION +#if defined(SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION) || defined(SQLITE_ORM_BROKEN_GCC_ALIAS_TARGS_84785) template struct spread_idxseq_helper { using type = expand_n_t>; @@ -80,7 +81,7 @@ namespace sqlite_orm { template constexpr auto spread_idxseq(std::index_sequence, std::index_sequence) { -#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION +#if !defined(SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION) && !defined(SQLITE_ORM_BROKEN_GCC_ALIAS_TARGS_84785) using type = pack>...>; #else using type = pack::type...>; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index d98bb5a51..9199a8a98 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -147,20 +147,34 @@ using std::nullptr_t; #define SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(...) SQLITE_ORM_CLANG_SUPPRESS("-Wmissing-braces", __VA_ARGS__) #if defined(_MSC_VER) && !defined(__clang__) // MSVC +#define SQLITE_ORM_MSVC_EMPTYBASES __declspec(empty_bases) +#else +#define SQLITE_ORM_MSVC_EMPTYBASES +#endif + +#if defined(_MSC_VER) && !defined(__clang__) // MSVC + #if __cplusplus < 202002L #define SQLITE_ORM_WORKAROUND_MSVC_MULTIPLECTOR_106654 #endif -#endif -#if defined(_MSC_VER) && (_MSC_VER < 1920) +#if _MSC_VER < 1920 #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #define SQLITE_ORM_BROKEN_CONSTEXPR_DELEGATING_CTORS #endif -#if defined(_MSC_VER) && !defined(__clang__) // MSVC -#define SQLITE_ORM_MSVC_EMPTYBASES __declspec(empty_bases) -#else -#define SQLITE_ORM_MSVC_EMPTYBASES +#elif defined(__clang__) && defined(_MSC_VER) // Clang-cl (Clang for Windows) + +#elif defined(__clang__) // genuine Clang + +#elif defined(__clang__) && defined(__apple_build_version__) // Apple's Clang + +#elif defined(__GNUC__) // GCC + +#if __GNUC__ < 11 || (__GNUC__ == 11 && __GNUC_MINOR__ < 3) +#define SQLITE_ORM_BROKEN_GCC_ALIAS_TARGS_84785 +#endif + #endif namespace sqlite_orm { @@ -1066,7 +1080,8 @@ namespace sqlite_orm { // #include "index_sequence_util.h" -#include // std::index_sequence, std::make_index_sequence +#include // std::integral_constant, std::declval +#include // std::index_sequence, std::make_index_sequence // #include "cxx_universal.h" @@ -1170,7 +1185,7 @@ namespace sqlite_orm { template using expand_n_t = decltype(expand_n(Times{})); -#ifdef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION +#if defined(SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION) || defined(SQLITE_ORM_BROKEN_GCC_ALIAS_TARGS_84785) template struct spread_idxseq_helper { using type = expand_n_t>; @@ -1179,7 +1194,7 @@ namespace sqlite_orm { template constexpr auto spread_idxseq(std::index_sequence, std::index_sequence) { -#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION +#if !defined(SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION) && !defined(SQLITE_ORM_BROKEN_GCC_ALIAS_TARGS_84785) using type = pack>...>; #else using type = pack::type...>; From dfa2fcd6f12667f5d8b3b8360b2a55638fde8756 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 20 Jun 2022 21:10:09 +0300 Subject: [PATCH 15/16] Corrected compiler detection chain --- dev/functional/cxx_compiler_quirks.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index 4f6d46d9e..6ba5d75ea 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -44,10 +44,10 @@ #elif defined(__clang__) && defined(_MSC_VER) // Clang-cl (Clang for Windows) -#elif defined(__clang__) // genuine Clang - #elif defined(__clang__) && defined(__apple_build_version__) // Apple's Clang +#elif defined(__clang__) // genuine Clang + #elif defined(__GNUC__) // GCC #if __GNUC__ < 11 || (__GNUC__ == 11 && __GNUC_MINOR__ < 3) From 9c5cfd80c7052f5f5234fff3ac56af320b874384 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Jun 2022 22:02:18 +0300 Subject: [PATCH 16/16] Revert "Temporarily disabled fast-fail for appveyor builds" This reverts commit a6af8926a8e40e31cb424b92643892e62e66a35d. --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 7486bcee1..69743a6b8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -77,8 +77,8 @@ environment: platform: x86 SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_20=ON" -#matrix: - #fast_finish: true +matrix: + fast_finish: true for: -