Skip to content
This repository has been archived by the owner on Jan 3, 2024. It is now read-only.

Commit

Permalink
Checking whether an optional's underlying type is bindable
Browse files Browse the repository at this point in the history
* Took care of optional's possibly const-qualified type
* Added statically executed unit test for is_printable
* Removed binding an optional's underlying value as a return value (wrong and unused anyway)
  • Loading branch information
trueqbit committed Mar 5, 2022
1 parent 78d4767 commit aef6673
Show file tree
Hide file tree
Showing 9 changed files with 200 additions and 110 deletions.
18 changes: 13 additions & 5 deletions dev/field_printer.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,14 @@ namespace sqlite_orm {
};
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
template<class T>
struct field_printer<T, std::enable_if_t<is_std_ptr<T>::value>> {
struct field_printer<T,
std::enable_if_t<is_std_ptr<T>::value &&
internal::is_printable_v<std::remove_cv_t<typename T::element_type>>>> {
using unqualified_type = std::remove_cv_t<typename T::element_type>;

std::string operator()(const T& t) const {
if(t) {
return field_printer<typename T::element_type>()(*t);
return field_printer<unqualified_type>()(*t);
} else {
return field_printer<std::nullptr_t>{}(nullptr);
}
Expand All @@ -134,10 +138,14 @@ namespace sqlite_orm {

#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
template<class T>
struct field_printer<std::optional<T>, void> {
std::string operator()(const std::optional<T>& t) const {
struct field_printer<T,
std::enable_if_t<internal::polyfill::is_specialization_of_v<T, std::optional> &&
internal::is_printable_v<std::remove_cv_t<typename T::value_type>>>> {
using unqualified_type = std::remove_cv_t<typename T::value_type>;

std::string operator()(const T& t) const {
if(t.has_value()) {
return field_printer<T>()(*t);
return field_printer<unqualified_type>()(*t);
} else {
return field_printer<std::nullopt_t>{}(std::nullopt);
}
Expand Down
10 changes: 6 additions & 4 deletions dev/is_std_ptr.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#pragma once
#include <type_traits>
#include <memory>

namespace sqlite_orm {

Expand All @@ -12,17 +14,17 @@ namespace sqlite_orm {
struct is_std_ptr<std::shared_ptr<T>> : std::true_type {
using element_type = typename std::shared_ptr<T>::element_type;

static std::shared_ptr<T> make(const T& v) {
return std::make_shared<T>(v);
static std::shared_ptr<T> make(std::remove_cv_t<T>&& v) {
return std::make_shared<T>(std::move(v));
}
};

template<typename T>
struct is_std_ptr<std::unique_ptr<T>> : std::true_type {
using element_type = typename std::unique_ptr<T>::element_type;

static std::unique_ptr<T> make(const T& v) {
return std::make_unique<T>(v);
static auto make(std::remove_cv_t<T>&& v) {
return std::make_unique<T>(std::move(v));
}
};
}
26 changes: 13 additions & 13 deletions dev/row_extractor.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,11 @@ namespace sqlite_orm {

template<class V>
struct row_extractor<V, std::enable_if_t<is_std_ptr<V>::value>> {
using value_type = typename is_std_ptr<V>::element_type;
using unqualified_type = std::remove_cv_t<typename V::element_type>;

V extract(const char* row_value) const {
if(row_value) {
return is_std_ptr<V>::make(row_extractor<value_type>().extract(row_value));
return is_std_ptr<V>::make(row_extractor<unqualified_type>().extract(row_value));
} else {
return {};
}
Expand All @@ -196,7 +196,7 @@ namespace sqlite_orm {
V extract(sqlite3_stmt* stmt, int columnIndex) const {
auto type = sqlite3_column_type(stmt, columnIndex);
if(type != SQLITE_NULL) {
return is_std_ptr<V>::make(row_extractor<value_type>().extract(stmt, columnIndex));
return is_std_ptr<V>::make(row_extractor<unqualified_type>().extract(stmt, columnIndex));
} else {
return {};
}
Expand All @@ -205,39 +205,39 @@ namespace sqlite_orm {
V extract(sqlite3_value* value) const {
auto type = sqlite3_value_type(value);
if(type != SQLITE_NULL) {
return is_std_ptr<V>::make(row_extractor<value_type>().extract(value));
return is_std_ptr<V>::make(row_extractor<unqualified_type>().extract(value));
} else {
return {};
}
}
};

#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
template<class T>
struct row_extractor<std::optional<T>, void> {
using value_type = T;
template<class V>
struct row_extractor<V, std::enable_if_t<internal::polyfill::is_specialization_of_v<V, std::optional>>> {
using unqualified_type = std::remove_cv_t<typename V::value_type>;

std::optional<T> extract(const char* row_value) const {
V extract(const char* row_value) const {
if(row_value) {
return std::make_optional(row_extractor<value_type>().extract(row_value));
return std::make_optional(row_extractor<unqualified_type>().extract(row_value));
} else {
return std::nullopt;
}
}

std::optional<T> extract(sqlite3_stmt* stmt, int columnIndex) const {
V extract(sqlite3_stmt* stmt, int columnIndex) const {
auto type = sqlite3_column_type(stmt, columnIndex);
if(type != SQLITE_NULL) {
return std::make_optional(row_extractor<value_type>().extract(stmt, columnIndex));
return std::make_optional(row_extractor<unqualified_type>().extract(stmt, columnIndex));
} else {
return std::nullopt;
}
}

std::optional<T> extract(sqlite3_value* value) const {
V extract(sqlite3_value* value) const {
auto type = sqlite3_value_type(value);
if(type != SQLITE_NULL) {
return std::make_optional(row_extractor<value_type>().extract(value));
return std::make_optional(row_extractor<unqualified_type>().extract(value));
} else {
return std::nullopt;
}
Expand Down
54 changes: 23 additions & 31 deletions dev/statement_binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ namespace sqlite_orm {
template<class V, typename Enable = void>
struct statement_binder;

namespace internal {

template<class T, class SFINAE = void>
SQLITE_ORM_INLINE_VAR constexpr bool is_bindable_v = false;
template<class T>
SQLITE_ORM_INLINE_VAR constexpr bool is_bindable_v<T, polyfill::void_t<decltype(statement_binder<T>{})>> = true;
template<class T>
using is_bindable = polyfill::bool_constant<is_bindable_v<T>>;

}

/**
* Specialization for 'pointer-passing interface'.
*/
Expand Down Expand Up @@ -209,24 +220,18 @@ namespace sqlite_orm {
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED

template<class V>
struct statement_binder<V, std::enable_if_t<is_std_ptr<V>::value>> {
using value_type = typename is_std_ptr<V>::element_type;
struct statement_binder<
V,
std::enable_if_t<is_std_ptr<V>::value && internal::is_bindable_v<std::remove_cv_t<typename V::element_type>>>> {
using unqualified_type = std::remove_cv_t<typename V::element_type>;

int bind(sqlite3_stmt* stmt, int index, const V& value) const {
if(value) {
return statement_binder<value_type>().bind(stmt, index, *value);
return statement_binder<unqualified_type>().bind(stmt, index, *value);
} else {
return statement_binder<std::nullptr_t>().bind(stmt, index, nullptr);
}
}

void result(sqlite3_context* context, const V& value) const {
if(value) {
statement_binder<value_type>().result(context, value);
} else {
statement_binder<std::nullptr_t>().result(context, nullptr);
}
}
};

/**
Expand All @@ -252,37 +257,24 @@ namespace sqlite_orm {
};

#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
template<class T>
struct statement_binder<std::optional<T>, void> {
using value_type = T;
template<class V>
struct statement_binder<V,
std::enable_if_t<internal::polyfill::is_specialization_of_v<V, std::optional> &&
internal::is_bindable_v<std::remove_cv_t<typename V::value_type>>>> {
using unqualified_type = std::remove_cv_t<typename V::value_type>;

int bind(sqlite3_stmt* stmt, int index, const std::optional<T>& value) const {
int bind(sqlite3_stmt* stmt, int index, const V& value) const {
if(value) {
return statement_binder<value_type>().bind(stmt, index, *value);
return statement_binder<unqualified_type>().bind(stmt, index, *value);
} else {
return statement_binder<std::nullopt_t>().bind(stmt, index, std::nullopt);
}
}

void result(sqlite3_context* context, const std::optional<T>& value) const {
if(value) {
statement_binder<value_type>().result(context, value);
} else {
statement_binder<std::nullopt_t>().result(context, std::nullopt);
}
}
};
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED

namespace internal {

template<class T, class SFINAE = void>
SQLITE_ORM_INLINE_VAR constexpr bool is_bindable_v = false;
template<class T>
SQLITE_ORM_INLINE_VAR constexpr bool is_bindable_v<T, polyfill::void_t<decltype(statement_binder<T>{})>> = true;
template<class T>
using is_bindable = polyfill::bool_constant<is_bindable_v<T>>;

struct conditional_binder_base {
sqlite3_stmt* stmt = nullptr;
int& index;
Expand Down
Loading

0 comments on commit aef6673

Please sign in to comment.