mikupad.html in ik_llama.cpp (functional but WIP)

This commit is contained in:
Saood Karim
2025-06-26 02:14:20 -05:00
parent 5236c98b41
commit 4c7579e617
14 changed files with 8838 additions and 2 deletions

View File

@@ -0,0 +1,70 @@
#pragma once
#include <string>
#include <stdexcept>
#include <sqlite3.h>
namespace sqlite {
class sqlite_exception: public std::runtime_error {
public:
sqlite_exception(const char* msg, str_ref sql, int code = -1): runtime_error(msg), code(code), sql(sql) {}
sqlite_exception(int code, str_ref sql, const char *msg = nullptr): runtime_error(msg ? msg : sqlite3_errstr(code)), code(code), sql(sql) {}
int get_code() const {return code & 0xFF;}
int get_extended_code() const {return code;}
std::string get_sql() const {return sql;}
const char *errstr() const {return code == -1 ? "Unknown error" : sqlite3_errstr(code);}
private:
int code;
std::string sql;
};
namespace errors {
//One more or less trivial derived error class for each SQLITE error.
//Note the following are not errors so have no classes:
//SQLITE_OK, SQLITE_NOTICE, SQLITE_WARNING, SQLITE_ROW, SQLITE_DONE
//
//Note these names are exact matches to the names of the SQLITE error codes.
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \
class name: public sqlite_exception { using sqlite_exception::sqlite_exception; };\
derived
#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE,SUB,base,sub) \
class base ## _ ## sub: public base { using base::base; };
#include "lists/error_codes.h"
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
#undef SQLITE_MODERN_CPP_ERROR_CODE
//Some additional errors are here for the C++ interface
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; };
class unknown_binding: public sqlite_exception { using sqlite_exception::sqlite_exception; };
static void throw_sqlite_error(const int& error_code, str_ref sql = "", const char *errmsg = nullptr) {
switch(error_code & 0xFF) {
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \
case SQLITE_ ## NAME: switch(error_code) { \
derived \
case SQLITE_ ## NAME: \
default: throw name(error_code, sql); \
}
#if SQLITE_VERSION_NUMBER < 3010000
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8))
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
#endif
#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE,SUB,base,sub) \
case SQLITE_ ## BASE ## _ ## SUB: throw base ## _ ## sub(error_code, sql, errmsg);
#include "lists/error_codes.h"
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
#undef SQLITE_MODERN_CPP_ERROR_CODE
default: throw sqlite_exception(error_code, sql, errmsg);
}
}
}
namespace exceptions = errors;
}

View File

@@ -0,0 +1,88 @@
SQLITE_MODERN_CPP_ERROR_CODE(ERROR,error,)
SQLITE_MODERN_CPP_ERROR_CODE(INTERNAL,internal,)
SQLITE_MODERN_CPP_ERROR_CODE(PERM,perm,)
SQLITE_MODERN_CPP_ERROR_CODE(ABORT,abort,
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(ABORT,ROLLBACK,abort,rollback)
)
SQLITE_MODERN_CPP_ERROR_CODE(BUSY,busy,
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BUSY,RECOVERY,busy,recovery)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BUSY,SNAPSHOT,busy,snapshot)
)
SQLITE_MODERN_CPP_ERROR_CODE(LOCKED,locked,
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(LOCKED,SHAREDCACHE,locked,sharedcache)
)
SQLITE_MODERN_CPP_ERROR_CODE(NOMEM,nomem,)
SQLITE_MODERN_CPP_ERROR_CODE(READONLY,readonly,)
SQLITE_MODERN_CPP_ERROR_CODE(INTERRUPT,interrupt,)
SQLITE_MODERN_CPP_ERROR_CODE(IOERR,ioerr,
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,READ,ioerr,read)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SHORT_READ,ioerr,short_read)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,WRITE,ioerr,write)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,FSYNC,ioerr,fsync)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,DIR_FSYNC,ioerr,dir_fsync)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,TRUNCATE,ioerr,truncate)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,FSTAT,ioerr,fstat)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,UNLOCK,ioerr,unlock)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,RDLOCK,ioerr,rdlock)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,DELETE,ioerr,delete)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,BLOCKED,ioerr,blocked)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,NOMEM,ioerr,nomem)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,ACCESS,ioerr,access)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,CHECKRESERVEDLOCK,ioerr,checkreservedlock)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,LOCK,ioerr,lock)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,CLOSE,ioerr,close)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,DIR_CLOSE,ioerr,dir_close)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SHMOPEN,ioerr,shmopen)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SHMSIZE,ioerr,shmsize)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SHMLOCK,ioerr,shmlock)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SHMMAP,ioerr,shmmap)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SEEK,ioerr,seek)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,DELETE_NOENT,ioerr,delete_noent)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,MMAP,ioerr,mmap)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,GETTEMPPATH,ioerr,gettemppath)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,CONVPATH,ioerr,convpath)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,VNODE,ioerr,vnode)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,AUTH,ioerr,auth)
)
SQLITE_MODERN_CPP_ERROR_CODE(CORRUPT,corrupt,
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CORRUPT,VTAB,corrupt,vtab)
)
SQLITE_MODERN_CPP_ERROR_CODE(NOTFOUND,notfound,)
SQLITE_MODERN_CPP_ERROR_CODE(FULL,full,)
SQLITE_MODERN_CPP_ERROR_CODE(CANTOPEN,cantopen,
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN,NOTEMPDIR,cantopen,notempdir)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN,ISDIR,cantopen,isdir)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN,FULLPATH,cantopen,fullpath)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN,CONVPATH,cantopen,convpath)
)
SQLITE_MODERN_CPP_ERROR_CODE(PROTOCOL,protocol,)
SQLITE_MODERN_CPP_ERROR_CODE(EMPTY,empty,)
SQLITE_MODERN_CPP_ERROR_CODE(SCHEMA,schema,)
SQLITE_MODERN_CPP_ERROR_CODE(TOOBIG,toobig,)
SQLITE_MODERN_CPP_ERROR_CODE(CONSTRAINT,constraint,
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,CHECK,constraint,check)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,COMMITHOOK,constraint,commithook)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,FOREIGNKEY,constraint,foreignkey)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,FUNCTION,constraint,function)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,NOTNULL,constraint,notnull)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,PRIMARYKEY,constraint,primarykey)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,TRIGGER,constraint,trigger)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,UNIQUE,constraint,unique)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,VTAB,constraint,vtab)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,ROWID,constraint,rowid)
)
SQLITE_MODERN_CPP_ERROR_CODE(MISMATCH,mismatch,)
SQLITE_MODERN_CPP_ERROR_CODE(MISUSE,misuse,)
SQLITE_MODERN_CPP_ERROR_CODE(NOLFS,nolfs,)
SQLITE_MODERN_CPP_ERROR_CODE(AUTH,auth,
)
SQLITE_MODERN_CPP_ERROR_CODE(FORMAT,format,)
SQLITE_MODERN_CPP_ERROR_CODE(RANGE,range,)
SQLITE_MODERN_CPP_ERROR_CODE(NOTADB,notadb,)
SQLITE_MODERN_CPP_ERROR_CODE(NOTICE,notice,
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(NOTICE,RECOVER_WAL,notice,recover_wal)
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(NOTICE,RECOVER_ROLLBACK,notice,recover_rollback)
)
SQLITE_MODERN_CPP_ERROR_CODE(WARNING,warning,
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(WARNING,AUTOINDEX,warning,autoindex)
)

View File

@@ -0,0 +1,101 @@
#include "errors.h"
#include <sqlite3.h>
#include <utility>
#include <tuple>
#include <type_traits>
namespace sqlite {
namespace detail {
template<class>
using void_t = void;
template<class T, class = void>
struct is_callable : std::false_type {};
template<class Functor, class ...Arguments>
struct is_callable<Functor(Arguments...), void_t<decltype(std::declval<Functor>()(std::declval<Arguments>()...))>> : std::true_type {};
template<class Functor, class ...Functors>
class FunctorOverload: public Functor, public FunctorOverload<Functors...> {
public:
template<class Functor1, class ...Remaining>
FunctorOverload(Functor1 &&functor, Remaining &&... remaining):
Functor(std::forward<Functor1>(functor)),
FunctorOverload<Functors...>(std::forward<Remaining>(remaining)...) {}
using Functor::operator();
using FunctorOverload<Functors...>::operator();
};
template<class Functor>
class FunctorOverload<Functor>: public Functor {
public:
template<class Functor1>
FunctorOverload(Functor1 &&functor):
Functor(std::forward<Functor1>(functor)) {}
using Functor::operator();
};
template<class Functor>
class WrapIntoFunctor: public Functor {
public:
template<class Functor1>
WrapIntoFunctor(Functor1 &&functor):
Functor(std::forward<Functor1>(functor)) {}
using Functor::operator();
};
template<class ReturnType, class ...Arguments>
class WrapIntoFunctor<ReturnType(*)(Arguments...)> {
ReturnType(*ptr)(Arguments...);
public:
WrapIntoFunctor(ReturnType(*ptr)(Arguments...)): ptr(ptr) {}
ReturnType operator()(Arguments... arguments) { return (*ptr)(std::forward<Arguments>(arguments)...); }
};
inline void store_error_log_data_pointer(std::shared_ptr<void> ptr) {
static std::shared_ptr<void> stored;
stored = std::move(ptr);
}
template<class T>
std::shared_ptr<typename std::decay<T>::type> make_shared_inferred(T &&t) {
return std::make_shared<typename std::decay<T>::type>(std::forward<T>(t));
}
}
template<class Handler>
typename std::enable_if<!detail::is_callable<Handler(const sqlite_exception&)>::value>::type
error_log(Handler &&handler);
template<class Handler>
typename std::enable_if<detail::is_callable<Handler(const sqlite_exception&)>::value>::type
error_log(Handler &&handler);
template<class ...Handler>
typename std::enable_if<sizeof...(Handler)>=2>::type
error_log(Handler &&...handler) {
return error_log(detail::FunctorOverload<detail::WrapIntoFunctor<typename std::decay<Handler>::type>...>(std::forward<Handler>(handler)...));
}
template<class Handler>
typename std::enable_if<!detail::is_callable<Handler(const sqlite_exception&)>::value>::type
error_log(Handler &&handler) {
return error_log(std::forward<Handler>(handler), [](const sqlite_exception&) {});
}
template<class Handler>
typename std::enable_if<detail::is_callable<Handler(const sqlite_exception&)>::value>::type
error_log(Handler &&handler) {
auto ptr = detail::make_shared_inferred([handler = std::forward<Handler>(handler)](int error_code, const char *errstr) mutable {
switch(error_code & 0xFF) {
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \
case SQLITE_ ## NAME: switch(error_code) { \
derived \
default: handler(errors::name(errstr, "", error_code)); \
};break;
#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE,SUB,base,sub) \
case SQLITE_ ## BASE ## _ ## SUB: \
handler(errors::base ## _ ## sub(errstr, "", error_code)); \
break;
#include "lists/error_codes.h"
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
#undef SQLITE_MODERN_CPP_ERROR_CODE
default: handler(sqlite_exception(errstr, "", error_code)); \
}
});
sqlite3_config(SQLITE_CONFIG_LOG, static_cast<void(*)(void*,int,const char*)>([](void *functor, int error_code, const char *errstr) {
(*static_cast<decltype(ptr.get())>(functor))(error_code, errstr);
}), ptr.get());
detail::store_error_log_data_pointer(std::move(ptr));
}
}

View File

@@ -0,0 +1,44 @@
#pragma once
#ifndef SQLITE_HAS_CODEC
#define SQLITE_HAS_CODEC
#endif
#include "../sqlite_modern_cpp.h"
namespace sqlite {
struct sqlcipher_config : public sqlite_config {
std::string key;
};
class sqlcipher_database : public database {
public:
sqlcipher_database(std::string db, const sqlcipher_config &config): database(db, config) {
set_key(config.key);
}
sqlcipher_database(std::u16string db, const sqlcipher_config &config): database(db, config) {
set_key(config.key);
}
void set_key(const std::string &key) {
if(auto ret = sqlite3_key(_db.get(), key.data(), key.size()))
errors::throw_sqlite_error(ret);
}
void set_key(const std::string &key, const std::string &db_name) {
if(auto ret = sqlite3_key_v2(_db.get(), db_name.c_str(), key.data(), key.size()))
errors::throw_sqlite_error(ret);
}
void rekey(const std::string &new_key) {
if(auto ret = sqlite3_rekey(_db.get(), new_key.data(), new_key.size()))
errors::throw_sqlite_error(ret);
}
void rekey(const std::string &new_key, const std::string &db_name) {
if(auto ret = sqlite3_rekey_v2(_db.get(), db_name.c_str(), new_key.data(), new_key.size()))
errors::throw_sqlite_error(ret);
}
};
}

View File

@@ -0,0 +1,433 @@
#pragma once
#include <type_traits>
#include <string>
#include <memory>
#include <vector>
#ifdef __has_include
#if (__cplusplus >= 201703 || _MSVC_LANG >= 201703) && __has_include(<string_view>)
#define MODERN_SQLITE_STRINGVIEW_SUPPORT
#endif
#endif
#ifdef __has_include
#if (__cplusplus > 201402 || _MSVC_LANG > 201402) && __has_include(<optional>)
#define MODERN_SQLITE_STD_OPTIONAL_SUPPORT
#elif __has_include(<experimental/optional>) && __apple_build_version__ < 11000000
#define MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
#endif
#endif
#ifdef __has_include
#if (__cplusplus > 201402 || _MSVC_LANG > 201402) && __has_include(<variant>)
#define MODERN_SQLITE_STD_VARIANT_SUPPORT
#endif
#endif
#ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
#include <optional>
#endif
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
#include <experimental/optional>
#define MODERN_SQLITE_STD_OPTIONAL_SUPPORT
#endif
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
#include <variant>
#endif
#ifdef MODERN_SQLITE_STRINGVIEW_SUPPORT
#include <string_view>
namespace sqlite
{
typedef const std::string_view str_ref;
typedef const std::u16string_view u16str_ref;
}
#else
namespace sqlite
{
typedef const std::string& str_ref;
typedef const std::u16string& u16str_ref;
}
#endif
#include <sqlite3.h>
#include "errors.h"
namespace sqlite {
template<class T, int Type, class = void>
struct has_sqlite_type : std::false_type {};
template<class T>
using is_sqlite_value = std::integral_constant<bool, false
|| has_sqlite_type<T, SQLITE_NULL>::value
|| has_sqlite_type<T, SQLITE_INTEGER>::value
|| has_sqlite_type<T, SQLITE_FLOAT>::value
|| has_sqlite_type<T, SQLITE_TEXT>::value
|| has_sqlite_type<T, SQLITE_BLOB>::value
>;
template<class T, int Type>
struct has_sqlite_type<T&, Type> : has_sqlite_type<T, Type> {};
template<class T, int Type>
struct has_sqlite_type<const T, Type> : has_sqlite_type<T, Type> {};
template<class T, int Type>
struct has_sqlite_type<volatile T, Type> : has_sqlite_type<T, Type> {};
template<class T>
struct result_type {
using type = T;
constexpr result_type() = default;
template<class U, class = typename std::enable_if<std::is_assignable<U, T>::value>>
constexpr result_type(result_type<U>) { }
};
// int
template<>
struct has_sqlite_type<int, SQLITE_INTEGER> : std::true_type {};
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const int& val) {
return sqlite3_bind_int(stmt, inx, val);
}
inline void store_result_in_db(sqlite3_context* db, const int& val) {
sqlite3_result_int(db, val);
}
inline int get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<int>) {
return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? 0 :
sqlite3_column_int(stmt, inx);
}
inline int get_val_from_db(sqlite3_value *value, result_type<int>) {
return sqlite3_value_type(value) == SQLITE_NULL ? 0 :
sqlite3_value_int(value);
}
// sqlite_int64
template<>
struct has_sqlite_type<sqlite_int64, SQLITE_INTEGER, void> : std::true_type {};
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const sqlite_int64& val) {
return sqlite3_bind_int64(stmt, inx, val);
}
inline void store_result_in_db(sqlite3_context* db, const sqlite_int64& val) {
sqlite3_result_int64(db, val);
}
inline sqlite_int64 get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<sqlite_int64 >) {
return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? 0 :
sqlite3_column_int64(stmt, inx);
}
inline sqlite3_int64 get_val_from_db(sqlite3_value *value, result_type<sqlite3_int64>) {
return sqlite3_value_type(value) == SQLITE_NULL ? 0 :
sqlite3_value_int64(value);
}
// float
template<>
struct has_sqlite_type<float, SQLITE_FLOAT, void> : std::true_type {};
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const float& val) {
return sqlite3_bind_double(stmt, inx, double(val));
}
inline void store_result_in_db(sqlite3_context* db, const float& val) {
sqlite3_result_double(db, val);
}
inline float get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<float>) {
return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? 0 :
sqlite3_column_double(stmt, inx);
}
inline float get_val_from_db(sqlite3_value *value, result_type<float>) {
return sqlite3_value_type(value) == SQLITE_NULL ? 0 :
sqlite3_value_double(value);
}
// double
template<>
struct has_sqlite_type<double, SQLITE_FLOAT, void> : std::true_type {};
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const double& val) {
return sqlite3_bind_double(stmt, inx, val);
}
inline void store_result_in_db(sqlite3_context* db, const double& val) {
sqlite3_result_double(db, val);
}
inline double get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<double>) {
return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? 0 :
sqlite3_column_double(stmt, inx);
}
inline double get_val_from_db(sqlite3_value *value, result_type<double>) {
return sqlite3_value_type(value) == SQLITE_NULL ? 0 :
sqlite3_value_double(value);
}
/* for nullptr support */
template<>
struct has_sqlite_type<std::nullptr_t, SQLITE_NULL, void> : std::true_type {};
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, std::nullptr_t) {
return sqlite3_bind_null(stmt, inx);
}
inline void store_result_in_db(sqlite3_context* db, std::nullptr_t) {
sqlite3_result_null(db);
}
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
template<>
struct has_sqlite_type<std::monostate, SQLITE_NULL, void> : std::true_type {};
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, std::monostate) {
return sqlite3_bind_null(stmt, inx);
}
inline void store_result_in_db(sqlite3_context* db, std::monostate) {
sqlite3_result_null(db);
}
inline std::monostate get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::monostate>) {
return std::monostate();
}
inline std::monostate get_val_from_db(sqlite3_value *value, result_type<std::monostate>) {
return std::monostate();
}
#endif
// 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, str_ref val) {
return sqlite3_bind_text(stmt, inx, val.data(), val.length(), SQLITE_TRANSIENT);
}
// 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>) {
if ( sqlite3_column_type(stmt, inx) == SQLITE_NULL ) {
return std::string();
}
char const * ptr = reinterpret_cast<char const *>(sqlite3_column_text(stmt, inx));
// call sqlite3_column_text explicitely before sqlite3_column_bytes: it may convert the value to text
return std::string(ptr, sqlite3_column_bytes(stmt, inx));
}
inline std::string get_val_from_db(sqlite3_value *value, result_type<std::string>) {
if ( sqlite3_value_type(value) == SQLITE_NULL ) {
return std::string();
}
char const * ptr = reinterpret_cast<char const *>(sqlite3_value_text(value));
// call sqlite3_column_text explicitely before sqlite3_column_bytes: it may convert the value to text
return std::string(ptr, sqlite3_value_bytes(value));
}
inline void store_result_in_db(sqlite3_context* db, str_ref val) {
sqlite3_result_text(db, val.data(), val.length(), SQLITE_TRANSIENT);
}
// 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, u16str_ref val) {
return sqlite3_bind_text16(stmt, inx, val.data(), sizeof(char16_t) * val.length(), SQLITE_TRANSIENT);
}
// 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], sizeof(char16_t) * (N-1), SQLITE_TRANSIENT);
}
inline std::u16string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::u16string>) {
if ( sqlite3_column_type(stmt, inx) == SQLITE_NULL ) {
return std::u16string();
}
char16_t const * ptr = reinterpret_cast<char16_t const *>(sqlite3_column_text16(stmt, inx));
// call sqlite3_column_text16 explicitely before sqlite3_column_bytes16: it may convert the value to text
return std::u16string(ptr, sqlite3_column_bytes16(stmt, inx));
}
inline std::u16string get_val_from_db(sqlite3_value *value, result_type<std::u16string>) {
if ( sqlite3_value_type(value) == SQLITE_NULL ) {
return std::u16string();
}
char16_t const * ptr = reinterpret_cast<char16_t const *>(sqlite3_value_text16(value));
return std::u16string(ptr, sqlite3_value_bytes16(value));
}
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
template<class Integral>
struct has_sqlite_type<Integral, SQLITE_INTEGER, typename std::enable_if<std::is_integral<Integral>::value>::type> : std::true_type {};
template<class Integral, class = typename std::enable_if<std::is_integral<Integral>::value>::type>
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const Integral& val) {
return bind_col_in_db(stmt, inx, static_cast<sqlite3_int64>(val));
}
template<class Integral, class = std::enable_if<std::is_integral<Integral>::type>>
inline void store_result_in_db(sqlite3_context* db, const Integral& val) {
store_result_in_db(db, static_cast<sqlite3_int64>(val));
}
template<class Integral, class = typename std::enable_if<std::is_integral<Integral>::value>::type>
inline Integral get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<Integral>) {
return get_col_from_db(stmt, inx, result_type<sqlite3_int64>());
}
template<class Integral, class = typename std::enable_if<std::is_integral<Integral>::value>::type>
inline Integral get_val_from_db(sqlite3_value *value, result_type<Integral>) {
return get_val_from_db(value, result_type<sqlite3_int64>());
}
// vector<T, A>
template<typename T, typename A>
struct has_sqlite_type<std::vector<T, A>, SQLITE_BLOB, void> : std::true_type {};
template<typename T, typename A> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::vector<T, A>& vec) {
void const* buf = reinterpret_cast<void const *>(vec.data());
int bytes = vec.size() * sizeof(T);
return sqlite3_bind_blob(stmt, inx, buf, bytes, SQLITE_TRANSIENT);
}
template<typename T, typename A> inline void store_result_in_db(sqlite3_context* db, const std::vector<T, A>& vec) {
void const* buf = reinterpret_cast<void const *>(vec.data());
int bytes = vec.size() * sizeof(T);
sqlite3_result_blob(db, buf, bytes, SQLITE_TRANSIENT);
}
template<typename T, typename A> inline std::vector<T, A> get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::vector<T, A>>) {
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
return {};
}
T const* buf = reinterpret_cast<T const *>(sqlite3_column_blob(stmt, inx));
int bytes = sqlite3_column_bytes(stmt, inx);
return std::vector<T, A>(buf, buf + bytes/sizeof(T));
}
template<typename T, typename A> inline std::vector<T, A> get_val_from_db(sqlite3_value *value, result_type<std::vector<T, A>>) {
if(sqlite3_value_type(value) == SQLITE_NULL) {
return {};
}
T const* buf = reinterpret_cast<T const *>(sqlite3_value_blob(value));
int bytes = sqlite3_value_bytes(value);
return std::vector<T, A>(buf, buf + bytes/sizeof(T));
}
/* for unique_ptr<T> support */
template<typename T, int Type>
struct has_sqlite_type<std::unique_ptr<T>, Type, void> : has_sqlite_type<T, Type> {};
template<typename T>
struct has_sqlite_type<std::unique_ptr<T>, SQLITE_NULL, void> : std::true_type {};
template<typename T> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::unique_ptr<T>& val) {
return val ? bind_col_in_db(stmt, inx, *val) : bind_col_in_db(stmt, inx, nullptr);
}
template<typename T> inline std::unique_ptr<T> get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::unique_ptr<T>>) {
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
return nullptr;
}
return std::make_unique<T>(get_col_from_db(stmt, inx, result_type<T>()));
}
template<typename T> inline std::unique_ptr<T> get_val_from_db(sqlite3_value *value, result_type<std::unique_ptr<T>>) {
if(sqlite3_value_type(value) == SQLITE_NULL) {
return nullptr;
}
return std::make_unique<T>(get_val_from_db(value, result_type<T>()));
}
// std::optional support for NULL values
#ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
template<class T>
using optional = std::experimental::optional<T>;
#else
template<class T>
using optional = std::optional<T>;
#endif
template<typename T, int Type>
struct has_sqlite_type<optional<T>, Type, void> : has_sqlite_type<T, Type> {};
template<typename T>
struct has_sqlite_type<optional<T>, SQLITE_NULL, void> : std::true_type {};
template <typename OptionalT> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const optional<OptionalT>& val) {
return val ? bind_col_in_db(stmt, inx, *val) : bind_col_in_db(stmt, inx, nullptr);
}
template <typename OptionalT> inline void store_result_in_db(sqlite3_context* db, const optional<OptionalT>& val) {
if(val)
store_result_in_db(db, *val);
else
sqlite3_result_null(db);
}
template <typename OptionalT> inline optional<OptionalT> get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<optional<OptionalT>>) {
#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<OptionalT>()));
#else
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
return std::nullopt;
}
return std::make_optional(get_col_from_db(stmt, inx, result_type<OptionalT>()));
#endif
}
template <typename OptionalT> inline optional<OptionalT> get_val_from_db(sqlite3_value *value, result_type<optional<OptionalT>>) {
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
if(sqlite3_value_type(value) == SQLITE_NULL) {
return std::experimental::nullopt;
}
return std::experimental::make_optional(get_val_from_db(value, result_type<OptionalT>()));
#else
if(sqlite3_value_type(value) == SQLITE_NULL) {
return std::nullopt;
}
return std::make_optional(get_val_from_db(value, result_type<OptionalT>()));
#endif
}
#endif
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
namespace detail {
template<class T, class U>
struct tag_trait : U { using tag = T; };
}
template<int Type, class ...Options>
struct has_sqlite_type<std::variant<Options...>, Type, void> : std::disjunction<detail::tag_trait<Options, has_sqlite_type<Options, Type>>...> {};
namespace detail {
template<int Type, typename ...Options, typename Callback, typename first_compatible = has_sqlite_type<std::variant<Options...>, Type>>
inline std::variant<Options...> variant_select_type(Callback &&callback) {
if constexpr(first_compatible::value)
return callback(result_type<typename first_compatible::tag>());
else
throw errors::mismatch("The value is unsupported by this variant.", "", SQLITE_MISMATCH);
}
template<typename ...Options, typename Callback> inline decltype(auto) variant_select(int type, Callback &&callback) {
switch(type) {
case SQLITE_NULL:
return variant_select_type<SQLITE_NULL, Options...>(std::forward<Callback>(callback));
case SQLITE_INTEGER:
return variant_select_type<SQLITE_INTEGER, Options...>(std::forward<Callback>(callback));
case SQLITE_FLOAT:
return variant_select_type<SQLITE_FLOAT, Options...>(std::forward<Callback>(callback));
case SQLITE_TEXT:
return variant_select_type<SQLITE_TEXT, Options...>(std::forward<Callback>(callback));
case SQLITE_BLOB:
return variant_select_type<SQLITE_BLOB, Options...>(std::forward<Callback>(callback));
}
#ifdef _MSC_VER
__assume(false);
#else
__builtin_unreachable();
#endif
}
}
template <typename ...Args> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::variant<Args...>& val) {
return std::visit([&](auto &&opt) {return bind_col_in_db(stmt, inx, std::forward<decltype(opt)>(opt));}, val);
}
template <typename ...Args> inline void store_result_in_db(sqlite3_context* db, const std::variant<Args...>& val) {
std::visit([&](auto &&opt) {store_result_in_db(db, std::forward<decltype(opt)>(opt));}, val);
}
template <typename ...Args> inline std::variant<Args...> get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::variant<Args...>>) {
return detail::variant_select<Args...>(sqlite3_column_type(stmt, inx), [&](auto v) {
return std::variant<Args...>(std::in_place_type<typename decltype(v)::type>, get_col_from_db(stmt, inx, v));
});
}
template <typename ...Args> inline std::variant<Args...> get_val_from_db(sqlite3_value *value, result_type<std::variant<Args...>>) {
return detail::variant_select<Args...>(sqlite3_value_type(value), [&](auto v) {
return std::variant<Args...>(std::in_place_type<typename decltype(v)::type>, get_val_from_db(value, v));
});
}
#endif
}

View File

@@ -0,0 +1,56 @@
#pragma once
#include <tuple>
#include<type_traits>
namespace sqlite {
namespace utility {
template<typename> struct function_traits;
template <typename Function>
struct function_traits : public function_traits<
decltype(&std::remove_reference<Function>::type::operator())
> { };
template <
typename ClassType,
typename ReturnType,
typename... Arguments
>
struct function_traits<
ReturnType(ClassType::*)(Arguments...) const
> : function_traits<ReturnType(*)(Arguments...)> { };
/* support the non-const operator ()
* this will work with user defined functors */
template <
typename ClassType,
typename ReturnType,
typename... Arguments
>
struct function_traits<
ReturnType(ClassType::*)(Arguments...)
> : function_traits<ReturnType(*)(Arguments...)> { };
template <
typename ReturnType,
typename... Arguments
>
struct function_traits<
ReturnType(*)(Arguments...)
> {
typedef ReturnType result_type;
using argument_tuple = std::tuple<Arguments...>;
template <std::size_t Index>
using argument = typename std::tuple_element<
Index,
argument_tuple
>::type;
static const std::size_t arity = sizeof...(Arguments);
};
}
}

View File

@@ -0,0 +1,41 @@
#pragma once
#include <cassert>
#include <exception>
#include <iostream>
// Consider that std::uncaught_exceptions is available if explicitly indicated
// by the standard library, if compiler advertises full C++17 support or, as a
// special case, for MSVS 2015+ (which doesn't define __cplusplus correctly by
// default as of 2017.7 version and couldn't do it at all until it).
#ifndef MODERN_SQLITE_UNCAUGHT_EXCEPTIONS_SUPPORT
#ifdef __cpp_lib_uncaught_exceptions
#define MODERN_SQLITE_UNCAUGHT_EXCEPTIONS_SUPPORT
#elif __cplusplus >= 201703L
#define MODERN_SQLITE_UNCAUGHT_EXCEPTIONS_SUPPORT
#elif defined(_MSC_VER) && _MSC_VER >= 1900
#define MODERN_SQLITE_UNCAUGHT_EXCEPTIONS_SUPPORT
#endif
#endif
namespace sqlite {
namespace utility {
#ifdef MODERN_SQLITE_UNCAUGHT_EXCEPTIONS_SUPPORT
class UncaughtExceptionDetector {
public:
operator bool() {
return count != std::uncaught_exceptions();
}
private:
int count = std::uncaught_exceptions();
};
#else
class UncaughtExceptionDetector {
public:
operator bool() {
return std::uncaught_exception();
}
};
#endif
}
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include <locale>
#include <string>
#include <algorithm>
#include "../errors.h"
namespace sqlite {
namespace utility {
inline std::string utf16_to_utf8(u16str_ref 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.data() + 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.data() + input.size() - remaining_input) * 3 / 2,
std::ptrdiff_t(4)));
}
}
}
} // namespace utility
} // namespace sqlite