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