Skip to content

Commit

Permalink
Turned type_is_nullable into a specializable struct again
Browse files Browse the repository at this point in the history
  • Loading branch information
trueqbit committed Jan 16, 2023
1 parent 5330ecd commit a0acab7
Show file tree
Hide file tree
Showing 5 changed files with 315 additions and 129 deletions.
2 changes: 1 addition & 1 deletion dev/storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ namespace sqlite_orm {
static_assert(is_preparable_v<self, Ex>, "Expression must be a high-level statement");

decltype(auto) e2 = static_if<is_select_v<Ex>>(
[](auto expression) -> auto {
[](auto expression) -> auto{
expression.highest_level = true;
return expression;
},
Expand Down
24 changes: 20 additions & 4 deletions dev/type_is_nullable.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <type_traits> // std::false_type, std::true_type, std::enable_if
#include <memory> // std::shared_ptr, std::unique_ptr
#include "functional/cxx_optional.h"

Expand All @@ -14,12 +15,27 @@ namespace sqlite_orm {
* custom type as `NULL` (for example: boost::optional) you have to create a specialiation
* of type_is_nullable for your type and derive from `std::true_type`.
*/
template<class T, class SFINAE = void>
struct type_is_nullable : std::false_type {
bool operator()(const T&) const {
return true;
}
};

/**
* This is a specialization for std::shared_ptr, std::unique_ptr, std::optional, which are nullable in sqlite_orm.
*/
template<class T>
using type_is_nullable = polyfill::disjunction<
struct type_is_nullable<T,
std::enable_if_t<polyfill::disjunction_v<
#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
polyfill::is_specialization_of<T, std::optional>,
polyfill::is_specialization_of<T, std::optional>,
#endif
polyfill::is_specialization_of<T, std::unique_ptr>,
polyfill::is_specialization_of<T, std::shared_ptr>>;
polyfill::is_specialization_of<T, std::unique_ptr>,
polyfill::is_specialization_of<T, std::shared_ptr>>>> : std::true_type {
bool operator()(const T& t) const {
return static_cast<bool>(t);
}
};

}
35 changes: 21 additions & 14 deletions dev/xdestroy_handling.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,20 @@ namespace sqlite_orm {
*/
template<typename D>
concept integral_fp_c = requires {
typename D::value_type;
D::value;
requires std::is_function_v<std::remove_pointer_t<typename D::value_type>>;
};
typename D::value_type;
D::value;
requires std::is_function_v<std::remove_pointer_t<typename D::value_type>>;
};

/**
* Constraints a deleter to be or to yield a function pointer.
*/
template<typename D>
concept yields_fp = requires(D d) {
// yielding function pointer by using the plus trick
{+d};
requires std::is_function_v<std::remove_pointer_t<decltype(+d)>>;
};
// yielding function pointer by using the plus trick
{ +d };
requires std::is_function_v<std::remove_pointer_t<decltype(+d)>>;
};
#endif

#if __cpp_lib_concepts >= 201907L
Expand All @@ -57,7 +57,7 @@ namespace sqlite_orm {

template<typename D>
SQLITE_ORM_INLINE_VAR constexpr bool is_stateless_deleter_v =
std::is_empty<D>::value&& std::is_default_constructible<D>::value;
std::is_empty<D>::value && std::is_default_constructible<D>::value;

template<typename D, typename SFINAE = void>
struct is_integral_fp_c : std::false_type {};
Expand Down Expand Up @@ -118,7 +118,8 @@ namespace sqlite_orm {
* it doesn't check so explicitly, but a compiler error will occur.
*/
template<typename D, typename P>
requires(!integral_fp_c<D>) void xdestroy_proxy(void* p) noexcept {
requires(!integral_fp_c<D>)
void xdestroy_proxy(void* p) noexcept {
// C-casting `void* -> P*` like statement_binder<pointer_binding<P, T, D>>
auto o = (P*)p;
// ignoring return code
Expand Down Expand Up @@ -146,7 +147,7 @@ namespace sqlite_orm {

template<typename D>
SQLITE_ORM_INLINE_VAR constexpr bool can_yield_xdestroy_v =
can_yield_fp_v<D>&& std::is_convertible<yielded_fn_t<D>, xdestroy_fn_t>::value;
can_yield_fp_v<D> && std::is_convertible<yielded_fn_t<D>, xdestroy_fn_t>::value;

template<typename D, typename P>
SQLITE_ORM_INLINE_VAR constexpr bool needs_xdestroy_proxy_v =
Expand Down Expand Up @@ -181,7 +182,9 @@ namespace sqlite_orm {
* Explicitly declared for better error messages.
*/
template<typename D, typename P>
constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::is_unusable_for_xdestroy<D>) {
constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept
requires(internal::is_unusable_for_xdestroy<D>)
{
static_assert(polyfill::always_false_v<D>,
"A function pointer, which is not of type xdestroy_fn_t, is prohibited.");
return nullptr;
Expand All @@ -200,7 +203,9 @@ namespace sqlite_orm {
* is invocable with the non-q-qualified pointer value.
*/
template<typename D, typename P>
constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::needs_xdestroy_proxy<D, P>) {
constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept
requires(internal::needs_xdestroy_proxy<D, P>)
{
return internal::xdestroy_proxy<D, P>;
}

Expand All @@ -219,7 +224,9 @@ namespace sqlite_orm {
* is invocable with the non-q-qualified pointer value.
*/
template<typename D, typename P>
constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept requires(internal::yields_xdestroy<D>) {
constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept
requires(internal::yields_xdestroy<D>)
{
return d;
}
#else
Expand Down
2 changes: 1 addition & 1 deletion examples/nullable_enum_binding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ namespace sqlite_orm {
* specializing type_is_nullable<T> and deriving from std::true_type.
*/
template<>
struct type_is_nullable<Gender> : public std::true_type {
struct type_is_nullable<Gender> : std::true_type {

// this function must return whether value null or not (false is null). Don't forget to implement it
bool operator()(const Gender& g) const {
Expand Down
Loading

0 comments on commit a0acab7

Please sign in to comment.