Skip to content

Commit c0086ee

Browse files
committed
Enable tombstone_traits for trivial_inplace_function
1 parent afe031a commit c0086ee

File tree

2 files changed

+130
-74
lines changed

2 files changed

+130
-74
lines changed

source/containers/test/trivial_inplace_function.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,95 @@
88

99
import containers.trivial_inplace_function;
1010

11+
import containers.array;
12+
13+
import bounded;
14+
import std_module;
15+
1116
namespace {
17+
using namespace bounded::literal;
1218

19+
using empty_const_function = containers::trivial_inplace_function<int() const, 0>;
1320
using const_function = containers::trivial_inplace_function<int() const, 24>;
21+
using empty_mutable_function = containers::trivial_inplace_function<int(), 0>;
1422
using mutable_function = containers::trivial_inplace_function<int(), 24>;
1523

24+
static_assert(std::is_trivially_copyable_v<empty_const_function>);
25+
static_assert(std::is_trivially_copyable_v<const_function>);
26+
static_assert(std::is_trivially_copyable_v<empty_mutable_function>);
27+
static_assert(std::is_trivially_copyable_v<mutable_function>);
28+
29+
static_assert(std::invocable<empty_const_function const &>);
30+
static_assert(std::invocable<const_function const &>);
31+
static_assert(std::invocable<empty_const_function &>);
32+
static_assert(std::invocable<const_function &>);
33+
34+
static_assert(!std::invocable<empty_mutable_function const &>);
35+
static_assert(!std::invocable<mutable_function const &>);
36+
static_assert(std::invocable<empty_mutable_function &>);
37+
static_assert(std::invocable<mutable_function &>);
38+
1639
constexpr auto normal_function() -> int {
1740
return 2;
1841
}
42+
static_assert(empty_const_function(normal_function)() == 2);
43+
static_assert(bounded::constructible_from<const_function, int(*)()>);
44+
static_assert(empty_mutable_function(normal_function)() == 2);
45+
static_assert(bounded::constructible_from<const_function, int(*)()>);
46+
47+
static_assert(!bounded::constructible_from<empty_const_function, void(*)()>);
48+
static_assert(!bounded::constructible_from<const_function, void(*)()>);
49+
static_assert(!bounded::constructible_from<empty_const_function, long(*)()>);
50+
static_assert(!bounded::constructible_from<const_function, long(*)()>);
51+
52+
template<std::size_t size>
53+
struct sized_function {
54+
[[no_unique_address]] containers::array<std::byte, bounded::constant<size>> a;
55+
auto operator()() const {
56+
return 1;
57+
}
58+
};
59+
60+
static_assert(bounded::constructible_from<empty_const_function, sized_function<0>>);
61+
static_assert(bounded::constructible_from<const_function, sized_function<0>>);
62+
static_assert(bounded::constructible_from<empty_mutable_function, sized_function<0>>);
63+
static_assert(bounded::constructible_from<mutable_function, sized_function<0>>);
64+
65+
static_assert(!bounded::constructible_from<empty_const_function, sized_function<24>>);
66+
static_assert(bounded::constructible_from<const_function, sized_function<24>>);
67+
static_assert(!bounded::constructible_from<empty_mutable_function, sized_function<24>>);
68+
static_assert(bounded::constructible_from<mutable_function, sized_function<24>>);
69+
70+
static_assert(!bounded::constructible_from<empty_const_function, sized_function<25>>);
71+
static_assert(!bounded::constructible_from<const_function, sized_function<25>>);
72+
static_assert(!bounded::constructible_from<empty_mutable_function, sized_function<25>>);
73+
static_assert(!bounded::constructible_from<mutable_function, sized_function<25>>);
74+
75+
static_assert(sizeof(containers::trivial_inplace_function<void() const, 0>) == sizeof(void(*)()));
76+
77+
constexpr auto returns_five = empty_const_function([] { return 5; });
78+
static_assert(returns_five() == 5);
79+
80+
[[maybe_unused]] void test_lambdas() {
81+
constexpr auto empty_capture_lambda = [=]{};
82+
using empty_capture_lambda_t = decltype(empty_capture_lambda);
83+
static_assert(std::is_empty_v<empty_capture_lambda_t>);
84+
static_assert(!bounded::trivially_default_constructible<empty_capture_lambda_t>);
85+
static_assert(!bounded::constructible_from<empty_const_function, empty_capture_lambda_t>);
86+
87+
constexpr auto non_empty_lambda = [x = 0]{ static_cast<void>(x); };
88+
using non_empty_lambda_t = decltype(non_empty_lambda);
89+
static_assert(!std::is_empty_v<non_empty_lambda_t>);
90+
static_assert(!bounded::constructible_from<empty_const_function, non_empty_lambda_t>);
91+
}
92+
93+
using tombstone_traits = bounded::tombstone_traits<
94+
containers::trivial_inplace_function<void() const, 0>
95+
>;
96+
static_assert(tombstone_traits::spare_representations == 1_bi);
97+
static_assert(tombstone_traits::index(tombstone_traits::make(0_bi)) == 0_bi);
98+
static_assert(tombstone_traits::index([]{}) == -1_bi);
99+
19100
constexpr auto big_returns_five = const_function([] { return 5; });
20101

21102
TEST_CASE("trivial_inplace_function lambda", "[trivial_inplace_function]") {

source/containers/trivial_inplace_function.cpp

Lines changed: 49 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module;
22

3+
#include <bounded/conditional.hpp>
34
#include <operators/forward.hpp>
45

56
export module containers.trivial_inplace_function;
@@ -131,10 +132,13 @@ struct trivial_inplace_function_impl {
131132
}
132133
}
133134

135+
constexpr explicit trivial_inplace_function_impl(bounded::tombstone_tag):
136+
m_function_indirection(nullptr)
137+
{
138+
}
139+
140+
friend bounded::tombstone_traits<trivial_inplace_function_impl>;
134141
public:
135-
// I would prefer that this not be default constructible. However, that
136-
// would mean it could not be stored in a constexpr static_vector
137-
trivial_inplace_function_impl() = default;
138142

139143
constexpr trivial_inplace_function_impl(trivially_storable<capacity, alignment, R, Args...> auto function):
140144
m_storage(make_storage(function)),
@@ -158,6 +162,25 @@ struct trivial_inplace_function_impl {
158162
}
159163
};
160164

165+
} // namespace containers
166+
167+
template<bool is_const, std::size_t capacity, std::size_t alignment, typename R, typename... Args>
168+
struct bounded::tombstone_traits<containers::trivial_inplace_function_impl<is_const, capacity, alignment, R, Args...>> {
169+
private:
170+
using T = containers::trivial_inplace_function_impl<is_const, capacity, alignment, R, Args...>;
171+
public:
172+
static constexpr auto spare_representations = 1_bi;
173+
174+
static constexpr auto make(bounded::constant_t<0>) noexcept {
175+
return T(bounded::tombstone_tag());
176+
}
177+
static constexpr auto index(T const & value) noexcept {
178+
return BOUNDED_CONDITIONAL(value.m_function_indirection, -1_bi, 0_bi);
179+
}
180+
};
181+
182+
namespace containers {
183+
161184
// If your function type is convertible to a function pointer, calling through
162185
// the function must have the same semantics as calling through the function
163186
// pointer.
@@ -174,8 +197,13 @@ struct trivial_inplace_function<R(Args...), capacity, alignment> :
174197
{
175198
private:
176199
using base = trivial_inplace_function_impl<false, capacity, alignment, R, Args...>;
200+
friend bounded::tombstone_traits<trivial_inplace_function>;
177201
public:
178202
using base::base;
203+
constexpr explicit trivial_inplace_function(base && b) noexcept:
204+
base(std::move(b))
205+
{
206+
}
179207
using base::operator();
180208
};
181209

@@ -185,83 +213,30 @@ struct trivial_inplace_function<R(Args...) const, capacity, alignment> :
185213
{
186214
private:
187215
using base = trivial_inplace_function_impl<true, capacity, alignment, R, Args...>;
216+
friend bounded::tombstone_traits<trivial_inplace_function>;
188217
public:
189218
using base::base;
219+
constexpr explicit trivial_inplace_function(base && b) noexcept:
220+
base(std::move(b))
221+
{
222+
}
190223
using base::operator();
191224
};
192225

193226
} // namespace containers
194227

195-
using empty_const_function = containers::trivial_inplace_function<int() const, 0>;
196-
using const_function = containers::trivial_inplace_function<int() const, 24>;
197-
using empty_mutable_function = containers::trivial_inplace_function<int(), 0>;
198-
using mutable_function = containers::trivial_inplace_function<int(), 24>;
199-
200-
static_assert(std::is_trivially_copyable_v<empty_const_function>);
201-
static_assert(std::is_trivially_copyable_v<const_function>);
202-
static_assert(std::is_trivially_copyable_v<empty_mutable_function>);
203-
static_assert(std::is_trivially_copyable_v<mutable_function>);
204-
205-
static_assert(std::invocable<empty_const_function const &>);
206-
static_assert(std::invocable<const_function const &>);
207-
static_assert(std::invocable<empty_const_function &>);
208-
static_assert(std::invocable<const_function &>);
209-
210-
static_assert(!std::invocable<empty_mutable_function const &>);
211-
static_assert(!std::invocable<mutable_function const &>);
212-
static_assert(std::invocable<empty_mutable_function &>);
213-
static_assert(std::invocable<mutable_function &>);
214-
215-
constexpr auto normal_function() -> int {
216-
return 2;
217-
}
218-
static_assert(empty_const_function(normal_function)() == 2);
219-
static_assert(bounded::constructible_from<const_function, int(*)()>);
220-
static_assert(empty_mutable_function(normal_function)() == 2);
221-
static_assert(bounded::constructible_from<const_function, int(*)()>);
222-
223-
static_assert(!bounded::constructible_from<empty_const_function, void(*)()>);
224-
static_assert(!bounded::constructible_from<const_function, void(*)()>);
225-
static_assert(!bounded::constructible_from<empty_const_function, long(*)()>);
226-
static_assert(!bounded::constructible_from<const_function, long(*)()>);
227-
228-
template<std::size_t size>
229-
struct sized_function {
230-
[[no_unique_address]] containers::array<std::byte, bounded::constant<size>> a;
231-
auto operator()() const {
232-
return 1;
228+
template<containers::function_signature Signature, std::size_t capacity, std::size_t alignment>
229+
struct bounded::tombstone_traits<containers::trivial_inplace_function<Signature, capacity, alignment>> {
230+
private:
231+
using T = containers::trivial_inplace_function<Signature, capacity, alignment>;
232+
using base = tombstone_traits<typename T::base>;
233+
public:
234+
static constexpr auto spare_representations = base::spare_representations;
235+
236+
static constexpr auto make(bounded::constant_t<0>) noexcept {
237+
return T(base::make(0_bi));
238+
}
239+
static constexpr auto index(T const & value) noexcept {
240+
return base::index(value);
233241
}
234242
};
235-
236-
static_assert(bounded::constructible_from<empty_const_function, sized_function<0>>);
237-
static_assert(bounded::constructible_from<const_function, sized_function<0>>);
238-
static_assert(bounded::constructible_from<empty_mutable_function, sized_function<0>>);
239-
static_assert(bounded::constructible_from<mutable_function, sized_function<0>>);
240-
241-
static_assert(!bounded::constructible_from<empty_const_function, sized_function<24>>);
242-
static_assert(bounded::constructible_from<const_function, sized_function<24>>);
243-
static_assert(!bounded::constructible_from<empty_mutable_function, sized_function<24>>);
244-
static_assert(bounded::constructible_from<mutable_function, sized_function<24>>);
245-
246-
static_assert(!bounded::constructible_from<empty_const_function, sized_function<25>>);
247-
static_assert(!bounded::constructible_from<const_function, sized_function<25>>);
248-
static_assert(!bounded::constructible_from<empty_mutable_function, sized_function<25>>);
249-
static_assert(!bounded::constructible_from<mutable_function, sized_function<25>>);
250-
251-
static_assert(sizeof(containers::trivial_inplace_function<void() const, 0>) == sizeof(void(*)()));
252-
253-
constexpr auto returns_five = empty_const_function([] { return 5; });
254-
static_assert(returns_five() == 5);
255-
256-
[[maybe_unused]] void test_lambdas() {
257-
constexpr auto empty_capture_lambda = [=]{};
258-
using empty_capture_lambda_t = decltype(empty_capture_lambda);
259-
static_assert(std::is_empty_v<empty_capture_lambda_t>);
260-
static_assert(!bounded::trivially_default_constructible<empty_capture_lambda_t>);
261-
static_assert(!bounded::constructible_from<empty_const_function, empty_capture_lambda_t>);
262-
263-
constexpr auto non_empty_lambda = [x = 0]{ static_cast<void>(x); };
264-
using non_empty_lambda_t = decltype(non_empty_lambda);
265-
static_assert(!std::is_empty_v<non_empty_lambda_t>);
266-
static_assert(!bounded::constructible_from<empty_const_function, non_empty_lambda_t>);
267-
}

0 commit comments

Comments
 (0)