Skip to content

Directly use std::codecvt<> without std::wstring_convert<> #143

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

Merged
merged 1 commit into from
Jan 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 3 additions & 14 deletions hdr/sqlite_modern_cpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
#include <tuple>
#include <memory>
#include <vector>
#include <locale>
#include <codecvt>

#define MODERN_SQLITE_VERSION 3002008

Expand Down Expand Up @@ -45,6 +43,7 @@
#include "sqlite_modern_cpp/errors.h"
#include "sqlite_modern_cpp/utility/function_traits.h"
#include "sqlite_modern_cpp/utility/uncaught_exceptions.h"
#include "sqlite_modern_cpp/utility/utf16_utf8.h"

#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
#include "sqlite_modern_cpp/utility/variant.h"
Expand Down Expand Up @@ -183,15 +182,9 @@ namespace sqlite {
}
}

#ifdef _MSC_VER
sqlite3_stmt* _prepare(const std::u16string& sql) {
return _prepare(std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t>().to_bytes(reinterpret_cast<const wchar_t*>(sql.c_str())));
return _prepare(utility::utf16_to_utf8(sql));
}
#else
sqlite3_stmt* _prepare(const std::u16string& sql) {
return _prepare(std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>().to_bytes(sql));
}
#endif

sqlite3_stmt* _prepare(const std::string& sql) {
int hresult;
Expand Down Expand Up @@ -421,11 +414,7 @@ namespace sqlite {
}

database(const std::u16string &db_name, const sqlite_config &config = {}): _db(nullptr) {
#ifdef _MSC_VER
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()));
#else
auto db_name_utf8 = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>().to_bytes(db_name);
#endif
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.
Expand Down
1 change: 1 addition & 0 deletions hdr/sqlite_modern_cpp/errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace sqlite {
class more_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
class no_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
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 = "") {
switch(error_code & 0xFF) {
Expand Down
41 changes: 41 additions & 0 deletions hdr/sqlite_modern_cpp/utility/utf16_utf8.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include <locale>
#include <string>

#include "../errors.h"

namespace sqlite {
namespace utility {
inline std::string utf16_to_utf8(const std::u16string &input) {
struct : std::codecvt<char16_t, char, std::mbstate_t> {
} codecvt;
std::mbstate_t state;
std::string result(std::max(input.size() * 3 / 2, std::size_t(4)), '\0');
const char16_t *remaining_input = input.data();
std::size_t produced_output = 0;
while(true) {
char *used_output;
switch(codecvt.out(state, remaining_input, &input[input.size()],
remaining_input, &result[produced_output],
&result[result.size() - 1] + 1, used_output)) {
case std::codecvt_base::ok:
result.resize(used_output - result.data());
return result;
case std::codecvt_base::noconv:
// This should be unreachable
case std::codecvt_base::error:
throw errors::invalid_utf16("Invalid UTF-16 input", "");
case std::codecvt_base::partial:
if(used_output == result.data() + produced_output)
throw errors::invalid_utf16("Unexpected end of input", "");
produced_output = used_output - result.data();
result.resize(
result.size()
+ std::max((&input[input.size()] - remaining_input) * 3 / 2,
std::ptrdiff_t(4)));
}
}
}
} // namespace utility
} // namespace sqlite