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