Skip to content

Commit d70e6bc

Browse files
committed
moving_ref committed with tests
1 parent d2c65c0 commit d70e6bc

File tree

4 files changed

+191
-1
lines changed

4 files changed

+191
-1
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#ifndef LEFTICUS_TOOLS_MOVING_REF_HPP
2+
#define LEFTICUS_TOOLS_MOVING_REF_HPP
3+
4+
#include <type_traits>
5+
#include <utility>
6+
7+
namespace lefticus {
8+
9+
10+
#ifdef __cpp_concepts
11+
template<class P>
12+
struct DetectMoveConstruction
13+
{
14+
constexpr operator P const&();
15+
constexpr operator P&&();
16+
};
17+
18+
template<typename T>
19+
concept copyable_xor_moveable = requires (T t, DetectMoveConstruction<T> m) {
20+
// borrowed from https://stackoverflow.com/questions/51901837/how-to-get-if-a-type-is-truly-move-constructible/51912859#51912859
21+
// if this line below compiles then we know we only have either
22+
// a move assignment or a copy assignment, otherwise
23+
// it would be ambiguous
24+
// we cannot detect the constructor because MSVC
25+
// seems to have a bug, but we can detect assignment!
26+
t = m;
27+
};
28+
29+
template<typename T>
30+
concept has_move_ctor =
31+
std::move_constructible<T> && !copyable_xor_moveable<T>;
32+
#endif
33+
34+
35+
36+
#ifdef __cpp_concepts
37+
template<has_move_ctor T>
38+
#else
39+
template<typename T>
40+
#endif
41+
42+
struct moving_ref {
43+
constexpr moving_ref(T &&val) : ref{std::move(val)} {}
44+
constexpr operator T&&() {
45+
return std::move(ref);
46+
}
47+
T &&ref;
48+
};
49+
50+
}
51+
52+
#endif
53+

test/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ add_constexpr_test_executables(
8383
simple_stack_string_tests.cpp
8484
flat_map_tests.cpp
8585
type_lists_tests.cpp
86-
strong_types_tests.cpp)
86+
strong_types_tests.cpp
87+
moving_ref.cpp)
8788
target_link_libraries(
8889
"constexpr_tests"
8990
PRIVATE lefticus::tools
@@ -132,3 +133,4 @@ test_header_compiles(static_views.hpp)
132133
test_header_compiles(utility.hpp)
133134
test_header_compiles(strong_types.hpp)
134135
test_header_compiles(type_lists.hpp)
136+
test_header_compiles(moving_ref.hpp)

test/curry_tests.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ TEST_CASE("[curry] lambda")
1717
STATIC_REQUIRE(lefticus::tools::curry(func)(1, 2, 3) == 6);
1818
STATIC_REQUIRE(lefticus::tools::curry(func, 1)(2, 3) == 6);
1919
STATIC_REQUIRE(lefticus::tools::curry(func, 1, 2)(3) == 6);
20+
STATIC_REQUIRE(lefticus::tools::curry(func, 1, 2, 3) == 6);
2021
}

test/moving_ref.cpp

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#include <catch2/catch.hpp>
2+
#include <lefticus/tools/moving_ref.hpp>
3+
4+
#ifdef CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
5+
#define CONSTEXPR
6+
#else
7+
// NOLINTNEXTLINE
8+
#define CONSTEXPR constexpr
9+
#endif
10+
11+
12+
13+
#include <string>
14+
15+
16+
struct CountsMovesCopies
17+
{
18+
constexpr CountsMovesCopies() = default;
19+
constexpr CountsMovesCopies(CountsMovesCopies &&other) noexcept {
20+
++other.move_constructed_from;
21+
}
22+
constexpr CountsMovesCopies(const CountsMovesCopies &other) noexcept {
23+
++other.copy_constructed_from;
24+
}
25+
26+
constexpr CountsMovesCopies &operator=(CountsMovesCopies &&other) noexcept {
27+
++other.move_assigned_from;
28+
return *this;
29+
}
30+
31+
constexpr CountsMovesCopies &operator=(const CountsMovesCopies &other) noexcept {
32+
++other.copy_assigned_from;
33+
return *this;
34+
}
35+
36+
mutable int move_constructed_from = 0;
37+
mutable int copy_constructed_from = 0;
38+
mutable int move_assigned_from = 0;
39+
mutable int copy_assigned_from = 0;
40+
41+
};
42+
43+
struct CopyOnlyType
44+
{
45+
~CopyOnlyType() = default;
46+
};
47+
48+
49+
50+
template <typename T>
51+
constexpr auto can_construct_ref() {
52+
return requires(T mct) {
53+
lefticus::moving_ref<T>{std::move(mct)};
54+
};
55+
}
56+
57+
template <typename T>
58+
constexpr auto can_construct_ref_const() {
59+
return requires(const T mct) {
60+
lefticus::moving_ref<T>{std::move(mct)};
61+
};
62+
}
63+
64+
template <typename T>
65+
constexpr auto can_assign() {
66+
return requires(T lhs, T mct) {
67+
lhs = lefticus::moving_ref<T>{std::move(mct)};
68+
};
69+
}
70+
71+
72+
template <typename T>
73+
constexpr auto can_assign_const() {
74+
return requires(T lhs, const T mct) {
75+
lhs = lefticus::moving_ref<T>{std::move(mct)};
76+
};
77+
}
78+
79+
template <typename T>
80+
constexpr auto can_construct() {
81+
return requires(T mct) {
82+
T{lefticus::moving_ref<T>{std::move(mct)}};
83+
};
84+
}
85+
86+
87+
template <typename T>
88+
constexpr auto can_construct_const() {
89+
return requires(const T mct) {
90+
T{lefticus::moving_ref<T>{std::move(mct)}};
91+
};
92+
}
93+
94+
95+
96+
TEST_CASE("[moving_ref] behaves as expected")
97+
{
98+
constexpr auto implicit_move = [](){
99+
CountsMovesCopies cmc;
100+
lefticus::moving_ref mr{std::move(cmc)};
101+
[[maybe_unused]] CountsMovesCopies cmc2 = mr;
102+
103+
return cmc.move_constructed_from;
104+
};
105+
106+
STATIC_REQUIRE(implicit_move() == 1);
107+
108+
constexpr auto implicit_move_assign = [](){
109+
CountsMovesCopies cmc;
110+
lefticus::moving_ref mr{std::move(cmc)};
111+
CountsMovesCopies cmc2;
112+
cmc2 = mr;
113+
114+
return cmc.move_assigned_from;
115+
};
116+
117+
STATIC_REQUIRE(implicit_move_assign() == 1);
118+
119+
STATIC_REQUIRE(can_construct_ref<CountsMovesCopies>());
120+
STATIC_REQUIRE(!can_construct_ref_const<CountsMovesCopies>());
121+
STATIC_REQUIRE(can_assign<CountsMovesCopies>());
122+
STATIC_REQUIRE(!can_assign_const<CountsMovesCopies>());
123+
STATIC_REQUIRE(can_construct<CountsMovesCopies>());
124+
STATIC_REQUIRE(!can_construct_const<CountsMovesCopies>());
125+
126+
STATIC_REQUIRE(!can_construct_ref<CopyOnlyType>());
127+
STATIC_REQUIRE(!can_construct_ref_const<CopyOnlyType>());
128+
STATIC_REQUIRE(!can_assign<CopyOnlyType>());
129+
STATIC_REQUIRE(!can_assign_const<CopyOnlyType>());
130+
STATIC_REQUIRE(!can_construct<CopyOnlyType>());
131+
STATIC_REQUIRE(!can_construct_const<CopyOnlyType>());
132+
133+
134+
}

0 commit comments

Comments
 (0)