/* Copyright 2019 Glen Joseph Fernandes (glenjofe@gmail.com) Distributed under the Boost Software License, Version 1.0. (http://www.boost.org/LICENSE_1_0.txt) */ #ifndef BOOST_SMART_PTR_ALLOCATE_UNIQUE_HPP #define BOOST_SMART_PTR_ALLOCATE_UNIQUE_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace detail { template struct sp_alloc_size { BOOST_STATIC_CONSTEXPR std::size_t value = 1; }; template struct sp_alloc_size { BOOST_STATIC_CONSTEXPR std::size_t value = sp_alloc_size::value; }; template struct sp_alloc_size { BOOST_STATIC_CONSTEXPR std::size_t value = N * sp_alloc_size::value; }; template struct sp_alloc_result { typedef T type; }; template struct sp_alloc_result { typedef T type[]; }; template struct sp_alloc_value { typedef typename boost::remove_cv::type>::type type; }; #if !defined(BOOST_NO_CXX11_ALLOCATOR) template struct sp_alloc_to { typedef typename std::allocator_traits::template rebind_alloc type; }; #else template struct sp_alloc_to { typedef typename A::template rebind::other type; }; #endif #if !defined(BOOST_NO_CXX11_ALLOCATOR) template struct sp_alloc_type { typedef typename std::allocator_traits::pointer type; }; #else template struct sp_alloc_type { typedef typename A::pointer type; }; #endif template class sp_alloc_ptr { public: typedef T element_type; sp_alloc_ptr() BOOST_SP_NOEXCEPT : p_() { } #if defined(BOOST_MSVC) && BOOST_MSVC == 1600 sp_alloc_ptr(T* p) BOOST_SP_NOEXCEPT : p_(const_cast::type*>(p)) { } #endif sp_alloc_ptr(std::size_t, P p) BOOST_SP_NOEXCEPT : p_(p) { } #if !defined(BOOST_NO_CXX11_NULLPTR) sp_alloc_ptr(detail::sp_nullptr_t) BOOST_SP_NOEXCEPT : p_() { } #endif T& operator*() const { return *p_; } T* operator->() const BOOST_SP_NOEXCEPT { return boost::to_address(p_); } #if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) explicit operator bool() const BOOST_SP_NOEXCEPT { return !!p_; } #endif bool operator!() const BOOST_SP_NOEXCEPT { return !p_; } P ptr() const BOOST_SP_NOEXCEPT { return p_; } BOOST_STATIC_CONSTEXPR std::size_t size() BOOST_SP_NOEXCEPT { return 1; } #if defined(BOOST_MSVC) && BOOST_MSVC < 1910 static sp_alloc_ptr pointer_to(T& v) { return sp_alloc_ptr(1, std::pointer_traits

::pointer_to(const_cast::type&>(v))); } #endif private: P p_; }; template class sp_alloc_ptr { public: typedef T element_type; sp_alloc_ptr() BOOST_SP_NOEXCEPT : p_() { } sp_alloc_ptr(std::size_t n, P p) BOOST_SP_NOEXCEPT : p_(p) , n_(n) { } #if !defined(BOOST_NO_CXX11_NULLPTR) sp_alloc_ptr(detail::sp_nullptr_t) BOOST_SP_NOEXCEPT : p_() { } #endif T& operator[](std::size_t i) const { return p_[i]; } #if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) explicit operator bool() const BOOST_SP_NOEXCEPT { return !!p_; } #endif bool operator!() const BOOST_SP_NOEXCEPT { return !p_; } P ptr() const BOOST_SP_NOEXCEPT { return p_; } std::size_t size() const BOOST_SP_NOEXCEPT { return n_; } #if defined(BOOST_MSVC) && BOOST_MSVC < 1910 static sp_alloc_ptr pointer_to(T& v) { return sp_alloc_ptr(n_, std::pointer_traits

::pointer_to(const_cast::type&>(v))); } #endif private: P p_; std::size_t n_; }; template class sp_alloc_ptr { public: typedef T element_type; sp_alloc_ptr() BOOST_SP_NOEXCEPT : p_() { } sp_alloc_ptr(std::size_t, P p) BOOST_SP_NOEXCEPT : p_(p) { } #if !defined(BOOST_NO_CXX11_NULLPTR) sp_alloc_ptr(detail::sp_nullptr_t) BOOST_SP_NOEXCEPT : p_() { } #endif T& operator[](std::size_t i) const { return p_[i]; } #if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) explicit operator bool() const BOOST_SP_NOEXCEPT { return !!p_; } #endif bool operator!() const BOOST_SP_NOEXCEPT { return !p_; } P ptr() const BOOST_SP_NOEXCEPT { return p_; } BOOST_STATIC_CONSTEXPR std::size_t size() BOOST_SP_NOEXCEPT { return N; } #if defined(BOOST_MSVC) && BOOST_MSVC < 1910 static sp_alloc_ptr pointer_to(T& v) { return sp_alloc_ptr(N, std::pointer_traits

::pointer_to(const_cast::type&>(v))); } #endif private: P p_; }; template inline bool operator==(const sp_alloc_ptr& lhs, const sp_alloc_ptr& rhs) { return lhs.ptr() == rhs.ptr(); } template inline bool operator!=(const sp_alloc_ptr& lhs, const sp_alloc_ptr& rhs) { return !(lhs == rhs); } #if !defined(BOOST_NO_CXX11_NULLPTR) template inline bool operator==(const sp_alloc_ptr& lhs, detail::sp_nullptr_t) BOOST_SP_NOEXCEPT { return !lhs.ptr(); } template inline bool operator==(detail::sp_nullptr_t, const sp_alloc_ptr& rhs) BOOST_SP_NOEXCEPT { return !rhs.ptr(); } template inline bool operator!=(const sp_alloc_ptr& lhs, detail::sp_nullptr_t) BOOST_SP_NOEXCEPT { return !!lhs.ptr(); } template inline bool operator!=(detail::sp_nullptr_t, const sp_alloc_ptr& rhs) BOOST_SP_NOEXCEPT { return !!rhs.ptr(); } #endif template inline void sp_alloc_clear(A& a, typename sp_alloc_type::type p, std::size_t, boost::false_type) { boost::alloc_destroy(a, boost::to_address(p)); } template inline void sp_alloc_clear(A& a, typename sp_alloc_type::type p, std::size_t n, boost::true_type) { #if defined(BOOST_MSVC) && BOOST_MSVC < 1800 if (!p) { return; } #endif boost::alloc_destroy_n(a, boost::first_scalar(boost::to_address(p)), n * sp_alloc_size::value); } } /* detail */ template class alloc_deleter : empty_value::type>::type> { typedef typename detail::sp_alloc_to::type>::type allocator; typedef empty_value base; public: typedef detail::sp_alloc_ptr::type> pointer; explicit alloc_deleter(const allocator& a) BOOST_SP_NOEXCEPT : base(empty_init_t(), a) { } void operator()(pointer p) { detail::sp_alloc_clear(base::get(), p.ptr(), p.size(), is_array()); base::get().deallocate(p.ptr(), p.size()); } }; #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) template using alloc_noinit_deleter = alloc_deleter >; #endif namespace detail { template class sp_alloc_make { public: typedef typename sp_alloc_to::type>::type allocator; private: typedef boost::alloc_deleter deleter; public: typedef std::unique_ptr::type, deleter> type; sp_alloc_make(const A& a, std::size_t n) : a_(a) , n_(n) , p_(a_.allocate(n)) { } ~sp_alloc_make() { if (p_) { a_.deallocate(p_, n_); } } typename allocator::value_type* get() const BOOST_SP_NOEXCEPT { return boost::to_address(p_); } allocator& state() BOOST_SP_NOEXCEPT { return a_; } type release() BOOST_SP_NOEXCEPT { pointer p = p_; p_ = pointer(); return type(typename deleter::pointer(n_, p), deleter(a_)); } private: typedef typename sp_alloc_type::type pointer; allocator a_; std::size_t n_; pointer p_; }; } /* detail */ template inline typename enable_if_::value, std::unique_ptr > >::type allocate_unique(const A& alloc) { detail::sp_alloc_make c(alloc, 1); boost::alloc_construct(c.state(), c.get()); return c.release(); } #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template inline typename enable_if_::value, std::unique_ptr > >::type allocate_unique(const A& alloc, Args&&... args) { detail::sp_alloc_make c(alloc, 1); boost::alloc_construct(c.state(), c.get(), std::forward(args)...); return c.release(); } #endif template inline typename enable_if_::value, std::unique_ptr > >::type allocate_unique(const A& alloc, typename type_identity::type&& value) { detail::sp_alloc_make c(alloc, 1); boost::alloc_construct(c.state(), c.get(), std::move(value)); return c.release(); } template inline typename enable_if_::value, std::unique_ptr > > >::type allocate_unique_noinit(const A& alloc) { return boost::allocate_unique >(alloc); } template inline typename enable_if_::value, std::unique_ptr > >::type allocate_unique(const A& alloc, std::size_t size) { detail::sp_alloc_make c(alloc, size); boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()), size * detail::sp_alloc_size::value); return c.release(); } template inline typename enable_if_::value, std::unique_ptr::type, alloc_deleter > >::type allocate_unique(const A& alloc) { detail::sp_alloc_make c(alloc, extent::value); boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()), detail::sp_alloc_size::value); return c.release(); } template inline typename enable_if_::value, std::unique_ptr > > >::type allocate_unique_noinit(const A& alloc, std::size_t size) { return boost::allocate_unique >(alloc, size); } template inline typename enable_if_::value, std::unique_ptr::type, alloc_deleter > > >::type allocate_unique_noinit(const A& alloc) { return boost::allocate_unique >(alloc); } template inline typename enable_if_::value, std::unique_ptr > >::type allocate_unique(const A& alloc, std::size_t size, const typename remove_extent::type& value) { detail::sp_alloc_make c(alloc, size); boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()), size * detail::sp_alloc_size::value, boost::first_scalar(&value), detail::sp_alloc_size::type>::value); return c.release(); } template inline typename enable_if_::value, std::unique_ptr::type, alloc_deleter > >::type allocate_unique(const A& alloc, const typename remove_extent::type& value) { detail::sp_alloc_make c(alloc, extent::value); boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()), detail::sp_alloc_size::value, boost::first_scalar(&value), detail::sp_alloc_size::type>::value); return c.release(); } } /* boost */ #endif