Skip to content

Commit 4dc6d82

Browse files
committed
Directly use std::codecvt<>.
Stops using the deprecated <codecvt> header and std::wstring_convert.
1 parent 76472db commit 4dc6d82

File tree

3 files changed

+45
-14
lines changed

3 files changed

+45
-14
lines changed

hdr/sqlite_modern_cpp.h

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
#include <tuple>
99
#include <memory>
1010
#include <vector>
11-
#include <locale>
12-
#include <codecvt>
1311

1412
#define MODERN_SQLITE_VERSION 3002008
1513

@@ -45,6 +43,7 @@
4543
#include "sqlite_modern_cpp/errors.h"
4644
#include "sqlite_modern_cpp/utility/function_traits.h"
4745
#include "sqlite_modern_cpp/utility/uncaught_exceptions.h"
46+
#include "sqlite_modern_cpp/utility/utf16_utf8.h"
4847

4948
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
5049
#include "sqlite_modern_cpp/utility/variant.h"
@@ -183,15 +182,9 @@ namespace sqlite {
183182
}
184183
}
185184

186-
#ifdef _MSC_VER
187185
sqlite3_stmt* _prepare(const std::u16string& sql) {
188-
return _prepare(std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t>().to_bytes(reinterpret_cast<const wchar_t*>(sql.c_str())));
186+
return _prepare(utility::utf16_to_utf8(sql));
189187
}
190-
#else
191-
sqlite3_stmt* _prepare(const std::u16string& sql) {
192-
return _prepare(std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>().to_bytes(sql));
193-
}
194-
#endif
195188

196189
sqlite3_stmt* _prepare(const std::string& sql) {
197190
int hresult;
@@ -421,11 +414,7 @@ namespace sqlite {
421414
}
422415

423416
database(const std::u16string &db_name, const sqlite_config &config = {}): _db(nullptr) {
424-
#ifdef _MSC_VER
425-
auto db_name_utf8 = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t>().to_bytes(reinterpret_cast<const wchar_t*>(db_name.c_str()));
426-
#else
427-
auto db_name_utf8 = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>().to_bytes(db_name);
428-
#endif
417+
auto db_name_utf8 = utility::utf16_to_utf8(db_name);
429418
sqlite3* tmp = nullptr;
430419
auto ret = sqlite3_open_v2(db_name_utf8.data(), &tmp, static_cast<int>(config.flags), config.zVfs);
431420
_db = std::shared_ptr<sqlite3>(tmp, [=](sqlite3* ptr) { sqlite3_close_v2(ptr); }); // this will close the connection eventually when no longer needed.

hdr/sqlite_modern_cpp/errors.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ namespace sqlite {
3838
class more_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
3939
class no_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
4040
class more_statements: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements can only contain one statement
41+
class invalid_utf16: public sqlite_exception { using sqlite_exception::sqlite_exception; };
4142

4243
static void throw_sqlite_error(const int& error_code, const std::string &sql = "") {
4344
switch(error_code & 0xFF) {
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#pragma once
2+
3+
#include <locale>
4+
#include <string>
5+
6+
#include "../errors.h"
7+
8+
namespace sqlite {
9+
namespace utility {
10+
inline std::string utf16_to_utf8(const std::u16string &input) {
11+
struct : std::codecvt<char16_t, char, std::mbstate_t> {
12+
} codecvt;
13+
std::mbstate_t state;
14+
std::string result(std::max(input.size() * 3 / 2, std::size_t(4)), '\0');
15+
const char16_t *remaining_input = input.data();
16+
std::size_t produced_output = 0;
17+
while(true) {
18+
char *used_output;
19+
switch(codecvt.out(state, remaining_input, &input[input.size()],
20+
remaining_input, &result[produced_output],
21+
&result[result.size() - 1] + 1, used_output)) {
22+
case std::codecvt_base::ok:
23+
result.resize(used_output - result.data());
24+
return result;
25+
case std::codecvt_base::noconv:
26+
// This should be unreachable
27+
case std::codecvt_base::error:
28+
throw errors::invalid_utf16("Invalid UTF-16 input", "");
29+
case std::codecvt_base::partial:
30+
if(used_output == result.data() + produced_output)
31+
throw errors::invalid_utf16("Unexpected end of input", "");
32+
produced_output = used_output - result.data();
33+
result.resize(
34+
result.size()
35+
+ std::max((&input[input.size()] - remaining_input) * 3 / 2,
36+
std::ptrdiff_t(4)));
37+
}
38+
}
39+
}
40+
} // namespace utility
41+
} // namespace sqlite

0 commit comments

Comments
 (0)