/* Copyright 2007 Tobias Schwinger 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_FUNCTIONAL_FACTORY_HPP #define BOOST_FUNCTIONAL_FACTORY_HPP #include #include #include #include #if !defined(BOOST_NO_CXX11_ALLOCATOR) #include #endif #include #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #include #endif namespace boost { enum factory_alloc_propagation { factory_alloc_for_pointee_and_deleter, factory_passes_alloc_to_smart_pointer }; namespace detail { template struct fc_tag { }; #if !defined(BOOST_NO_CXX11_ALLOCATOR) template struct fc_rebind { typedef typename std::allocator_traits::template rebind_alloc type; }; template struct fc_pointer { typedef typename std::allocator_traits::pointer type; }; #else template struct fc_rebind { typedef typename A::template rebind::other type; }; template struct fc_pointer { typedef typename A::pointer type; }; #endif #if !defined(BOOST_NO_CXX11_ALLOCATOR) && \ !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template inline void fc_destroy(A& a, T* p) { std::allocator_traits::destroy(a, p); } #else template inline void fc_destroy(A&, T* p) { p->~T(); } #endif #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #if !defined(BOOST_NO_CXX11_ALLOCATOR) template inline void fc_construct(A& a, T* p, Args&&... args) { std::allocator_traits::construct(a, p, std::forward(args)...); } #else template inline void fc_construct(A&, T* p, Args&&... args) { ::new((void*)p) T(std::forward(args)...); } #endif #endif template class fc_delete : boost::empty_value { typedef boost::empty_value base; public: explicit fc_delete(const A& a) BOOST_NOEXCEPT : base(boost::empty_init_t(), a) { } void operator()(typename fc_pointer::type p) { boost::detail::fc_destroy(base::get(), boost::to_address(p)); base::get().deallocate(p, 1); } }; template class fc_allocate { public: explicit fc_allocate(const A& a) : a_(a) , p_(a_.allocate(1)) { } ~fc_allocate() { if (p_) { a_.deallocate(p_, 1); } } A& state() BOOST_NOEXCEPT { return a_; } typename A::value_type* get() const BOOST_NOEXCEPT { return boost::to_address(p_); } R release(fc_tag) { return R(release(), fc_delete(a_), a_); } R release(fc_tag) { return R(release(), fc_delete(a_)); } private: typedef typename fc_pointer::type pointer; pointer release() BOOST_NOEXCEPT { pointer p = p_; p_ = pointer(); return p; } fc_allocate(const fc_allocate&); fc_allocate& operator=(const fc_allocate&); A a_; pointer p_; }; } /* detail */ template class factory; template class factory { public: typedef typename remove_cv::type result_type; private: typedef typename pointer_traits::element_type type; public: #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template result_type operator()(Args&&... args) const { return result_type(new type(std::forward(args)...)); } #else result_type operator()() const { return result_type(new type()); } template result_type operator()(A0& a0) const { return result_type(new type(a0)); } template result_type operator()(A0& a0, A1& a1) const { return result_type(new type(a0, a1)); } template result_type operator()(A0& a0, A1& a1, A2& a2) const { return result_type(new type(a0, a1, a2)); } template result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3) const { return result_type(new type(a0, a1, a2, a3)); } template result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4) const { return result_type(new type(a0, a1, a2, a3, a4)); } template result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5) const { return result_type(new type(a0, a1, a2, a3, a4, a5)); } template result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6) const { return result_type(new type(a0, a1, a2, a3, a4, a5, a6)); } template result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7) const { return result_type(new type(a0, a1, a2, a3, a4, a5, a6, a7)); } template result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8) const { return result_type(new type(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } template result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8, A9& a9) const { return result_type(new type(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } #endif }; template class factory : empty_value::type>::element_type>::type> { public: typedef typename remove_cv::type result_type; private: typedef typename pointer_traits::element_type type; typedef typename detail::fc_rebind::type allocator; typedef empty_value base; public: factory() BOOST_NOEXCEPT : base(empty_init_t()) { } explicit factory(const Allocator& a) BOOST_NOEXCEPT : base(empty_init_t(), a) { } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template result_type operator()(Args&&... args) const { detail::fc_allocate s(base::get()); detail::fc_construct(s.state(), s.get(), std::forward(args)...); return s.release(detail::fc_tag()); } #else result_type operator()() const { detail::fc_allocate s(base::get()); ::new((void*)s.get()) type(); return s.release(detail::fc_tag()); } template result_type operator()(A0& a0) const { detail::fc_allocate s(base::get()); ::new((void*)s.get()) type(a0); return s.release(detail::fc_tag()); } template result_type operator()(A0& a0, A1& a1) const { detail::fc_allocate s(base::get()); ::new((void*)s.get()) type(a0, a1); return s.release(detail::fc_tag()); } template result_type operator()(A0& a0, A1& a1, A2& a2) const { detail::fc_allocate s(base::get()); ::new((void*)s.get()) type(a0, a1, a2); return s.release(detail::fc_tag()); } template result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3) const { detail::fc_allocate s(base::get()); ::new((void*)s.get()) type(a0, a1, a2, a3); return s.release(detail::fc_tag()); } template result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4) const { detail::fc_allocate s(base::get()); ::new((void*)s.get()) type(a0, a1, a2, a3, a4); return s.release(detail::fc_tag()); } template result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5) const { detail::fc_allocate s(base::get()); ::new((void*)s.get()) type(a0, a1, a2, a3, a4, a5); return s.release(detail::fc_tag()); } template result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6) const { detail::fc_allocate s(base::get()); ::new((void*)s.get()) type(a0, a1, a2, a3, a4, a5, a6); return s.release(detail::fc_tag()); } template result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7) const { detail::fc_allocate s(base::get()); ::new((void*)s.get()) type(a0, a1, a2, a3, a4, a5, a6, a7); return s.release(detail::fc_tag()); } template result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8) const { detail::fc_allocate s(base::get()); ::new((void*)s.get()) type(a0, a1, a2, a3, a4, a5, a6, a7, a8); return s.release(detail::fc_tag()); } template result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8, A9& a9) const { detail::fc_allocate s(base::get()); ::new((void*)s.get()) type(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return s.release(detail::fc_tag()); } #endif }; template class factory { }; } /* boost */ #endif