qswiki/database/hdr/sqlite_modern_cpp/log.h

125 lines
4.6 KiB
C++

#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));
}
} // namespace detail
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));
}
} // namespace sqlite