xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/__detail/__manual_lifetime.hpp (revision 10d0b4b7d1498cfd5c3d37edea271a54d1984e41)
1 /*
2  * Copyright (c) 2023 Maikel Nadolski
3  * Copyright (c) 2023 NVIDIA Corporation
4  *
5  * Licensed under the Apache License Version 2.0 with LLVM Exceptions
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  *   https://llvm.org/LICENSE.txt
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #pragma once
18 
19 #include "__concepts.hpp"
20 
21 #include <memory>
22 #include <new>
23 
24 namespace stdexec {
25 
26   //! Holds storage for a `_Ty`, but allows clients to `__construct(...)`, `__destry()`,
27   //! and `__get()` the `_Ty` without regard for usual lifetime rules.
28   template <class _Ty>
29   class __manual_lifetime {
30    public:
31     //! Constructor does nothing: It's on you to call `__construct(...)` or `__construct_from(...)`
32     //! if you want the `_Ty`'s lifetime to begin.
33     constexpr __manual_lifetime() noexcept = default;
34 
35     //! Destructor does nothing: It's on you to call `__destroy()` if you mean to.
36     constexpr ~__manual_lifetime() = default;
37 
38     __manual_lifetime(const __manual_lifetime&) = delete;
39     auto operator=(const __manual_lifetime&) -> __manual_lifetime& = delete;
40 
41     __manual_lifetime(__manual_lifetime&&) = delete;
42     auto operator=(__manual_lifetime&&) -> __manual_lifetime& = delete;
43 
44     //! Construct the `_Ty` in place.
45     //! There are no safeties guarding against the case that there's already one there.
46     template <class... _Args>
__construct(_Args &&...__args)47     auto __construct(_Args&&... __args)
48       noexcept(stdexec::__nothrow_constructible_from<_Ty, _Args...>) -> _Ty& {
49       // Use placement new instead of std::construct_at to support aggregate initialization with
50       // brace elision.
51       return *std::launder(::new (static_cast<void*>(__buffer_))
52                              _Ty{static_cast<_Args&&>(__args)...});
53     }
54 
55     //! Construct the `_Ty` in place from the result of calling `func`.
56     //! There are no safeties guarding against the case that there's already one there.
57     template <class _Func, class... _Args>
__construct_from(_Func && func,_Args &&...__args)58     auto __construct_from(_Func&& func, _Args&&... __args) -> _Ty& {
59       // Use placement new instead of std::construct_at in case the function returns an immovable
60       // type.
61       return *std::launder(::new (static_cast<void*>(__buffer_))
62                              _Ty{(static_cast<_Func&&>(func))(static_cast<_Args&&>(__args)...)});
63     }
64 
65     //! End the lifetime of the contained `_Ty`.
66     //! Precondition: The lifetime has started.
__destroy()67     void __destroy() noexcept {
68       std::destroy_at(&__get());
69     }
70 
71     //! Get access to the `_Ty`.
72     //! Precondition: The lifetime has started.
__get()73     auto __get() & noexcept -> _Ty& {
74       return *reinterpret_cast<_Ty*>(__buffer_);
75     }
76 
77     //! Get access to the `_Ty`.
78     //! Precondition: The lifetime has started.
__get()79     auto __get() && noexcept -> _Ty&& {
80       return static_cast<_Ty&&>(*reinterpret_cast<_Ty*>(__buffer_));
81     }
82 
83     //! Get access to the `_Ty`.
84     //! Precondition: The lifetime has started.
__get() const85     auto __get() const & noexcept -> const _Ty& {
86       return *reinterpret_cast<const _Ty*>(__buffer_);
87     }
88 
89     //! Move semantics aren't supported.
90     //! If you want to move the `_Ty`, use `std::move(ml.__get())`.
91     auto __get() const && noexcept -> const _Ty&& = delete;
92 
93    private:
94     alignas(_Ty) unsigned char __buffer_[sizeof(_Ty)]{};
95   };
96 } // namespace stdexec
97