Skip to content

Commit 1faeed4

Browse files
authored
Merge pull request #1290 from fnc12/colconstraints_and_mpl
Improvements to the MPL and checking column constraints
2 parents 1195ab3 + e9a03af commit 1faeed4

File tree

14 files changed

+320
-64
lines changed

14 files changed

+320
-64
lines changed

dev/alias.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#endif
1010

1111
#include "functional/cxx_type_traits_polyfill.h"
12+
#include "functional/mpl/conditional.h"
1213
#include "functional/cstring_literal.h"
1314
#include "type_traits.h"
1415
#include "alias_traits.h"
@@ -228,7 +229,7 @@ namespace sqlite_orm {
228229
static_assert(is_field_of_v<F O::*, aliased_type>, "Column must be from aliased table");
229230

230231
using C1 =
231-
std::conditional_t<std::is_same<O, aliased_type>::value, F O::*, column_pointer<aliased_type, F O::*>>;
232+
mpl::conditional_t<std::is_same<O, aliased_type>::value, F O::*, column_pointer<aliased_type, F O::*>>;
232233
return alias_column_t<A, C1>{C1{field}};
233234
}
234235

dev/arithmetic_tag.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
2-
#include <type_traits>
2+
#include <type_traits> // std::is_integral
3+
4+
#include "functional/mpl/conditional.h"
35

46
namespace sqlite_orm {
57

@@ -12,9 +14,9 @@ namespace sqlite_orm {
1214

1315
template<class V>
1416
using arithmetic_tag_t =
15-
std::conditional_t<std::is_integral<V>::value,
17+
mpl::conditional_t<std::is_integral<V>::value,
1618
// Integer class
17-
std::conditional_t<sizeof(V) <= sizeof(int), int_or_smaller_tag, bigint_tag>,
19+
mpl::conditional_t<sizeof(V) <= sizeof(int), int_or_smaller_tag, bigint_tag>,
1820
// Floating-point class
1921
real_tag>;
2022
}

dev/constraints.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -464,22 +464,23 @@ namespace sqlite_orm {
464464
/**
465465
* PRIMARY KEY INSERTABLE traits.
466466
*/
467-
template<typename T>
467+
template<typename Column>
468468
struct is_primary_key_insertable
469469
: polyfill::disjunction<
470-
mpl::invoke_t<mpl::disjunction<check_if_has_template<default_t>,
471-
check_if_has_template<primary_key_with_autoincrement>>,
472-
constraints_type_t<T>>,
473-
std::is_base_of<integer_printer, type_printer<field_type_t<T>>>> {
470+
mpl::invoke_t<mpl::disjunction<check_if_has_template<primary_key_with_autoincrement>,
471+
check_if_has_template<default_t>>,
472+
constraints_type_t<Column>>,
473+
std::is_base_of<integer_printer, type_printer<field_type_t<Column>>>> {
474474

475-
static_assert(tuple_has<constraints_type_t<T>, is_primary_key>::value, "an unexpected type was passed");
475+
static_assert(tuple_has<constraints_type_t<Column>, is_primary_key>::value,
476+
"an unexpected type was passed");
476477
};
477478

478479
template<class T>
479-
using is_column_constraint = mpl::invoke_t<mpl::disjunction<check_if<is_primary_key>,
480+
using is_column_constraint = mpl::invoke_t<mpl::disjunction<check_if<std::is_base_of, primary_key_t<>>,
480481
check_if_is_type<null_t>,
481482
check_if_is_type<not_null_t>,
482-
check_if_is_template<unique_t>,
483+
check_if_is_type<unique_t<>>,
483484
check_if_is_template<default_t>,
484485
check_if_is_template<check_t>,
485486
check_if_is_type<collate_constraint_t>,

dev/core_functions.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <vector> // std::vector
88

99
#include "functional/cxx_type_traits_polyfill.h"
10+
#include "functional/mpl/conditional.h"
1011
#include "is_base_of_template.h"
1112
#include "tuple_helper/tuple_traits.h"
1213
#include "conditions.h"
@@ -1672,7 +1673,7 @@ namespace sqlite_orm {
16721673
*/
16731674
template<class R = void, class... Args>
16741675
auto coalesce(Args... args)
1675-
-> internal::built_in_function_t<typename std::conditional_t< // choose R or common type
1676+
-> internal::built_in_function_t<typename mpl::conditional_t< // choose R or common type
16761677
std::is_void<R>::value,
16771678
std::common_type<internal::field_type_or_type_t<Args>...>,
16781679
polyfill::type_identity<R>>::type,
@@ -1686,7 +1687,7 @@ namespace sqlite_orm {
16861687
*/
16871688
template<class R = void, class X, class Y>
16881689
auto ifnull(X x, Y y) -> internal::built_in_function_t<
1689-
typename std::conditional_t< // choose R or common type
1690+
typename mpl::conditional_t< // choose R or common type
16901691
std::is_void<R>::value,
16911692
std::common_type<internal::field_type_or_type_t<X>, internal::field_type_or_type_t<Y>>,
16921693
polyfill::type_identity<R>>::type,

dev/functional/cxx_type_traits_polyfill.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <type_traits>
33

44
#include "cxx_universal.h"
5+
#include "mpl/conditional.h"
56

67
namespace sqlite_orm {
78
namespace internal {
@@ -40,7 +41,7 @@ namespace sqlite_orm {
4041
template<typename B1>
4142
struct conjunction<B1> : B1 {};
4243
template<typename B1, typename... Bn>
43-
struct conjunction<B1, Bn...> : std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
44+
struct conjunction<B1, Bn...> : mpl::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
4445
template<typename... Bs>
4546
SQLITE_ORM_INLINE_VAR constexpr bool conjunction_v = conjunction<Bs...>::value;
4647

@@ -49,7 +50,7 @@ namespace sqlite_orm {
4950
template<typename B1>
5051
struct disjunction<B1> : B1 {};
5152
template<typename B1, typename... Bn>
52-
struct disjunction<B1, Bn...> : std::conditional_t<bool(B1::value), B1, disjunction<Bn...>> {};
53+
struct disjunction<B1, Bn...> : mpl::conditional_t<bool(B1::value), B1, disjunction<Bn...>> {};
5354
template<typename... Bs>
5455
SQLITE_ORM_INLINE_VAR constexpr bool disjunction_v = disjunction<Bs...>::value;
5556

dev/functional/mpl.h

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
* - "higher order" denotes a metafunction that operates on another metafunction (i.e. takes it as an argument).
2929
*/
3030

31-
#include <type_traits> // std::enable_if, std::is_same
31+
#include <type_traits> // std::true_type, std::false_type, std::is_same, std::negation, std::conjunction, std::disjunction
3232
#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED
3333
#include <initializer_list>
3434
#else
@@ -37,6 +37,7 @@
3737

3838
#include "cxx_universal.h" // ::size_t
3939
#include "cxx_type_traits_polyfill.h"
40+
#include "mpl/conditional.h"
4041

4142
namespace sqlite_orm {
4243
namespace internal {
@@ -59,6 +60,12 @@ namespace sqlite_orm {
5960
template<class T>
6061
struct is_quoted_metafuntion : polyfill::bool_constant<is_quoted_metafuntion_v<T>> {};
6162

63+
/*
64+
* Type pack.
65+
*/
66+
template<class...>
67+
struct pack {};
68+
6269
/*
6370
* The indirection through `defer_fn` works around the language inability
6471
* to expand `Args...` into a fixed parameter list of an alias template.
@@ -164,7 +171,7 @@ namespace sqlite_orm {
164171

165172
/*
166173
* Quoted metafunction that invokes the specified quoted metafunctions,
167-
* and passes its result on to the next quoted metafunction.
174+
* and passes their results on to the next quoted metafunction.
168175
*/
169176
template<class Q, class... Qs>
170177
struct pass_result_of {
@@ -175,7 +182,7 @@ namespace sqlite_orm {
175182

176183
/*
177184
* Quoted metafunction that invokes the specified metafunctions,
178-
* and passes its result on to the next quoted metafunction.
185+
* and passes their results on to the next quoted metafunction.
179186
*/
180187
template<class Q, template<class...> class... Fn>
181188
using pass_result_of_fn = pass_result_of<Q, quote_fn<Fn>...>;
@@ -223,13 +230,71 @@ namespace sqlite_orm {
223230
* Quoted metafunction equivalent to `std::conjunction`.
224231
*/
225232
template<class... TraitQ>
226-
using conjunction = pass_result_of<quote_fn<polyfill::conjunction>, TraitQ...>;
233+
struct conjunction {
234+
template<class... Args>
235+
using fn = std::true_type;
236+
};
237+
238+
template<class FirstQ, class... TraitQ>
239+
struct conjunction<FirstQ, TraitQ...> {
240+
// match last or `std::false_type`
241+
template<class ArgPack, class ResultTrait, class...>
242+
struct invoke_this_fn {
243+
static_assert(std::is_same<ResultTrait, std::true_type>::value ||
244+
std::is_same<ResultTrait, std::false_type>::value,
245+
"Resulting trait must be a std::bool_constant");
246+
using type = ResultTrait;
247+
};
248+
249+
// match `std::true_type` and one or more remaining
250+
template<class... Args, class NextQ, class... RestQ>
251+
struct invoke_this_fn<pack<Args...>, std::true_type, NextQ, RestQ...>
252+
: invoke_this_fn<pack<Args...>,
253+
// access resulting trait::type
254+
typename defer<NextQ, Args...>::type::type,
255+
RestQ...> {};
256+
257+
template<class... Args>
258+
using fn = typename invoke_this_fn<pack<Args...>,
259+
// access resulting trait::type
260+
typename defer<FirstQ, Args...>::type::type,
261+
TraitQ...>::type;
262+
};
227263

228264
/*
229265
* Quoted metafunction equivalent to `std::disjunction`.
230266
*/
231267
template<class... TraitQ>
232-
using disjunction = pass_result_of<quote_fn<polyfill::disjunction>, TraitQ...>;
268+
struct disjunction {
269+
template<class... Args>
270+
using fn = std::false_type;
271+
};
272+
273+
template<class FirstQ, class... TraitQ>
274+
struct disjunction<FirstQ, TraitQ...> {
275+
// match last or `std::true_type`
276+
template<class ArgPack, class ResultTrait, class...>
277+
struct invoke_this_fn {
278+
static_assert(std::is_same<ResultTrait, std::true_type>::value ||
279+
std::is_same<ResultTrait, std::false_type>::value,
280+
"Resulting trait must be a std::bool_constant");
281+
using type = ResultTrait;
282+
};
283+
284+
// match `std::false_type` and one or more remaining
285+
template<class... Args, class NextQ, class... RestQ>
286+
struct invoke_this_fn<pack<Args...>, std::false_type, NextQ, RestQ...>
287+
: invoke_this_fn<pack<Args...>,
288+
// access resulting trait::type
289+
typename defer<NextQ, Args...>::type::type,
290+
RestQ...> {};
291+
292+
template<class... Args>
293+
using fn = typename invoke_this_fn<pack<Args...>,
294+
// access resulting trait::type
295+
typename defer<FirstQ, Args...>::type::type,
296+
TraitQ...>::type;
297+
};
233298

234299
/*
235300
* Metafunction equivalent to `std::conjunction`.
@@ -380,7 +445,7 @@ namespace sqlite_orm {
380445
<sizeof...(T)>
381446
#endif
382447
({TraitQ::template fn<typename ProjectQ::template fn<T>>::value...}));
383-
using type = polyfill::index_constant<value>;
448+
using type = polyfill::bool_constant<value>;
384449
};
385450

386451
template<class Pack, class ProjectQ = identity>
@@ -399,8 +464,9 @@ namespace sqlite_orm {
399464
/*
400465
* Quoted trait metafunction that checks if a type has the specified trait.
401466
*/
402-
template<template<class...> class TraitFn>
403-
using check_if = mpl::quote_fn<TraitFn>;
467+
template<template<class...> class TraitFn, class... Bound>
468+
using check_if =
469+
mpl::conditional_t<sizeof...(Bound) == 0, mpl::quote_fn<TraitFn>, mpl::bind_front_fn<TraitFn, Bound...>>;
404470

405471
/*
406472
* Quoted trait metafunction that checks if a type doesn't have the specified trait.
@@ -410,6 +476,7 @@ namespace sqlite_orm {
410476

411477
/*
412478
* Quoted trait metafunction that checks if a type is the same as the specified type.
479+
* Commonly used named abbreviation for `check_if<std::is_same, Type>`.
413480
*/
414481
template<class Type>
415482
using check_if_is_type = mpl::bind_front_fn<std::is_same, Type>;

dev/functional/mpl/conditional.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#pragma once
2+
3+
namespace sqlite_orm {
4+
namespace internal {
5+
namespace mpl {
6+
7+
/*
8+
* Binary quoted metafunction equivalent to `std::conditional`,
9+
* using an improved implementation in respect to memoization.
10+
*
11+
* Because `conditional` is only typed on a single bool non-type template parameter,
12+
* the compiler only ever needs to memoize 2 instances of this class template.
13+
* The type selection is a nested cheap alias template.
14+
*/
15+
template<bool>
16+
struct conditional {
17+
template<typename A, typename>
18+
using fn = A;
19+
};
20+
21+
template<>
22+
struct conditional<false> {
23+
template<typename, typename B>
24+
using fn = B;
25+
};
26+
27+
// directly invoke `conditional`
28+
template<bool v, typename A, typename B>
29+
using conditional_t = typename conditional<v>::template fn<A, B>;
30+
}
31+
}
32+
33+
namespace mpl = internal::mpl;
34+
}

dev/storage.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,9 +1531,9 @@ namespace sqlite_orm {
15311531
#ifdef SQLITE_ORM_WITH_CTE
15321532
template<class... CTEs, class T, class... Args>
15331533
auto execute(const prepared_statement_t<with_t<select_t<T, Args...>, CTEs...>>& statement) {
1534-
using ExprDBOs =
1535-
decltype(db_objects_for_expression(this->db_objects,
1536-
std::declval<with_t<select_t<T, Args...>, CTEs...>>()));
1534+
using ExprDBOs = decltype(db_objects_for_expression(this->db_objects, statement.expression));
1535+
// note: it is enough to only use the 'expression DBOs' at compile-time to determine the column results;
1536+
// because we cannot select objects/structs from a CTE, the permanently defined DBOs are enough.
15371537
using ColResult = column_result_of_t<ExprDBOs, T>;
15381538
return _execute_select<ColResult>(statement);
15391539
}

dev/tuple_helper/tuple_filter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <tuple> // std::tuple
55

66
#include "../functional/cxx_universal.h" // ::size_t
7+
#include "../functional/mpl/conditional.h"
78
#include "../functional/index_sequence_util.h"
89

910
namespace sqlite_orm {
@@ -34,7 +35,7 @@ namespace sqlite_orm {
3435
#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION
3536
template<class Tpl, template<class...> class Pred, template<class...> class Proj, size_t... Idx>
3637
struct filter_tuple_sequence<Tpl, Pred, Proj, std::index_sequence<Idx...>>
37-
: flatten_idxseq<std::conditional_t<Pred<mpl::invoke_fn_t<Proj, std::tuple_element_t<Idx, Tpl>>>::value,
38+
: flatten_idxseq<mpl::conditional_t<Pred<mpl::invoke_fn_t<Proj, std::tuple_element_t<Idx, Tpl>>>::value,
3839
std::index_sequence<Idx>,
3940
std::index_sequence<>>...> {};
4041
#else

examples/common_table_expressions.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,12 @@ void all_integers_between(int from, int end) {
9999
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
100100
constexpr auto cnt = "cnt"_cte;
101101
constexpr auto x = "x"_col;
102-
auto ast = with(cnt(x).as(union_all(select(from), select(cnt->*x + 1, limit(end)))), select(cnt->*x));
102+
auto ast = with_recursive(cnt(x).as(union_all(select(from), select(cnt->*x + 1, limit(end)))), select(cnt->*x));
103103
#else
104104
using cnt = decltype(1_ctealias);
105105
constexpr auto x = colalias_i{};
106-
auto ast = with(cte<cnt>(x).as(union_all(select(from), select(column<cnt>(x) + 1, limit(end)))),
107-
select(column<cnt>(x)));
106+
auto ast = with_recursive(cte<cnt>(x).as(union_all(select(from), select(column<cnt>(x) + 1, limit(end)))),
107+
select(column<cnt>(x)));
108108
#endif
109109

110110
string sql = storage.dump(ast);

0 commit comments

Comments
 (0)