Skip to content

Commit f79efdb

Browse files
New operators.hpp utilities
1 parent f5e1d02 commit f79efdb

File tree

2 files changed

+166
-0
lines changed

2 files changed

+166
-0
lines changed

src/bsoncxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ set_dist_list(src_bsoncxx_include_DIST
5858
bsoncxx/v_noabi/bsoncxx/oid.hpp
5959
bsoncxx/v_noabi/bsoncxx/stdx/make_unique.hpp
6060
bsoncxx/v_noabi/bsoncxx/stdx/optional.hpp
61+
bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp
6162
bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp
6263
bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp
6364
bsoncxx/v_noabi/bsoncxx/string/to_string.hpp
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
#pragma once
2+
3+
#include <cstddef>
4+
#include <functional>
5+
#include <type_traits>
6+
7+
#include "./type_traits.hpp"
8+
9+
#include <bsoncxx/config/prelude.hpp>
10+
11+
namespace bsoncxx {
12+
inline namespace v_noabi {
13+
namespace detail {
14+
15+
/**
16+
* @brief Detect whether two types are equality-comparable.
17+
*
18+
* Requires L == R, L != R, R == L, and R != L
19+
*/
20+
template <typename L, typename R, typename = void>
21+
struct is_equality_comparable : std::false_type {};
22+
23+
template <typename L, typename R>
24+
struct is_equality_comparable<
25+
L,
26+
R,
27+
void_t<decltype(std::declval<const_reference_t<L>>() == std::declval<const_reference_t<R>>()),
28+
decltype(std::declval<const_reference_t<L>>() != std::declval<const_reference_t<R>>()),
29+
decltype(std::declval<const_reference_t<R>>() == std::declval<const_reference_t<L>>()),
30+
decltype(std::declval<const_reference_t<R>>() != std::declval<const_reference_t<L>>())>>
31+
: std::true_type {};
32+
33+
/**
34+
* @brief Callable object and tag type for equality comparison
35+
*
36+
*/
37+
struct equal_to {
38+
template <typename L, typename R>
39+
constexpr requires_t<bool, is_equality_comparable<L, R>> //
40+
operator()(L&& l, R&& r) const noexcept(noexcept(l == r)) {
41+
return l == r;
42+
}
43+
};
44+
45+
/**
46+
* @brief Derive from this class to define ADL-only operator== and operator!= on the basis of
47+
* an ADL-only tag_invoke(equal_to, l, r)
48+
*/
49+
class equality_operators {
50+
template <typename Left, typename Other>
51+
constexpr friend auto operator==(const Left& self, const Other& other)
52+
bsoncxx_returns(tag_invoke(equal_to{}, self, other));
53+
54+
template <typename Left, typename Other>
55+
constexpr friend auto operator!=(const Left& self, const Other& other)
56+
bsoncxx_returns(!tag_invoke(equal_to{}, self, other));
57+
};
58+
59+
/**
60+
* @brief Very basic impl of C++20 std::strong_ordering
61+
*
62+
* We don't need other weaker orderings yet, so this is all that we have
63+
*/
64+
class strong_ordering {
65+
signed char _c;
66+
struct _construct {};
67+
68+
constexpr strong_ordering(_construct, signed char c) noexcept : _c(c) {}
69+
70+
public:
71+
static const strong_ordering less;
72+
static const strong_ordering greater;
73+
static const strong_ordering equivalent;
74+
static const strong_ordering equal;
75+
76+
constexpr strong_ordering(std::nullptr_t) noexcept : strong_ordering(_construct{}, 0) {}
77+
78+
constexpr bool operator==(strong_ordering o) const noexcept {
79+
return _c == o._c;
80+
}
81+
constexpr bool operator!=(strong_ordering o) const noexcept {
82+
return !(*this == o);
83+
}
84+
85+
#define DEFOP(Op) \
86+
constexpr bool operator Op(std::nullptr_t) const noexcept { \
87+
return _c Op 0; \
88+
} \
89+
static_assert(true, "")
90+
DEFOP(<);
91+
DEFOP(>);
92+
DEFOP(<=);
93+
DEFOP(>=);
94+
#undef DEFOP
95+
};
96+
97+
#ifdef __GNUC__
98+
#define psuedo_inline [[gnu::weak]]
99+
#elif defined _MSC_VER
100+
#define psuedo_inline __declspec(selectany)
101+
#else
102+
#define pseudo_inline
103+
#endif
104+
105+
psuedo_inline const strong_ordering strong_ordering::less =
106+
strong_ordering(strong_ordering::_construct{}, -1);
107+
psuedo_inline const strong_ordering strong_ordering::greater =
108+
strong_ordering(strong_ordering::_construct{}, 1);
109+
psuedo_inline const strong_ordering strong_ordering::equivalent =
110+
strong_ordering(strong_ordering::_construct{}, 0);
111+
psuedo_inline const strong_ordering strong_ordering::equal =
112+
strong_ordering(strong_ordering::_construct{}, 0);
113+
114+
#undef psuedo_inline
115+
116+
/**
117+
* @brief Implements a three-way comparison between two objects. That is, in
118+
* a single operation, determine whether the left operand is less-than, greater-than,
119+
* or equal-to the right-hand operand.
120+
*/
121+
struct compare_three_way {
122+
template <typename L,
123+
typename R,
124+
typename = decltype(std::declval<L>() < std::declval<R>()),
125+
typename = decltype(std::declval<L>() == std::declval<R>())>
126+
constexpr static strong_ordering impl(L const& l, R const& r, rank<1>) {
127+
return (l < r) ? strong_ordering::less
128+
: (l == r ? strong_ordering::equal //
129+
: strong_ordering::greater);
130+
}
131+
132+
template <typename L,
133+
typename R,
134+
typename = decltype(tag_invoke(
135+
std::declval<compare_three_way>(), std::declval<L>(), std::declval<R>()))>
136+
constexpr strong_ordering impl(L const& l, R const& r, rank<2>) const {
137+
return tag_invoke(*this, l, r);
138+
}
139+
140+
template <typename L, typename R>
141+
constexpr auto operator()(L const& l, R const& r) const
142+
bsoncxx_returns((impl)(l, r, rank<2>{}));
143+
};
144+
145+
/**
146+
* @brief Inherit to define ADL-visible ordering operators based on an ADL-visible
147+
* implementation of tag_invoke(compare_three_way, l, r)
148+
*/
149+
struct ordering_operators {
150+
#define DEFOP(Oper) \
151+
template <typename L, typename R> \
152+
constexpr friend auto operator Oper(const L& l, const R& r) \
153+
bsoncxx_returns(tag_invoke(compare_three_way{}, l, r) Oper 0)
154+
DEFOP(<);
155+
DEFOP(>);
156+
DEFOP(<=);
157+
DEFOP(>=);
158+
#undef DEFOP
159+
};
160+
161+
} // namespace detail
162+
} // namespace v_noabi
163+
} // namespace bsoncxx
164+
165+
#include <bsoncxx/config/postlude.hpp>

0 commit comments

Comments
 (0)