Skip to content

Commit 1b320fd

Browse files
committed
fix(box): fix runtime error
1 parent ae0d8ce commit 1b320fd

File tree

11 files changed

+330
-151
lines changed

11 files changed

+330
-151
lines changed

include/stdsharp/concepts/object.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -262,11 +262,4 @@ namespace stdsharp
262262
{ t1 <<= t2 } -> std::same_as<T&>;
263263
{ t1 >>= t2 } -> std::same_as<T&>;
264264
};
265-
266-
template<typename T, typename U>
267-
concept decay_derived =
268-
std::is_base_of_v<std::remove_reference_t<U>, std::remove_reference_t<T>>;
269-
270-
template<typename T, typename U>
271-
concept not_decay_derived = !decay_derived<T, U>;
272265
}

include/stdsharp/concepts/type.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,14 @@ namespace stdsharp
6767
template<typename T>
6868
concept carray = std::is_array_v<T>;
6969

70-
template<typename T, typename U>
71-
concept base_of = std::is_base_of_v<T, U>;
70+
template<typename B, typename D>
71+
concept base_of = std::is_base_of_v<B, D>;
72+
73+
template<typename D, typename B>
74+
concept decay_derived = base_of<std::remove_reference_t<B>, std::remove_reference_t<D>>;
75+
76+
template<typename D, typename B>
77+
concept not_decay_derived = !decay_derived<D, B>;
7278

7379
template<typename T>
7480
concept class_ = std::is_class_v<T>;

include/stdsharp/memory/allocation_value.h

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,18 @@ namespace stdsharp
2020

2121
[[nodiscard]] bool operator==(const allocation_value&) const = default;
2222

23+
static constexpr auto data = allocation_traits::template data<T>;
24+
static constexpr auto get = allocation_traits::template get<T>;
25+
2326
private:
2427
using ctor = allocator_traits::constructor;
2528
using dtor = allocator_traits::destructor;
2629

27-
static constexpr auto data = allocation_traits::template data<T>;
28-
static constexpr auto get = allocation_traits::template get<T>;
29-
3030
constexpr void size_validate(const auto& allocation) const noexcept
3131
{
32-
Expects(allocation.size() * sizeof(allocation_traits::value_type) >= value_size());
32+
Expects(
33+
allocation.size() * sizeof(typename allocation_traits::value_type) >= value_size()
34+
);
3335
}
3436

3537
constexpr void
@@ -40,10 +42,14 @@ namespace stdsharp
4042
}
4143

4244
public:
45+
static constexpr struct default_construct_t
46+
{
47+
} default_construct{};
48+
4349
constexpr void operator()(
4450
allocator_type& allocator,
4551
const allocation<Allocator> auto& allocation,
46-
const empty_t /*unused*/
52+
const default_construct_t /*unused*/
4753
) const noexcept(nothrow_invocable<ctor, allocator_type&, T*>)
4854
requires std::invocable<ctor, allocator_type&, T*>
4955
{
@@ -112,13 +118,14 @@ namespace stdsharp
112118
using allocator_type = allocation_traits::allocator_type;
113119
using size_type = allocator_traits::size_type;
114120

121+
static constexpr auto data = allocation_traits::template data<T>;
122+
static constexpr auto get = allocation_traits::template get<T>;
123+
115124
private:
116125
using ctor = allocator_traits::constructor;
117126
using dtor = allocator_traits::destructor;
118127
using size_t = std::size_t;
119128

120-
static constexpr auto data = allocation_traits::template data<T>;
121-
122129
size_t size_;
123130

124131
constexpr void size_validate(const auto& allocation) const noexcept
@@ -154,10 +161,14 @@ namespace stdsharp
154161

155162
[[nodiscard]] bool operator==(const allocation_value&) const = default;
156163

164+
static constexpr struct default_construct_t
165+
{
166+
} default_construct{};
167+
157168
constexpr void operator()(
158169
allocator_type& allocator,
159170
const allocation<Allocator> auto& allocation,
160-
const empty_t /*unused*/
171+
const default_construct_t /*unused*/
161172
) const noexcept(nothrow_invocable<ctor, allocator_type&, T*>)
162173
requires std::invocable<ctor, allocator_type&, T*>
163174
{

include/stdsharp/memory/allocator_traits.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -305,13 +305,13 @@ namespace stdsharp
305305

306306
using m_base::max_size;
307307

308-
static constexpr allocator_type
308+
[[nodiscard]] static constexpr allocator_type
309309
select_on_container_copy_construction(const allocator_type& alloc) noexcept
310310
{
311311
return alloc;
312312
}
313313

314-
static constexpr allocator_type
314+
[[nodiscard]] static constexpr allocator_type
315315
select_on_container_copy_construction(const allocator_type& alloc)
316316
noexcept(noexcept(alloc.select_on_container_copy_construction()))
317317
requires requires {
@@ -323,7 +323,7 @@ namespace stdsharp
323323
return alloc.select_on_container_copy_construction();
324324
}
325325

326-
static constexpr pointer allocate(
326+
[[nodiscard]] static constexpr pointer allocate(
327327
allocator_type& alloc,
328328
const size_type count,
329329
const const_void_pointer hint = nullptr
@@ -342,7 +342,7 @@ namespace stdsharp
342342
m_base::deallocate(alloc, ptr, count);
343343
}
344344

345-
static constexpr pointer try_allocate(
345+
[[nodiscard]] static constexpr pointer try_allocate(
346346
allocator_type& alloc,
347347
const size_type count,
348348
const const_void_pointer hint = nullptr
@@ -360,7 +360,7 @@ namespace stdsharp
360360
}
361361
}
362362

363-
static constexpr auto try_allocate(
363+
[[nodiscard]] static constexpr auto try_allocate(
364364
allocator_type& alloc,
365365
const size_type count,
366366
[[maybe_unused]] const const_void_pointer hint = nullptr

include/stdsharp/utility/forward_cast.h

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,38 +23,48 @@ namespace stdsharp
2323
using next_fn = forward_cast_fn<current_cast_t, Rest...>;
2424

2525
public:
26-
[[nodiscard]] constexpr decltype(auto) operator()(auto&& from) const noexcept
27-
requires std::invocable<current_fn, From> && std::invocable<next_fn, current_cast_t>
26+
using from_t = std::remove_reference_t<From>;
27+
28+
[[nodiscard]] constexpr decltype(auto) operator()(from_t&& from) const noexcept
29+
requires std::invocable<current_fn, from_t> && std::invocable<next_fn, current_cast_t>
2830
{
29-
return next_fn{}(current_fn{}(static_cast<From&&>(from)));
31+
return next_fn{}(current_fn{}(cpp_move(from)));
32+
}
33+
34+
[[nodiscard]] constexpr decltype(auto) operator()(from_t& from) const noexcept
35+
requires std::invocable<current_fn, from_t&> && std::invocable<next_fn, current_cast_t>
36+
{
37+
return next_fn{}(current_fn{}(from));
3038
}
3139
};
3240

3341
template<typename From, typename To>
34-
requires requires(std::remove_cvref_t<From> f, std::remove_cvref_t<To> t) {
35-
requires not_same_as<decltype(f), decltype(t)>;
36-
requires !(base_of<decltype(f), decltype(t)> || base_of<decltype(t), decltype(f)>);
37-
}
42+
requires not_decay_derived<From, To> && not_decay_derived<To, From> &&
43+
not_same_as<std::remove_cvref_t<From>, std::remove_cvref_t<To>>
3844
struct forward_cast_fn<From, To>
3945
{
4046
};
4147

4248
template<typename From, typename To>
4349
struct forward_cast_fn<From, To>
4450
{
51+
using from_t = std::remove_reference_t<From>;
4552
using cast_t = forward_cast_t<From, To>;
4653

47-
// c-style cast allow us cast to inaccessible base
48-
[[nodiscard]] constexpr decltype(auto) operator()(std::remove_reference_t<From>&& from) //
54+
[[nodiscard]] constexpr decltype(auto) operator()(from_t& from) //
4955
const noexcept
5056
{
51-
return (cast_t)from; // NOLINT
57+
// c-style cast allow us cast to inaccessible base
58+
if constexpr(decay_derived<From, To>) return (cast_t)from; // NOLINT
59+
else return static_cast<cast_t>(from);
5260
}
5361

54-
[[nodiscard]] constexpr decltype(auto) operator()(std::remove_reference_t<From>& from) //
62+
[[nodiscard]] constexpr decltype(auto) operator()(from_t&& from) //
5563
const noexcept
5664
{
57-
return (cast_t)from; // NOLINT
65+
// c-style cast allow us cast to inaccessible base
66+
if constexpr(decay_derived<From, To>) return (cast_t)from; // NOLINT
67+
else return static_cast<cast_t>(from);
5868
}
5969
};
6070

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ set(src
2121
src/functional/pipeable.cpp
2222
src/functional/sequenced_invocables.cpp
2323
src/functional/symmetric_operations.cpp
24+
src/memory/allocation_value.cpp
2425
src/memory/box.cpp
2526
src/memory/composed_allocator.cpp
2627
src/memory/pointer_traits.cpp

tests/include/test_worst_type.h

Lines changed: 6 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
#include "stdsharp/concepts/concepts.h"
44
#include "test.h"
55

6-
using namespace stdsharp;
7-
using namespace std;
8-
96
struct test_worst_type
107
{
118
test_worst_type() = default;
@@ -18,82 +15,9 @@ struct test_worst_type
1815
test_worst_type& operator=(test_worst_type&&) = default;
1916
};
2017

21-
template<typename Normal, typename Unique, typename Worst>
22-
void allocation_type_requirement_test()
23-
{
24-
STATIC_REQUIRE(copyable<Normal>);
25-
STATIC_REQUIRE(nothrow_movable<Unique>);
26-
STATIC_REQUIRE(nothrow_swappable<Unique>);
27-
STATIC_REQUIRE(nothrow_movable<Worst>);
28-
STATIC_REQUIRE(nothrow_swappable<Worst>);
29-
}
30-
31-
template<typename T, typename Value, typename Predicate>
32-
void allocation_emplace_value_test(T& box, const Value& value, Predicate predicate)
33-
{
34-
WHEN("emplace a value")
35-
{
36-
const auto& res = box.emplace(value);
37-
38-
THEN("the return value should correct") { predicate(res, value); }
39-
40-
AND_THEN("type should be expected") { REQUIRE(box.template is_type<Value>()); }
41-
}
42-
}
43-
44-
template<typename T>
45-
void allocation_emplace_execution_test(T& box)
46-
{
47-
auto invoked = 0u;
48-
49-
struct local : reference_wrapper<unsigned>
50-
{
51-
local(unsigned& value): reference_wrapper(value) { ++get(); }
52-
};
53-
54-
WHEN("assign custom type twice")
55-
{
56-
INFO("custom type");
57-
58-
box.template emplace<local>(invoked);
59-
box.template emplace<local>(invoked);
60-
61-
THEN("assign operator should be invoked") { REQUIRE(invoked == 2); }
62-
63-
AND_THEN("destroy allocation and check content")
64-
{
65-
box.reset();
66-
REQUIRE(!box.has_value());
67-
}
68-
}
69-
}
70-
71-
template<typename T>
72-
void allocation_functionality_test(T box = {})
73-
{
74-
GIVEN("an object allocation")
75-
{
76-
allocation_emplace_value_test(
77-
box,
78-
1,
79-
[](const int v, const int value) { REQUIRE(v == value); }
80-
);
81-
82-
allocation_emplace_value_test(
83-
box,
84-
std::array<unsigned, 5>{1, 2, 3, 4, 5},
85-
[](const auto& v, const auto& value) { REQUIRE(v == value); }
86-
);
87-
88-
allocation_emplace_value_test(
89-
box,
90-
vector<int>{1, 2},
91-
[](const vector<int>& v, const vector<int>& value)
92-
{
93-
REQUIRE_THAT(v, Catch::Matchers::RangeEquals(value)); //
94-
}
95-
);
96-
97-
allocation_emplace_execution_test(box);
98-
}
99-
}
18+
#define ALLOCATION_TYPE_REQUIRE(Normal, Unique, Worst) \
19+
STATIC_REQUIRE(copyable<Normal>); \
20+
STATIC_REQUIRE(nothrow_movable<Unique>); \
21+
STATIC_REQUIRE(nothrow_swappable<Unique>); \
22+
STATIC_REQUIRE(nothrow_movable<Worst>); \
23+
STATIC_REQUIRE(nothrow_swappable<Worst>)

0 commit comments

Comments
 (0)