This repository has been archived by the owner on Jan 3, 2024. It is now read-only.
forked from fnc12/sqlite_orm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpointer_value.h
173 lines (146 loc) · 5.63 KB
/
pointer_value.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#pragma once
#include <type_traits>
#include <memory>
#include <utility>
#include "functional/cxx_universal.h"
#include "xdestroy_handling.h"
namespace sqlite_orm {
/**
* Wraps a pointer and tags it with a pointer type,
* used for accepting function parameters,
* facilitating the 'pointer-passing interface'.
*
* Template parameters:
* - P: The value type, possibly const-qualified.
* - T: An integral constant string denoting the pointer type, e.g. `carray_pvt_name`.
*
*/
template<typename P, typename T>
struct pointer_arg {
static_assert(std::is_convertible<typename T::value_type, const char*>::value,
"`std::integral_constant<>` must be convertible to `const char*`");
using tag = T;
P* p_;
P* ptr() const noexcept {
return p_;
}
operator P*() const noexcept {
return p_;
}
};
/**
* Pointer value with associated deleter function,
* used for returning or binding pointer values
* as part of facilitating the 'pointer-passing interface'.
*
* Template parameters:
* - D: The deleter for the pointer value;
* can be one of:
* - function pointer
* - integral function pointer constant
* - state-less (empty) deleter
* - non-capturing lambda
* - structure implicitly yielding a function pointer
*
* @note Use one of the factory functions to create a pointer binding,
* e.g. bindable_carray_pointer or statically_bindable_carray_pointer().
*
* @example
* ```
* int64 rememberedId;
* storage.select(func<remember_fn>(&Object::id, statically_bindable_carray_pointer(&rememberedId)));
* ```
*/
template<typename P, typename T, typename D>
class pointer_binding {
P* p_;
SQLITE_ORM_NOUNIQUEADDRESS
D d_;
protected:
// Constructing pointer bindings must go through bindable_pointer()
template<class T2, class P2, class D2>
friend auto bindable_pointer(P2*, D2) noexcept -> pointer_binding<P2, T2, D2>;
template<class B>
friend B bindable_pointer(typename B::qualified_type*, typename B::deleter_type) noexcept;
// Construct from pointer and deleter.
// Transfers ownership of the passed in object.
pointer_binding(P* p, D d = {}) noexcept : p_{p}, d_{std::move(d)} {}
public:
using qualified_type = P;
using tag = T;
using deleter_type = D;
pointer_binding(const pointer_binding&) = delete;
pointer_binding& operator=(const pointer_binding&) = delete;
pointer_binding& operator=(pointer_binding&&) = delete;
pointer_binding(pointer_binding&& other) noexcept :
p_{std::exchange(other.p_, nullptr)}, d_{std::move(other.d_)} {}
~pointer_binding() {
if(p_) {
if(auto xDestroy = get_xdestroy()) {
// note: C-casting `P* -> void*` like statement_binder<pointer_binding<P, T, D>>
xDestroy((void*)p_);
}
}
}
P* ptr() const noexcept {
return p_;
}
P* take_ptr() noexcept {
return std::exchange(p_, nullptr);
}
xdestroy_fn_t get_xdestroy() const noexcept {
return obtain_xdestroy_for(d_, p_);
}
};
/**
* Template alias for a static pointer value binding.
* 'Static' means that ownership won't be transferred to sqlite,
* sqlite doesn't delete it, and sqlite assumes the object
* pointed to is valid throughout the lifetime of a statement.
*/
template<typename P, typename T>
using static_pointer_binding = pointer_binding<P, T, null_xdestroy_t>;
}
namespace sqlite_orm {
/**
* Wrap a pointer, its type and its deleter function for binding it to a statement.
*
* Unless the deleter yields a nullptr 'xDestroy' function the ownership of the pointed-to-object
* is transferred to the pointer binding, which will delete it through
* the deleter when the statement finishes.
*/
template<class T, class P, class D>
auto bindable_pointer(P* p, D d) noexcept -> pointer_binding<P, T, D> {
return {p, std::move(d)};
}
template<class T, class P, class D>
auto bindable_pointer(std::unique_ptr<P, D> p) noexcept -> pointer_binding<P, T, D> {
return bindable_pointer<T>(p.release(), p.get_deleter());
}
template<typename B>
B bindable_pointer(typename B::qualified_type* p, typename B::deleter_type d = {}) noexcept {
return B{p, std::move(d)};
}
/**
* Wrap a pointer and its type for binding it to a statement.
*
* Note: 'Static' means that ownership of the pointed-to-object won't be transferred
* and sqlite assumes the object pointed to is valid throughout the lifetime of a statement.
*/
template<class T, class P>
auto statically_bindable_pointer(P* p) noexcept -> static_pointer_binding<P, T> {
return bindable_pointer<T>(p, null_xdestroy_f);
}
template<typename B>
B statically_bindable_pointer(typename B::qualified_type* p,
typename B::deleter_type* /*exposition*/ = nullptr) noexcept {
return bindable_pointer<B>(p);
}
/**
* Forward a pointer value from an argument.
*/
template<class P, class T>
auto rebind_statically(const pointer_arg<P, T>& pv) noexcept -> static_pointer_binding<P, T> {
return statically_bindable_pointer<T>(pv.ptr());
}
}