Skip to content

Commit 754710e

Browse files
authored
Merge pull request #1316 from fnc12/pointer-passing-cpp20
Modernized the pointer passing interface with C++20 features
2 parents 865fdb6 + e678730 commit 754710e

File tree

13 files changed

+559
-109
lines changed

13 files changed

+559
-109
lines changed

dev/carray.h

Lines changed: 78 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,13 @@ 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+
carray_pointer_binding<P, D> bind_carray_pointer(P* p, D d) noexcept {
42+
return bind_pointer<carray_pointer_tag>(p, std::move(d));
43+
}
44+
45+
template<class P>
46+
static_carray_pointer_binding<P> bind_carray_pointer_statically(P* p) noexcept {
47+
return bind_pointer_statically<carray_pointer_tag>(p);
3848
}
3949

4050
/**
@@ -43,10 +53,67 @@ namespace sqlite_orm {
4353
* Note: 'Static' means that ownership of the pointed-to-object won't be transferred
4454
* and sqlite assumes the object pointed to is valid throughout the lifetime of a statement.
4555
*/
56+
template<class P, class D>
57+
[[deprecated("Use the better named function `bind_carray_pointer(...)`")]] carray_pointer_binding<P, D>
58+
bindable_carray_pointer(P* p, D d) noexcept {
59+
return bind_pointer<carray_pointer_tag>(p, std::move(d));
60+
}
61+
4662
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);
63+
[[deprecated(
64+
"Use the better named function `bind_carray_pointer_statically(...)` ")]] static_carray_pointer_binding<P>
65+
statically_bindable_carray_pointer(P* p) noexcept {
66+
return bind_pointer_statically<carray_pointer_tag>(p);
4967
}
68+
#else
69+
inline constexpr const char carray_pointer_name[] = "carray";
70+
using carray_pointer_type = std::integral_constant<const char*, carray_pointer_name>;
71+
// [Deprecation notice] This type is deprecated and will be removed in v1.10. Use the alias type `carray_pointer_type` instead.
72+
using carray_pvt [[deprecated]] = carray_pointer_type;
73+
74+
template<typename P>
75+
using carray_pointer_arg = pointer_arg<P, carray_pointer_type>;
76+
template<typename P, typename D>
77+
using carray_pointer_binding = pointer_binding<P, carray_pointer_type, D>;
78+
template<typename P>
79+
using static_carray_pointer_binding = static_pointer_binding<P, carray_pointer_type>;
80+
81+
/**
82+
* Wrap a pointer of type 'carray' and its deleter function for binding it to a statement.
83+
*
84+
* Unless the deleter yields a nullptr 'xDestroy' function the ownership of the pointed-to-object
85+
* is transferred to the pointer binding, which will delete it through
86+
* the deleter when the statement finishes.
87+
*/
88+
template<class P, class D>
89+
carray_pointer_binding<P, D> bind_carray_pointer(P* p, D d) noexcept {
90+
return bind_pointer<carray_pointer_type>(p, std::move(d));
91+
}
92+
93+
/**
94+
* Wrap a pointer of type 'carray' for binding it to a statement.
95+
*
96+
* Note: 'Static' means that ownership of the pointed-to-object won't be transferred
97+
* and sqlite assumes the object pointed to is valid throughout the lifetime of a statement.
98+
*/
99+
template<class P>
100+
static_carray_pointer_binding<P> bind_carray_pointer_statically(P* p) noexcept {
101+
return bind_pointer_statically<carray_pointer_type>(p);
102+
}
103+
104+
template<class P, class D>
105+
[[deprecated("Use the better named function `bind_carray_pointer(...)`")]] carray_pointer_binding<P, D>
106+
bindable_carray_pointer(P* p, D d) noexcept {
107+
return bind_carray_pointer(p, std::move(d));
108+
}
109+
110+
template<class P>
111+
[[deprecated(
112+
"Use the better named function `bind_carray_pointer_statically(...)` ")]] static_carray_pointer_binding<P>
113+
statically_bindable_carray_pointer(P* p) noexcept {
114+
return bind_carray_pointer_statically(p);
115+
}
116+
#endif
50117

51118
/**
52119
* 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: 137 additions & 18 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
@@ -68,11 +103,16 @@ namespace sqlite_orm {
68103
D d_;
69104

70105
protected:
71-
// Constructing pointer bindings must go through bindable_pointer()
106+
// Constructing pointer bindings must go through bind_pointer()
72107
template<class T2, class P2, class D2>
73-
friend auto bindable_pointer(P2*, D2) noexcept -> pointer_binding<P2, T2, D2>;
108+
friend auto bind_pointer(P2*, D2) noexcept -> pointer_binding<P2, T2, D2>;
109+
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
110+
// Constructing pointer bindings must go through bind_pointer()
111+
template<orm_pointer_type auto tag, class P2, class D2>
112+
friend auto bind_pointer(P2*, D2) noexcept -> pointer_binding<P2, decltype(tag), D2>;
113+
#endif
74114
template<class B>
75-
friend B bindable_pointer(typename B::qualified_type*, typename B::deleter_type) noexcept;
115+
friend B bind_pointer(typename B::qualified_type*, typename B::deleter_type) noexcept;
76116

77117
// Construct from pointer and deleter.
78118
// Transfers ownership of the passed in object.
@@ -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
*
@@ -132,42 +188,105 @@ namespace sqlite_orm {
132188
* the deleter when the statement finishes.
133189
*/
134190
template<class T, class P, class D>
135-
auto bindable_pointer(P* p, D d) noexcept -> pointer_binding<P, T, D> {
191+
auto bind_pointer(P* p, D d) noexcept -> pointer_binding<P, T, D> {
136192
return {p, std::move(d)};
137193
}
138194

139195
template<class T, class P, class D>
140-
auto bindable_pointer(std::unique_ptr<P, D> p) noexcept -> pointer_binding<P, T, D> {
141-
return bindable_pointer<T>(p.release(), p.get_deleter());
196+
auto bind_pointer(std::unique_ptr<P, D> p) noexcept -> pointer_binding<P, T, D> {
197+
return bind_pointer<T>(p.release(), p.get_deleter());
142198
}
143199

144200
template<typename B>
145-
B bindable_pointer(typename B::qualified_type* p, typename B::deleter_type d = {}) noexcept {
201+
auto bind_pointer(typename B::qualified_type* p, typename B::deleter_type d = {}) noexcept -> B {
146202
return B{p, std::move(d)};
147203
}
148204

205+
template<class T, class P, class D>
206+
[[deprecated("Use the better named function `bind_pointer(...)`")]] pointer_binding<P, T, D>
207+
bindable_pointer(P* p, D d) noexcept {
208+
return bind_pointer<T>(p, std::move(d));
209+
}
210+
211+
template<class T, class P, class D>
212+
[[deprecated("Use the better named function `bind_pointer(...)`")]] pointer_binding<P, T, D>
213+
bindable_pointer(std::unique_ptr<P, D> p) noexcept {
214+
return bind_pointer<T>(p.release(), p.get_deleter());
215+
}
216+
217+
template<typename B>
218+
[[deprecated("Use the better named function `bind_pointer(...)`")]] B
219+
bindable_pointer(typename B::qualified_type* p, typename B::deleter_type d = {}) noexcept {
220+
return bind_pointer<B>(p, std::move(d));
221+
}
222+
223+
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
224+
/**
225+
* Wrap a pointer, its type (tag) and its deleter function for binding it to a statement.
226+
*
227+
* Unless the deleter yields a nullptr 'xDestroy' function the ownership of the pointed-to-object
228+
* is transferred to the pointer binding, which will delete it through
229+
* the deleter when the statement finishes.
230+
*/
231+
template<orm_pointer_type auto tag, class P, class D>
232+
auto bind_pointer(P* p, D d) noexcept -> pointer_binding<P, decltype(tag), D> {
233+
return {p, std::move(d)};
234+
}
235+
236+
template<orm_pointer_type auto tag, class P, class D>
237+
auto bind_pointer(std::unique_ptr<P, D> p) noexcept -> pointer_binding<P, decltype(tag), D> {
238+
return bind_pointer<tag>(p.release(), p.get_deleter());
239+
}
240+
#endif
241+
149242
/**
150243
* Wrap a pointer and its type for binding it to a statement.
151244
*
152245
* Note: 'Static' means that ownership of the pointed-to-object won't be transferred
153246
* and sqlite assumes the object pointed to is valid throughout the lifetime of a statement.
154247
*/
155248
template<class T, class P>
156-
auto statically_bindable_pointer(P* p) noexcept -> static_pointer_binding<P, T> {
157-
return bindable_pointer<T>(p, null_xdestroy_f);
249+
auto bind_pointer_statically(P* p) noexcept -> static_pointer_binding<P, T> {
250+
return bind_pointer<T>(p, null_xdestroy_f);
158251
}
159252

160253
template<typename B>
161-
B statically_bindable_pointer(typename B::qualified_type* p,
162-
typename B::deleter_type* /*exposition*/ = nullptr) noexcept {
163-
return bindable_pointer<B>(p);
254+
B bind_pointer_statically(typename B::qualified_type* p,
255+
typename B::deleter_type* /*exposition*/ = nullptr) noexcept {
256+
return bind_pointer<B>(p);
257+
}
258+
259+
template<class T, class P>
260+
[[deprecated("Use the better named function `bind_pointer_statically(...)`")]] static_pointer_binding<P, T>
261+
statically_bindable_pointer(P* p) noexcept {
262+
return bind_pointer<T>(p, null_xdestroy_f);
263+
}
264+
265+
template<typename B>
266+
[[deprecated("Use the better named function `bind_pointer_statically(...)`")]] B
267+
statically_bindable_pointer(typename B::qualified_type* p,
268+
typename B::deleter_type* /*exposition*/ = nullptr) noexcept {
269+
return bind_pointer<B>(p);
270+
}
271+
272+
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
273+
/**
274+
* Wrap a pointer and its type (tag) for binding it to a statement.
275+
*
276+
* Note: 'Static' means that ownership of the pointed-to-object won't be transferred
277+
* and sqlite assumes the object pointed to is valid throughout the lifetime of a statement.
278+
*/
279+
template<orm_pointer_type auto tag, class P>
280+
auto bind_pointer_statically(P* p) noexcept -> static_pointer_binding<P, decltype(tag)> {
281+
return bind_pointer<tag>(p, null_xdestroy_f);
164282
}
283+
#endif
165284

166285
/**
167286
* Forward a pointer value from an argument.
168287
*/
169288
template<class P, class T>
170289
auto rebind_statically(const pointer_arg<P, T>& pv) noexcept -> static_pointer_binding<P, T> {
171-
return statically_bindable_pointer<T>(pv.ptr());
290+
return bind_pointer_statically<T>(pv.ptr());
172291
}
173292
}

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> {

0 commit comments

Comments
 (0)