Skip to content

Commit 8327ea6

Browse files
authored
Merge pull request #167 from zowpowow/dev
Use std::string_view as argument instead of std::string on C++17 Compilers
2 parents f55a47e + b0e3c8d commit 8327ea6

File tree

9 files changed

+87
-52
lines changed

9 files changed

+87
-52
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ OPTION(ENABLE_SQLCIPHER_TESTS "enable sqlchipher test")
33

44
# Creates the file compile_commands.json in the build directory.
55
SET(CMAKE_EXPORT_COMPILE_COMMANDS ON)
6-
set (CMAKE_CXX_STANDARD 14)
6+
set (CMAKE_CXX_STANDARD 17)
77

88
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
99
include("cmake/HunterGate.cmake")
@@ -43,6 +43,7 @@ else()
4343
endif()
4444

4545
catch_discover_tests(tests)
46+
target_compile_options(tests PUBLIC $<$<CXX_COMPILER_ID:MSVC>:/Zc:__cplusplus> )
4647

4748
# Place the file in the source directory, permitting us to place a single configuration file for YCM there.
4849
# YCM is the code-completion engine for (neo)vim https://github.com/Valloric/YouCompleteMe

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ int main() {
3232
// int ,long, long long, float, double
3333
// string , u16string
3434
// sqlite3 only supports utf8 and utf16 strings, you should use std::string for utf8 and std::u16string for utf16.
35+
// If you're using c++17, it takes `string_view` and `u16string_view` as arguments
3536
// note that u"my text" is a utf16 string literal of type char16_t * .
3637
db << "insert into user (age,name,weight) values (?,?,?);"
3738
<< 20

hdr/sqlite_modern_cpp.h

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,15 @@ namespace sqlite {
8585
return ++_inx;
8686
}
8787

88-
sqlite3_stmt* _prepare(const std::u16string& sql) {
88+
sqlite3_stmt* _prepare(u16str_ref sql) {
8989
return _prepare(utility::utf16_to_utf8(sql));
9090
}
9191

92-
sqlite3_stmt* _prepare(const std::string& sql) {
92+
sqlite3_stmt* _prepare(str_ref sql) {
9393
int hresult;
9494
sqlite3_stmt* tmp = nullptr;
9595
const char *remaining;
96-
hresult = sqlite3_prepare_v2(_db.get(), sql.data(), -1, &tmp, &remaining);
96+
hresult = sqlite3_prepare_v2(_db.get(), sql.data(), sql.length(), &tmp, &remaining);
9797
if(hresult != SQLITE_OK) errors::throw_sqlite_error(hresult, sql);
9898
if(!std::all_of(remaining, sql.data() + sql.size(), [](char ch) {return std::isspace(ch);}))
9999
throw errors::more_statements("Multiple semicolon separated statements are unsupported", sql);
@@ -105,13 +105,13 @@ namespace sqlite {
105105

106106
public:
107107

108-
database_binder(std::shared_ptr<sqlite3> db, std::u16string const & sql):
108+
database_binder(std::shared_ptr<sqlite3> db, u16str_ref sql):
109109
_db(db),
110110
_stmt(_prepare(sql), sqlite3_finalize),
111111
_inx(0) {
112112
}
113113

114-
database_binder(std::shared_ptr<sqlite3> db, std::string const & sql):
114+
database_binder(std::shared_ptr<sqlite3> db, str_ref sql):
115115
_db(db),
116116
_stmt(_prepare(sql), sqlite3_finalize),
117117
_inx(0) {
@@ -372,36 +372,22 @@ namespace sqlite {
372372
*this << R"(PRAGMA encoding = "UTF-16";)";
373373
}
374374

375-
database(const std::u16string &db_name, const sqlite_config &config = {}): _db(nullptr) {
376-
auto db_name_utf8 = utility::utf16_to_utf8(db_name);
377-
sqlite3* tmp = nullptr;
378-
auto ret = sqlite3_open_v2(db_name_utf8.data(), &tmp, static_cast<int>(config.flags), config.zVfs);
379-
_db = std::shared_ptr<sqlite3>(tmp, [=](sqlite3* ptr) { sqlite3_close_v2(ptr); }); // this will close the connection eventually when no longer needed.
380-
if(ret != SQLITE_OK) errors::throw_sqlite_error(_db ? sqlite3_extended_errcode(_db.get()) : ret);
381-
sqlite3_extended_result_codes(_db.get(), true);
382-
if(config.encoding != Encoding::UTF8)
375+
database(const std::u16string &db_name, const sqlite_config &config = {}): database(utility::utf16_to_utf8(db_name), config) {
376+
if (config.encoding == Encoding::ANY)
383377
*this << R"(PRAGMA encoding = "UTF-16";)";
384378
}
385379

386380
database(std::shared_ptr<sqlite3> db):
387381
_db(db) {}
388382

389-
database_binder operator<<(const std::string& sql) {
383+
database_binder operator<<(str_ref sql) {
390384
return database_binder(_db, sql);
391385
}
392386

393-
database_binder operator<<(const char* sql) {
394-
return *this << std::string(sql);
395-
}
396-
397-
database_binder operator<<(const std::u16string& sql) {
387+
database_binder operator<<(u16str_ref sql) {
398388
return database_binder(_db, sql);
399389
}
400390

401-
database_binder operator<<(const char16_t* sql) {
402-
return *this << std::u16string(sql);
403-
}
404-
405391
connection_type connection() const { return _db; }
406392

407393
sqlite3_int64 last_insert_rowid() const {
@@ -418,7 +404,7 @@ namespace sqlite {
418404

419405
auto funcPtr = new auto(std::forward<Function>(func));
420406
if(int result = sqlite3_create_function_v2(
421-
_db.get(), name.c_str(), traits::arity, SQLITE_UTF8, funcPtr,
407+
_db.get(), name.data(), traits::arity, SQLITE_UTF8, funcPtr,
422408
sql_function_binder::scalar<traits::arity, typename std::remove_reference<Function>::type>,
423409
nullptr, nullptr, [](void* ptr){
424410
delete static_cast<decltype(funcPtr)>(ptr);
@@ -652,3 +638,4 @@ namespace sqlite {
652638
}
653639
}
654640
}
641+

hdr/sqlite_modern_cpp/errors.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ namespace sqlite {
99

1010
class sqlite_exception: public std::runtime_error {
1111
public:
12-
sqlite_exception(const char* msg, std::string sql, int code = -1): runtime_error(msg), code(code), sql(sql) {}
13-
sqlite_exception(int code, std::string sql): runtime_error(sqlite3_errstr(code)), code(code), sql(sql) {}
12+
sqlite_exception(const char* msg, str_ref sql, int code = -1): runtime_error(msg), code(code), sql(sql) {}
13+
sqlite_exception(int code, str_ref sql): runtime_error(sqlite3_errstr(code)), code(code), sql(sql) {}
1414
int get_code() const {return code & 0xFF;}
1515
int get_extended_code() const {return code;}
1616
std::string get_sql() const {return sql;}
@@ -40,7 +40,7 @@ namespace sqlite {
4040
class more_statements: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements can only contain one statement
4141
class invalid_utf16: public sqlite_exception { using sqlite_exception::sqlite_exception; };
4242

43-
static void throw_sqlite_error(const int& error_code, const std::string &sql = "") {
43+
static void throw_sqlite_error(const int& error_code, str_ref sql = "") {
4444
switch(error_code & 0xFF) {
4545
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \
4646
case SQLITE_ ## NAME: switch(error_code) { \

hdr/sqlite_modern_cpp/log.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@ namespace sqlite {
9393
}
9494
});
9595

96-
sqlite3_config(SQLITE_CONFIG_LOG, (void(*)(void*,int,const char*))[](void *functor, int error_code, const char *errstr) {
96+
sqlite3_config(SQLITE_CONFIG_LOG, static_cast<void(*)(void*,int,const char*)>([](void *functor, int error_code, const char *errstr) {
9797
(*static_cast<decltype(ptr.get())>(functor))(error_code, errstr);
98-
}, ptr.get());
98+
}), ptr.get());
9999
detail::store_error_log_data_pointer(std::move(ptr));
100100
}
101101
}

hdr/sqlite_modern_cpp/type_wrapper.h

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
#include <string>
55
#include <memory>
66
#include <vector>
7-
7+
#ifdef __has_include
8+
#if __cplusplus >= 201703 && __has_include(<string_view>)
9+
#define MODERN_SQLITE_STRINGVIEW_SUPPORT
10+
#endif
11+
#endif
812
#ifdef __has_include
913
#if __cplusplus > 201402 && __has_include(<optional>)
1014
#define MODERN_SQLITE_STD_OPTIONAL_SUPPORT
@@ -31,7 +35,20 @@
3135
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
3236
#include <variant>
3337
#endif
34-
38+
#ifdef MODERN_SQLITE_STRINGVIEW_SUPPORT
39+
#include <string_view>
40+
namespace sqlite
41+
{
42+
typedef const std::string_view str_ref;
43+
typedef const std::u16string_view u16str_ref;
44+
}
45+
#else
46+
namespace sqlite
47+
{
48+
typedef const std::string& str_ref;
49+
typedef const std::u16string& u16str_ref;
50+
}
51+
#endif
3552
#include <sqlite3.h>
3653
#include "errors.h"
3754

@@ -150,16 +167,17 @@ namespace sqlite {
150167
sqlite3_result_null(db);
151168
}
152169

153-
// std::string
170+
// str_ref
154171
template<>
155172
struct has_sqlite_type<std::string, SQLITE3_TEXT, void> : std::true_type {};
156-
157-
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::string& val) {
158-
return sqlite3_bind_text(stmt, inx, val.data(), -1, SQLITE_TRANSIENT);
173+
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, str_ref val) {
174+
return sqlite3_bind_text(stmt, inx, val.data(), val.length(), SQLITE_TRANSIENT);
159175
}
160176

161-
// Convert char* to string to trigger op<<(..., const std::string )
162-
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)); }
177+
// Convert char* to string_view to trigger op<<(..., const str_ref )
178+
template<std::size_t N> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char(&STR)[N]) {
179+
return sqlite3_bind_text(stmt, inx, &STR[0], N-1, SQLITE_TRANSIENT);
180+
}
163181

164182
inline std::string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::string>) {
165183
return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? std::string() :
@@ -170,31 +188,32 @@ namespace sqlite {
170188
std::string(reinterpret_cast<char const *>(sqlite3_value_text(value)), sqlite3_value_bytes(value));
171189
}
172190

173-
inline void store_result_in_db(sqlite3_context* db, const std::string& val) {
174-
sqlite3_result_text(db, val.data(), -1, SQLITE_TRANSIENT);
191+
inline void store_result_in_db(sqlite3_context* db, str_ref val) {
192+
sqlite3_result_text(db, val.data(), val.length(), SQLITE_TRANSIENT);
175193
}
176-
// std::u16string
194+
// u16str_ref
177195
template<>
178196
struct has_sqlite_type<std::u16string, SQLITE3_TEXT, void> : std::true_type {};
179-
180-
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::u16string& val) {
181-
return sqlite3_bind_text16(stmt, inx, val.data(), -1, SQLITE_TRANSIENT);
197+
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, u16str_ref val) {
198+
return sqlite3_bind_text16(stmt, inx, val.data(), sizeof(char16_t) * val.length(), SQLITE_TRANSIENT);
182199
}
183200

184-
// Convert char* to string to trigger op<<(..., const std::string )
185-
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)); }
201+
// Convert char* to string_view to trigger op<<(..., const str_ref )
202+
template<std::size_t N> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char16_t(&STR)[N]) {
203+
return sqlite3_bind_text16(stmt, inx, &STR[0], sizeof(char16_t) * (N-1), SQLITE_TRANSIENT);
204+
}
186205

187206
inline std::u16string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::u16string>) {
188207
return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? std::u16string() :
189208
std::u16string(reinterpret_cast<char16_t const *>(sqlite3_column_text16(stmt, inx)), sqlite3_column_bytes16(stmt, inx));
190209
}
191-
inline std::u16string get_val_from_db(sqlite3_value *value, result_type<std::u16string >) {
210+
inline std::u16string get_val_from_db(sqlite3_value *value, result_type<std::u16string>) {
192211
return sqlite3_value_type(value) == SQLITE_NULL ? std::u16string() :
193212
std::u16string(reinterpret_cast<char16_t const *>(sqlite3_value_text16(value)), sqlite3_value_bytes16(value));
194213
}
195214

196-
inline void store_result_in_db(sqlite3_context* db, const std::u16string& val) {
197-
sqlite3_result_text16(db, val.data(), -1, SQLITE_TRANSIENT);
215+
inline void store_result_in_db(sqlite3_context* db, u16str_ref val) {
216+
sqlite3_result_text16(db, val.data(), sizeof(char16_t) * val.length(), SQLITE_TRANSIENT);
198217
}
199218

200219
// Other integer types

hdr/sqlite_modern_cpp/utility/utf16_utf8.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
namespace sqlite {
1010
namespace utility {
11-
inline std::string utf16_to_utf8(const std::u16string &input) {
11+
inline std::string utf16_to_utf8(u16str_ref input) {
1212
struct : std::codecvt<char16_t, char, std::mbstate_t> {
1313
} codecvt;
1414
std::mbstate_t state{};

tests/flags.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ struct TmpFile {
1313
TmpFile(): fname("./flags.db") { }
1414
~TmpFile() { remove(fname.c_str()); }
1515
};
16-
17-
#if BYTE_ORDER == BIG_ENDIAN
16+
#ifdef _WIN32
17+
#define OUR_UTF16 "UTF-16le"
18+
#elif BYTE_ORDER == BIG_ENDIAN
1819
#define OUR_UTF16 "UTF-16be"
1920
#else
2021
#define OUR_UTF16 "UTF-16le"

tests/string_view.cc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include <iostream>
2+
#include <cstdlib>
3+
#include <sqlite_modern_cpp.h>
4+
#include <catch.hpp>
5+
6+
7+
#ifdef MODERN_SQLITE_STRINGVIEW_SUPPORT
8+
#include <string_view>
9+
10+
using namespace sqlite;
11+
using namespace std;
12+
TEST_CASE("std::string_view works", "[string_view]") {
13+
database db(":memory:");;
14+
db << "CREATE TABLE foo (a integer, b string);\n";
15+
const std::string_view test1 = "null terminated string view";
16+
db << "INSERT INTO foo VALUES (?, ?)" << 1 << test1;
17+
std::string str;
18+
db << "SELECT b from FOO where a=?;" << 1 >> str;
19+
REQUIRE(test1 == str);
20+
const char s[] = "hello world";
21+
std::string_view test2(&s[0], 2);
22+
db << "INSERT INTO foo VALUES (?,?)" << 2 << test2;
23+
db << "SELECT b from FOO where a=?" << 2 >> str;
24+
REQUIRE(str == "he");
25+
}
26+
#endif

0 commit comments

Comments
 (0)