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