Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C++ operator overloads for bitwise operators #1340

Merged
merged 6 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions dev/column_result.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ namespace sqlite_orm {
using type = std::string;
};

template<class DBOs, class T>
struct column_result_t<DBOs, unary_minus_t<T>, void> {
using type = double;
};

template<class DBOs, class L, class R>
struct column_result_t<DBOs, add_t<L, R>, void> {
using type = double;
Expand Down
10 changes: 6 additions & 4 deletions dev/conditions.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,11 @@ namespace sqlite_orm {
*/
template<class C>
struct negated_condition_t : condition_t, negated_condition_string {
C c;
using argument_type = C;

constexpr negated_condition_t(C c_) : c(std::move(c_)) {}
argument_type c;

constexpr negated_condition_t(argument_type arg) : c(std::move(arg)) {}
};

/**
Expand Down Expand Up @@ -153,7 +155,7 @@ namespace sqlite_orm {
* Result of and operator
*/
template<class L, class R>
struct and_condition_t : binary_condition<L, R, and_condition_string, bool> {
struct and_condition_t : binary_condition<L, R, and_condition_string, bool>, negatable_t {
using super = binary_condition<L, R, and_condition_string, bool>;

using super::super;
Expand All @@ -169,7 +171,7 @@ namespace sqlite_orm {
* Result of or operator
*/
template<class L, class R>
struct or_condition_t : binary_condition<L, R, or_condition_string, bool> {
struct or_condition_t : binary_condition<L, R, or_condition_string, bool>, negatable_t {
using super = binary_condition<L, R, or_condition_string, bool>;

using super::super;
Expand Down
60 changes: 60 additions & 0 deletions dev/core_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -2041,6 +2041,14 @@ namespace sqlite_orm {
// Intentionally place operators for types classified as arithmetic or general operator arguments in the internal namespace
// to facilitate ADL (Argument Dependent Lookup)
namespace internal {
template<
class T,
std::enable_if_t<polyfill::disjunction<std::is_base_of<arithmetic_t, T>, is_operator_argument<T>>::value,
bool> = true>
constexpr unary_minus_t<unwrap_expression_t<T>> operator-(T arg) {
return {get_from_expression(std::forward<T>(arg))};
}

template<class L,
class R,
std::enable_if_t<polyfill::disjunction<std::is_base_of<arithmetic_t, L>,
Expand Down Expand Up @@ -2095,6 +2103,58 @@ namespace sqlite_orm {
constexpr mod_t<unwrap_expression_t<L>, unwrap_expression_t<R>> operator%(L l, R r) {
return {get_from_expression(std::forward<L>(l)), get_from_expression(std::forward<R>(r))};
}

template<
class T,
std::enable_if_t<polyfill::disjunction<std::is_base_of<arithmetic_t, T>, is_operator_argument<T>>::value,
bool> = true>
constexpr bitwise_not_t<unwrap_expression_t<T>> operator~(T arg) {
return {get_from_expression(std::forward<T>(arg))};
}

template<class L,
class R,
std::enable_if_t<polyfill::disjunction<std::is_base_of<arithmetic_t, L>,
std::is_base_of<arithmetic_t, R>,
is_operator_argument<L>,
is_operator_argument<R>>::value,
bool> = true>
constexpr bitwise_shift_left_t<unwrap_expression_t<L>, unwrap_expression_t<R>> operator<<(L l, R r) {
return {get_from_expression(std::forward<L>(l)), get_from_expression(std::forward<R>(r))};
}

template<class L,
class R,
std::enable_if_t<polyfill::disjunction<std::is_base_of<arithmetic_t, L>,
std::is_base_of<arithmetic_t, R>,
is_operator_argument<L>,
is_operator_argument<R>>::value,
bool> = true>
constexpr bitwise_shift_right_t<unwrap_expression_t<L>, unwrap_expression_t<R>> operator>>(L l, R r) {
return {get_from_expression(std::forward<L>(l)), get_from_expression(std::forward<R>(r))};
}

template<class L,
class R,
std::enable_if_t<polyfill::disjunction<std::is_base_of<arithmetic_t, L>,
std::is_base_of<arithmetic_t, R>,
is_operator_argument<L>,
is_operator_argument<R>>::value,
bool> = true>
constexpr bitwise_and_t<unwrap_expression_t<L>, unwrap_expression_t<R>> operator&(L l, R r) {
return {get_from_expression(std::forward<L>(l)), get_from_expression(std::forward<R>(r))};
}

template<class L,
class R,
std::enable_if_t<polyfill::disjunction<std::is_base_of<arithmetic_t, L>,
std::is_base_of<arithmetic_t, R>,
is_operator_argument<L>,
is_operator_argument<R>>::value,
bool> = true>
constexpr bitwise_or_t<unwrap_expression_t<L>, unwrap_expression_t<R>> operator|(L l, R r) {
return {get_from_expression(std::forward<L>(l)), get_from_expression(std::forward<R>(r))};
}
}

template<class T, class X, class Y, class Z>
Expand Down
14 changes: 12 additions & 2 deletions dev/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,25 @@ namespace sqlite_orm {
is_operator_argument_v<T, std::enable_if_t<polyfill::is_specialization_of<T, expression_t>::value>> = true;

template<class T>
constexpr T get_from_expression(T value) {
constexpr T get_from_expression(T&& value) {
return std::move(value);
}

template<class T>
constexpr T get_from_expression(expression_t<T> expression) {
constexpr const T& get_from_expression(const T& value) {
return value;
}

template<class T>
constexpr T get_from_expression(expression_t<T>&& expression) {
return std::move(expression.value);
}

template<class T>
constexpr const T& get_from_expression(const expression_t<T>& expression) {
return expression.value;
}

template<class T>
using unwrap_expression_t = decltype(get_from_expression(std::declval<T>()));
}
Expand Down
6 changes: 6 additions & 0 deletions dev/node_tuple.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,12 @@ namespace sqlite_orm {
template<class C>
struct node_tuple<negated_condition_t<C>, void> : node_tuple<C> {};

template<class T>
struct node_tuple<unary_minus_t<T>, void> : node_tuple<T> {};

template<class T>
struct node_tuple<bitwise_not_t<T>, void> : node_tuple<T> {};

template<class R, class S, class... Args>
struct node_tuple<built_in_function_t<R, S, Args...>, void> : node_tuple_for<Args...> {};

Expand Down
25 changes: 24 additions & 1 deletion dev/operators.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ namespace sqlite_orm {
template<class L, class R>
using conc_t = binary_operator<L, R, conc_string>;

struct unary_minus_string {
serialize_result_type serialize() const {
return "-";
}
};

/**
* Result of unary minus - operator
*/
template<class T>
struct unary_minus_t : unary_minus_string, arithmetic_t, negatable_t {
using argument_type = T;

argument_type argument;

unary_minus_t(argument_type argument_) : argument(std::move(argument_)) {}
};

struct add_string {
serialize_result_type serialize() const {
return "+";
Expand All @@ -60,7 +78,7 @@ namespace sqlite_orm {
};

/**
* Result of substitute - operator
* Result of substraction - operator
trueqbit marked this conversation as resolved.
Show resolved Hide resolved
*/
template<class L, class R>
using sub_t = binary_operator<L, R, sub_string, arithmetic_t, negatable_t>;
Expand Down Expand Up @@ -201,6 +219,11 @@ namespace sqlite_orm {
return {std::move(l), std::move(r)};
}

template<class T>
constexpr internal::unary_minus_t<T> minus(T t) {
return {std::move(t)};
}

/**
* Public interface for + operator. Example: `select(add(&User::age, 100));` => SELECT age + 100 FROM users
*/
Expand Down
48 changes: 38 additions & 10 deletions dev/statement_serializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "type_printer.h"
#include "field_printer.h"
#include "literal.h"
#include "expression.h"
#include "table_name_collector.h"
#include "column_names_getter.h"
#include "cte_column_names_collector.h"
Expand Down Expand Up @@ -717,15 +718,30 @@ namespace sqlite_orm {
};

template<class T>
struct statement_serializer<bitwise_not_t<T>, void> {
using statement_type = bitwise_not_t<T>;
struct statement_serializer<
T,
std::enable_if_t<polyfill::disjunction<polyfill::is_specialization_of<T, unary_minus_t>,
polyfill::is_specialization_of<T, bitwise_not_t>>::value>> {
using statement_type = T;

template<class Ctx>
std::string operator()(const statement_type& statement, const Ctx& context) const {
std::string operator()(const statement_type& expression, const Ctx& context) const {
// subqueries should always use parentheses in binary expressions
auto subCtx = context;
subCtx.use_parentheses = true;
// parentheses for sub-trees to ensure the order of precedence
constexpr bool parenthesize = is_binary_condition<typename statement_type::argument_type>::value ||
is_binary_operator<typename statement_type::argument_type>::value;

std::stringstream ss;
ss << statement.serialize() << " ";
auto cString = serialize(statement.argument, context);
ss << " (" << cString << " )";
ss << expression.serialize();
if SQLITE_ORM_CONSTEXPR_IF(parenthesize) {
ss << "(";
}
ss << serialize(get_from_expression(expression.argument), subCtx);
if SQLITE_ORM_CONSTEXPR_IF(parenthesize) {
ss << ")";
}
return ss.str();
}
};
Expand All @@ -735,11 +751,23 @@ namespace sqlite_orm {
using statement_type = negated_condition_t<T>;

template<class Ctx>
std::string operator()(const statement_type& c, const Ctx& context) const {
std::string operator()(const statement_type& expression, const Ctx& context) const {
// subqueries should always use parentheses in binary expressions
auto subCtx = context;
subCtx.use_parentheses = true;
// parentheses for sub-trees to ensure the order of precedence
constexpr bool parenthesize = is_binary_condition<typename statement_type::argument_type>::value ||
is_binary_operator<typename statement_type::argument_type>::value;

std::stringstream ss;
ss << static_cast<std::string>(c) << " ";
auto cString = serialize(c.c, context);
ss << " (" << cString << " )";
ss << static_cast<std::string>(expression) << " ";
if SQLITE_ORM_CONSTEXPR_IF(parenthesize) {
ss << "(";
}
ss << serialize(get_from_expression(expression.c), subCtx);
if SQLITE_ORM_CONSTEXPR_IF(parenthesize) {
ss << ")";
}
return ss.str();
}
};
Expand Down
Loading