Skip to content

Commit f1b340d

Browse files
committed
Use placement new instead of std::construct_at. This allows me to get rid of the superconstructing_super_elider and no_lazy_construction. In other words, it compiles faster with less code and no edge cases.
1 parent 61a70a7 commit f1b340d

File tree

4 files changed

+7
-81
lines changed

4 files changed

+7
-81
lines changed

source/bounded/construct_at.cpp

Lines changed: 3 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -17,53 +17,11 @@ import std_module;
1717

1818
namespace bounded {
1919

20-
// https://quuxplusone.github.io/blog/2018/05/17/super-elider-round-2/
21-
template<typename T, typename Function>
22-
struct superconstructing_super_elider {
23-
static_assert(std::is_reference_v<Function>);
24-
25-
constexpr explicit superconstructing_super_elider(Function function) noexcept:
26-
m_function(OPERATORS_FORWARD(function))
27-
{
28-
}
29-
30-
// Deleting the move constructor limits the cases where this will silently
31-
// collide with an "accepts anything" constructor. For instance, this class
32-
// can be used with std::any.
33-
superconstructing_super_elider(superconstructing_super_elider &&) = delete;
34-
35-
constexpr operator T() && noexcept(noexcept(static_cast<T>(declval<Function>()()))) {
36-
return static_cast<T>(OPERATORS_FORWARD(m_function)());
37-
}
38-
39-
private:
40-
Function m_function;
41-
};
42-
43-
template<typename T>
44-
constexpr auto is_no_lazy_construction = false;
45-
46-
template<typename T>
47-
constexpr auto is_no_lazy_construction<no_lazy_construction<T>> = true;
48-
49-
template<typename T, typename Function>
50-
constexpr auto is_noexcept_construct_at = noexcept(static_cast<T>(declval<Function>()()));
51-
52-
template<typename T, typename Function> requires is_no_lazy_construction<std::invoke_result_t<Function>>
53-
constexpr auto is_noexcept_construct_at<T, Function> = noexcept(static_cast<T>(declval<Function>()().value));
54-
5520
// https://github.com/llvm/llvm-project/issues/59513
5621
struct construct_at_t {
5722
template<non_const T, construct_function_for<T> Function>
58-
static constexpr auto operator()(T & ref, Function && function) noexcept(is_noexcept_construct_at<T, Function>) -> T & {
59-
auto make = [&] {
60-
if constexpr (is_no_lazy_construction<std::invoke_result_t<Function>>) {
61-
return OPERATORS_FORWARD(function)().value;
62-
} else {
63-
return superconstructing_super_elider<T, Function &&>(OPERATORS_FORWARD(function));
64-
}
65-
};
66-
return *std::construct_at(std::addressof(ref), make());
23+
static constexpr auto operator()(T & ref, Function && function) noexcept(noexcept(static_cast<T>(declval<Function>()()))) -> T & {
24+
return *::new(static_cast<void *>(std::addressof(ref))) T(std::invoke(OPERATORS_FORWARD(function)));
6725
}
6826
};
6927
export constexpr auto construct_at = construct_at_t();
@@ -92,7 +50,7 @@ union u {
9250

9351
static_assert([]{
9452
auto x = u();
95-
bounded::construct_at(x.a, [] { return bounded::no_lazy_construction(accepts_anything(5)); });
53+
bounded::construct_at(x.a, [] { return accepts_anything(5); });
9654
return true;
9755
}());
9856

@@ -108,13 +66,4 @@ struct convert_to_int_throws {
10866
auto make_convert_to_int_throws() noexcept -> convert_to_int_throws;
10967
static_assert(!noexcept(bounded::construct_at(bounded::declval<int &>(), make_convert_to_int_throws)));
11068

111-
auto make_no_lazy_construction_int_noexcept() noexcept -> bounded::no_lazy_construction<int>;
112-
static_assert(noexcept(bounded::construct_at(bounded::declval<int &>(), make_no_lazy_construction_int_noexcept)));
113-
114-
auto make_no_lazy_construction_int_throws() -> bounded::no_lazy_construction<int>;
115-
static_assert(!noexcept(bounded::construct_at(bounded::declval<int &>(), make_no_lazy_construction_int_throws)));
116-
117-
auto make_no_lazy_construction_convert_to_int_throws() noexcept -> bounded::no_lazy_construction<convert_to_int_throws>;
118-
static_assert(!noexcept(bounded::construct_at(bounded::declval<int &>(), make_no_lazy_construction_convert_to_int_throws)));
119-
12069
} // namespace

source/bounded/lazy_init.cpp

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,9 @@ export struct lazy_init_t {
1515
};
1616
export constexpr auto lazy_init = lazy_init_t();
1717

18-
// If your function returns this type, the value will be unwrapped and then
19-
// copied / moved instead of constructed in place. This is necessary for types
20-
// like `std::jthread` that have constructors with unconstrained reference
21-
// parameters where the conversion would not work inside the constructor.
22-
export template<typename T>
23-
struct no_lazy_construction {
24-
T value;
25-
constexpr operator T() && {
26-
return OPERATORS_FORWARD(value);
27-
}
28-
};
29-
template<typename T>
30-
no_lazy_construction(T) -> no_lazy_construction<T>;
31-
32-
template<typename T>
33-
struct unwrapped_function_result_type {
34-
using type = T;
35-
};
36-
37-
template<typename T>
38-
struct unwrapped_function_result_type<no_lazy_construction<T>> {
39-
using type = T;
40-
};
41-
4218
export template<typename Function, typename T>
4319
concept construct_function_for = convertible_to<
44-
typename unwrapped_function_result_type<std::invoke_result_t<Function>>::type,
20+
std::invoke_result_t<Function>,
4521
T
4622
>;
4723

source/containers/test/test_set_size.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export module containers.test.test_set_size;
1212

1313
import containers.begin_end;
1414
import containers.data;
15+
import containers.range_value_t;
1516

1617
import bounded;
1718

@@ -48,7 +49,7 @@ constexpr auto test_add_one() -> void {
4849
auto v = Container({1});
4950
bounded::destroy(*containers::begin(v));
5051
v.set_size(0_bi);
51-
bounded::construct_at(*containers::data(v), [] { return 5; });
52+
bounded::construct_at(*containers::data(v), [] { return static_cast<containers::range_value_t<Container>>(5); });
5253
v.set_size(1_bi);
5354
BOUNDED_ASSERT(v == Container({5}));
5455
}

source/containers/test/vector_benchmark.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ auto DoNotOptimize(auto && value) -> void {
1717
}
1818

1919
template<typename T>
20-
auto default_value() {
20+
auto default_value() -> T {
2121
if constexpr (std::integral<T>) {
2222
return 0;
2323
} else {

0 commit comments

Comments
 (0)