Skip to content

Commit

Permalink
C++ operator overloads for bitwise operators
Browse files Browse the repository at this point in the history
The bitwise operators were missing C++ operator equivalents.
Also:
* Added serialization unit tests for bitwise operators
* Added missing column result type unit tests for bitwise operators
* Added missing serialization unit tests for logical not
* Improved parenthesizing logical and bitwise "not" expressions
  • Loading branch information
trueqbit committed Jul 23, 2024
1 parent 388ed52 commit 766861e
Show file tree
Hide file tree
Showing 12 changed files with 327 additions and 43 deletions.
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
52 changes: 52 additions & 0 deletions dev/core_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -2095,6 +2095,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
41 changes: 33 additions & 8 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 @@ -721,11 +722,23 @@ namespace sqlite_orm {
using statement_type = bitwise_not_t<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 +748,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
118 changes: 104 additions & 14 deletions include/sqlite_orm/sqlite_orm.h
Original file line number Diff line number Diff line change
Expand Up @@ -4717,15 +4717,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 Expand Up @@ -4850,9 +4860,11 @@ namespace sqlite_orm {
*/
template<class C>
struct negated_condition_t : condition_t, negated_condition_string {
C c;
using argument_type = C;

argument_type c;

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

/**
Expand Down Expand Up @@ -4892,7 +4904,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 @@ -4908,7 +4920,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 Expand Up @@ -8133,6 +8145,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 Expand Up @@ -18463,6 +18527,8 @@ namespace sqlite_orm {

// #include "literal.h"

// #include "expression.h"

// #include "table_name_collector.h"

// #include "column_names_getter.h"
Expand Down Expand Up @@ -19879,11 +19945,23 @@ namespace sqlite_orm {
using statement_type = bitwise_not_t<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 @@ -19893,11 +19971,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
6 changes: 3 additions & 3 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,15 @@ add_executable(unit_tests
built_in_functions_tests/math_functions.cpp
user_defined_functions.cpp
constraints/composite_key.cpp
operators/arithmetic_operators.cpp
operators/like.cpp
operators/glob.cpp
operators/in.cpp
operators/cast.cpp
operators/is_null.cpp
operators/not_operator.cpp
operators/bitwise.cpp
operators/arithmetic_operators.cpp
operators/bitwise_operators.cpp
operators/binary_operators.cpp
operators/not_operator.cpp
prepared_statement_tests/select.cpp
prepared_statement_tests/get_all.cpp
prepared_statement_tests/get_all_pointer.cpp
Expand Down
Loading

0 comments on commit 766861e

Please sign in to comment.