1 // Temporary buffer implementation -*- C++ -*-
2 
3 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
4 // 2010, 2011
5 // Free Software Foundation, Inc.
6 //
7 // This file is part of the GNU ISO C++ Library.  This library is free
8 // software; you can redistribute it and/or modify it under the
9 // terms of the GNU General Public License as published by the
10 // Free Software Foundation; either version 3, or (at your option)
11 // any later version.
12 
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 
18 // Under Section 7 of GPL version 3, you are granted additional
19 // permissions described in the GCC Runtime Library Exception, version
20 // 3.1, as published by the Free Software Foundation.
21 
22 // You should have received a copy of the GNU General Public License and
23 // a copy of the GCC Runtime Library Exception along with this program;
24 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
25 // <http://www.gnu.org/licenses/>.
26 
27 /*
28  *
29  * Copyright (c) 1994
30  * Hewlett-Packard Company
31  *
32  * Permission to use, copy, modify, distribute and sell this software
33  * and its documentation for any purpose is hereby granted without fee,
34  * provided that the above copyright notice appear in all copies and
35  * that both that copyright notice and this permission notice appear
36  * in supporting documentation.  Hewlett-Packard Company makes no
37  * representations about the suitability of this software for any
38  * purpose.  It is provided "as is" without express or implied warranty.
39  *
40  *
41  * Copyright (c) 1996,1997
42  * Silicon Graphics Computer Systems, Inc.
43  *
44  * Permission to use, copy, modify, distribute and sell this software
45  * and its documentation for any purpose is hereby granted without fee,
46  * provided that the above copyright notice appear in all copies and
47  * that both that copyright notice and this permission notice appear
48  * in supporting documentation.  Silicon Graphics makes no
49  * representations about the suitability of this software for any
50  * purpose.  It is provided "as is" without express or implied warranty.
51  */
52 
53 /** @file bits/stl_tempbuf.h
54  *  This is an internal header file, included by other library headers.
55  *  Do not attempt to use it directly. @headername{memory}
56  */
57 
58 #ifndef _STL_TEMPBUF_H
59 #define _STL_TEMPBUF_H 1
60 
61 #include <bits/stl_algobase.h>
62 #include <bits/stl_construct.h>
63 
64 namespace std _GLIBCXX_VISIBILITY(default)
65 {
66 _GLIBCXX_BEGIN_NAMESPACE_VERSION
67 
68   /**
69    *  @brief Allocates a temporary buffer.
70    *  @param  __len  The number of objects of type Tp.
71    *  @return See full description.
72    *
73    *  Reinventing the wheel, but this time with prettier spokes!
74    *
75    *  This function tries to obtain storage for @c __len adjacent Tp
76    *  objects.  The objects themselves are not constructed, of course.
77    *  A pair<> is returned containing <em>the buffer s address and
78    *  capacity (in the units of sizeof(_Tp)), or a pair of 0 values if
79    *  no storage can be obtained.</em>  Note that the capacity obtained
80    *  may be less than that requested if the memory is unavailable;
81    *  you should compare len with the .second return value.
82    *
83    * Provides the nothrow exception guarantee.
84    */
85   template<typename _Tp>
86     pair<_Tp*, ptrdiff_t>
87     get_temporary_buffer(ptrdiff_t __len) _GLIBCXX_NOEXCEPT
88     {
89       const ptrdiff_t __max =
90 	__gnu_cxx::__numeric_traits<ptrdiff_t>::__max / sizeof(_Tp);
91       if (__len > __max)
92 	__len = __max;
93 
94       while (__len > 0)
95 	{
96 	  _Tp* __tmp = static_cast<_Tp*>(::operator new(__len * sizeof(_Tp),
97 							std::nothrow));
98 	  if (__tmp != 0)
99 	    return std::pair<_Tp*, ptrdiff_t>(__tmp, __len);
100 	  __len /= 2;
101 	}
102       return std::pair<_Tp*, ptrdiff_t>(static_cast<_Tp*>(0), 0);
103     }
104 
105   /**
106    *  @brief The companion to get_temporary_buffer().
107    *  @param  __p  A buffer previously allocated by get_temporary_buffer.
108    *  @return   None.
109    *
110    *  Frees the memory pointed to by __p.
111    */
112   template<typename _Tp>
113     inline void
114     return_temporary_buffer(_Tp* __p)
115     { ::operator delete(__p, std::nothrow); }
116 
117 
118   /**
119    *  This class is used in two places: stl_algo.h and ext/memory,
120    *  where it is wrapped as the temporary_buffer class.  See
121    *  temporary_buffer docs for more notes.
122    */
123   template<typename _ForwardIterator, typename _Tp>
124     class _Temporary_buffer
125     {
126       // concept requirements
127       __glibcxx_class_requires(_ForwardIterator, _ForwardIteratorConcept)
128 
129     public:
130       typedef _Tp         value_type;
131       typedef value_type* pointer;
132       typedef pointer     iterator;
133       typedef ptrdiff_t   size_type;
134 
135     protected:
136       size_type  _M_original_len;
137       size_type  _M_len;
138       pointer    _M_buffer;
139 
140     public:
141       /// As per Table mumble.
142       size_type
143       size() const
144       { return _M_len; }
145 
146       /// Returns the size requested by the constructor; may be >size().
147       size_type
148       requested_size() const
149       { return _M_original_len; }
150 
151       /// As per Table mumble.
152       iterator
153       begin()
154       { return _M_buffer; }
155 
156       /// As per Table mumble.
157       iterator
158       end()
159       { return _M_buffer + _M_len; }
160 
161       /**
162        * Constructs a temporary buffer of a size somewhere between
163        * zero and the size of the given range.
164        */
165       _Temporary_buffer(_ForwardIterator __first, _ForwardIterator __last);
166 
167       ~_Temporary_buffer()
168       {
169 	std::_Destroy(_M_buffer, _M_buffer + _M_len);
170 	std::return_temporary_buffer(_M_buffer);
171       }
172 
173     private:
174       // Disable copy constructor and assignment operator.
175       _Temporary_buffer(const _Temporary_buffer&);
176 
177       void
178       operator=(const _Temporary_buffer&);
179     };
180 
181 
182   template<bool>
183     struct __uninitialized_construct_buf_dispatch
184     {
185       template<typename _ForwardIterator, typename _Tp>
186         static void
187         __ucr(_ForwardIterator __first, _ForwardIterator __last,
188 	      _Tp& __value)
189         {
190 	  if(__first == __last)
191 	    return;
192 
193 	  _ForwardIterator __cur = __first;
194 	  __try
195 	    {
196 	      std::_Construct(std::__addressof(*__first),
197 			      _GLIBCXX_MOVE(__value));
198 	      _ForwardIterator __prev = __cur;
199 	      ++__cur;
200 	      for(; __cur != __last; ++__cur, ++__prev)
201 		std::_Construct(std::__addressof(*__cur),
202 				_GLIBCXX_MOVE(*__prev));
203 	      __value = _GLIBCXX_MOVE(*__prev);
204 	    }
205 	  __catch(...)
206 	    {
207 	      std::_Destroy(__first, __cur);
208 	      __throw_exception_again;
209 	    }
210 	}
211     };
212 
213   template<>
214     struct __uninitialized_construct_buf_dispatch<true>
215     {
216       template<typename _ForwardIterator, typename _Tp>
217         static void
218         __ucr(_ForwardIterator, _ForwardIterator, _Tp&) { }
219     };
220 
221   // Constructs objects in the range [first, last).
222   // Note that while these new objects will take valid values,
223   // their exact value is not defined. In particular they may
224   // be 'moved from'.
225   //
226   // While __value may altered during this algorithm, it will have
227   // the same value when the algorithm finishes, unless one of the
228   // constructions throws.
229   //
230   // Requirements: _ForwardIterator::value_type(_Tp&&) is valid.
231   template<typename _ForwardIterator, typename _Tp>
232     inline void
233     __uninitialized_construct_buf(_ForwardIterator __first,
234 				  _ForwardIterator __last,
235 				  _Tp& __value)
236     {
237       typedef typename std::iterator_traits<_ForwardIterator>::value_type
238 	_ValueType;
239 
240       std::__uninitialized_construct_buf_dispatch<
241         __has_trivial_constructor(_ValueType)>::
242 	  __ucr(__first, __last, __value);
243     }
244 
245   template<typename _ForwardIterator, typename _Tp>
246     _Temporary_buffer<_ForwardIterator, _Tp>::
247     _Temporary_buffer(_ForwardIterator __first, _ForwardIterator __last)
248     : _M_original_len(std::distance(__first, __last)),
249       _M_len(0), _M_buffer(0)
250     {
251       __try
252 	{
253 	  std::pair<pointer, size_type> __p(std::get_temporary_buffer<
254 					    value_type>(_M_original_len));
255 	  _M_buffer = __p.first;
256 	  _M_len = __p.second;
257 	  if(_M_buffer)
258 	    std::__uninitialized_construct_buf(_M_buffer, _M_buffer + _M_len,
259 					       *__first);
260 	}
261       __catch(...)
262 	{
263 	  std::return_temporary_buffer(_M_buffer);
264 	  _M_buffer = 0;
265 	  _M_len = 0;
266 	  __throw_exception_again;
267 	}
268     }
269 
270 _GLIBCXX_END_NAMESPACE_VERSION
271 } // namespace
272 
273 #endif /* _STL_TEMPBUF_H */
274 
275