Skip to content

Commit 6367ec5

Browse files
committed
Reimplement variant with new value interface
1 parent 3f7f674 commit 6367ec5

File tree

2 files changed

+127
-243
lines changed

2 files changed

+127
-243
lines changed

hdr/sqlite_modern_cpp/type_wrapper.h

Lines changed: 127 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -29,27 +29,41 @@
2929
#endif
3030

3131
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
32-
#include "sqlite_modern_cpp/utility/variant.h"
32+
#include <variant>
3333
#endif
3434

3535
#include <sqlite3.h>
36+
#include "errors.h"
3637

3738
namespace sqlite {
39+
template<class T, int Type, class = void>
40+
struct has_sqlite_type : std::false_type {};
41+
42+
template<class T, int Type>
43+
struct has_sqlite_type<T&, Type> : has_sqlite_type<T, Type> {};
44+
template<class T, int Type>
45+
struct has_sqlite_type<const T, Type> : has_sqlite_type<T, Type> {};
46+
template<class T, int Type>
47+
struct has_sqlite_type<volatile T, Type> : has_sqlite_type<T, Type> {};
48+
3849
// int
50+
template<>
51+
struct has_sqlite_type<int, SQLITE_INTEGER> : std::true_type {};
52+
3953
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const int& val) {
4054
return sqlite3_bind_int(stmt, inx, val);
4155
}
42-
inline void store_result_in_db(sqlite3_context* db, const int& val) {
43-
sqlite3_result_int(db, val);
56+
inline void store_result_in_db(sqlite3_context* db, const int& val) {
57+
sqlite3_result_int(db, val);
4458
}
45-
inline void get_col_from_db(sqlite3_stmt* stmt, int inx, int& val) {
59+
inline void get_col_from_db(sqlite3_stmt* stmt, int inx, int& val) {
4660
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
4761
val = 0;
4862
} else {
4963
val = sqlite3_column_int(stmt, inx);
5064
}
5165
}
52-
inline void get_val_from_db(sqlite3_value *value, int& val) {
66+
inline void get_val_from_db(sqlite3_value *value, int& val) {
5367
if(sqlite3_value_type(value) == SQLITE_NULL) {
5468
val = 0;
5569
} else {
@@ -58,20 +72,23 @@ namespace sqlite {
5872
}
5973

6074
// sqlite_int64
75+
template<>
76+
struct has_sqlite_type<sqlite_int64, SQLITE_INTEGER, void> : std::true_type {};
77+
6178
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const sqlite_int64& val) {
6279
return sqlite3_bind_int64(stmt, inx, val);
6380
}
64-
inline void store_result_in_db(sqlite3_context* db, const sqlite_int64& val) {
65-
sqlite3_result_int64(db, val);
81+
inline void store_result_in_db(sqlite3_context* db, const sqlite_int64& val) {
82+
sqlite3_result_int64(db, val);
6683
}
67-
inline void get_col_from_db(sqlite3_stmt* stmt, int inx, sqlite3_int64& i) {
84+
inline void get_col_from_db(sqlite3_stmt* stmt, int inx, sqlite3_int64& i) {
6885
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
6986
i = 0;
7087
} else {
7188
i = sqlite3_column_int64(stmt, inx);
7289
}
7390
}
74-
inline void get_val_from_db(sqlite3_value *value, sqlite3_int64& i) {
91+
inline void get_val_from_db(sqlite3_value *value, sqlite3_int64& i) {
7592
if(sqlite3_value_type(value) == SQLITE_NULL) {
7693
i = 0;
7794
} else {
@@ -80,20 +97,23 @@ namespace sqlite {
8097
}
8198

8299
// float
100+
template<>
101+
struct has_sqlite_type<float, SQLITE_FLOAT, void> : std::true_type {};
102+
83103
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const float& val) {
84104
return sqlite3_bind_double(stmt, inx, double(val));
85105
}
86-
inline void store_result_in_db(sqlite3_context* db, const float& val) {
87-
sqlite3_result_double(db, val);
106+
inline void store_result_in_db(sqlite3_context* db, const float& val) {
107+
sqlite3_result_double(db, val);
88108
}
89-
inline void get_col_from_db(sqlite3_stmt* stmt, int inx, float& f) {
109+
inline void get_col_from_db(sqlite3_stmt* stmt, int inx, float& f) {
90110
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
91111
f = 0;
92112
} else {
93113
f = float(sqlite3_column_double(stmt, inx));
94114
}
95115
}
96-
inline void get_val_from_db(sqlite3_value *value, float& f) {
116+
inline void get_val_from_db(sqlite3_value *value, float& f) {
97117
if(sqlite3_value_type(value) == SQLITE_NULL) {
98118
f = 0;
99119
} else {
@@ -102,20 +122,23 @@ namespace sqlite {
102122
}
103123

104124
// double
125+
template<>
126+
struct has_sqlite_type<double, SQLITE_FLOAT, void> : std::true_type {};
127+
105128
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const double& val) {
106129
return sqlite3_bind_double(stmt, inx, val);
107130
}
108-
inline void store_result_in_db(sqlite3_context* db, const double& val) {
109-
sqlite3_result_double(db, val);
131+
inline void store_result_in_db(sqlite3_context* db, const double& val) {
132+
sqlite3_result_double(db, val);
110133
}
111-
inline void get_col_from_db(sqlite3_stmt* stmt, int inx, double& d) {
134+
inline void get_col_from_db(sqlite3_stmt* stmt, int inx, double& d) {
112135
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
113136
d = 0;
114137
} else {
115138
d = sqlite3_column_double(stmt, inx);
116139
}
117140
}
118-
inline void get_val_from_db(sqlite3_value *value, double& d) {
141+
inline void get_val_from_db(sqlite3_value *value, double& d) {
119142
if(sqlite3_value_type(value) == SQLITE_NULL) {
120143
d = 0;
121144
} else {
@@ -124,30 +147,36 @@ namespace sqlite {
124147
}
125148

126149
/* for nullptr support */
150+
template<>
151+
struct has_sqlite_type<std::nullptr_t, SQLITE_NULL, void> : std::true_type {};
152+
127153
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, std::nullptr_t) {
128154
return sqlite3_bind_null(stmt, inx);
129155
}
130-
inline void store_result_in_db(sqlite3_context* db, std::nullptr_t) {
131-
sqlite3_result_null(db);
156+
inline void store_result_in_db(sqlite3_context* db, std::nullptr_t) {
157+
sqlite3_result_null(db);
132158
}
133159

134160
// std::string
161+
template<>
162+
struct has_sqlite_type<std::string, SQLITE3_TEXT, void> : std::true_type {};
163+
135164
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::string& val) {
136165
return sqlite3_bind_text(stmt, inx, val.data(), -1, SQLITE_TRANSIENT);
137166
}
138167

139168
// Convert char* to string to trigger op<<(..., const std::string )
140169
template<std::size_t N> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char(&STR)[N]) { return bind_col_in_db(stmt, inx, std::string(STR, N-1)); }
141170

142-
inline void get_col_from_db(sqlite3_stmt* stmt, int inx, std::string & s) {
171+
inline void get_col_from_db(sqlite3_stmt* stmt, int inx, std::string & s) {
143172
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
144173
s = std::string();
145174
} else {
146175
sqlite3_column_bytes(stmt, inx);
147176
s = std::string(reinterpret_cast<char const *>(sqlite3_column_text(stmt, inx)));
148177
}
149178
}
150-
inline void get_val_from_db(sqlite3_value *value, std::string & s) {
179+
inline void get_val_from_db(sqlite3_value *value, std::string & s) {
151180
if(sqlite3_value_type(value) == SQLITE_NULL) {
152181
s = std::string();
153182
} else {
@@ -156,26 +185,29 @@ namespace sqlite {
156185
}
157186
}
158187

159-
inline void store_result_in_db(sqlite3_context* db, const std::string& val) {
160-
sqlite3_result_text(db, val.data(), -1, SQLITE_TRANSIENT);
188+
inline void store_result_in_db(sqlite3_context* db, const std::string& val) {
189+
sqlite3_result_text(db, val.data(), -1, SQLITE_TRANSIENT);
161190
}
162191
// std::u16string
192+
template<>
193+
struct has_sqlite_type<std::u16string, SQLITE3_TEXT, void> : std::true_type {};
194+
163195
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::u16string& val) {
164196
return sqlite3_bind_text16(stmt, inx, val.data(), -1, SQLITE_TRANSIENT);
165197
}
166198

167199
// Convert char* to string to trigger op<<(..., const std::string )
168200
template<std::size_t N> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char16_t(&STR)[N]) { return bind_col_in_db(stmt, inx, std::u16string(STR, N-1)); }
169201

170-
inline void get_col_from_db(sqlite3_stmt* stmt, int inx, std::u16string & w) {
202+
inline void get_col_from_db(sqlite3_stmt* stmt, int inx, std::u16string & w) {
171203
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
172204
w = std::u16string();
173205
} else {
174206
sqlite3_column_bytes16(stmt, inx);
175207
w = std::u16string(reinterpret_cast<char16_t const *>(sqlite3_column_text16(stmt, inx)));
176208
}
177209
}
178-
inline void get_val_from_db(sqlite3_value *value, std::u16string & w) {
210+
inline void get_val_from_db(sqlite3_value *value, std::u16string & w) {
179211
if(sqlite3_value_type(value) == SQLITE_NULL) {
180212
w = std::u16string();
181213
} else {
@@ -184,33 +216,39 @@ namespace sqlite {
184216
}
185217
}
186218

187-
inline void store_result_in_db(sqlite3_context* db, const std::u16string& val) {
188-
sqlite3_result_text16(db, val.data(), -1, SQLITE_TRANSIENT);
219+
inline void store_result_in_db(sqlite3_context* db, const std::u16string& val) {
220+
sqlite3_result_text16(db, val.data(), -1, SQLITE_TRANSIENT);
189221
}
190222

191223
// Other integer types
224+
template<class Integral>
225+
struct has_sqlite_type<Integral, SQLITE_INTEGER, typename std::enable_if<std::is_integral<Integral>::value>::type> : std::true_type {};
226+
192227
template<class Integral, class = typename std::enable_if<std::is_integral<Integral>::value>::type>
193228
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const Integral& val) {
194229
return bind_col_in_db(stmt, inx, static_cast<sqlite3_int64>(val));
195230
}
196-
template<class Integral, class = std::enable_if<std::is_integral<Integral>::type>>
197-
inline void store_result_in_db(sqlite3_context* db, const Integral& val) {
198-
store_result_in_db(db, static_cast<sqlite3_int64>(val));
231+
template<class Integral, class = std::enable_if<std::is_integral<Integral>::type>>
232+
inline void store_result_in_db(sqlite3_context* db, const Integral& val) {
233+
store_result_in_db(db, static_cast<sqlite3_int64>(val));
199234
}
200-
template<class Integral, class = typename std::enable_if<std::is_integral<Integral>::value>::type>
201-
inline void get_col_from_db(sqlite3_stmt* stmt, int inx, Integral& val) {
235+
template<class Integral, class = typename std::enable_if<std::is_integral<Integral>::value>::type>
236+
inline void get_col_from_db(sqlite3_stmt* stmt, int inx, Integral& val) {
202237
sqlite3_int64 i;
203238
get_col_from_db(stmt, inx, i);
204239
val = i;
205240
}
206-
template<class Integral, class = typename std::enable_if<std::is_integral<Integral>::value>::type>
207-
inline void get_val_from_db(sqlite3_value *value, Integral& val) {
241+
template<class Integral, class = typename std::enable_if<std::is_integral<Integral>::value>::type>
242+
inline void get_val_from_db(sqlite3_value *value, Integral& val) {
208243
sqlite3_int64 i;
209244
get_val_from_db(value, i);
210245
val = i;
211246
}
212247

213248
// vector<T, A>
249+
template<typename T, typename A>
250+
struct has_sqlite_type<std::vector<T, A>, SQLITE_BLOB, void> : std::true_type {};
251+
214252
template<typename T, typename A> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::vector<T, A>& vec) {
215253
void const* buf = reinterpret_cast<void const *>(vec.data());
216254
int bytes = vec.size() * sizeof(T);
@@ -241,6 +279,11 @@ namespace sqlite {
241279
}
242280

243281
/* for unique_ptr<T> support */
282+
template<typename T, int Type>
283+
struct has_sqlite_type<std::unique_ptr<T>, Type, void> : has_sqlite_type<T, Type> {};
284+
template<typename T>
285+
struct has_sqlite_type<std::unique_ptr<T>, SQLITE_NULL, void> : std::true_type {};
286+
244287
template<typename T> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::unique_ptr<T>& val) {
245288
return val ? bind_col_in_db(stmt, inx, *val) : bind_col_in_db(stmt, inx, nullptr);
246289
}
@@ -273,6 +316,11 @@ namespace sqlite {
273316
using optional = std::optional<T>;
274317
#endif
275318

319+
template<typename T, int Type>
320+
struct has_sqlite_type<optional<T>, Type, void> : has_sqlite_type<T, Type> {};
321+
template<typename T>
322+
struct has_sqlite_type<optional<T>, SQLITE_NULL, void> : std::true_type {};
323+
276324
template <typename OptionalT> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const optional<OptionalT>& val) {
277325
return val ? bind_col_in_db(stmt, inx, *val) : bind_col_in_db(stmt, inx, nullptr);
278326
}
@@ -285,11 +333,11 @@ namespace sqlite {
285333

286334
template <typename OptionalT> inline void get_col_from_db(sqlite3_stmt* stmt, int inx, optional<OptionalT>& o) {
287335
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
288-
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
336+
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
289337
o = std::experimental::nullopt;
290-
#else
338+
#else
291339
o.reset();
292-
#endif
340+
#endif
293341
} else {
294342
OptionalT v;
295343
get_col_from_db(stmt, inx, v);
@@ -298,11 +346,11 @@ namespace sqlite {
298346
}
299347
template <typename OptionalT> inline void get_val_from_db(sqlite3_value *value, optional<OptionalT>& o) {
300348
if(sqlite3_value_type(value) == SQLITE_NULL) {
301-
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
349+
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
302350
o = std::experimental::nullopt;
303-
#else
351+
#else
304352
o.reset();
305-
#endif
353+
#endif
306354
} else {
307355
OptionalT v;
308356
get_val_from_db(value, v);
@@ -312,20 +360,57 @@ namespace sqlite {
312360
#endif
313361

314362
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
363+
namespace detail {
364+
template<class T, class U>
365+
struct tag_trait : U { using tag = T; };
366+
}
367+
368+
template<int Type, class ...Options>
369+
struct has_sqlite_type<std::variant<Options...>, Type, void> : std::disjunction<detail::tag_trait<Options, has_sqlite_type<Options, Type>>...> {};
370+
371+
namespace detail {
372+
template<int Type, typename ...Options, typename Callback, typename first_compatible = has_sqlite_type<std::variant<Options...>, Type>>
373+
inline void variant_select_type(Callback &&callback) {
374+
if constexpr(first_compatible::value)
375+
callback(typename first_compatible::tag());
376+
else
377+
throw errors::mismatch("The value is unsupported by this variant.", "", SQLITE_MISMATCH);
378+
}
379+
template<typename ...Options, typename Callback> inline void variant_select(int type, Callback &&callback) {
380+
switch(type) {
381+
case SQLITE_NULL:
382+
variant_select_type<SQLITE_NULL, Options...>(std::forward<Callback>(callback));
383+
break;
384+
case SQLITE_INTEGER:
385+
variant_select_type<SQLITE_INTEGER, Options...>(std::forward<Callback>(callback));
386+
break;
387+
case SQLITE_FLOAT:
388+
variant_select_type<SQLITE_FLOAT, Options...>(std::forward<Callback>(callback));
389+
break;
390+
case SQLITE_TEXT:
391+
variant_select_type<SQLITE_TEXT, Options...>(std::forward<Callback>(callback));
392+
break;
393+
case SQLITE_BLOB:
394+
variant_select_type<SQLITE_BLOB, Options...>(std::forward<Callback>(callback));
395+
break;
396+
default:;
397+
}
398+
}
399+
}
315400
template <typename ...Args> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::variant<Args...>& val) {
316401
return std::visit([&](auto &&opt) {return bind_col_in_db(stmt, inx, std::forward<decltype(opt)>(opt));}, val);
317402
}
318403
template <typename ...Args> inline void store_result_in_db(sqlite3_context* db, const std::variant<Args...>& val) {
319404
std::visit([&](auto &&opt) {store_result_in_db(db, std::forward<decltype(opt)>(opt));}, val);
320405
}
321406
template <typename ...Args> inline void get_col_from_db(sqlite3_stmt* stmt, int inx, std::variant<Args...>& val) {
322-
utility::variant_select<Args...>(sqlite3_column_type(stmt, inx))([&](auto v) {
407+
detail::variant_select<Args...>(sqlite3_column_type(stmt, inx), [&](auto v) {
323408
get_col_from_db(stmt, inx, v);
324409
val = std::move(v);
325410
});
326411
}
327412
template <typename ...Args> inline void get_val_from_db(sqlite3_value *value, std::variant<Args...>& val) {
328-
utility::variant_select<Args...>(sqlite3_value_type(value))([&](auto v) {
413+
detail::variant_select<Args...>(sqlite3_value_type(value), [&](auto v) {
329414
get_val_from_db(value, v);
330415
val = std::move(v);
331416
});

0 commit comments

Comments
 (0)