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