diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index 238a2bad..69d63476 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -135,11 +135,15 @@ namespace sqlite { value_type(database_binder *_binder): _binder(_binder) {}; template typename std::enable_if::value, value_type &>::type operator >>(T &result) { - get_col_from_db(_binder->_stmt.get(), next_index++, result); + result = get_col_from_db(_binder->_stmt.get(), next_index++, result_type()); return *this; } template - value_type &operator >>(std::tuple& values); + value_type &operator >>(std::tuple& values) { + values = handle_tuple::type...>>(std::index_sequence_for()); + next_index += sizeof...(Types); + return *this; + } template value_type &operator >>(std::tuple&& values) { return *this >> values; @@ -154,6 +158,14 @@ namespace sqlite { return sqlite3_column_count(_binder->_stmt.get()) >= next_index; } private: + template + Tuple handle_tuple(std::index_sequence) { + return Tuple( + get_col_from_db( + _binder->_stmt.get(), + next_index + Index, + result_type::type>())...); + } database_binder *_binder; int next_index = 0; }; @@ -198,27 +210,6 @@ namespace sqlite { mutable value_type value{_binder}; // mutable, because `changing` the value is just reading it }; - namespace detail { - template::value == Element)> struct tuple_iterate { - static void iterate(Tuple& t, row_iterator::value_type& row) { - row >> std::get(t); - tuple_iterate::iterate(t, row); - } - }; - - template struct tuple_iterate { - static void iterate(Tuple&, row_iterator::value_type&) {} - }; - } - - template - row_iterator::value_type &row_iterator::value_type::operator >>(std::tuple& values) { - assert(!next_index); - detail::tuple_iterate>::iterate(values, *this); - next_index = sizeof...(Types) + 1; - return *this; - } - inline row_iterator database_binder::begin() { return row_iterator(*this); } @@ -558,16 +549,20 @@ namespace sqlite { sqlite3_value** vals, Values&&... values ) { - typename std::remove_cv< + using arg_type = typename std::remove_cv< typename std::remove_reference< typename utility::function_traits< typename Functions::first_type >::template argument >::type - >::type value{}; - get_val_from_db(vals[sizeof...(Values) - 1], value); + >::type; - step(db, count, vals, std::forward(values)..., std::move(value)); + step( + db, + count, + vals, + std::forward(values)..., + get_val_from_db(vals[sizeof...(Values) - 1], result_type())); } template< @@ -618,14 +613,18 @@ namespace sqlite { sqlite3_value** vals, Values&&... values ) { - typename std::remove_cv< + using arg_type = typename std::remove_cv< typename std::remove_reference< typename utility::function_traits::template argument >::type - >::type value{}; - get_val_from_db(vals[sizeof...(Values)], value); - - scalar(db, count, vals, std::forward(values)..., std::move(value)); + >::type; + + scalar( + db, + count, + vals, + std::forward(values)..., + get_val_from_db(vals[sizeof...(Values)], result_type())); } template< diff --git a/hdr/sqlite_modern_cpp/type_wrapper.h b/hdr/sqlite_modern_cpp/type_wrapper.h index 9bc32cdc..375f8d0f 100644 --- a/hdr/sqlite_modern_cpp/type_wrapper.h +++ b/hdr/sqlite_modern_cpp/type_wrapper.h @@ -55,6 +55,14 @@ namespace sqlite { template struct has_sqlite_type : has_sqlite_type {}; + template + struct result_type { + using type = T; + constexpr result_type() = default; + template::value>> + constexpr result_type(result_type) { } + }; + // int template<> struct has_sqlite_type : std::true_type {}; @@ -65,19 +73,13 @@ namespace sqlite { inline void store_result_in_db(sqlite3_context* db, const int& val) { sqlite3_result_int(db, val); } - inline void get_col_from_db(sqlite3_stmt* stmt, int inx, int& val) { - if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) { - val = 0; - } else { - val = sqlite3_column_int(stmt, inx); - } + inline int get_col_from_db(sqlite3_stmt* stmt, int inx, result_type) { + return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? 0 : + sqlite3_column_int(stmt, inx); } - inline void get_val_from_db(sqlite3_value *value, int& val) { - if(sqlite3_value_type(value) == SQLITE_NULL) { - val = 0; - } else { - val = sqlite3_value_int(value); - } + inline int get_val_from_db(sqlite3_value *value, result_type) { + return sqlite3_value_type(value) == SQLITE_NULL ? 0 : + sqlite3_value_int(value); } // sqlite_int64 @@ -90,19 +92,13 @@ namespace sqlite { inline void store_result_in_db(sqlite3_context* db, const sqlite_int64& val) { sqlite3_result_int64(db, val); } - inline void get_col_from_db(sqlite3_stmt* stmt, int inx, sqlite3_int64& i) { - if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) { - i = 0; - } else { - i = sqlite3_column_int64(stmt, inx); - } + inline sqlite_int64 get_col_from_db(sqlite3_stmt* stmt, int inx, result_type) { + return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? 0 : + sqlite3_column_int64(stmt, inx); } - inline void get_val_from_db(sqlite3_value *value, sqlite3_int64& i) { - if(sqlite3_value_type(value) == SQLITE_NULL) { - i = 0; - } else { - i = sqlite3_value_int64(value); - } + inline sqlite3_int64 get_val_from_db(sqlite3_value *value, result_type) { + return sqlite3_value_type(value) == SQLITE_NULL ? 0 : + sqlite3_value_int64(value); } // float @@ -115,19 +111,13 @@ namespace sqlite { inline void store_result_in_db(sqlite3_context* db, const float& val) { sqlite3_result_double(db, val); } - inline void get_col_from_db(sqlite3_stmt* stmt, int inx, float& f) { - if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) { - f = 0; - } else { - f = float(sqlite3_column_double(stmt, inx)); - } + inline float get_col_from_db(sqlite3_stmt* stmt, int inx, result_type) { + return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? 0 : + sqlite3_column_double(stmt, inx); } - inline void get_val_from_db(sqlite3_value *value, float& f) { - if(sqlite3_value_type(value) == SQLITE_NULL) { - f = 0; - } else { - f = float(sqlite3_value_double(value)); - } + inline float get_val_from_db(sqlite3_value *value, result_type) { + return sqlite3_value_type(value) == SQLITE_NULL ? 0 : + sqlite3_value_double(value); } // double @@ -140,19 +130,13 @@ namespace sqlite { inline void store_result_in_db(sqlite3_context* db, const double& val) { sqlite3_result_double(db, val); } - inline void get_col_from_db(sqlite3_stmt* stmt, int inx, double& d) { - if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) { - d = 0; - } else { - d = sqlite3_column_double(stmt, inx); - } + inline double get_col_from_db(sqlite3_stmt* stmt, int inx, result_type) { + return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? 0 : + sqlite3_column_double(stmt, inx); } - inline void get_val_from_db(sqlite3_value *value, double& d) { - if(sqlite3_value_type(value) == SQLITE_NULL) { - d = 0; - } else { - d = sqlite3_value_double(value); - } + inline double get_val_from_db(sqlite3_value *value, result_type) { + return sqlite3_value_type(value) == SQLITE_NULL ? 0 : + sqlite3_value_double(value); } /* for nullptr support */ @@ -177,21 +161,13 @@ namespace sqlite { // Convert char* to string to trigger op<<(..., const std::string ) template 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)); } - inline void get_col_from_db(sqlite3_stmt* stmt, int inx, std::string & s) { - if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) { - s = std::string(); - } else { - sqlite3_column_bytes(stmt, inx); - s = std::string(reinterpret_cast(sqlite3_column_text(stmt, inx))); - } + inline std::string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type) { + return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? std::string() : + std::string(reinterpret_cast(sqlite3_column_text(stmt, inx)), sqlite3_column_bytes(stmt, inx)); } - inline void get_val_from_db(sqlite3_value *value, std::string & s) { - if(sqlite3_value_type(value) == SQLITE_NULL) { - s = std::string(); - } else { - sqlite3_value_bytes(value); - s = std::string(reinterpret_cast(sqlite3_value_text(value))); - } + inline std::string get_val_from_db(sqlite3_value *value, result_type) { + return sqlite3_value_type(value) == SQLITE_NULL ? std::string() : + std::string(reinterpret_cast(sqlite3_value_text(value)), sqlite3_value_bytes(value)); } inline void store_result_in_db(sqlite3_context* db, const std::string& val) { @@ -208,21 +184,13 @@ namespace sqlite { // Convert char* to string to trigger op<<(..., const std::string ) template 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)); } - inline void get_col_from_db(sqlite3_stmt* stmt, int inx, std::u16string & w) { - if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) { - w = std::u16string(); - } else { - sqlite3_column_bytes16(stmt, inx); - w = std::u16string(reinterpret_cast(sqlite3_column_text16(stmt, inx))); - } + inline std::u16string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type) { + return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? std::u16string() : + std::u16string(reinterpret_cast(sqlite3_column_text16(stmt, inx)), sqlite3_column_bytes16(stmt, inx)); } - inline void get_val_from_db(sqlite3_value *value, std::u16string & w) { - if(sqlite3_value_type(value) == SQLITE_NULL) { - w = std::u16string(); - } else { - sqlite3_value_bytes16(value); - w = std::u16string(reinterpret_cast(sqlite3_value_text16(value))); - } + inline std::u16string get_val_from_db(sqlite3_value *value, result_type) { + return sqlite3_value_type(value) == SQLITE_NULL ? std::u16string() : + std::u16string(reinterpret_cast(sqlite3_value_text16(value)), sqlite3_value_bytes16(value)); } inline void store_result_in_db(sqlite3_context* db, const std::u16string& val) { @@ -242,16 +210,12 @@ namespace sqlite { store_result_in_db(db, static_cast(val)); } template::value>::type> - inline void get_col_from_db(sqlite3_stmt* stmt, int inx, Integral& val) { - sqlite3_int64 i; - get_col_from_db(stmt, inx, i); - val = i; + inline Integral get_col_from_db(sqlite3_stmt* stmt, int inx, result_type) { + return get_col_from_db(stmt, inx, result_type()); } template::value>::type> - inline void get_val_from_db(sqlite3_value *value, Integral& val) { - sqlite3_int64 i; - get_val_from_db(value, i); - val = i; + inline Integral get_val_from_db(sqlite3_value *value, result_type) { + return get_val_from_db(value, result_type()); } // vector @@ -268,23 +232,21 @@ namespace sqlite { int bytes = vec.size() * sizeof(T); sqlite3_result_blob(db, buf, bytes, SQLITE_TRANSIENT); } - template inline void get_col_from_db(sqlite3_stmt* stmt, int inx, std::vector& vec) { + template inline std::vector get_col_from_db(sqlite3_stmt* stmt, int inx, result_type>) { if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) { - vec.clear(); - } else { - int bytes = sqlite3_column_bytes(stmt, inx); - T const* buf = reinterpret_cast(sqlite3_column_blob(stmt, inx)); - vec = std::vector(buf, buf + bytes/sizeof(T)); + return {}; } + int bytes = sqlite3_column_bytes(stmt, inx); + T const* buf = reinterpret_cast(sqlite3_column_blob(stmt, inx)); + return std::vector(buf, buf + bytes/sizeof(T)); } - template inline void get_val_from_db(sqlite3_value *value, std::vector& vec) { + template inline std::vector get_val_from_db(sqlite3_value *value, result_type>) { if(sqlite3_value_type(value) == SQLITE_NULL) { - vec.clear(); - } else { - int bytes = sqlite3_value_bytes(value); - T const* buf = reinterpret_cast(sqlite3_value_blob(value)); - vec = std::vector(buf, buf + bytes/sizeof(T)); + return {}; } + int bytes = sqlite3_value_bytes(value); + T const* buf = reinterpret_cast(sqlite3_value_blob(value)); + return std::vector(buf, buf + bytes/sizeof(T)); } /* for unique_ptr support */ @@ -296,23 +258,17 @@ namespace sqlite { template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::unique_ptr& val) { return val ? bind_col_in_db(stmt, inx, *val) : bind_col_in_db(stmt, inx, nullptr); } - template inline void get_col_from_db(sqlite3_stmt* stmt, int inx, std::unique_ptr& _ptr_) { + template inline std::unique_ptr get_col_from_db(sqlite3_stmt* stmt, int inx, result_type>) { if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) { - _ptr_ = nullptr; - } else { - auto underling_ptr = new T(); - get_col_from_db(stmt, inx, *underling_ptr); - _ptr_.reset(underling_ptr); + return nullptr; } + return std::make_unique(get_col_from_db(stmt, inx, result_type())); } - template inline void get_val_from_db(sqlite3_value *value, std::unique_ptr& _ptr_) { + template inline std::unique_ptr get_val_from_db(sqlite3_value *value, result_type>) { if(sqlite3_value_type(value) == SQLITE_NULL) { - _ptr_ = nullptr; - } else { - auto underling_ptr = new T(); - get_val_from_db(value, *underling_ptr); - _ptr_.reset(underling_ptr); + return nullptr; } + return std::make_unique(get_val_from_db(value, result_type())); } // std::optional support for NULL values @@ -340,31 +296,31 @@ namespace sqlite { sqlite3_result_null(db); } - template inline void get_col_from_db(sqlite3_stmt* stmt, int inx, optional& o) { + template inline optional get_col_from_db(sqlite3_stmt* stmt, int inx, result_type>) { + #ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT + if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) { + return std::experimental::nullopt; + } + return std::experimental::make_optional(get_col_from_db(stmt, inx, result_type())); + #else if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) { - #ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT - o = std::experimental::nullopt; - #else - o.reset(); - #endif - } else { - OptionalT v; - get_col_from_db(stmt, inx, v); - o = std::move(v); + return std::nullopt; } + return std::make_optional(get_col_from_db(stmt, inx, result_type())); + #endif } - template inline void get_val_from_db(sqlite3_value *value, optional& o) { + template inline optional get_val_from_db(sqlite3_value *value, result_type>) { + #ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT if(sqlite3_value_type(value) == SQLITE_NULL) { - #ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT - o = std::experimental::nullopt; - #else - o.reset(); - #endif - } else { - OptionalT v; - get_val_from_db(value, v); - o = std::move(v); + return std::experimental::nullopt; } + return std::experimental::make_optional(get_val_from_db(value, result_type())); + #else + if(sqlite3_value_type(value) == SQLITE_NULL) { + return std::nullopt; + } + return std::make_optional(get_val_from_db(value, result_type())); + #endif } #endif @@ -379,31 +335,30 @@ namespace sqlite { namespace detail { template, Type>> - inline void variant_select_type(Callback &&callback) { + inline std::variant variant_select_type(Callback &&callback) { if constexpr(first_compatible::value) - callback(typename first_compatible::tag()); + return callback(result_type()); else throw errors::mismatch("The value is unsupported by this variant.", "", SQLITE_MISMATCH); } - template inline void variant_select(int type, Callback &&callback) { + template inline decltype(auto) variant_select(int type, Callback &&callback) { switch(type) { case SQLITE_NULL: - variant_select_type(std::forward(callback)); - break; + return variant_select_type(std::forward(callback)); case SQLITE_INTEGER: - variant_select_type(std::forward(callback)); - break; + return variant_select_type(std::forward(callback)); case SQLITE_FLOAT: - variant_select_type(std::forward(callback)); - break; + return variant_select_type(std::forward(callback)); case SQLITE_TEXT: - variant_select_type(std::forward(callback)); - break; + return variant_select_type(std::forward(callback)); case SQLITE_BLOB: - variant_select_type(std::forward(callback)); - break; - default:; + return variant_select_type(std::forward(callback)); } +#ifdef _MSC_VER + __assume(false); +#else + __builtin_unreachable(); +#endif } } template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::variant& val) { @@ -412,16 +367,14 @@ namespace sqlite { template inline void store_result_in_db(sqlite3_context* db, const std::variant& val) { std::visit([&](auto &&opt) {store_result_in_db(db, std::forward(opt));}, val); } - template inline void get_col_from_db(sqlite3_stmt* stmt, int inx, std::variant& val) { - detail::variant_select(sqlite3_column_type(stmt, inx), [&](auto v) { - get_col_from_db(stmt, inx, v); - val = std::move(v); + template inline std::variant get_col_from_db(sqlite3_stmt* stmt, int inx, result_type>) { + return detail::variant_select(sqlite3_column_type(stmt, inx), [&](auto v) { + return std::variant(std::in_place_type, get_col_from_db(stmt, inx, v)); }); } - template inline void get_val_from_db(sqlite3_value *value, std::variant& val) { - detail::variant_select(sqlite3_value_type(value), [&](auto v) { - get_val_from_db(value, v); - val = std::move(v); + template inline std::variant get_val_from_db(sqlite3_value *value, result_type>) { + return detail::variant_select(sqlite3_value_type(value), [&](auto v) { + return std::variant(std::in_place_type, get_val_from_db(value, v)); }); } #endif