diff --git a/include/etl/memory.h b/include/etl/memory.h index 40dd1183..f923a6ce 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -74,6 +74,323 @@ namespace etl return etl::to_address(itr.operator->()); } +#if ETL_USING_STL && ETL_USING_CPP17 && defined(__cpp_lib_launder) + using std::launder; +#else + //***************************************************************************** + /// Obtains a pointer to the object created in the storage pointed to by p. + /// Prevents the compiler from making invalid assumptions when the lifetime of + /// an object has ended and a new object has been created in the same storage. + /// T must not be a function type nor a (possibly cv-qualified) void type. + /// https://en.cppreference.com/w/cpp/utility/launder + ///\ingroup memory + //***************************************************************************** + template + ETL_NODISCARD ETL_CONSTEXPR17 T* launder(T* p) ETL_NOEXCEPT + { + #if ETL_USING_CPP11 + // etl::is_function is only defined for C++11 and later. + ETL_STATIC_ASSERT(!etl::is_function::value, "etl::launder argument must not be a function type"); + #endif + ETL_STATIC_ASSERT(!etl::is_void::value, "etl::launder argument must not be a void type"); + + #if defined(__has_builtin) && !defined(ETL_COMPILER_MICROSOFT) + #if __has_builtin(__builtin_launder) + return __builtin_launder(p); + #else + return p; + #endif + #elif ETL_USING_GCC_COMPILER && (ETL_COMPILER_FULL_VERSION >= 70000) + // GCC 7, 8 and 9 provide __builtin_launder but not __has_builtin. + return __builtin_launder(p); + #else + return p; + #endif + } +#endif + +#if ETL_USING_STL && ETL_USING_CPP23 && defined(__cpp_lib_start_lifetime_as) + using std::start_lifetime_as; + using std::start_lifetime_as_array; +#else + namespace private_memory + { + //************************************************************************* + /// Implicitly create the objects in [p, p + n) and return a usable pointer + /// to the first one. Used by start_lifetime_as / start_lifetime_as_array. + //************************************************************************* + template + ETL_NODISCARD + inline T* start_lifetime_as_impl(void* p, size_t n) ETL_NOEXCEPT + { + if (n == 0U) + { + // No objects are created, so there is nothing to launder. + // Return the original pointer to preserve pointer identity. + return static_cast(p); + } + + #if ETL_USING_BUILTIN_MEMMOVE + void* const q = __builtin_memmove(p, p, sizeof(T) * n); + #else + void* const q = ::memmove(p, p, sizeof(T) * n); + #endif + + return etl::launder(static_cast(q)); + } + } // namespace private_memory + + //***************************************************************************** + /// Implicitly creates an object of type T in the storage pointed to by p and + /// starts its lifetime. T must be a trivially copyable (implicit-lifetime) + /// type. The storage must be suitably sized and aligned for T. + /// https://en.cppreference.com/w/cpp/memory/start_lifetime_as + ///\ingroup memory + //***************************************************************************** + template + ETL_NODISCARD + T* start_lifetime_as(void* p) ETL_NOEXCEPT + { + ETL_STATIC_ASSERT(etl::is_trivially_copyable::value, "T must be trivially copyable"); + return etl::private_memory::start_lifetime_as_impl(p, 1U); + } + + template + ETL_NODISCARD + const T* start_lifetime_as(const void* p) ETL_NOEXCEPT + { + ETL_STATIC_ASSERT(etl::is_trivially_copyable::value, "T must be trivially copyable"); + return etl::private_memory::start_lifetime_as_impl(const_cast(p), 1U); + } + + template + ETL_NODISCARD + volatile T* start_lifetime_as(volatile void* p) ETL_NOEXCEPT + { + ETL_STATIC_ASSERT(etl::is_trivially_copyable::value, "T must be trivially copyable"); + return etl::private_memory::start_lifetime_as_impl(const_cast(p), 1U); + } + + template + ETL_NODISCARD + const volatile T* start_lifetime_as(const volatile void* p) ETL_NOEXCEPT + { + ETL_STATIC_ASSERT(etl::is_trivially_copyable::value, "T must be trivially copyable"); + return etl::private_memory::start_lifetime_as_impl(const_cast(p), 1U); + } + + //***************************************************************************** + /// Implicitly creates an array of n objects of type T in the storage pointed + /// to by p and starts their lifetimes. T must be a trivially copyable + /// (implicit-lifetime) type. Returns a pointer to the first element, or a + /// pointer comparing equal to p when n is zero. + /// https://en.cppreference.com/w/cpp/memory/start_lifetime_as + ///\ingroup memory + //***************************************************************************** + template + ETL_NODISCARD + T* start_lifetime_as_array(void* p, size_t n) ETL_NOEXCEPT + { + ETL_STATIC_ASSERT(etl::is_trivially_copyable::value, "T must be trivially copyable"); + return etl::private_memory::start_lifetime_as_impl(p, n); + } + + template + ETL_NODISCARD + const T* start_lifetime_as_array(const void* p, size_t n) ETL_NOEXCEPT + { + ETL_STATIC_ASSERT(etl::is_trivially_copyable::value, "T must be trivially copyable"); + return etl::private_memory::start_lifetime_as_impl(const_cast(p), n); + } + + template + ETL_NODISCARD + volatile T* start_lifetime_as_array(volatile void* p, size_t n) ETL_NOEXCEPT + { + ETL_STATIC_ASSERT(etl::is_trivially_copyable::value, "T must be trivially copyable"); + return etl::private_memory::start_lifetime_as_impl(const_cast(p), n); + } + + template + ETL_NODISCARD + const volatile T* start_lifetime_as_array(const volatile void* p, size_t n) ETL_NOEXCEPT + { + ETL_STATIC_ASSERT(etl::is_trivially_copyable::value, "T must be trivially copyable"); + return etl::private_memory::start_lifetime_as_impl(const_cast(p), n); + } +#endif + +#if ETL_USING_STL && ETL_USING_CPP11 + using std::pointer_traits; +#else + #if ETL_USING_CPP11 + namespace private_memory + { + //************************************************************************* + /// Decomposes a pointer-like class template of the form + /// Pointer to recover its first template parameter and + /// to rebind it to a different first parameter. Left undefined for types + /// that are not such a template instantiation. + //************************************************************************* + template + struct pointer_traits_template; + + template