Skip to content

Commit

Permalink
Cleanup in operator-related meta code (modernized, fixed some warnings)
Browse files Browse the repository at this point in the history
  • Loading branch information
nadult committed Nov 26, 2023
1 parent 3ced5af commit 286a566
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 45 deletions.
10 changes: 5 additions & 5 deletions include/fwk/algorithm.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ bool anyOf(const TRange &range, const Functor &functor) {
}

template <c_range TRange, class R, class T = RangeBase<TRange>>
requires(is_same<EqualResult<T, R>, bool>)
requires(equality_comparable<T, R>)
bool anyOf(const TRange &range, const R &ref) {
return std::any_of(begin(range), end(range), [&](const T &val) { return val == ref; });
}
Expand All @@ -88,7 +88,7 @@ bool anyOf(const TRange &range) {
}

template <c_span TSpan, class R, class T = SpanBase<TSpan>>
requires(is_same<EqualResult<T, R>, bool>)
requires(equality_comparable<T, R>)
int indexOf(const TSpan &span, const R &ref) {
for(int i = 0, span_size = fwk::size(span); i < span_size; i++)
if(span[i] == ref)
Expand All @@ -103,13 +103,13 @@ bool allOf(const TRange &range, const Functor &functor) {
}

template <c_range TRange, class R, class T = RangeBase<TRange>>
requires(is_same<EqualResult<T, R>, bool>)
requires(equality_comparable<T, R>)
bool allOf(const TRange &range, const R &ref) {
return std::all_of(begin(range), end(range), [&](const T &val) { return val == ref; });
}

template <class T, c_range R, class U = RangeBase<R>>
requires(equality_comparable<T, U>)
template <class T, c_range R>
requires(equality_comparable<T, RangeBase<R>>)
bool isOneOf(const T &value, const R &range) {
return anyOf(range, value);
}
Expand Down
2 changes: 1 addition & 1 deletion include/fwk/light_tuple.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ namespace detail {

template <class... Args>
constexpr bool operator<(const LightTuple<Args...> &lhs, const LightTuple<Args...> &rhs) {
static_assert((less_comparable<Args> && ...));
static_assert((less_comparable<Args, Args> && ...));
return detail::cmpLess<0>(lhs, rhs);
}

Expand Down
3 changes: 1 addition & 2 deletions include/fwk/meta/iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

#include "fwk/meta/operator.h"
#include "fwk/sys_base.h"
#include <climits>

namespace fwk {

Expand All @@ -15,7 +14,7 @@ constexpr bool is_forward_iter =
equality_comparable<T, T>;

template <class T>
constexpr bool is_random_iter = is_forward_iter<T> && std::is_integral<SubResult<T, T>>::value;
constexpr bool is_random_iter = is_forward_iter<T> && std::is_integral_v<SubResult<T, T>>;

template <class T> using IterBase = RemoveReference<DereferenceResult<T>>;

Expand Down
77 changes: 45 additions & 32 deletions include/fwk/meta/operator.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@

namespace fwk {

template <class L, class R>
concept equality_comparable = requires(const L &l, const R &r) {
{ l == r } -> is_convertible<bool>;
};

template <class L, class R>
concept less_comparable = requires(const L &l, const R &r) {
{ l < r } -> is_convertible<bool>;
};

namespace detail {
template <class L, class R> struct BinaryOps {
FWK_SFINAE_TYPE(Add, L, DECLVAL(const U &) + DECLVAL(const R &));
Expand All @@ -18,89 +28,92 @@ namespace detail {
FWK_SFINAE_TYPE(Apply, L, DECLVAL(const U &)(DECLVAL(const R &)));
};

template <class L, class R> struct CmpOps {
FWK_SFINAE_TYPE(Less, L, DECLVAL(const U &) < DECLVAL(const R &));
FWK_SFINAE_TYPE(Equal, L, DECLVAL(const U &) == DECLVAL(const R &));
};

template <class T> struct UnaryOps {
FWK_SFINAE_TYPE(Dereference, T, *DECLVAL(const U &));
FWK_SFINAE_TYPE(PreIncrement, T, ++DECLVAL(U &));
};

template <class L, class R>
constexpr bool can_auto_compare = is_same<typename CmpOps<L, R>::Less, bool> &&
(!std::is_scalar_v<L> || !std::is_scalar_v<R>);
concept can_auto_compare =
less_comparable<L, R> && (!std::is_scalar_v<L> || !std::is_scalar_v<R>);
}

#define BINARY_OP_RESULT(name, Base) \
template <class L, class R> using name##Result = typename detail::Base<L, R>::name;
#define BINARY_OP_RESULT(name) \
template <class L, class R> using name##Result = typename detail::BinaryOps<L, R>::name;
#define UNARY_OP_RESULT(name) \
template <class T> using name##Result = typename detail::UnaryOps<T>::name;

BINARY_OP_RESULT(Add, BinaryOps)
BINARY_OP_RESULT(Sub, BinaryOps)
BINARY_OP_RESULT(Mul, BinaryOps)
BINARY_OP_RESULT(Div, BinaryOps)
BINARY_OP_RESULT(Or, BinaryOps)
BINARY_OP_RESULT(And, BinaryOps)
BINARY_OP_RESULT(Less, CmpOps)
BINARY_OP_RESULT(Equal, CmpOps)
BINARY_OP_RESULT(Apply, BinaryOps)
BINARY_OP_RESULT(Add)
BINARY_OP_RESULT(Sub)
BINARY_OP_RESULT(Mul)
BINARY_OP_RESULT(Div)
BINARY_OP_RESULT(Or)
BINARY_OP_RESULT(And)
BINARY_OP_RESULT(Apply)
UNARY_OP_RESULT(Dereference)
UNARY_OP_RESULT(PreIncrement)

#undef BINARY_OP_RESULT
#undef UNARY_OP_RESULT

template <class L, class R>
constexpr bool equality_comparable = is_convertible<EqualResult<L, R>, bool>;
template <class T> static constexpr bool less_comparable = is_convertible<LessResult<T, T>, bool>;

// Automatic operators for user types: +=, -=, *=, /=, |=, &=, <=, >=, >, !=

template <class L, class R, EnableIf<is_same<AddResult<L, R>, L> && !std::is_scalar_v<L>>...>
template <class L, class R>
requires(is_same<AddResult<L, R>, L> && !std::is_scalar_v<L>)
void operator+=(L &a, const R &b) {
a = a + b;
}
template <class L, class R, EnableIf<is_same<SubResult<L, R>, L> && !std::is_scalar_v<L>>...>

template <class L, class R>
requires(is_same<SubResult<L, R>, L> && !std::is_scalar_v<L>)
void operator-=(L &a, const R &b) {
a = a - b;
}
template <class L, class R, EnableIf<is_same<MulResult<L, R>, L> && !std::is_scalar_v<L>>...>

template <class L, class R>
requires(is_same<MulResult<L, R>, L> && !std::is_scalar_v<L>)
void operator*=(L &a, const R &b) {
a = a * b;
}
template <class L, class R, EnableIf<is_same<DivResult<L, R>, L> && !std::is_scalar_v<L>>...>

template <class L, class R>
requires(is_same<DivResult<L, R>, L> && !std::is_scalar_v<L>)
void operator/=(L &a, const R &b) {
a = a / b;
}

template <class L, class R, EnableIf<is_same<OrResult<L, R>, L> && !std::is_scalar_v<L>>...>
template <class L, class R>
requires(is_same<OrResult<L, R>, L> && !std::is_scalar_v<L>)
void operator|=(L &a, const R &b) {
a = a | b;
}
template <class L, class R, EnableIf<is_same<AndResult<L, R>, L> && !std::is_scalar_v<L>>...>

template <class L, class R>
requires(is_same<AndResult<L, R>, L> && !std::is_scalar_v<L>)
void operator&=(L &a, const R &b) {
a = a & b;
}

template <class L, class R, EnableIf<detail::can_auto_compare<R, L>>...>
template <class L, class R>
requires(detail::can_auto_compare<R, L>)
bool operator>(const L &a, const R &b) {
return b < a;
}

template <class L, class R, EnableIf<detail::can_auto_compare<L, R>>...>
template <class L, class R>
requires(detail::can_auto_compare<L, R>)
bool operator>=(const L &a, const R &b) {
return !(a < b);
}

template <class L, class R, EnableIf<detail::can_auto_compare<R, L>>...>
template <class L, class R>
requires(detail::can_auto_compare<R, L>)
bool operator<=(const L &a, const R &b) {
return !(b < a);
}

template <class L, class R, EnableIf<equality_comparable<L, R>>...>
template <class L, class R>
requires(equality_comparable<L, R>)
bool operator!=(const L &a, const R &b) {
return !(a == b);
}
Expand Down
5 changes: 2 additions & 3 deletions include/fwk/meta_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,9 @@ using SubtractTypes = typename detail::SubTypes<TFrom, TWhat>::Type;
template <int N, class... Args> using NthType = typename detail::NthType<N, Args...>::type;

template <bool cond, class InvalidArg = DisabledType>
using EnableIf =
typename std::conditional<cond, detail::ValidType, InvalidArg>::type::template Arg<EnabledType>;
using EnableIf = std::conditional_t<cond, detail::ValidType, InvalidArg>::template Arg<EnabledType>;

template <class T1, class T2> constexpr bool is_convertible = std::is_convertible<T1, T2>::value;
template <class T1, class T2> concept is_convertible = std::is_convertible_v<T1, T2>;

// Checks if class is brace constructible: T{Args...}
template <class T, class... Args>
Expand Down
6 changes: 4 additions & 2 deletions include/fwk/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,14 @@ template <class T> class Vector {
operator Span<T>() { return Span<T>(data(), m_base.size); }
operator CSpan<T>() const { return CSpan<T>(data(), m_base.size); }

template <class U = T, EnableIf<equality_comparable<U, U>>...>
template <class U = T>
requires(equality_comparable<U, U>)
bool operator==(const Vector &rhs) const {
return size() == rhs.size() && std::equal(begin(), end(), rhs.begin(), rhs.end());
}

template <class U = T, EnableIf<less_comparable<U>>...>
template <class U = T>
requires(less_comparable<U, U>)
bool operator<(const Vector &rhs) const {
return std::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end());
}
Expand Down

0 comments on commit 286a566

Please sign in to comment.