Skip to content

Commit 722ec86

Browse files
committed
Modernized the pointer passing interface with C++20 features
1 parent 865fdb6 commit 722ec86

File tree

13 files changed

+406
-69
lines changed

13 files changed

+406
-69
lines changed

dev/carray.h

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,28 @@
77
*/
88

99
#ifdef SQLITE_ORM_INLINE_VARIABLES_SUPPORTED
10-
#include <type_traits> // std::integral_constant
1110
#include <utility> // std::move
11+
#ifndef SQLITE_ORM_WITH_CPP20_ALIASES
12+
#include <type_traits> // std::integral_constant
13+
#endif
14+
#endif
1215

13-
#include "functional/cxx_universal.h"
1416
#include "pointer_value.h"
1517

18+
#ifdef SQLITE_ORM_INLINE_VARIABLES_SUPPORTED
1619
namespace sqlite_orm {
1720

18-
inline constexpr const char carray_pvt_name[] = "carray";
19-
using carray_pvt = std::integral_constant<const char*, carray_pvt_name>;
21+
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
22+
inline constexpr orm_pointer_type auto carray_pointer_tag = "carray"_pointer_type;
23+
// [Deprecation notice] This type is deprecated and will be removed in v1.10. Use the inline variable `carray_pointer_tag` instead.
24+
using carray_pvt [[deprecated]] = decltype("carray"_pointer_type);
2025

2126
template<typename P>
22-
using carray_pointer_arg = pointer_arg<P, carray_pvt>;
27+
using carray_pointer_arg = pointer_arg_t<P, carray_pointer_tag>;
2328
template<typename P, typename D>
24-
using carray_pointer_binding = pointer_binding<P, carray_pvt, D>;
29+
using carray_pointer_binding = pointer_binding_t<P, carray_pointer_tag, D>;
2530
template<typename P>
26-
using static_carray_pointer_binding = static_pointer_binding<P, carray_pvt>;
31+
using static_carray_pointer_binding = static_pointer_binding_t<P, carray_pointer_tag>;
2732

2833
/**
2934
* Wrap a pointer of type 'carray' and its deleter function for binding it to a statement.
@@ -33,8 +38,8 @@ namespace sqlite_orm {
3338
* the deleter when the statement finishes.
3439
*/
3540
template<class P, class D>
36-
auto bindable_carray_pointer(P* p, D d) noexcept -> pointer_binding<P, carray_pvt, D> {
37-
return bindable_pointer<carray_pvt>(p, std::move(d));
41+
auto bindable_carray_pointer(P* p, D d) noexcept -> pointer_binding_t<P, carray_pointer_tag, D> {
42+
return bindable_pointer<carray_pointer_tag>(p, std::move(d));
3843
}
3944

4045
/**
@@ -44,9 +49,45 @@ namespace sqlite_orm {
4449
* and sqlite assumes the object pointed to is valid throughout the lifetime of a statement.
4550
*/
4651
template<class P>
47-
auto statically_bindable_carray_pointer(P* p) noexcept -> static_pointer_binding<P, carray_pvt> {
48-
return statically_bindable_pointer<carray_pvt>(p);
52+
auto statically_bindable_carray_pointer(P* p) noexcept -> static_pointer_binding_t<P, carray_pointer_tag> {
53+
return statically_bindable_pointer<carray_pointer_tag>(p);
4954
}
55+
#else
56+
inline constexpr const char carray_pointer_name[] = "carray";
57+
using carray_pointer_type = std::integral_constant<const char*, carray_pointer_name>;
58+
// [Deprecation notice] This type is deprecated and will be removed in v1.10. Use the alias type `carray_pointer_type` instead.
59+
using carray_pvt [[deprecated]] = carray_pointer_type;
60+
61+
template<typename P>
62+
using carray_pointer_arg = pointer_arg<P, carray_pointer_type>;
63+
template<typename P, typename D>
64+
using carray_pointer_binding = pointer_binding<P, carray_pointer_type, D>;
65+
template<typename P>
66+
using static_carray_pointer_binding = static_pointer_binding<P, carray_pointer_type>;
67+
68+
/**
69+
* Wrap a pointer of type 'carray' and its deleter function for binding it to a statement.
70+
*
71+
* Unless the deleter yields a nullptr 'xDestroy' function the ownership of the pointed-to-object
72+
* is transferred to the pointer binding, which will delete it through
73+
* the deleter when the statement finishes.
74+
*/
75+
template<class P, class D>
76+
auto bindable_carray_pointer(P* p, D d) noexcept -> pointer_binding<P, carray_pointer_type, D> {
77+
return bindable_pointer<carray_pointer_type>(p, std::move(d));
78+
}
79+
80+
/**
81+
* Wrap a pointer of type 'carray' for binding it to a statement.
82+
*
83+
* Note: 'Static' means that ownership of the pointed-to-object won't be transferred
84+
* and sqlite assumes the object pointed to is valid throughout the lifetime of a statement.
85+
*/
86+
template<class P>
87+
auto statically_bindable_carray_pointer(P* p) noexcept -> static_pointer_binding<P, carray_pointer_type> {
88+
return statically_bindable_pointer<carray_pointer_type>(p);
89+
}
90+
#endif
5091

5192
/**
5293
* Generalized form of the 'remember' SQL function that is a pass-through for values

dev/function.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#include <algorithm> // std::min, std::copy_n
99
#include <utility> // std::move, std::forward
1010

11-
#include "functional/cxx_universal.h"
11+
#include "functional/cxx_universal.h" // ::size_t
1212
#include "functional/cxx_type_traits_polyfill.h"
1313
#include "functional/cstring_literal.h"
1414
#include "functional/function_traits.h"
@@ -19,9 +19,9 @@ namespace sqlite_orm {
1919

2020
struct arg_values;
2121

22-
template<class T, class P>
22+
template<class P, class T>
2323
struct pointer_arg;
24-
template<class T, class P, class D>
24+
template<class P, class T, class D>
2525
class pointer_binding;
2626

2727
namespace internal {

dev/pointer_value.h

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,38 @@
33
#include <type_traits>
44
#include <memory>
55
#include <utility>
6+
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
7+
#include <concepts>
8+
#endif
69

7-
#include "functional/cxx_universal.h"
10+
#include "functional/cstring_literal.h"
811
#include "xdestroy_handling.h"
912

1013
namespace sqlite_orm {
14+
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
15+
namespace internal {
16+
template<char... C>
17+
struct pointer_type {
18+
using value_type = const char[sizeof...(C) + 1];
19+
static inline constexpr value_type value = {C..., '\0'};
20+
};
21+
}
22+
23+
inline namespace literals {
24+
template<internal::cstring_literal tag>
25+
[[nodiscard]] consteval auto operator"" _pointer_type() {
26+
return internal::explode_into<internal::pointer_type, tag>(std::make_index_sequence<tag.size()>{});
27+
}
28+
}
29+
30+
/** @short Specifies that a type is an integral constant string usable as a pointer type.
31+
*/
32+
template<class T>
33+
concept orm_pointer_type = requires {
34+
typename T::value_type;
35+
{ T::value } -> std::convertible_to<const char*>;
36+
};
37+
#endif
1138

1239
/**
1340
* Wraps a pointer and tags it with a pointer type,
@@ -16,14 +43,20 @@ namespace sqlite_orm {
1643
*
1744
* Template parameters:
1845
* - P: The value type, possibly const-qualified.
19-
* - T: An integral constant string denoting the pointer type, e.g. `carray_pvt_name`.
46+
* - T: An integral constant string denoting the pointer type, e.g. `carray_pointer_type`.
2047
*
2148
*/
2249
template<typename P, typename T>
2350
struct pointer_arg {
2451

52+
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
53+
// note (internal): this is currently a static assertion instead of a type constraint because
54+
// of forward declarations in other places (e.g. function.h)
55+
static_assert(orm_pointer_type<T>, "The pointer type (tag) must be convertible to `const char*`");
56+
#else
2557
static_assert(std::is_convertible<typename T::value_type, const char*>::value,
26-
"`std::integral_constant<>` must be convertible to `const char*`");
58+
"The pointer type (tag) must be convertible to `const char*`");
59+
#endif
2760

2861
using tag = T;
2962
P* p_;
@@ -43,6 +76,8 @@ namespace sqlite_orm {
4376
* as part of facilitating the 'pointer-passing interface'.
4477
*
4578
* Template parameters:
79+
* - P: The value type, possibly const-qualified.
80+
* - T: An integral constant string denoting the pointer type, e.g. `carray_pointer_type`.
4681
* - D: The deleter for the pointer value;
4782
* can be one of:
4883
* - function pointer
@@ -71,6 +106,11 @@ namespace sqlite_orm {
71106
// Constructing pointer bindings must go through bindable_pointer()
72107
template<class T2, class P2, class D2>
73108
friend auto bindable_pointer(P2*, D2) noexcept -> pointer_binding<P2, T2, D2>;
109+
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
110+
// Constructing pointer bindings must go through bindable_pointer()
111+
template<orm_pointer_type auto tag, class P2, class D2>
112+
friend auto bindable_pointer(P2*, D2) noexcept -> pointer_binding<P2, decltype(tag), D2>;
113+
#endif
74114
template<class B>
75115
friend B bindable_pointer(typename B::qualified_type*, typename B::deleter_type) noexcept;
76116

@@ -113,17 +153,33 @@ namespace sqlite_orm {
113153
};
114154

115155
/**
116-
* Template alias for a static pointer value binding.
156+
* Alias template for a static pointer value binding.
117157
* 'Static' means that ownership won't be transferred to sqlite,
118158
* sqlite doesn't delete it, and sqlite assumes the object
119159
* pointed to is valid throughout the lifetime of a statement.
120160
*/
121161
template<typename P, typename T>
122162
using static_pointer_binding = pointer_binding<P, T, null_xdestroy_t>;
163+
164+
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
165+
template<class P, orm_pointer_type auto tag>
166+
using pointer_arg_t = pointer_arg<P, decltype(tag)>;
167+
168+
template<class P, orm_pointer_type auto tag, class D>
169+
using pointer_binding_t = pointer_binding<P, decltype(tag), D>;
170+
171+
/**
172+
* Alias template for a static pointer value binding.
173+
* 'Static' means that ownership won't be transferred to sqlite,
174+
* sqlite doesn't delete it, and sqlite assumes the object
175+
* pointed to is valid throughout the lifetime of a statement.
176+
*/
177+
template<typename P, orm_pointer_type auto tag>
178+
using static_pointer_binding_t = pointer_binding_t<P, tag, null_xdestroy_t>;
179+
#endif
123180
}
124181

125182
namespace sqlite_orm {
126-
127183
/**
128184
* Wrap a pointer, its type and its deleter function for binding it to a statement.
129185
*
@@ -146,6 +202,25 @@ namespace sqlite_orm {
146202
return B{p, std::move(d)};
147203
}
148204

205+
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
206+
/**
207+
* Wrap a pointer, its type (tag) and its deleter function for binding it to a statement.
208+
*
209+
* Unless the deleter yields a nullptr 'xDestroy' function the ownership of the pointed-to-object
210+
* is transferred to the pointer binding, which will delete it through
211+
* the deleter when the statement finishes.
212+
*/
213+
template<orm_pointer_type auto tag, class P, class D>
214+
auto bindable_pointer(P* p, D d) noexcept -> pointer_binding<P, decltype(tag), D> {
215+
return {p, std::move(d)};
216+
}
217+
218+
template<orm_pointer_type auto tag, class P, class D>
219+
auto bindable_pointer(std::unique_ptr<P, D> p) noexcept -> pointer_binding<P, decltype(tag), D> {
220+
return bindable_pointer<tag>(p.release(), p.get_deleter());
221+
}
222+
#endif
223+
149224
/**
150225
* Wrap a pointer and its type for binding it to a statement.
151226
*
@@ -163,6 +238,19 @@ namespace sqlite_orm {
163238
return bindable_pointer<B>(p);
164239
}
165240

241+
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
242+
/**
243+
* Wrap a pointer and its type (tag) for binding it to a statement.
244+
*
245+
* Note: 'Static' means that ownership of the pointed-to-object won't be transferred
246+
* and sqlite assumes the object pointed to is valid throughout the lifetime of a statement.
247+
*/
248+
template<orm_pointer_type auto tag, class P>
249+
auto statically_bindable_pointer(P* p) noexcept -> static_pointer_binding<P, decltype(tag)> {
250+
return bindable_pointer<tag>(p, null_xdestroy_f);
251+
}
252+
#endif
253+
166254
/**
167255
* Forward a pointer value from an argument.
168256
*/

dev/statement_binder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ namespace sqlite_orm {
5050
}
5151

5252
/**
53-
* Specialization for 'pointer-passing interface'.
53+
* Specialization for pointer bindings (part of the 'pointer-passing interface').
5454
*/
5555
template<class P, class T, class D>
5656
struct statement_binder<pointer_binding<P, T, D>, void> {

examples/custom_aliases.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ int main(int, char** argv) {
107107
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
108108
constexpr orm_table_alias auto c_als = "c"_alias.for_<Employee>();
109109
constexpr orm_table_alias auto d = "d"_alias.for_<Department>();
110-
static_assert(std::is_empty_v<EmployeeIdAlias>); // note: it's
110+
static_assert(std::is_empty_v<EmployeeIdAlias>);
111111
constexpr orm_column_alias auto empId = EmployeeIdAlias{};
112112
auto rowsWithTableAliases = storage.select(
113113
columns(c_als->*&Employee::id, c_als->*&Employee::name, c_als->*&Employee::age, d->*&Department::dept),

0 commit comments

Comments
 (0)