Skip to content

Commit 21e19c3

Browse files
committed
behaves like builtin
1 parent 89a2cc8 commit 21e19c3

File tree

2 files changed

+48
-34
lines changed

2 files changed

+48
-34
lines changed

include/libfork/ev.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
#pragma once
22

3+
#include <concepts>
34
#include <memory>
45
#include <optional>
56
#include <type_traits>
67
#include <utility>
78

9+
#include "libfork/macros/assert.hpp"
810
#include "libfork/macros/utility.hpp"
911
#include "libfork/utility.hpp"
1012

@@ -22,8 +24,7 @@ namespace lf {
2224
* @tparam T The type to test.
2325
*/
2426
template <typename T>
25-
concept trivial_return =
26-
std::is_trivially_default_constructible_v<T> && std::is_trivially_destructible_v<T>;
27+
concept trivial_return = std::default_initializable<T> && std::is_trivially_destructible_v<T>;
2728

2829
/**
2930
* @brief A wrapper for return values from libfork's coroutines.
@@ -43,14 +44,14 @@ class ev : detail::immovable<ev<T>> {
4344
template <typename Self>
4445
[[nodiscard]] constexpr auto operator->(this Self &self) LF_HOF_RETURNS(self.m_value.operator->())
4546

46-
private:
4747
template <typename... Args>
4848
requires std::constructible_from<T, Args...>
4949
constexpr void emplace(Args &&...args) & {
5050
LF_ASSERT(!m_value.has_value());
5151
m_value.emplace(std::forward<Args>(args)...);
5252
}
5353

54+
private:
5455
std::optional<T> m_value;
5556
};
5657

@@ -76,9 +77,9 @@ class ev<T> : detail::immovable<ev<T>> {
7677
// return std::addressof(m_value);
7778
// }
7879

79-
private:
8080
constexpr auto get() & -> T * { return std::addressof(m_value); }
8181

82+
private:
8283
T m_value;
8384
};
8485

test/src/test_ev.cpp

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11

2+
#include <memory>
23
#include <type_traits>
34

45
#include <catch2/catch_template_test_macros.hpp>
@@ -8,56 +9,68 @@
89

910
namespace {
1011

11-
template <typename T>
12-
concept good_deref = requires (lf::ev<T> val, T ref) {
12+
template <typename T, typename Ref>
13+
concept deref_like = requires (T val, Ref ref) {
1314
{ *val } -> std::same_as<decltype((ref))>;
15+
{ *std::move(val) } -> std::same_as<decltype(std::move(ref))>;
1416
};
1517

16-
template <typename T>
17-
struct add_const : std::type_identity<T const> {};
18+
struct non_trivial {
19+
constexpr ~non_trivial() {}
20+
};
1821

19-
template <typename T>
20-
struct add_const<T &> : std::type_identity<T const &> {};
22+
static_assert(!lf::trivial_return<non_trivial>);
2123

22-
template <typename T>
23-
struct add_const<T &&> : std::type_identity<T const &&> {};
24+
consteval auto const_test() -> bool {
2425

25-
template <typename T>
26-
concept good_decref = requires (lf::ev<T> const val, typename add_const<T>::type ref) {
27-
{ *val } -> std::same_as<decltype((ref))>;
28-
};
26+
{
27+
lf::ev<non_trivial const> x;
28+
x.emplace();
29+
}
2930

30-
struct nt {
31-
nt() {}
32-
};
31+
{
32+
lf::ev<int> x;
33+
int const *p = x.get();
34+
std::construct_at(p, 3);
35+
}
3336

34-
static_assert(!lf::trivial_return<nt>);
37+
return true;
38+
}
3539

3640
} // namespace
3741

38-
TEMPLATE_TEST_CASE("Ev operator *", "[ev]", nt, int, int &, int &&, int const &, int const &&) {
42+
TEST_CASE("Ev constexpr tests", "[ev]") { REQUIRE(const_test()); }
3943

40-
using U = std::remove_reference_t<TestType>;
44+
TEMPLATE_TEST_CASE("Ev operator *", "[ev]", non_trivial, int) {
4145

42-
static_assert(good_deref<TestType>);
43-
static_assert(good_decref<TestType>);
46+
using lf::ev;
4447

45-
lf::ev<TestType> val{};
46-
static_assert(std::same_as<decltype(*val), U &>);
47-
static_assert(std::same_as<decltype(*std::move(val)), U &&>);
48+
static_assert(deref_like<ev<TestType>, TestType>);
49+
static_assert(deref_like<ev<TestType> const, TestType const>);
4850

49-
lf::ev<TestType> const cval{};
50-
static_assert(std::same_as<decltype(*cval), U const &>);
51-
static_assert(std::same_as<decltype(*std::move(cval)), U const &&>);
51+
static_assert(deref_like<ev<TestType const>, TestType const>);
52+
static_assert(deref_like<ev<TestType const> const, TestType const>);
53+
54+
static_assert(deref_like<ev<TestType &>, TestType &>);
55+
static_assert(deref_like<ev<TestType &> const, TestType const &>);
56+
57+
static_assert(deref_like<ev<TestType const &>, TestType const &>);
58+
static_assert(deref_like<ev<TestType const &> const, TestType const &>);
59+
60+
static_assert(deref_like<ev<TestType &&>, TestType &&>);
61+
static_assert(deref_like<ev<TestType &&> const, TestType const &&>);
62+
63+
static_assert(deref_like<ev<TestType const &&>, TestType const &&>);
64+
static_assert(deref_like<ev<TestType const &&> const, TestType const &&>);
5265
}
5366

54-
TEMPLATE_TEST_CASE("Eventually operator ->", "[ev]", nt, int, int &) {
67+
TEMPLATE_TEST_CASE("Eventually operator ->", "[ev]", non_trivial, non_trivial &, int, int &) {
5568

56-
using U = std::remove_reference_t<TestType>;
69+
using deref = std::remove_reference_t<TestType>;
5770

5871
lf::ev<TestType> val{};
59-
static_assert(std::same_as<decltype(val.operator->()), U *>);
72+
static_assert(std::same_as<decltype(val.operator->()), deref *>);
6073

6174
lf::ev<TestType> const cval{};
62-
static_assert(std::same_as<decltype(cval.operator->()), U const *>);
75+
static_assert(std::same_as<decltype(cval.operator->()), deref const *>);
6376
}

0 commit comments

Comments
 (0)