Skip to content

Commit

Permalink
🎨 🆕 [terse] Support all operators with terse syntax
Browse files Browse the repository at this point in the history
Problem:
- Not all operators have been supported with `terse` syntax.

Solution:
- Add support for `terse` syntax with `==, !=, >, >=, <, <=` operators.
  • Loading branch information
kris-jusiak authored and krzysztof-jusiak committed Mar 15, 2020
1 parent 620380a commit 06a1cf9
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 9 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<p>

<p align="center">
<a href="https://godbolt.org/z/f2BdeZ"><img src="doc/images/ut.png"></a>
<a href="https://godbolt.org/z/Jqb5Ye"><img src="doc/images/ut.png"></a>
</p>

<a name="motivation"></a>
Expand Down
9 changes: 3 additions & 6 deletions example/terse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,8 @@ int main() {
using namespace boost::ut::operators::terse;

"terse"_test = [] {
42_i == sum(40, 2);
2_i == sum(1, 1);
sum(1, 1, 2) == 4_i;
42_i == sum(40, 2) and 2_i == sum(2) and 3_i == 3;
3_i == sum(1, 1, 2);
sum(1, 2, 3) == 6_i;
6_i == sum(1, 2, 3);
sum(1, 1) == 2_i;
42_i == sum(40, 2) and 0_i != sum(1) or 4_i == 3;
};
}
160 changes: 159 additions & 1 deletion include/boost/ut.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1971,6 +1971,7 @@ constexpr auto operator==(
using eq_t =
ut::detail::eq_<T, detail::value_location<typename T::value_type>>;
struct eq_ : eq_t {
using type = eq_t;
using eq_t::eq_t;
const detail::terse<eq_t> _{*this};
};
Expand All @@ -1983,23 +1984,180 @@ constexpr auto operator==(
using eq_t =
ut::detail::eq_<detail::value_location<typename T::value_type>, T>;
struct eq_ : eq_t {
using type = eq_t;
using eq_t::eq_t;
const detail::terse<eq_t> _{*this};
};
return eq_{lhs, rhs};
}

template <class T, type_traits::requires_t<type_traits::is_op_v<T>> = 0>
constexpr auto operator!=(
const T& lhs, const detail::value_location<typename T::value_type>& rhs) {
using neq_t =
ut::detail::neq_<T, detail::value_location<typename T::value_type>>;
struct neq_ : neq_t {
using type = neq_t;
using neq_t::neq_t;
const detail::terse<neq_t> _{*this};
};
return neq_{lhs, rhs};
}

template <class T, type_traits::requires_t<type_traits::is_op_v<T>> = 0>
constexpr auto operator!=(
const detail::value_location<typename T::value_type>& lhs, const T& rhs) {
using neq_t =
ut::detail::neq_<detail::value_location<typename T::value_type>, T>;
struct neq_ : neq_t {
using type = neq_t;
using neq_t::neq_t;
const detail::terse<neq_t> _{*this};
};
return neq_{lhs, rhs};
}

template <class T, type_traits::requires_t<type_traits::is_op_v<T>> = 0>
constexpr auto operator>(
const T& lhs, const detail::value_location<typename T::value_type>& rhs) {
using gt_t =
ut::detail::gt_<T, detail::value_location<typename T::value_type>>;
struct gt_ : gt_t {
using type = gt_t;
using gt_t::gt_t;
const detail::terse<gt_t> _{*this};
};
return gt_{lhs, rhs};
}

template <class T, type_traits::requires_t<type_traits::is_op_v<T>> = 0>
constexpr auto operator>(
const detail::value_location<typename T::value_type>& lhs, const T& rhs) {
using gt_t =
ut::detail::gt_<detail::value_location<typename T::value_type>, T>;
struct gt_ : gt_t {
using type = gt_t;
using gt_t::gt_t;
const detail::terse<gt_t> _{*this};
};
return gt_{lhs, rhs};
}

template <class T, type_traits::requires_t<type_traits::is_op_v<T>> = 0>
constexpr auto operator>=(
const T& lhs, const detail::value_location<typename T::value_type>& rhs) {
using ge_t =
ut::detail::ge_<T, detail::value_location<typename T::value_type>>;
struct ge_ : ge_t {
using type = ge_t;
using ge_t::ge_t;
const detail::terse<ge_t> _{*this};
};
return ge_{lhs, rhs};
}

template <class T, type_traits::requires_t<type_traits::is_op_v<T>> = 0>
constexpr auto operator>=(
const detail::value_location<typename T::value_type>& lhs, const T& rhs) {
using ge_t =
ut::detail::ge_<detail::value_location<typename T::value_type>, T>;
struct ge_ : ge_t {
using type = ge_t;
using ge_t::ge_t;
const detail::terse<ge_t> _{*this};
};
return ge_{lhs, rhs};
}

template <class T, type_traits::requires_t<type_traits::is_op_v<T>> = 0>
constexpr auto operator<(
const T& lhs, const detail::value_location<typename T::value_type>& rhs) {
using lt_t =
ut::detail::lt_<T, detail::value_location<typename T::value_type>>;
struct lt_ : lt_t {
using type = lt_t;
using lt_t::lt_t;
const detail::terse<lt_t> _{*this};
};
return lt_{lhs, rhs};
}

template <class T, type_traits::requires_t<type_traits::is_op_v<T>> = 0>
constexpr auto operator<(
const detail::value_location<typename T::value_type>& lhs, const T& rhs) {
using lt_t =
ut::detail::lt_<detail::value_location<typename T::value_type>, T>;
struct lt_ : lt_t {
using type = lt_t;
using lt_t::lt_t;
const detail::terse<lt_t> _{*this};
};
return lt_{lhs, rhs};
}

template <class T, type_traits::requires_t<type_traits::is_op_v<T>> = 0>
constexpr auto operator<=(
const T& lhs, const detail::value_location<typename T::value_type>& rhs) {
using le_t =
ut::detail::le_<T, detail::value_location<typename T::value_type>>;
struct le_ : le_t {
using type = le_t;
using le_t::le_t;
const detail::terse<le_t> _{*this};
};
return le_{lhs, rhs};
}

template <class T, type_traits::requires_t<type_traits::is_op_v<T>> = 0>
constexpr auto operator<=(
const detail::value_location<typename T::value_type>& lhs, const T& rhs) {
using le_t =
ut::detail::le_<detail::value_location<typename T::value_type>, T>;
struct le_ : le_t {
using type = le_t;
using le_t::le_t;
const detail::terse<le_t> _{*this};
};
return le_{lhs, rhs};
}

template <class TLhs, class TRhs,
type_traits::requires_t<type_traits::is_op_v<TLhs> or
type_traits::is_op_v<TRhs>> = 0>
constexpr auto operator and(const TLhs& lhs, const TRhs& rhs) {
using and_t = ut::detail::and_<TLhs, TRhs>;
using and_t = ut::detail::and_<typename TLhs::type, typename TRhs::type>;
struct and_ : and_t {
using type = and_t;
using and_t::and_t;
const detail::terse<and_t> _{*this};
};
return and_{lhs, rhs};
}

template <class TLhs, class TRhs,
type_traits::requires_t<type_traits::is_op_v<TLhs> or
type_traits::is_op_v<TRhs>> = 0>
constexpr auto operator or(const TLhs& lhs, const TRhs& rhs) {
using or_t = ut::detail::or_<typename TLhs::type, typename TRhs::type>;
struct or_ : or_t {
using type = or_t;
using or_t::or_t;
const detail::terse<or_t> _{*this};
};
return or_{lhs, rhs};
}

template <class T, type_traits::requires_t<type_traits::is_op_v<T>> = 0>
constexpr auto operator not(const T& t) {
using not_t = ut::detail::not_<typename T::type>;
struct not_ : not_t {
using type = not_t;
using not_t::not_t;
const detail::terse<not_t> _{*this};
};
return not_{t};
}

} // namespace terse
} // namespace operators

Expand Down
7 changes: 6 additions & 1 deletion test/ut/ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1419,13 +1419,18 @@ int main() {

42_i == 42;
1 == 2_i;
0_i == 1 and 1_i > 2 or 3 <= 3_i;

test_assert(2 == std::size(test_cfg.assertion_calls));
test_assert(3 == std::size(test_cfg.assertion_calls));

test_assert("42 == 42" == test_cfg.assertion_calls[0].expr);
test_assert(test_cfg.assertion_calls[0].result);

test_assert("1 == 2" == test_cfg.assertion_calls[1].expr);
test_assert(not test_cfg.assertion_calls[1].result);

test_assert("((0 == 1 and 1 > 2) or 3 <= 3)" ==
test_cfg.assertion_calls[2].expr);
test_assert(test_cfg.assertion_calls[2].result);
}
}

0 comments on commit 06a1cf9

Please sign in to comment.