#ifndef CORE_MEMORY_HPP #define CORE_MEMORY_HPP #include #include #include #include #include #include #include #include #ifndef CORE_NO_EXCEPTIONS #include #endif /* CORE_NO_EXCEPTIONS */ #ifndef CORE_NO_RTTI #include #endif /* CORE_NO_RTTI */ /* Small hack just for libstdc++ released with 4.8.x. Trust me, it's needed */ #define CORE_LIBSTDCXX_MAX_ALIGN_HACK 0 #if defined(__clang__) and defined(__GLIBCXX__) #if defined(__is_identifier) #if __is_identifier(max_align_t) #undef CORE_LIBSTDCXX_MAX_ALIGN_HACK #define CORE_LIBSTDCXX_MAX_ALIGN_HACK 1 #endif /* __is_identifier(max_align_t) */ #elif defined(__has_include) #if not __has_include() and __has_include() #undef CORE_LIBSTDCXX_MAX_ALIGN_HACK #define CORE_LIBSTDCXX_MAX_ALIGN_HACK 1 #endif /* __has_include(...) */ #endif /* defined(__is_identifier) : defined(__has_include) */ #endif /* defined(__clang__) and defined(__GLIBCXX__) */ /* separate check for g++ is done because of spurious failures in travis-ci */ #if not defined(__clang__) and defined(__GXX_ABI_VERSION) #if __GNUC__ == 4 and __GNUC_MINOR__ == 8 #undef CORE_LIBSTDCXX_MAX_ALIGN_HACK #define CORE_LIBSTDCXX_MAX_ALIGN_HACK 1 #endif /* __GNUC__ == 4 and __GNUC_MINOR__ == 8 */ #endif /* not defined(__clang__) */ #if CORE_LIBSTDCXX_MAX_ALIGN_HACK namespace std { using ::max_align_t; } /* namespace std */ #endif /* CORE_LIBSTDCXX_MAX_ALIGN_HACK */ namespace core { inline namespace v2 { namespace impl { template using pointer_t = typename T::pointer; template using deep_lvalue = conditional_t<::std::is_reference::value, T, T const&>; }}} /* namespace core::v2::impl */ namespace core { inline namespace v2 { #ifndef CORE_NO_EXCEPTIONS struct bad_polymorphic_reset : ::std::logic_error { using ::std::logic_error::logic_error; }; [[noreturn]] inline void throw_bad_poly_reset (char const* msg) { throw bad_polymorphic_reset { msg }; } [[noreturn]] inline void throw_bad_alloc () { throw ::std::bad_alloc { }; } #else /* CORE_NO_EXCEPTIONS */ [[noreturn]] inline void throw_bad_poly_reset (char const*) { ::std::abort(); } [[noreturn]] inline void throw_bad_alloc () { ::std::abort(); } #endif /* CORE_NO_EXCEPTIONS */ inline void* align ( ::std::size_t alignment, ::std::size_t size, void*& ptr, ::std::size_t& space ) noexcept { if (size > space) { return nullptr; } auto const beg = static_cast<::std::uint8_t*>(ptr); auto const mix = as_int(beg + (alignment - 1)); auto const end = reinterpret_cast<::std::uint8_t*>(mix & -alignment); auto const distance = static_cast<::std::size_t>(::std::distance(beg, end)); if (distance > space - size) { return nullptr; } space -= distance; return ptr = end; } }} /* namespace core::v2 */ namespace core { inline namespace v2 { namespace memory { template <::std::size_t N> struct arena final { static_assert(N != 0, "N may not be 0"); using size_type = ::std::size_t; arena () noexcept = default; ~arena () noexcept = default; arena (arena const&) noexcept = delete; arena& operator = (arena const&) noexcept = delete; static constexpr size_type alignment () noexcept { return alignof(::std::max_align_t); } static constexpr size_type size () noexcept { return N; } size_type max_size () const noexcept { return N; } size_type used () const noexcept { return N - this->available; } void reset () noexcept { this->available = N; } void* allocate (size_type n) { auto current = this->pointer() + this->used(); auto ptr = ::core::align(alignment(), n, current, this->available); if (not ptr) { return ptr; } this->available -= n; return ptr; } void deallocate (void* p, size_type n) { auto incoming = static_cast<::std::uint8_t*>(p) + n; auto ptr = this->pointer() + this->used(); if (ptr != incoming) { return; } this->available += n; } /* used by arena_allocator to permit default construction */ static arena& ref () noexcept { static arena instance; return instance; } private: ::std::uint8_t* pointer () noexcept { return static_cast<::std::uint8_t*>(::core::as_void(this->data)); } aligned_storage_t data { }; size_type available { N }; }; }}} /* namespace core::v2::memory */ namespace core { inline namespace v2 { /* An SG14 influenced raw_storage_iterator */ template struct raw_storage_iterator { using difference_type = void; using value_type = void; using reference = void; using pointer = void; using iterator_category = ::std::output_iterator_tag; explicit raw_storage_iterator (OutputIt iter) : iter { iter } { } template < class U, meta::inhibit< ::std::is_same, raw_storage_iterator>::value > = __LINE__, meta::require<::std::is_constructible::value> = __LINE__ > raw_storage_iterator& operator = (U&& item) { ::new (::core::as_void(*this->iter)) T(::core::forward(item)); return *this; } raw_storage_iterator& operator * () { return *this; } raw_storage_iterator& operator ++ () { ++this->iter; return *this; } raw_storage_iterator& operator ++ (int) { return raw_storage_iterator(this->iter++); } OutputIt base () const { return this->iter; } private: OutputIt iter; }; template struct arena_allocator { using difference_type = ::std::ptrdiff_t; using value_type = T; using size_type = ::std::size_t; using const_reference = add_lvalue_reference_t>; using const_pointer = add_pointer_t>; using reference = add_lvalue_reference_t; using pointer = add_pointer_t; using const_void_pointer = add_pointer_t>; using void_pointer = add_pointer_t; using propagate_on_container_copy_assignment = ::std::true_type; using propagate_on_container_move_assignment = ::std::true_type; using propagate_on_container_swap = ::std::true_type; using is_always_equal = ::std::false_type; template friend struct arena_allocator; template struct rebind { using other = arena_allocator; }; explicit arena_allocator (memory::arena& ref) noexcept : ref { ref } { } arena_allocator () noexcept : arena_allocator { memory::arena::ref() } { } template arena_allocator (arena_allocator const& that) noexcept : ref { that.ref } { } arena_allocator (arena_allocator const& that) noexcept = default; template arena_allocator& operator = (arena_allocator const& that) noexcept { arena_allocator { that }.swap(*this); return *this; } arena_allocator& operator = (arena_allocator const& that) noexcept = default; void swap (arena_allocator& that) noexcept { ::std::swap(this->ref, that.ref); } pointer allocate (size_type n, const_void_pointer=nullptr) noexcept(false) { auto const size = n * sizeof(value_type); auto ptr = static_cast(this->arena().allocate(size)); if (not ptr) { throw_bad_alloc(); } return ptr; } void deallocate (pointer ptr, size_type n) noexcept { this->arena().deallocate(ptr, n * sizeof(value_type)); } size_type max_size () const noexcept { return N / sizeof(value_type); } memory::arena const& arena () const noexcept { return this->ref; } memory::arena& arena () noexcept { return this->ref; } private: ::std::reference_wrapper> ref; }; /* poly-ptr related definitions */ #ifndef CORE_NO_RTTI /* poly_ptr copier */ template ::std::unique_ptr default_poly_copy ( ::std::unique_ptr const& ptr ) { auto value = *dynamic_cast(ptr.get()); auto const& deleter = ptr.get_deleter(); return ::std::unique_ptr { new U { ::std::move(value) }, deleter }; } /* null-state poly_ptr copier (don't copy that poly!) */ template ::std::unique_ptr null_poly_copy ( ::std::unique_ptr const& ) noexcept { return ::std::unique_ptr { }; } #endif /* CORE_NO_RTTI */ /* deep_ptr copier */ template struct default_copy { using pointer = T*; constexpr default_copy () = default; template default_copy (default_copy const&) noexcept { } pointer operator ()(pointer const ptr) const { return new T { *ptr }; } }; #ifndef CORE_NO_RTTI template > struct poly_ptr final { using unique_type = ::std::unique_ptr; using element_type = typename unique_type::element_type; using deleter_type = typename unique_type::deleter_type; using copier_type = unique_type (*)(unique_type const&); using pointer = typename unique_type::pointer; template explicit poly_ptr (U* ptr) noexcept : poly_ptr { ptr, deleter_type { } } { } template explicit poly_ptr ( ::std::unique_ptr&& ptr, copier_type copier=::std::addressof( default_poly_copy ) ) noexcept : copier { copier }, ptr { ::std::move(ptr) } { constexpr bool abstract = ::std::is_abstract::value; constexpr bool base = ::std::is_base_of::value; static_assert(not abstract, "cannot create poly_ptr with abstract ptr"); static_assert(base, "cannot create poly_ptr with non-derived type"); } template poly_ptr ( U* ptr, E&& deleter, copier_type copier=::std::addressof( default_poly_copy ) ) noexcept : poly_ptr { unique_type { ::std::move(ptr), ::core::forward(deleter) }, copier } { } poly_ptr (poly_ptr const& that) : copier { that.copier }, ptr { that.copier(that.ptr) } { } poly_ptr (poly_ptr&& that) noexcept : copier { ::std::move(that.copier) }, ptr { ::std::move(that.ptr) } { that.copier = null_poly_copy; } constexpr poly_ptr () noexcept = default; ~poly_ptr () noexcept = default; template poly_ptr& operator = (::std::unique_ptr&& ptr) { poly_ptr { ::std::move(ptr) }.swap(*this); return *this; } template poly_ptr& operator = (U* ptr) { poly_ptr { ptr }.swap(*this); return *this; } poly_ptr& operator = (::std::nullptr_t) noexcept { this->reset(); return *this; } poly_ptr& operator = (poly_ptr const& that) { return *this = poly_ptr { that }; } poly_ptr& operator = (poly_ptr&& that) noexcept { poly_ptr { ::std::move(that) }.swap(*this); return *this; } explicit operator bool () const noexcept { return bool(this->ptr); } add_lvalue_reference_t operator * () const noexcept { return *this->ptr; } pointer operator -> () const noexcept { return this->ptr.get(); } pointer get () const noexcept { return this->ptr.get(); } deleter_type const& get_deleter () const noexcept { return this->ptr.get_deleter(); } deleter_type& get_deleter () noexcept { return this->ptr.get_deleter(); } copier_type const& get_copier () const noexcept { return this->copier; } copier_type& get_copier () noexcept { return this->copier; } pointer release () noexcept { this->copier = null_poly_copy; return this->ptr.release(); } void reset (pointer ptr = pointer { }) { constexpr auto invalid = "cannot reset null poly_ptr with valid pointer"; constexpr auto type = "cannot reset poly_ptr with different type"; if (ptr and not this->ptr) { throw_bad_poly_reset(invalid); } if (ptr and typeid(*this->ptr) != typeid(*ptr)) { throw_bad_poly_reset(type); } this->ptr.reset(ptr); if (not ptr) { this->copier = null_poly_copy; } } void swap (poly_ptr& that) noexcept { using ::std::swap; swap(this->get_copier(), that.get_copier()); swap(this->ptr, that.ptr); } private: static_assert( ::std::is_polymorphic::value, "cannot create a poly_ptr with a non-polymorphic type" ); copier_type copier { null_poly_copy }; unique_type ptr; }; #endif /* CORE_NO_RTTI */ template < class T, class Deleter=::std::default_delete, class Copier=default_copy > struct deep_ptr final { using element_type = T; using deleter_type = Deleter; using copier_type = Copier; using pointer = detected_or_t< add_pointer_t, impl::pointer_t, deleter_type >; static_assert( ::std::is_same, pointer>::value, "deleter_type and copier_type have differing pointer types" ); using data_type = ::std::tuple; deep_ptr ( pointer ptr, impl::deep_lvalue deleter, impl::deep_lvalue copier ) noexcept : data { ptr, deleter, copier } { } deep_ptr ( pointer ptr, remove_reference_t&& deleter, remove_reference_t&& copier ) noexcept : data { ::std::move(ptr), ::std::move(deleter), ::std::move(copier) } { } template deep_ptr (::std::unique_ptr&& that) noexcept : deep_ptr { that.release(), ::std::move(that.get_deleter()), copier_type { } } { } explicit deep_ptr (pointer ptr) noexcept : deep_ptr { ptr, deleter_type { }, copier_type { } } { } constexpr deep_ptr (::std::nullptr_t) noexcept : deep_ptr { } { } deep_ptr (deep_ptr const& that) : deep_ptr { that.get() ? that.get_copier()(that.get()) : that.get(), that.get_deleter(), that.get_copier() } { } deep_ptr (deep_ptr&& that) noexcept : data { that.release(), ::std::move(that.get_deleter()), ::std::move(that.get_copier()) } { } /* This is not defaulted because of an issue with libstdc++ pre 5.1. But * what else is new. */ constexpr deep_ptr () noexcept { } ~deep_ptr () noexcept { auto& ptr = ::std::get<0>(this->data); if (not ptr) { return; } this->get_deleter()(ptr); ptr = nullptr; } deep_ptr& operator = (::std::nullptr_t) noexcept { this->reset(); return *this; } deep_ptr& operator = (deep_ptr const& that) { return *this = deep_ptr { that }; } deep_ptr& operator = (deep_ptr&& that) noexcept { deep_ptr { ::std::move(that) }.swap(*this); return *this; } explicit operator bool () const noexcept { return this->get(); } add_lvalue_reference_t operator * () const noexcept { return *this->get(); } pointer operator -> () const noexcept { return this->get(); } pointer get () const noexcept { return ::std::get<0>(this->data); } deleter_type const& get_deleter () const noexcept { return ::std::get<1>(this->data); } deleter_type& get_deleter () noexcept { return ::std::get<1>(this->data); } copier_type const& get_copier () const noexcept { return ::std::get<2>(this->data); } copier_type& get_copier () noexcept { return ::std::get<2>(this->data); } pointer release () noexcept { auto ptr = this->get(); ::std::get<0>(this->data) = nullptr; return ptr; } void reset (pointer ptr = pointer { }) noexcept { using ::std::swap; swap(::std::get<0>(this->data), ptr); if (not ptr) { return; } this->get_deleter()(ptr); } void swap (deep_ptr& that) noexcept(is_nothrow_swappable::value) { using ::std::swap; swap(this->data, that.data); } private: data_type data; }; template struct observer_ptr final { using element_type = W; using const_pointer = add_pointer_t>; using pointer = add_pointer_t; using const_reference = add_lvalue_reference_t>; using reference = add_lvalue_reference_t; observer_ptr (observer_ptr const&) noexcept = default; constexpr observer_ptr (::std::nullptr_t) noexcept : ptr { nullptr } { } explicit observer_ptr (pointer ptr) noexcept : ptr { ptr } { } template explicit observer_ptr (::std::unique_ptr const& ptr) : observer_ptr { ptr.get() } { } template < class T, class=enable_if_t<::std::is_convertible>::value> > explicit observer_ptr (add_pointer_t ptr) noexcept : ptr { dynamic_cast(ptr) } { } template < class T, class=enable_if_t<::std::is_convertible>::value> > observer_ptr (observer_ptr const& that) noexcept : observer_ptr { that.get() } { } constexpr observer_ptr () noexcept = default; ~observer_ptr () noexcept = default; template < class T, class=enable_if_t<::std::is_convertible>::value> > observer_ptr& operator = (add_pointer_t ptr) noexcept { observer_ptr { ptr }.swap(*this); return *this; } observer_ptr& operator = (observer_ptr const&) noexcept = default; template < class T, class=enable_if_t<::std::is_convertible>::value> > observer_ptr& operator = (observer_ptr const& that) noexcept { observer_ptr { that }.swap(*this); return *this; } observer_ptr& operator = (::std::nullptr_t) noexcept { this->reset(); return *this; } void swap (observer_ptr& that) noexcept { using ::std::swap; swap(this->ptr, that.ptr); } explicit operator const_pointer () const noexcept { return this->get(); } explicit operator pointer () noexcept { return this->get(); } explicit operator bool () const noexcept { return this->get(); } reference operator * () const noexcept { return *this->get(); } pointer operator -> () const noexcept { return this->get(); } pointer get () const noexcept { return this->ptr; } pointer release () noexcept { auto result = this->get(); this->reset(); return result; } void reset (pointer ptr = nullptr) noexcept { this->ptr = ptr; } private: pointer ptr { nullptr }; }; template bool operator == ( arena_allocator const& lhs, arena_allocator const& rhs ) noexcept { return N == M and ::std::addressof(lhs.arena()) == ::std::addressof(rhs.arena()); } template bool operator != ( arena_allocator const& lhs, arena_allocator const& rhs ) noexcept { return N != M or ::std::addressof(lhs.arena()) != ::std::addressof(rhs.arena()); } #ifndef CORE_NO_RTTI /* poly_ptr convention for type and deleter is: T, D : U, E */ template bool operator == ( poly_ptr const& lhs, poly_ptr const& rhs ) noexcept { return lhs.get() == rhs.get(); } template bool operator != ( poly_ptr const& lhs, poly_ptr const& rhs ) noexcept { return lhs.get() != rhs.get(); } template bool operator >= ( poly_ptr const& lhs, poly_ptr const& rhs ) noexcept { return not (lhs < rhs); } template bool operator <= ( poly_ptr const& lhs, poly_ptr const& rhs ) noexcept { return not (rhs < lhs); } template bool operator > ( poly_ptr const& lhs, poly_ptr const& rhs ) noexcept { return rhs < lhs; } template bool operator < ( poly_ptr const& lhs, poly_ptr const& rhs ) noexcept { using common_type = typename ::std::common_type< typename poly_ptr::pointer, typename poly_ptr::pointer >::type; return ::std::less { }(lhs.get(), rhs.get()); } #endif /* CORE_NO_RTTI */ /* deep_ptr convention for type, deleter, copier is * T, D, C : U, E, K */ template bool operator == ( deep_ptr const& lhs, deep_ptr const& rhs ) noexcept { return lhs.get() == rhs.get(); } template bool operator != ( deep_ptr const& lhs, deep_ptr const& rhs ) noexcept { return lhs.get() != rhs.get(); } template bool operator >= ( deep_ptr const& lhs, deep_ptr const& rhs ) noexcept { return not (lhs < rhs); } template bool operator <= ( deep_ptr const& lhs, deep_ptr const& rhs ) noexcept { return not (rhs < lhs); } template bool operator > ( deep_ptr const& lhs, deep_ptr const& rhs ) noexcept { return rhs < lhs; } template bool operator < ( deep_ptr const& lhs, deep_ptr const& rhs ) noexcept { using common_type = common_type_t< typename deep_ptr::pointer, typename deep_ptr::pointer >; return ::std::less { }(lhs.get(), rhs.get()); } #ifndef CORE_NO_RTTI /* poly_ptr nullptr operator overloads */ template bool operator == (poly_ptr const& lhs, ::std::nullptr_t) noexcept { return not lhs; } template bool operator == (::std::nullptr_t, poly_ptr const& rhs) noexcept { return not rhs; } template bool operator != (poly_ptr const& lhs, ::std::nullptr_t) noexcept { return bool(lhs); } template bool operator != (::std::nullptr_t, poly_ptr const& rhs) noexcept { return bool(rhs); } template bool operator >= (poly_ptr const& lhs, ::std::nullptr_t) noexcept { return not (lhs < nullptr); } template bool operator >= (::std::nullptr_t, poly_ptr const& rhs) noexcept { return not (nullptr < rhs); } template bool operator <= (poly_ptr const& lhs, ::std::nullptr_t) noexcept { return not (nullptr < lhs); } template bool operator <= (::std::nullptr_t, poly_ptr const& rhs) noexcept { return not (rhs < nullptr); } template bool operator > (poly_ptr const& lhs, ::std::nullptr_t) noexcept { return nullptr < lhs; } template bool operator > (::std::nullptr_t, poly_ptr const& rhs) noexcept { return rhs < nullptr; } template bool operator < (poly_ptr const& lhs, ::std::nullptr_t) noexcept { using pointer = typename poly_ptr::pointer; return ::std::less { }(lhs.get(), nullptr); } template bool operator < (::std::nullptr_t, poly_ptr const& rhs) noexcept { using pointer = typename poly_ptr::pointer; return ::std::less { }(nullptr, rhs.get()); } #endif /* CORE_NO_RTTI */ /* deep_ptr nullptr operator overloads */ template bool operator == (deep_ptr const& lhs, ::std::nullptr_t) noexcept { return not lhs; } template bool operator == (::std::nullptr_t, deep_ptr const& rhs) noexcept { return not rhs; } template bool operator != (deep_ptr const& lhs, ::std::nullptr_t) noexcept { return bool(lhs); } template bool operator != (::std::nullptr_t, deep_ptr const& rhs) noexcept { return bool(rhs); } template bool operator >= (deep_ptr const& lhs, ::std::nullptr_t) noexcept { return not (lhs < nullptr); } template bool operator >= (::std::nullptr_t, deep_ptr const& rhs) noexcept { return not (nullptr < rhs); } template bool operator <= (deep_ptr const& lhs, ::std::nullptr_t) noexcept { return not (nullptr < lhs); } template bool operator <= (::std::nullptr_t, deep_ptr const& rhs) noexcept { return not (rhs < nullptr); } template bool operator > (deep_ptr const& lhs, ::std::nullptr_t) noexcept { return nullptr < lhs; } template bool operator > (::std::nullptr_t, deep_ptr const& rhs) noexcept { return rhs < nullptr; } template bool operator < (deep_ptr const& lhs, ::std::nullptr_t) noexcept { using pointer = typename deep_ptr::pointer; return ::std::less { }(lhs.get(), nullptr); } template bool operator < (::std::nullptr_t, deep_ptr const& rhs) noexcept { using pointer = typename deep_ptr::pointer; return ::std::less { }(nullptr, rhs.get()); } /* observer_ptr and nullptr overloads */ template bool operator == ( observer_ptr const& lhs, observer_ptr const& rhs ) noexcept { return lhs.get() == rhs.get(); } template bool operator != ( observer_ptr const& lhs, observer_ptr const& rhs ) noexcept { return lhs.get() != rhs.get(); } template bool operator == (observer_ptr const& lhs, ::std::nullptr_t) noexcept { return lhs.get() == nullptr; } template bool operator != (observer_ptr const& lhs, ::std::nullptr_t) noexcept { return lhs.get() != nullptr; } template bool operator == (::std::nullptr_t, observer_ptr const& rhs) noexcept { return nullptr == rhs.get(); } template bool operator != (::std::nullptr_t, observer_ptr const& rhs) noexcept { return nullptr != rhs.get(); } template bool operator >= ( observer_ptr const& lhs, observer_ptr const& rhs ) noexcept { return lhs.get() >= rhs.get(); } template bool operator <= ( observer_ptr const& lhs, observer_ptr const& rhs ) noexcept { return lhs.get() <= rhs.get(); } template bool operator > ( observer_ptr const& lhs, observer_ptr const& rhs ) noexcept { return lhs.get() > rhs.get(); } template bool operator < ( observer_ptr const& lhs, observer_ptr const& rhs ) noexcept { return lhs.get() < rhs.get(); } /* make_observer */ template observer_ptr make_observer (W* ptr) noexcept { return observer_ptr { ptr }; } template observer_ptr make_observer (::std::unique_ptr const& ptr) noexcept { return observer_ptr { ptr.get() }; } template observer_ptr make_observer (::std::shared_ptr const& ptr) noexcept { return observer_ptr { ptr.get() }; } template observer_ptr make_observer (::std::weak_ptr const& ptr) noexcept { return make_observer(ptr.lock()); } template observer_ptr make_observer (deep_ptr const& ptr) noexcept { return observer_ptr { ptr.get() }; } #ifndef CORE_NO_RTTI template observer_ptr make_observer (poly_ptr const& ptr) noexcept { return observer_ptr { ptr.get() }; } #endif /* CORE_NO_RTTI */ #ifndef CORE_NO_RTTI /* make_poly */ template < class T, class U, class=enable_if_t< ::std::is_polymorphic::value and ::std::is_base_of::value > > auto make_poly (U&& value) -> poly_ptr { return poly_ptr { new U(::core::forward(value)) }; } #endif /* CORE_NO_RTTI */ /* make_deep */ template < class T, class=enable_if_t::value>, class... Args > auto make_deep (Args&&... args) -> deep_ptr { return deep_ptr { new T(::core::forward(args)...) }; } /* make_unique */ template < class Type, class=enable_if_t::value>, class... Args > auto make_unique(Args&&... args) -> ::std::unique_ptr { return ::std::unique_ptr { new Type(::core::forward(args)...) }; } template < class Type, class=enable_if_t< ::std::is_array::value>, class=enable_if_t::value> > auto make_unique(::std::size_t size) -> ::std::unique_ptr { return ::std::unique_ptr { new remove_extent_t[size] { } }; } template < class Type, class=enable_if_t< ::std::is_array::value>, class=enable_if_t< ::std::extent::value>, class... Args > auto make_unique(Args&&...) -> void = delete; template void swap (arena_allocator& lhs, arena_allocator& rhs) noexcept { lhs.swap(rhs); } #ifndef CORE_NO_RTTI template void swap (poly_ptr& lhs, poly_ptr& rhs) noexcept( noexcept(lhs.swap(rhs)) ) { lhs.swap(rhs); } #endif /* CORE_NO_RTTI */ template void swap (deep_ptr& lhs, deep_ptr& rhs) noexcept( noexcept(lhs.swap(rhs)) ) { lhs.swap(rhs); } template void swap (observer_ptr& lhs, observer_ptr& rhs) noexcept( noexcept(lhs.swap(rhs)) ) { lhs.swap(rhs); } /* SG14 Suggestions */ template raw_storage_iterator, T> make_storage_iterator (It&& iter) { return raw_storage_iterator, T>(::core::forward(iter)); } template void destroy (ForwardIt first, ForwardIt last) { using type = typename ::std::iterator_traits::value_type; while (first != last) { *first.~type(); ++first; } } #ifndef CORE_NO_EXCEPTIONS template ForwardIt uninitialized_move (InputIt first, InputIt last, ForwardIt dest) { using type = typename ::std::iterator_traits::value_type; auto current = dest; try { while (first != last) { ::new (::core::as_void(*current)) type(::core::move(*first)); ++current; ++first; } } catch (...) { destroy(dest, current); throw; } return current; } template ForwardIt uninitialized_move_n (InputIt first, Size count, ForwardIt dest) { using type = typename ::std::iterator_traits::value_type; auto current = dest; try { while (count > 0) { ::new (::core::as_void(*dest)) type(::core::move(*first)); ++dest; ++first; --count; } } catch (...) { destroy(dest, current); throw; } return current; } template ForwardIt uninitialized_value_construct (ForwardIt first, ForwardIt last) { using type = typename ::std::iterator_traits::value_type; auto current = first; try { while (current != last) { ::new (::core::as_void(*current)) type(); ++current; } } catch (...) { destroy(first, current); throw; } return current; } template ForwardIt uninitialized_default_construct (ForwardIt first, ForwardIt last) { using type = typename ::std::iterator_traits::value_type; auto current = first; try { while (current != last) { ::new (::core::as_void(*current)) type(); ++current; } } catch (...) { destroy(first, current); throw; } return current; } /* Personal Extension to SG14 mentioned during CppCon 2015 */ template ForwardIt uninitialized_transform ( InputIt first, InputIt last, ForwardIt dest, UnaryOp op ) { using type = typename ::std::iterator_traits::value_type; auto current = dest; try { while (first != last) { ::new (::core::as_void(*current)) type(::core::invoke(op, *first)); ++current; ++first; } } catch (...) { destroy(dest, current); throw; } return current; } #else /* CORE_NO_EXCEPTIONS */ template ForwardIt uninitialized_move (InputIt first, InputIt last, ForwardIt dest) { using type = typename ::std::iterator_traits::value_type; while (first != last) { ::new (::core::as_void(*first)) type(::core::move(*first)); ++first; } return first; } template ForwardIt uninitialized_move_n (InputIt first, Size count, ForwardIt dest) { using type = typename ::std::iterator_traits::value_type; while (count > 0) { ::new (::core::as_void(*dest)) type (::core::move(*first)); ++dest; ++first; --count; } return first; } template ForwardIt uninitialized_value_construct (ForwardIt first, ForwardIt last) { using type = typename ::std::iterator_traits::value_type; while (first != last) { ::new (::core::as_void(*first)) type(); ++first; } return first; } template ForwardIt uninitialized_default_construct (ForwardIt first, ForwardIt last) { using type = typename ::std::iterator_traits::value_type; while (first != last) { ::new (::core::as_void(*first)) type; ++first; } return first; } template ForwardIt uninitialized_transform ( InputIt first, InputIt last, ForwardIt dest, UnaryOp ) { using type = typename ::std::iterator_traits::value_type; while (first != last) { ::new (::core::as_void(*dest)) type(::core::invoke(op, *first)); ++dest; ++first; } return dest; } #endif /* CORE_NO_EXCEPTIONS */ }} /* namespace core::v2 */ namespace std { #ifndef CORE_NO_RTTI template struct hash> { using value_type = core::v2::poly_ptr; size_t operator ()(value_type const& value) const noexcept { return hash{ }(value.get()); } }; #endif /* CORE_NO_RTTI */ template struct hash<::core::v2::deep_ptr> { using value_type = ::core::v2::deep_ptr; size_t operator ()(value_type const& value) const noexcept { return hash { }(value.get()); } }; template struct hash<::core::v2::observer_ptr> { using value_type = ::core::v2::observer_ptr; size_t operator ()(value_type const& value) const noexcept { return hash { }(value.get()); } }; } /* namespace std */ template void* operator new ( ::std::size_t s, ::core::v2::raw_storage_iterator it ) noexcept { return ::operator new(s, it.base()); } template void operator delete ( void* p, ::core::v2::raw_storage_iterator it ) noexcept { return ::operator delete(p, it.base()); } #endif /* CORE_MEMORY_HPP */