////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Benedek Thaler 2015-2016 // (C) Copyright Ion Gaztanaga 2019-2020. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // See http://erenon.hu/container for documentation. // ////////////////////////////////////////////////////////////////////////////// #ifndef BOOST_CONTAINER_DETAIL_GUARDS_HPP #define BOOST_CONTAINER_DETAIL_GUARDS_HPP #include #include #include // BOOST_MOVABLE_BUT_NOT_COPYABLE // move/detail #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #include #endif #include namespace boost { namespace container { namespace detail { class null_construction_guard { public: #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) template null_construction_guard(Args&&...) {} #else #define NULL_CONSTRUCTION_GUARD_CODE(N) \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_CONTAINER_FORCEINLINE null_construction_guard(BOOST_MOVE_UREFANON##N)\ {}\ // BOOST_MOVE_ITERATE_0TO9(NULL_CONSTRUCTION_GUARD_CODE) #undef NULL_CONSTRUCTION_GUARD_CODE #endif void release() {} void extend() {} }; template class construction_guard { typedef typename boost::container::allocator_traits::pointer pointer; typedef typename boost::container::allocator_traits::size_type size_type; BOOST_MOVABLE_BUT_NOT_COPYABLE(construction_guard) public: construction_guard() : _alloc_ptr() , _elem_count() , _allocator() {} construction_guard(pointer alloc_ptr, Allocator& allocator) :_alloc_ptr(alloc_ptr) , _elem_count(0) , _allocator(&allocator) {} construction_guard(BOOST_RV_REF(construction_guard) rhs) :_alloc_ptr(rhs._alloc_ptr) , _elem_count(rhs._elem_count) , _allocator(rhs._allocator) { rhs._elem_count = 0; } ~construction_guard() { while (_elem_count) { --_elem_count; boost::container::allocator_traits::destroy(*_allocator, _alloc_ptr++); } } void release() { _elem_count = 0; } void extend() { ++_elem_count; } private: pointer _alloc_ptr; size_type _elem_count; Allocator* _allocator; }; /** * Has two ranges * * On success, destroys the first range (src), * on failure, destroys the second range (dst). * * Can be used when copying/moving a range */ template class nand_construction_guard { typedef typename boost::container::allocator_traits::pointer pointer; typedef typename boost::container::allocator_traits::size_type size_type; construction_guard _src; construction_guard _dst; bool _dst_released; public: nand_construction_guard() : _src() , _dst() , _dst_released(false) {} nand_construction_guard( pointer src, Allocator& src_alloc , pointer dst, Allocator& dst_alloc) :_src(src, src_alloc), _dst(dst, dst_alloc), _dst_released(false) {} void extend() { _src.extend(); _dst.extend(); } void release() // on success { _dst.release(); _dst_released = true; } ~nand_construction_guard() { if (! _dst_released) { _src.release(); } } }; template class allocation_guard { typedef typename boost::container::allocator_traits::pointer pointer; typedef typename boost::container::allocator_traits::size_type size_type; BOOST_MOVABLE_BUT_NOT_COPYABLE(allocation_guard) public: allocation_guard(pointer alloc_ptr, size_type alloc_size, Allocator& allocator) :_alloc_ptr(alloc_ptr), _alloc_size(alloc_size), _allocator(allocator) {} ~allocation_guard() { if (_alloc_ptr) { boost::container::allocator_traits::deallocate(_allocator, _alloc_ptr, _alloc_size); } } void release() { _alloc_ptr = 0; } private: pointer _alloc_ptr; size_type _alloc_size; Allocator& _allocator; }; }}} // namespace boost::container::detail #include #endif // BOOST_CONTAINER_DETAIL_GUARDS_HPP