-
Notifications
You must be signed in to change notification settings - Fork 182
/
manual_lifetime_union.hpp
122 lines (108 loc) · 3.89 KB
/
manual_lifetime_union.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License Version 2.0 with LLVM Exceptions
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://llvm.org/LICENSE.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <unifex/manual_lifetime.hpp>
#include <unifex/scope_guard.hpp>
#include <algorithm>
#include <type_traits>
#include <utility>
#include <unifex/detail/prologue.hpp>
namespace unifex {
template <typename... Ts>
class manual_lifetime_union {
public:
manual_lifetime_union() = default;
template <typename T, typename... Args>
[[maybe_unused]] T& construct(Args&&... args) noexcept(
std::is_nothrow_constructible_v<T, Args...>) {
return unifex::activate_union_member(
*static_cast<manual_lifetime<T>*>(static_cast<void*>(&storage_)),
static_cast<Args&&>(args)...);
}
template <typename T, typename Func>
[[maybe_unused]] T&
construct_with(Func&& func) noexcept(std::is_nothrow_invocable_v<Func>) {
return unifex::activate_union_member_with(
*static_cast<manual_lifetime<T>*>(static_cast<void*>(&storage_)),
static_cast<Func&&>(func));
}
template <typename T>
void destruct() noexcept {
unifex::deactivate_union_member(
*static_cast<manual_lifetime<T>*>(static_cast<void*>(&storage_)));
}
template <typename T>
decltype(auto) get() & noexcept {
static_assert(is_one_of_v<T, Ts...>);
return static_cast<manual_lifetime<T>*>(static_cast<void*>(&storage_))
->get();
}
template <typename T>
decltype(auto) get() const& noexcept {
static_assert(is_one_of_v<T, Ts...>);
return static_cast<manual_lifetime<T> const*>(
static_cast<void const*>(&storage_))
->get();
}
template <typename T>
decltype(auto) get() && noexcept {
static_assert(is_one_of_v<T, Ts...>);
return std::move(
*static_cast<manual_lifetime<T>*>(static_cast<void*>(&storage_)))
.get();
}
private:
alignas(
Ts...) unsigned char storage_[std::max({sizeof(manual_lifetime<Ts>)...})];
};
template <>
class manual_lifetime_union<> {};
// For activating a manual_lifetime_union when it is in a union and initializing
// its value from arguments to its constructor.
template <typename T, typename... Ts, typename... Args>
[[maybe_unused]] //
T& activate_union_member(manual_lifetime_union<Ts...>& box, Args&&... args) //
noexcept(std::is_nothrow_constructible_v<T, Args...>) {
auto* p = ::new (&box) manual_lifetime_union<Ts...>{};
scope_guard guard = [=]() noexcept {
p->~manual_lifetime_union();
};
auto& t = p->template construct<T>(static_cast<Args&&>(args)...);
guard.release();
return t;
}
// For activating a manual_lifetime_union when it is in a union and initializing
// its value from the result of calling a function.
template <typename T, typename... Ts, typename Func>
[[maybe_unused]] //
T& activate_union_member_with(manual_lifetime_union<Ts...>& box, Func&& func)
noexcept(std::is_nothrow_invocable_v<Func>) {
auto* p = ::new (&box) manual_lifetime_union<Ts...>{};
scope_guard guard = [=]() noexcept {
p->~manual_lifetime_union();
};
auto& t = p->template construct_with<T>(static_cast<Func&&>(func));
guard.release();
return t;
}
// For deactivating a manual_lifetime_union when it is in a union
template <typename T, typename... Ts>
void deactivate_union_member(manual_lifetime_union<Ts...>& box) noexcept {
box.template destruct<T>();
box.~manual_lifetime_union();
}
} // namespace unifex
#include <unifex/detail/epilogue.hpp>