1 ////////////////////////////////////////////////////////////////////////////// 2 // 3 // (C) Copyright Benedek Thaler 2015-2016 4 // (C) Copyright Ion Gaztanaga 2019-2020. Distributed under the Boost 5 // Software License, Version 1.0. (See accompanying file 6 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 // 8 // See http://erenon.hu/container for documentation. 9 // 10 ////////////////////////////////////////////////////////////////////////////// 11 12 #ifndef BOOST_CONTAINER_DETAIL_GUARDS_HPP 13 #define BOOST_CONTAINER_DETAIL_GUARDS_HPP 14 15 #include <boost/container/detail/config_begin.hpp> 16 #include <boost/container/detail/workaround.hpp> 17 18 #include <boost/move/core.hpp> // BOOST_MOVABLE_BUT_NOT_COPYABLE 19 20 // move/detail 21 #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) 22 #include <boost/move/detail/fwd_macros.hpp> 23 #endif 24 25 #include <boost/container/allocator_traits.hpp> 26 27 namespace boost { 28 namespace container { 29 namespace detail { 30 31 class null_construction_guard 32 { 33 public: 34 35 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) 36 37 template <typename... Args> null_construction_guard(Args &&...)38 null_construction_guard(Args&&...) {} 39 40 #else 41 42 #define NULL_CONSTRUCTION_GUARD_CODE(N) \ 43 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ 44 BOOST_CONTAINER_FORCEINLINE null_construction_guard(BOOST_MOVE_UREFANON##N)\ 45 {}\ 46 // 47 BOOST_MOVE_ITERATE_0TO9(NULL_CONSTRUCTION_GUARD_CODE) 48 #undef NULL_CONSTRUCTION_GUARD_CODE 49 #endif 50 release()51 void release() {} extend()52 void extend() {} 53 }; 54 55 template <typename Allocator> 56 class construction_guard 57 { 58 typedef typename boost::container::allocator_traits<Allocator>::pointer pointer; 59 typedef typename boost::container::allocator_traits<Allocator>::size_type size_type; 60 61 BOOST_MOVABLE_BUT_NOT_COPYABLE(construction_guard) 62 63 public: construction_guard()64 construction_guard() 65 : _alloc_ptr() 66 , _elem_count() 67 , _allocator() 68 {} 69 construction_guard(pointer alloc_ptr,Allocator & allocator)70 construction_guard(pointer alloc_ptr, Allocator& allocator) 71 :_alloc_ptr(alloc_ptr) 72 , _elem_count(0) 73 , _allocator(&allocator) 74 {} 75 construction_guard(BOOST_RV_REF (construction_guard)rhs)76 construction_guard(BOOST_RV_REF(construction_guard) rhs) 77 :_alloc_ptr(rhs._alloc_ptr) 78 , _elem_count(rhs._elem_count) 79 , _allocator(rhs._allocator) 80 { 81 rhs._elem_count = 0; 82 } 83 ~construction_guard()84 ~construction_guard() 85 { 86 while (_elem_count) { 87 --_elem_count; 88 boost::container::allocator_traits<Allocator>::destroy(*_allocator, _alloc_ptr++); 89 } 90 } 91 release()92 void release() 93 { 94 _elem_count = 0; 95 } 96 extend()97 void extend() 98 { 99 ++_elem_count; 100 } 101 102 private: 103 pointer _alloc_ptr; 104 size_type _elem_count; 105 Allocator* _allocator; 106 }; 107 108 109 /** 110 * Has two ranges 111 * 112 * On success, destroys the first range (src), 113 * on failure, destroys the second range (dst). 114 * 115 * Can be used when copying/moving a range 116 */ 117 template <class Allocator> 118 class nand_construction_guard 119 { 120 typedef typename boost::container::allocator_traits<Allocator>::pointer pointer; 121 typedef typename boost::container::allocator_traits<Allocator>::size_type size_type; 122 123 construction_guard<Allocator> _src; 124 construction_guard<Allocator> _dst; 125 bool _dst_released; 126 127 public: nand_construction_guard()128 nand_construction_guard() 129 : _src() 130 , _dst() 131 , _dst_released(false) 132 {} 133 nand_construction_guard(pointer src,Allocator & src_alloc,pointer dst,Allocator & dst_alloc)134 nand_construction_guard( pointer src, Allocator& src_alloc 135 , pointer dst, Allocator& dst_alloc) 136 :_src(src, src_alloc), 137 _dst(dst, dst_alloc), 138 _dst_released(false) 139 {} 140 extend()141 void extend() 142 { 143 _src.extend(); 144 _dst.extend(); 145 } 146 release()147 void release() // on success 148 { 149 _dst.release(); 150 _dst_released = true; 151 } 152 ~nand_construction_guard()153 ~nand_construction_guard() 154 { 155 if (! _dst_released) { _src.release(); } 156 } 157 }; 158 159 160 template <typename Allocator> 161 class allocation_guard 162 { 163 typedef typename boost::container::allocator_traits<Allocator>::pointer pointer; 164 typedef typename boost::container::allocator_traits<Allocator>::size_type size_type; 165 166 BOOST_MOVABLE_BUT_NOT_COPYABLE(allocation_guard) 167 168 public: allocation_guard(pointer alloc_ptr,size_type alloc_size,Allocator & allocator)169 allocation_guard(pointer alloc_ptr, size_type alloc_size, Allocator& allocator) 170 :_alloc_ptr(alloc_ptr), 171 _alloc_size(alloc_size), 172 _allocator(allocator) 173 {} 174 ~allocation_guard()175 ~allocation_guard() 176 { 177 if (_alloc_ptr) 178 { 179 boost::container::allocator_traits<Allocator>::deallocate(_allocator, _alloc_ptr, _alloc_size); 180 } 181 } 182 release()183 void release() 184 { 185 _alloc_ptr = 0; 186 } 187 188 private: 189 pointer _alloc_ptr; 190 size_type _alloc_size; 191 Allocator& _allocator; 192 }; 193 194 }}} // namespace boost::container::detail 195 196 #include <boost/container/detail/config_end.hpp> 197 198 #endif // BOOST_CONTAINER_DETAIL_GUARDS_HPP 199