diff options
Diffstat (limited to 'ext/sqlite_modern_cpp/sqlite_modern_cpp/log.h')
-rw-r--r-- | ext/sqlite_modern_cpp/sqlite_modern_cpp/log.h | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/ext/sqlite_modern_cpp/sqlite_modern_cpp/log.h b/ext/sqlite_modern_cpp/sqlite_modern_cpp/log.h new file mode 100644 index 0000000..a8f7be2 --- /dev/null +++ b/ext/sqlite_modern_cpp/sqlite_modern_cpp/log.h @@ -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, (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)); + } +} |