-
Notifications
You must be signed in to change notification settings - Fork 164
Use std::string_view as argument instead of std::string on C++17 Compilers #167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 16 commits
64c40af
2f2e7d8
5515487
fd3f0bf
c69ffc1
e0e3a22
6c95d0a
3b181fe
b9ddb6b
b08f6b6
080411a
64f5f66
9e56736
a1849e2
fac3344
8e09803
7d6ea22
c03e4e8
b12f949
dffc090
b0e3c8d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -85,15 +85,15 @@ namespace sqlite { | |
| return ++_inx; | ||
| } | ||
|
|
||
| sqlite3_stmt* _prepare(const std::u16string& sql) { | ||
| sqlite3_stmt* _prepare(U16STR_REF sql) { | ||
| return _prepare(utility::utf16_to_utf8(sql)); | ||
| } | ||
|
|
||
| sqlite3_stmt* _prepare(const std::string& sql) { | ||
| sqlite3_stmt* _prepare(STR_REF sql) { | ||
| int hresult; | ||
| sqlite3_stmt* tmp = nullptr; | ||
| const char *remaining; | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
| hresult = sqlite3_prepare_v2(_db.get(), sql.data(), -1, &tmp, &remaining); | ||
| hresult = sqlite3_prepare_v2(_db.get(), sql.data(), sql.length(), &tmp, &remaining); | ||
| if(hresult != SQLITE_OK) errors::throw_sqlite_error(hresult, sql); | ||
| if(!std::all_of(remaining, sql.data() + sql.size(), [](char ch) {return std::isspace(ch);})) | ||
| throw errors::more_statements("Multiple semicolon separated statements are unsupported", sql); | ||
|
|
@@ -105,13 +105,13 @@ namespace sqlite { | |
|
|
||
| public: | ||
|
|
||
| database_binder(std::shared_ptr<sqlite3> db, std::u16string const & sql): | ||
| database_binder(std::shared_ptr<sqlite3> db, U16STR_REF sql): | ||
| _db(db), | ||
| _stmt(_prepare(sql), sqlite3_finalize), | ||
| _inx(0) { | ||
| } | ||
|
|
||
| database_binder(std::shared_ptr<sqlite3> db, std::string const & sql): | ||
| database_binder(std::shared_ptr<sqlite3> db, STR_REF sql): | ||
| _db(db), | ||
| _stmt(_prepare(sql), sqlite3_finalize), | ||
| _inx(0) { | ||
|
|
@@ -372,36 +372,22 @@ namespace sqlite { | |
| *this << R"(PRAGMA encoding = "UTF-16";)"; | ||
| } | ||
|
|
||
| database(const std::u16string &db_name, const sqlite_config &config = {}): _db(nullptr) { | ||
| auto db_name_utf8 = utility::utf16_to_utf8(db_name); | ||
| sqlite3* tmp = nullptr; | ||
| auto ret = sqlite3_open_v2(db_name_utf8.data(), &tmp, static_cast<int>(config.flags), config.zVfs); | ||
| _db = std::shared_ptr<sqlite3>(tmp, [=](sqlite3* ptr) { sqlite3_close_v2(ptr); }); // this will close the connection eventually when no longer needed. | ||
| if(ret != SQLITE_OK) errors::throw_sqlite_error(_db ? sqlite3_extended_errcode(_db.get()) : ret); | ||
| sqlite3_extended_result_codes(_db.get(), true); | ||
| if(config.encoding != Encoding::UTF8) | ||
| database(const std::u16string &db_name, const sqlite_config &config = {}): database(utility::utf16_to_utf8(db_name.data()), config) { | ||
|
||
| if (config.encoding == Encoding::ANY) | ||
| *this << R"(PRAGMA encoding = "UTF-16";)"; | ||
| } | ||
|
|
||
| database(std::shared_ptr<sqlite3> db): | ||
| _db(db) {} | ||
|
|
||
| database_binder operator<<(const std::string& sql) { | ||
| database_binder operator<<(STR_REF sql) { | ||
| return database_binder(_db, sql); | ||
| } | ||
|
|
||
| database_binder operator<<(const char* sql) { | ||
| return *this << std::string(sql); | ||
| } | ||
|
|
||
| database_binder operator<<(const std::u16string& sql) { | ||
| database_binder operator<<(U16STR_REF sql) { | ||
| return database_binder(_db, sql); | ||
| } | ||
|
|
||
| database_binder operator<<(const char16_t* sql) { | ||
| return *this << std::u16string(sql); | ||
| } | ||
|
|
||
| connection_type connection() const { return _db; } | ||
|
|
||
| sqlite3_int64 last_insert_rowid() const { | ||
|
|
@@ -418,7 +404,7 @@ namespace sqlite { | |
|
|
||
| auto funcPtr = new auto(std::forward<Function>(func)); | ||
| if(int result = sqlite3_create_function_v2( | ||
| _db.get(), name.c_str(), traits::arity, SQLITE_UTF8, funcPtr, | ||
| _db.get(), name.data(), traits::arity, SQLITE_UTF8, funcPtr, | ||
This comment was marked as resolved.
Sorry, something went wrong.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should stick to |
||
| sql_function_binder::scalar<traits::arity, typename std::remove_reference<Function>::type>, | ||
| nullptr, nullptr, [](void* ptr){ | ||
| delete static_cast<decltype(funcPtr)>(ptr); | ||
|
|
@@ -433,7 +419,7 @@ namespace sqlite { | |
|
|
||
| auto funcPtr = new auto(std::make_pair(std::forward<StepFunction>(step), std::forward<FinalFunction>(final))); | ||
| if(int result = sqlite3_create_function_v2( | ||
| _db.get(), name.c_str(), traits::arity - 1, SQLITE_UTF8, funcPtr, nullptr, | ||
| _db.get(), name.data(), traits::arity - 1, SQLITE_UTF8, funcPtr, nullptr, | ||
|
||
| sql_function_binder::step<ContextType, traits::arity, typename std::remove_reference<decltype(*funcPtr)>::type>, | ||
| sql_function_binder::final<ContextType, typename std::remove_reference<decltype(*funcPtr)>::type>, | ||
| [](void* ptr){ | ||
|
|
@@ -652,3 +638,4 @@ namespace sqlite { | |
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,8 +9,8 @@ namespace sqlite { | |
|
|
||
| class sqlite_exception: public std::runtime_error { | ||
| public: | ||
| sqlite_exception(const char* msg, std::string sql, int code = -1): runtime_error(msg), code(code), sql(sql) {} | ||
| sqlite_exception(int code, std::string sql): runtime_error(sqlite3_errstr(code)), code(code), sql(sql) {} | ||
| sqlite_exception(const char* msg, STR_REF sql, int code = -1): runtime_error(msg), code(code), sql(std::move(sql)) {} | ||
| sqlite_exception(int code, STR_REF sql): runtime_error(sqlite3_errstr(code)), code(code), sql(std::move(sql)) {} | ||
|
||
| int get_code() const {return code & 0xFF;} | ||
| int get_extended_code() const {return code;} | ||
| std::string get_sql() const {return sql;} | ||
|
|
@@ -40,7 +40,7 @@ namespace sqlite { | |
| class more_statements: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements can only contain one statement | ||
| class invalid_utf16: public sqlite_exception { using sqlite_exception::sqlite_exception; }; | ||
|
|
||
| static void throw_sqlite_error(const int& error_code, const std::string &sql = "") { | ||
| static void throw_sqlite_error(const int& error_code, const STR_REF &sql = "") { | ||
|
||
| switch(error_code & 0xFF) { | ||
| #define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \ | ||
| case SQLITE_ ## NAME: switch(error_code) { \ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,11 @@ | |
| #include <string> | ||
| #include <memory> | ||
| #include <vector> | ||
|
|
||
| #ifdef __has_include | ||
| #if __cplusplus >= 201703 && __has_include(<string_view>) | ||
| #define MODERN_SQLITE_STRINGVIEW_SUPPORT | ||
| #endif | ||
| #endif | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is more modern and more robust to use typedefs instead of macros. It is also more consistant with |
||
| #ifdef __has_include | ||
| #if __cplusplus > 201402 && __has_include(<optional>) | ||
| #define MODERN_SQLITE_STD_OPTIONAL_SUPPORT | ||
|
|
@@ -31,7 +35,14 @@ | |
| #ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT | ||
| #include <variant> | ||
| #endif | ||
|
|
||
| #ifdef MODERN_SQLITE_STRINGVIEW_SUPPORT | ||
| #include <string_view> | ||
| typedef const std::string_view STR_REF; | ||
| typedef const std::u16string_view U16STR_REF; | ||
| #else | ||
| typedef const std::string& STR_REF; | ||
| typedef const std::u16string& U16STR_REF; | ||
| #endif | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The typedef should be in out namespace to avoid introducing names in the global namespace. Also they are no longer macros, so the names should no longer be uppercase. |
||
| #include <sqlite3.h> | ||
| #include "errors.h" | ||
|
|
||
|
|
@@ -150,16 +161,17 @@ namespace sqlite { | |
| sqlite3_result_null(db); | ||
| } | ||
|
|
||
| // std::string | ||
| // STR_REF | ||
| template<> | ||
| struct has_sqlite_type<std::string, SQLITE3_TEXT, void> : std::true_type {}; | ||
|
|
||
| inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::string& val) { | ||
| return sqlite3_bind_text(stmt, inx, val.data(), -1, SQLITE_TRANSIENT); | ||
| inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, STR_REF val) { | ||
| return sqlite3_bind_text(stmt, inx, val.data(), val.length(), SQLITE_TRANSIENT); | ||
| } | ||
|
|
||
| // Convert char* to string to trigger op<<(..., const std::string ) | ||
| 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)); } | ||
| // Convert char* to string_view to trigger op<<(..., const STR_REF ) | ||
| template<std::size_t N> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char(&STR)[N]) { | ||
| return sqlite3_bind_text(stmt, inx, &STR[0], N-1, SQLITE_TRANSIENT); | ||
| } | ||
|
|
||
| inline std::string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::string>) { | ||
| return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? std::string() : | ||
|
|
@@ -170,31 +182,32 @@ namespace sqlite { | |
| std::string(reinterpret_cast<char const *>(sqlite3_value_text(value)), sqlite3_value_bytes(value)); | ||
| } | ||
|
|
||
| inline void store_result_in_db(sqlite3_context* db, const std::string& val) { | ||
| sqlite3_result_text(db, val.data(), -1, SQLITE_TRANSIENT); | ||
| inline void store_result_in_db(sqlite3_context* db, STR_REF val) { | ||
| sqlite3_result_text(db, val.data(), val.length(), SQLITE_TRANSIENT); | ||
| } | ||
| // std::u16string | ||
| // U16STR_REF | ||
| template<> | ||
| struct has_sqlite_type<std::u16string, SQLITE3_TEXT, void> : std::true_type {}; | ||
|
|
||
| inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::u16string& val) { | ||
| return sqlite3_bind_text16(stmt, inx, val.data(), -1, SQLITE_TRANSIENT); | ||
| inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, U16STR_REF val) { | ||
| return sqlite3_bind_text16(stmt, inx, val.data(), sizeof(char16_t) * val.length(), SQLITE_TRANSIENT); | ||
| } | ||
|
|
||
| // Convert char* to string to trigger op<<(..., const std::string ) | ||
| 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)); } | ||
| // Convert char* to string_view to trigger op<<(..., const STR_REF ) | ||
| template<std::size_t N> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char16_t(&STR)[N]) { | ||
| return sqlite3_bind_text16(stmt, inx, &STR[0], N-1, SQLITE_TRANSIENT); | ||
| } | ||
|
|
||
| inline std::u16string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::u16string>) { | ||
| return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? std::u16string() : | ||
| std::u16string(reinterpret_cast<char16_t const *>(sqlite3_column_text16(stmt, inx)), sqlite3_column_bytes16(stmt, inx)); | ||
| } | ||
| inline std::u16string get_val_from_db(sqlite3_value *value, result_type<std::u16string >) { | ||
| inline std::u16string get_val_from_db(sqlite3_value *value, result_type<std::u16string>) { | ||
| return sqlite3_value_type(value) == SQLITE_NULL ? std::u16string() : | ||
| std::u16string(reinterpret_cast<char16_t const *>(sqlite3_value_text16(value)), sqlite3_value_bytes16(value)); | ||
| } | ||
|
|
||
| inline void store_result_in_db(sqlite3_context* db, const std::u16string& val) { | ||
| sqlite3_result_text16(db, val.data(), -1, SQLITE_TRANSIENT); | ||
| inline void store_result_in_db(sqlite3_context* db, U16STR_REF val) { | ||
| sqlite3_result_text16(db, val.data(), sizeof(char16_t) * val.length(), SQLITE_TRANSIENT); | ||
| } | ||
|
|
||
| // Other integer types | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,7 @@ | |
|
|
||
| namespace sqlite { | ||
| namespace utility { | ||
| inline std::string utf16_to_utf8(const std::u16string &input) { | ||
| inline std::string utf16_to_utf8(const U16STR_REF &input) { | ||
|
||
| struct : std::codecvt<char16_t, char, std::mbstate_t> { | ||
| } codecvt; | ||
| std::mbstate_t state{}; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We still support C++14, so it would make sense to keep this set to 14. Especially since our Travis compiler is so old that it does not support most C++17 features anyway.