libstdc++
bitmap_allocator.h
Go to the documentation of this file.
1 // Bitmap Allocator. -*- C++ -*-
2 
3 // Copyright (C) 2004-2022 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 /** @file ext/bitmap_allocator.h
26  * This file is a GNU extension to the Standard C++ Library.
27  */
28 
29 #ifndef _BITMAP_ALLOCATOR_H
30 #define _BITMAP_ALLOCATOR_H 1
31 
32 #include <utility> // For std::pair.
33 #include <bits/functexcept.h> // For __throw_bad_alloc().
34 #include <bits/stl_function.h> // For greater_equal, and less_equal.
35 #include <new> // For operator new.
36 #include <debug/debug.h> // _GLIBCXX_DEBUG_ASSERT
37 #include <ext/concurrence.h>
38 #include <bits/move.h>
39 
40 /** @brief The constant in the expression below is the alignment
41  * required in bytes.
42  */
43 #define _BALLOC_ALIGN_BYTES 8
44 
45 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
46 {
47 _GLIBCXX_BEGIN_NAMESPACE_VERSION
48 
49  namespace __detail
50  {
51  /** @class __mini_vector bitmap_allocator.h bitmap_allocator.h
52  *
53  * @brief __mini_vector<> is a stripped down version of the
54  * full-fledged std::vector<>.
55  *
56  * It is to be used only for built-in types or PODs. Notable
57  * differences are:
58  *
59  * 1. Not all accessor functions are present.
60  * 2. Used ONLY for PODs.
61  * 3. No Allocator template argument. Uses ::operator new() to get
62  * memory, and ::operator delete() to free it.
63  * Caveat: The dtor does NOT free the memory allocated, so this a
64  * memory-leaking vector!
65  */
66  template<typename _Tp>
68  {
70  __mini_vector& operator=(const __mini_vector&);
71 
72  public:
73  typedef _Tp value_type;
74  typedef _Tp* pointer;
75  typedef _Tp& reference;
76  typedef const _Tp& const_reference;
77  typedef std::size_t size_type;
78  typedef std::ptrdiff_t difference_type;
79  typedef pointer iterator;
80 
81  private:
82  pointer _M_start;
83  pointer _M_finish;
84  pointer _M_end_of_storage;
85 
86  size_type
87  _M_space_left() const throw()
88  { return _M_end_of_storage - _M_finish; }
89 
90  _GLIBCXX_NODISCARD pointer
91  allocate(size_type __n)
92  { return static_cast<pointer>(::operator new(__n * sizeof(_Tp))); }
93 
94  void
95  deallocate(pointer __p, size_type)
96  { ::operator delete(__p); }
97 
98  public:
99  // Members used: size(), push_back(), pop_back(),
100  // insert(iterator, const_reference), erase(iterator),
101  // begin(), end(), back(), operator[].
102 
103  __mini_vector()
104  : _M_start(0), _M_finish(0), _M_end_of_storage(0) { }
105 
106  size_type
107  size() const throw()
108  { return _M_finish - _M_start; }
109 
110  iterator
111  begin() const throw()
112  { return this->_M_start; }
113 
114  iterator
115  end() const throw()
116  { return this->_M_finish; }
117 
118  reference
119  back() const throw()
120  { return *(this->end() - 1); }
121 
122  reference
123  operator[](const size_type __pos) const throw()
124  { return this->_M_start[__pos]; }
125 
126  void
127  insert(iterator __pos, const_reference __x);
128 
129  void
130  push_back(const_reference __x)
131  {
132  if (this->_M_space_left())
133  {
134  *this->end() = __x;
135  ++this->_M_finish;
136  }
137  else
138  this->insert(this->end(), __x);
139  }
140 
141  void
142  pop_back() throw()
143  { --this->_M_finish; }
144 
145  void
146  erase(iterator __pos) throw();
147 
148  void
149  clear() throw()
150  { this->_M_finish = this->_M_start; }
151  };
152 
153  // Out of line function definitions.
154  template<typename _Tp>
156  insert(iterator __pos, const_reference __x)
157  {
158  if (this->_M_space_left())
159  {
160  size_type __to_move = this->_M_finish - __pos;
161  iterator __dest = this->end();
162  iterator __src = this->end() - 1;
163 
164  ++this->_M_finish;
165  while (__to_move)
166  {
167  *__dest = *__src;
168  --__dest; --__src; --__to_move;
169  }
170  *__pos = __x;
171  }
172  else
173  {
174  size_type __new_size = this->size() ? this->size() * 2 : 1;
175  iterator __new_start = this->allocate(__new_size);
176  iterator __first = this->begin();
177  iterator __start = __new_start;
178  while (__first != __pos)
179  {
180  *__start = *__first;
181  ++__start; ++__first;
182  }
183  *__start = __x;
184  ++__start;
185  while (__first != this->end())
186  {
187  *__start = *__first;
188  ++__start; ++__first;
189  }
190  if (this->_M_start)
191  this->deallocate(this->_M_start, this->size());
192 
193  this->_M_start = __new_start;
194  this->_M_finish = __start;
195  this->_M_end_of_storage = this->_M_start + __new_size;
196  }
197  }
198 
199  template<typename _Tp>
201  erase(iterator __pos) throw()
202  {
203  while (__pos + 1 != this->end())
204  {
205  *__pos = __pos[1];
206  ++__pos;
207  }
208  --this->_M_finish;
209  }
210 
211 
212  template<typename _Tp>
213  struct __mv_iter_traits
214  {
215  typedef typename _Tp::value_type value_type;
216  typedef typename _Tp::difference_type difference_type;
217  };
218 
219  template<typename _Tp>
220  struct __mv_iter_traits<_Tp*>
221  {
222  typedef _Tp value_type;
223  typedef std::ptrdiff_t difference_type;
224  };
225 
226  enum
227  {
228  bits_per_byte = 8,
229  bits_per_block = sizeof(std::size_t) * std::size_t(bits_per_byte)
230  };
231 
232  template<typename _ForwardIterator, typename _Tp, typename _Compare>
233  _ForwardIterator
234  __lower_bound(_ForwardIterator __first, _ForwardIterator __last,
235  const _Tp& __val, _Compare __comp)
236  {
237  typedef typename __mv_iter_traits<_ForwardIterator>::difference_type
238  _DistanceType;
239 
240  _DistanceType __len = __last - __first;
241  _DistanceType __half;
242  _ForwardIterator __middle;
243 
244  while (__len > 0)
245  {
246  __half = __len >> 1;
247  __middle = __first;
248  __middle += __half;
249  if (__comp(*__middle, __val))
250  {
251  __first = __middle;
252  ++__first;
253  __len = __len - __half - 1;
254  }
255  else
256  __len = __half;
257  }
258  return __first;
259  }
260 
261  /** @brief The number of Blocks pointed to by the address pair
262  * passed to the function.
263  */
264  template<typename _AddrPair>
265  inline std::size_t
266  __num_blocks(_AddrPair __ap)
267  { return (__ap.second - __ap.first) + 1; }
268 
269  /** @brief The number of Bit-maps pointed to by the address pair
270  * passed to the function.
271  */
272  template<typename _AddrPair>
273  inline std::size_t
274  __num_bitmaps(_AddrPair __ap)
275  { return __num_blocks(__ap) / std::size_t(bits_per_block); }
276 
277  // _Tp should be a pointer type.
278  template<typename _Tp>
279  class _Inclusive_between
280  {
281  typedef _Tp pointer;
282  pointer _M_ptr_value;
283  typedef typename std::pair<_Tp, _Tp> _Block_pair;
284 
285  public:
286  _Inclusive_between(pointer __ptr) : _M_ptr_value(__ptr)
287  { }
288 
289  bool
290  operator()(_Block_pair __bp) const throw()
291  {
292  if (std::less_equal<pointer>()(_M_ptr_value, __bp.second)
293  && std::greater_equal<pointer>()(_M_ptr_value, __bp.first))
294  return true;
295  else
296  return false;
297  }
298  };
299 
300  // Used to pass a Functor to functions by reference.
301  template<typename _Functor>
302  class _Functor_Ref
303  {
304  _Functor& _M_fref;
305 
306  public:
307  typedef typename _Functor::argument_type argument_type;
308  typedef typename _Functor::result_type result_type;
309 
310  _Functor_Ref(_Functor& __fref) : _M_fref(__fref)
311  { }
312 
313  result_type
314  operator()(argument_type __arg)
315  { return _M_fref(__arg); }
316  };
317 
318  /** @class _Ffit_finder bitmap_allocator.h bitmap_allocator.h
319  *
320  * @brief The class which acts as a predicate for applying the
321  * first-fit memory allocation policy for the bitmap allocator.
322  */
323  // _Tp should be a pointer type, and _Alloc is the Allocator for
324  // the vector.
325  template<typename _Tp>
327  {
330  typedef typename _BPVector::difference_type _Counter_type;
331 
332  std::size_t* _M_pbitmap;
333  _Counter_type _M_data_offset;
334 
335  public:
336  typedef bool result_type;
337  typedef _Block_pair argument_type;
338 
339  _Ffit_finder() : _M_pbitmap(0), _M_data_offset(0)
340  { }
341 
342  bool
343  operator()(_Block_pair __bp) throw()
344  {
345  using std::size_t;
346  // Set the _rover to the last physical location bitmap,
347  // which is the bitmap which belongs to the first free
348  // block. Thus, the bitmaps are in exact reverse order of
349  // the actual memory layout. So, we count down the bitmaps,
350  // which is the same as moving up the memory.
351 
352  // If the used count stored at the start of the Bit Map headers
353  // is equal to the number of Objects that the current Block can
354  // store, then there is definitely no space for another single
355  // object, so just return false.
356  _Counter_type __diff = __detail::__num_bitmaps(__bp);
357 
358  if (*(reinterpret_cast<size_t*>
359  (__bp.first) - (__diff + 1)) == __detail::__num_blocks(__bp))
360  return false;
361 
362  size_t* __rover = reinterpret_cast<size_t*>(__bp.first) - 1;
363 
364  for (_Counter_type __i = 0; __i < __diff; ++__i)
365  {
366  _M_data_offset = __i;
367  if (*__rover)
368  {
369  _M_pbitmap = __rover;
370  return true;
371  }
372  --__rover;
373  }
374  return false;
375  }
376 
377  std::size_t*
378  _M_get() const throw()
379  { return _M_pbitmap; }
380 
381  _Counter_type
382  _M_offset() const throw()
383  { return _M_data_offset * std::size_t(bits_per_block); }
384  };
385 
386  /** @class _Bitmap_counter bitmap_allocator.h bitmap_allocator.h
387  *
388  * @brief The bitmap counter which acts as the bitmap
389  * manipulator, and manages the bit-manipulation functions and
390  * the searching and identification functions on the bit-map.
391  */
392  // _Tp should be a pointer type.
393  template<typename _Tp>
395  {
396  typedef typename
398  typedef typename _BPVector::size_type _Index_type;
399  typedef _Tp pointer;
400 
401  _BPVector& _M_vbp;
402  std::size_t* _M_curr_bmap;
403  std::size_t* _M_last_bmap_in_block;
404  _Index_type _M_curr_index;
405 
406  public:
407  // Use the 2nd parameter with care. Make sure that such an
408  // entry exists in the vector before passing that particular
409  // index to this ctor.
410  _Bitmap_counter(_BPVector& Rvbp, long __index = -1) : _M_vbp(Rvbp)
411  { this->_M_reset(__index); }
412 
413  void
414  _M_reset(long __index = -1) throw()
415  {
416  if (__index == -1)
417  {
418  _M_curr_bmap = 0;
419  _M_curr_index = static_cast<_Index_type>(-1);
420  return;
421  }
422 
423  _M_curr_index = __index;
424  _M_curr_bmap = reinterpret_cast<std::size_t*>
425  (_M_vbp[_M_curr_index].first) - 1;
426 
427  _GLIBCXX_DEBUG_ASSERT(__index <= (long)_M_vbp.size() - 1);
428 
429  _M_last_bmap_in_block = _M_curr_bmap
430  - ((_M_vbp[_M_curr_index].second
431  - _M_vbp[_M_curr_index].first + 1)
432  / std::size_t(bits_per_block) - 1);
433  }
434 
435  // Dangerous Function! Use with extreme care. Pass to this
436  // function ONLY those values that are known to be correct,
437  // otherwise this will mess up big time.
438  void
439  _M_set_internal_bitmap(std::size_t* __new_internal_marker) throw()
440  { _M_curr_bmap = __new_internal_marker; }
441 
442  bool
443  _M_finished() const throw()
444  { return(_M_curr_bmap == 0); }
445 
447  operator++() throw()
448  {
449  if (_M_curr_bmap == _M_last_bmap_in_block)
450  {
451  if (++_M_curr_index == _M_vbp.size())
452  _M_curr_bmap = 0;
453  else
454  this->_M_reset(_M_curr_index);
455  }
456  else
457  --_M_curr_bmap;
458  return *this;
459  }
460 
461  std::size_t*
462  _M_get() const throw()
463  { return _M_curr_bmap; }
464 
465  pointer
466  _M_base() const throw()
467  { return _M_vbp[_M_curr_index].first; }
468 
469  _Index_type
470  _M_offset() const throw()
471  {
472  return std::size_t(bits_per_block)
473  * ((reinterpret_cast<std::size_t*>(this->_M_base())
474  - _M_curr_bmap) - 1);
475  }
476 
477  _Index_type
478  _M_where() const throw()
479  { return _M_curr_index; }
480  };
481 
482  /** @brief Mark a memory address as allocated by re-setting the
483  * corresponding bit in the bit-map.
484  */
485  inline void
486  __bit_allocate(std::size_t* __pbmap, std::size_t __pos) throw()
487  {
488  std::size_t __mask = 1 << __pos;
489  __mask = ~__mask;
490  *__pbmap &= __mask;
491  }
492 
493  /** @brief Mark a memory address as free by setting the
494  * corresponding bit in the bit-map.
495  */
496  inline void
497  __bit_free(std::size_t* __pbmap, std::size_t __pos) throw()
498  {
499  std::size_t __mask = 1 << __pos;
500  *__pbmap |= __mask;
501  }
502  } // namespace __detail
503 
504  /** @brief Generic Version of the bsf instruction.
505  */
506  inline std::size_t
507  _Bit_scan_forward(std::size_t __num)
508  { return static_cast<std::size_t>(__builtin_ctzl(__num)); }
509 
510  /** @class free_list bitmap_allocator.h bitmap_allocator.h
511  *
512  * @brief The free list class for managing chunks of memory to be
513  * given to and returned by the bitmap_allocator.
514  */
515  class free_list
516  {
517  public:
518  typedef std::size_t* value_type;
520  typedef vector_type::iterator iterator;
521  typedef __mutex __mutex_type;
522 
523  private:
524  struct _LT_pointer_compare
525  {
526  bool
527  operator()(const std::size_t* __pui,
528  const std::size_t __cui) const throw()
529  { return *__pui < __cui; }
530  };
531 
532 #if defined __GTHREADS
533  __mutex_type&
534  _M_get_mutex()
535  {
536  static __mutex_type _S_mutex;
537  return _S_mutex;
538  }
539 #endif
540 
541  vector_type&
542  _M_get_free_list()
543  {
544  static vector_type _S_free_list;
545  return _S_free_list;
546  }
547 
548  /** @brief Performs validation of memory based on their size.
549  *
550  * @param __addr The pointer to the memory block to be
551  * validated.
552  *
553  * Validates the memory block passed to this function and
554  * appropriately performs the action of managing the free list of
555  * blocks by adding this block to the free list or deleting this
556  * or larger blocks from the free list.
557  */
558  void
559  _M_validate(std::size_t* __addr) throw()
560  {
561  vector_type& __free_list = _M_get_free_list();
562  const vector_type::size_type __max_size = 64;
563  if (__free_list.size() >= __max_size)
564  {
565  // Ok, the threshold value has been reached. We determine
566  // which block to remove from the list of free blocks.
567  if (*__addr >= *__free_list.back())
568  {
569  // Ok, the new block is greater than or equal to the
570  // last block in the list of free blocks. We just free
571  // the new block.
572  ::operator delete(static_cast<void*>(__addr));
573  return;
574  }
575  else
576  {
577  // Deallocate the last block in the list of free lists,
578  // and insert the new one in its correct position.
579  ::operator delete(static_cast<void*>(__free_list.back()));
580  __free_list.pop_back();
581  }
582  }
583 
584  // Just add the block to the list of free lists unconditionally.
585  iterator __temp = __detail::__lower_bound
586  (__free_list.begin(), __free_list.end(),
587  *__addr, _LT_pointer_compare());
588 
589  // We may insert the new free list before _temp;
590  __free_list.insert(__temp, __addr);
591  }
592 
593  /** @brief Decides whether the wastage of memory is acceptable for
594  * the current memory request and returns accordingly.
595  *
596  * @param __block_size The size of the block available in the free
597  * list.
598  *
599  * @param __required_size The required size of the memory block.
600  *
601  * @return true if the wastage incurred is acceptable, else returns
602  * false.
603  */
604  bool
605  _M_should_i_give(std::size_t __block_size,
606  std::size_t __required_size) throw()
607  {
608  const std::size_t __max_wastage_percentage = 36;
609  if (__block_size >= __required_size &&
610  (((__block_size - __required_size) * 100 / __block_size)
611  < __max_wastage_percentage))
612  return true;
613  else
614  return false;
615  }
616 
617  public:
618  /** @brief This function returns the block of memory to the
619  * internal free list.
620  *
621  * @param __addr The pointer to the memory block that was given
622  * by a call to the _M_get function.
623  */
624  inline void
625  _M_insert(std::size_t* __addr) throw()
626  {
627 #if defined __GTHREADS
628  __scoped_lock __bfl_lock(_M_get_mutex());
629 #endif
630  // Call _M_validate to decide what should be done with
631  // this particular free list.
632  this->_M_validate(reinterpret_cast<std::size_t*>(__addr) - 1);
633  // See discussion as to why this is 1!
634  }
635 
636  /** @brief This function gets a block of memory of the specified
637  * size from the free list.
638  *
639  * @param __sz The size in bytes of the memory required.
640  *
641  * @return A pointer to the new memory block of size at least
642  * equal to that requested.
643  */
644  std::size_t*
645  _M_get(std::size_t __sz) _GLIBCXX_THROW(std::bad_alloc);
646 
647  /** @brief This function just clears the internal Free List, and
648  * gives back all the memory to the OS.
649  */
650  void
651  _M_clear();
652  };
653 
654 
655  // Forward declare the class.
656  template<typename _Tp>
658 
659  // Specialize for void:
660  template<>
661  class bitmap_allocator<void>
662  {
663  public:
664  typedef void* pointer;
665  typedef const void* const_pointer;
666 
667  // Reference-to-void members are impossible.
668  typedef void value_type;
669  template<typename _Tp1>
670  struct rebind
671  {
672  typedef bitmap_allocator<_Tp1> other;
673  };
674  };
675 
676  /**
677  * @brief Bitmap Allocator, primary template.
678  * @ingroup allocators
679  */
680  template<typename _Tp>
681  class bitmap_allocator : private free_list
682  {
683  public:
684  typedef std::size_t size_type;
685  typedef std::ptrdiff_t difference_type;
686  typedef _Tp* pointer;
687  typedef const _Tp* const_pointer;
688  typedef _Tp& reference;
689  typedef const _Tp& const_reference;
690  typedef _Tp value_type;
691  typedef free_list::__mutex_type __mutex_type;
692 
693  template<typename _Tp1>
694  struct rebind
695  {
696  typedef bitmap_allocator<_Tp1> other;
697  };
698 
699 #if __cplusplus >= 201103L
700  // _GLIBCXX_RESOLVE_LIB_DEFECTS
701  // 2103. propagate_on_container_move_assignment
703 #endif
704 
705  private:
706  template<std::size_t _BSize, std::size_t _AlignSize>
707  struct aligned_size
708  {
709  enum
710  {
711  modulus = _BSize % _AlignSize,
712  value = _BSize + (modulus ? _AlignSize - (modulus) : 0)
713  };
714  };
715 
716  struct _Alloc_block
717  {
718  char __M_unused[aligned_size<sizeof(value_type),
719  _BALLOC_ALIGN_BYTES>::value];
720  };
721 
722 
724 
726  typedef typename _BPVector::iterator _BPiter;
727 
728  template<typename _Predicate>
729  static _BPiter
730  _S_find(_Predicate __p)
731  {
732  _BPiter __first = _S_mem_blocks.begin();
733  while (__first != _S_mem_blocks.end() && !__p(*__first))
734  ++__first;
735  return __first;
736  }
737 
738 #if defined _GLIBCXX_DEBUG
739  // Complexity: O(lg(N)). Where, N is the number of block of size
740  // sizeof(value_type).
741  void
742  _S_check_for_free_blocks() throw()
743  {
744  typedef typename __detail::_Ffit_finder<_Alloc_block*> _FFF;
745  _BPiter __bpi = _S_find(_FFF());
746 
747  _GLIBCXX_DEBUG_ASSERT(__bpi == _S_mem_blocks.end());
748  }
749 #endif
750 
751  /** @brief Responsible for exponentially growing the internal
752  * memory pool.
753  *
754  * @throw std::bad_alloc. If memory cannot be allocated.
755  *
756  * Complexity: O(1), but internally depends upon the
757  * complexity of the function free_list::_M_get. The part where
758  * the bitmap headers are written has complexity: O(X),where X
759  * is the number of blocks of size sizeof(value_type) within
760  * the newly acquired block. Having a tight bound.
761  */
762  void
763  _S_refill_pool() _GLIBCXX_THROW(std::bad_alloc)
764  {
765  using std::size_t;
766 #if defined _GLIBCXX_DEBUG
767  _S_check_for_free_blocks();
768 #endif
769 
770  const size_t __num_bitmaps = (_S_block_size
771  / size_t(__detail::bits_per_block));
772  const size_t __size_to_allocate = sizeof(size_t)
773  + _S_block_size * sizeof(_Alloc_block)
774  + __num_bitmaps * sizeof(size_t);
775 
776  size_t* __temp =
777  reinterpret_cast<size_t*>(this->_M_get(__size_to_allocate));
778  *__temp = 0;
779  ++__temp;
780 
781  // The Header information goes at the Beginning of the Block.
782  _Block_pair __bp =
783  std::make_pair(reinterpret_cast<_Alloc_block*>
784  (__temp + __num_bitmaps),
785  reinterpret_cast<_Alloc_block*>
786  (__temp + __num_bitmaps)
787  + _S_block_size - 1);
788 
789  // Fill the Vector with this information.
790  _S_mem_blocks.push_back(__bp);
791 
792  for (size_t __i = 0; __i < __num_bitmaps; ++__i)
793  __temp[__i] = ~static_cast<size_t>(0); // 1 Indicates all Free.
794 
795  _S_block_size *= 2;
796  }
797 
798  static _BPVector _S_mem_blocks;
799  static std::size_t _S_block_size;
800  static __detail::_Bitmap_counter<_Alloc_block*> _S_last_request;
801  static typename _BPVector::size_type _S_last_dealloc_index;
802 #if defined __GTHREADS
803  static __mutex_type _S_mut;
804 #endif
805 
806  public:
807 
808  /** @brief Allocates memory for a single object of size
809  * sizeof(_Tp).
810  *
811  * @throw std::bad_alloc. If memory cannot be allocated.
812  *
813  * Complexity: Worst case complexity is O(N), but that
814  * is hardly ever hit. If and when this particular case is
815  * encountered, the next few cases are guaranteed to have a
816  * worst case complexity of O(1)! That's why this function
817  * performs very well on average. You can consider this
818  * function to have a complexity referred to commonly as:
819  * Amortized Constant time.
820  */
821  pointer
822  _M_allocate_single_object() _GLIBCXX_THROW(std::bad_alloc)
823  {
824  using std::size_t;
825 #if defined __GTHREADS
826  __scoped_lock __bit_lock(_S_mut);
827 #endif
828 
829  // The algorithm is something like this: The last_request
830  // variable points to the last accessed Bit Map. When such a
831  // condition occurs, we try to find a free block in the
832  // current bitmap, or succeeding bitmaps until the last bitmap
833  // is reached. If no free block turns up, we resort to First
834  // Fit method.
835 
836  // WARNING: Do not re-order the condition in the while
837  // statement below, because it relies on C++'s short-circuit
838  // evaluation. The return from _S_last_request->_M_get() will
839  // NOT be dereference able if _S_last_request->_M_finished()
840  // returns true. This would inevitably lead to a NULL pointer
841  // dereference if tinkered with.
842  while (_S_last_request._M_finished() == false
843  && (*(_S_last_request._M_get()) == 0))
844  _S_last_request.operator++();
845 
846  if (__builtin_expect(_S_last_request._M_finished() == true, false))
847  {
848  // Fall Back to First Fit algorithm.
849  typedef typename __detail::_Ffit_finder<_Alloc_block*> _FFF;
850  _FFF __fff;
851  _BPiter __bpi = _S_find(__detail::_Functor_Ref<_FFF>(__fff));
852 
853  if (__bpi != _S_mem_blocks.end())
854  {
855  // Search was successful. Ok, now mark the first bit from
856  // the right as 0, meaning Allocated. This bit is obtained
857  // by calling _M_get() on __fff.
858  size_t __nz_bit = _Bit_scan_forward(*__fff._M_get());
859  __detail::__bit_allocate(__fff._M_get(), __nz_bit);
860 
861  _S_last_request._M_reset(__bpi - _S_mem_blocks.begin());
862 
863  // Now, get the address of the bit we marked as allocated.
864  pointer __ret = reinterpret_cast<pointer>
865  (__bpi->first + __fff._M_offset() + __nz_bit);
866  size_t* __puse_count =
867  reinterpret_cast<size_t*>
868  (__bpi->first) - (__detail::__num_bitmaps(*__bpi) + 1);
869 
870  ++(*__puse_count);
871  return __ret;
872  }
873  else
874  {
875  // Search was unsuccessful. We Add more memory to the
876  // pool by calling _S_refill_pool().
877  _S_refill_pool();
878 
879  // _M_Reset the _S_last_request structure to the first
880  // free block's bit map.
881  _S_last_request._M_reset(_S_mem_blocks.size() - 1);
882 
883  // Now, mark that bit as allocated.
884  }
885  }
886 
887  // _S_last_request holds a pointer to a valid bit map, that
888  // points to a free block in memory.
889  size_t __nz_bit = _Bit_scan_forward(*_S_last_request._M_get());
890  __detail::__bit_allocate(_S_last_request._M_get(), __nz_bit);
891 
892  pointer __ret = reinterpret_cast<pointer>
893  (_S_last_request._M_base() + _S_last_request._M_offset() + __nz_bit);
894 
895  size_t* __puse_count = reinterpret_cast<size_t*>
896  (_S_mem_blocks[_S_last_request._M_where()].first)
897  - (__detail::
898  __num_bitmaps(_S_mem_blocks[_S_last_request._M_where()]) + 1);
899 
900  ++(*__puse_count);
901  return __ret;
902  }
903 
904  /** @brief Deallocates memory that belongs to a single object of
905  * size sizeof(_Tp).
906  *
907  * Complexity: O(lg(N)), but the worst case is not hit
908  * often! This is because containers usually deallocate memory
909  * close to each other and this case is handled in O(1) time by
910  * the deallocate function.
911  */
912  void
913  _M_deallocate_single_object(pointer __p) throw()
914  {
915  using std::size_t;
916 #if defined __GTHREADS
917  __scoped_lock __bit_lock(_S_mut);
918 #endif
919  _Alloc_block* __real_p = reinterpret_cast<_Alloc_block*>(__p);
920 
921  typedef typename _BPVector::iterator _Iterator;
922  typedef typename _BPVector::difference_type _Difference_type;
923 
924  _Difference_type __diff;
925  long __displacement;
926 
927  _GLIBCXX_DEBUG_ASSERT(_S_last_dealloc_index >= 0);
928 
929  __detail::_Inclusive_between<_Alloc_block*> __ibt(__real_p);
930  if (__ibt(_S_mem_blocks[_S_last_dealloc_index]))
931  {
932  _GLIBCXX_DEBUG_ASSERT(_S_last_dealloc_index
933  <= _S_mem_blocks.size() - 1);
934 
935  // Initial Assumption was correct!
936  __diff = _S_last_dealloc_index;
937  __displacement = __real_p - _S_mem_blocks[__diff].first;
938  }
939  else
940  {
941  _Iterator _iter = _S_find(__ibt);
942 
943  _GLIBCXX_DEBUG_ASSERT(_iter != _S_mem_blocks.end());
944 
945  __diff = _iter - _S_mem_blocks.begin();
946  __displacement = __real_p - _S_mem_blocks[__diff].first;
947  _S_last_dealloc_index = __diff;
948  }
949 
950  // Get the position of the iterator that has been found.
951  const size_t __rotate = (__displacement
952  % size_t(__detail::bits_per_block));
953  size_t* __bitmapC =
954  reinterpret_cast<size_t*>
955  (_S_mem_blocks[__diff].first) - 1;
956  __bitmapC -= (__displacement / size_t(__detail::bits_per_block));
957 
958  __detail::__bit_free(__bitmapC, __rotate);
959  size_t* __puse_count = reinterpret_cast<size_t*>
960  (_S_mem_blocks[__diff].first)
961  - (__detail::__num_bitmaps(_S_mem_blocks[__diff]) + 1);
962 
963  _GLIBCXX_DEBUG_ASSERT(*__puse_count != 0);
964 
965  --(*__puse_count);
966 
967  if (__builtin_expect(*__puse_count == 0, false))
968  {
969  _S_block_size /= 2;
970 
971  // We can safely remove this block.
972  // _Block_pair __bp = _S_mem_blocks[__diff];
973  this->_M_insert(__puse_count);
974  _S_mem_blocks.erase(_S_mem_blocks.begin() + __diff);
975 
976  // Reset the _S_last_request variable to reflect the
977  // erased block. We do this to protect future requests
978  // after the last block has been removed from a particular
979  // memory Chunk, which in turn has been returned to the
980  // free list, and hence had been erased from the vector,
981  // so the size of the vector gets reduced by 1.
982  if ((_Difference_type)_S_last_request._M_where() >= __diff--)
983  _S_last_request._M_reset(__diff);
984 
985  // If the Index into the vector of the region of memory
986  // that might hold the next address that will be passed to
987  // deallocated may have been invalidated due to the above
988  // erase procedure being called on the vector, hence we
989  // try to restore this invariant too.
990  if (_S_last_dealloc_index >= _S_mem_blocks.size())
991  {
992  _S_last_dealloc_index =(__diff != -1 ? __diff : 0);
993  _GLIBCXX_DEBUG_ASSERT(_S_last_dealloc_index >= 0);
994  }
995  }
996  }
997 
998  public:
999  bitmap_allocator() _GLIBCXX_USE_NOEXCEPT
1000  { }
1001 
1002  bitmap_allocator(const bitmap_allocator&) _GLIBCXX_USE_NOEXCEPT
1003  { }
1004 
1005  template<typename _Tp1>
1006  bitmap_allocator(const bitmap_allocator<_Tp1>&) _GLIBCXX_USE_NOEXCEPT
1007  { }
1008 
1009  ~bitmap_allocator() _GLIBCXX_USE_NOEXCEPT
1010  { }
1011 
1012  _GLIBCXX_NODISCARD pointer
1013  allocate(size_type __n)
1014  {
1015  if (__n > this->max_size())
1016  std::__throw_bad_alloc();
1017 
1018 #if __cpp_aligned_new
1019  if (alignof(value_type) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
1020  {
1021  const size_type __b = __n * sizeof(value_type);
1022  std::align_val_t __al = std::align_val_t(alignof(value_type));
1023  return static_cast<pointer>(::operator new(__b, __al));
1024  }
1025 #endif
1026 
1027  if (__builtin_expect(__n == 1, true))
1028  return this->_M_allocate_single_object();
1029  else
1030  {
1031  const size_type __b = __n * sizeof(value_type);
1032  return reinterpret_cast<pointer>(::operator new(__b));
1033  }
1034  }
1035 
1036  _GLIBCXX_NODISCARD pointer
1037  allocate(size_type __n, typename bitmap_allocator<void>::const_pointer)
1038  { return allocate(__n); }
1039 
1040  void
1041  deallocate(pointer __p, size_type __n) throw()
1042  {
1043  if (__builtin_expect(__p != 0, true))
1044  {
1045 #if __cpp_aligned_new
1046  // Types with extended alignment are handled by operator delete.
1047  if (alignof(value_type) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
1048  {
1049  ::operator delete(__p, std::align_val_t(alignof(value_type)));
1050  return;
1051  }
1052 #endif
1053 
1054  if (__builtin_expect(__n == 1, true))
1055  this->_M_deallocate_single_object(__p);
1056  else
1057  ::operator delete(__p);
1058  }
1059  }
1060 
1061  pointer
1062  address(reference __r) const _GLIBCXX_NOEXCEPT
1063  { return std::__addressof(__r); }
1064 
1065  const_pointer
1066  address(const_reference __r) const _GLIBCXX_NOEXCEPT
1067  { return std::__addressof(__r); }
1068 
1069  size_type
1070  max_size() const _GLIBCXX_USE_NOEXCEPT
1071  { return size_type(-1) / sizeof(value_type); }
1072 
1073 #if __cplusplus >= 201103L
1074  template<typename _Up, typename... _Args>
1075  void
1076  construct(_Up* __p, _Args&&... __args)
1077  { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
1078 
1079  template<typename _Up>
1080  void
1081  destroy(_Up* __p)
1082  { __p->~_Up(); }
1083 #else
1084  void
1085  construct(pointer __p, const_reference __data)
1086  { ::new((void *)__p) value_type(__data); }
1087 
1088  void
1089  destroy(pointer __p)
1090  { __p->~value_type(); }
1091 #endif
1092  };
1093 
1094  template<typename _Tp1, typename _Tp2>
1095  bool
1096  operator==(const bitmap_allocator<_Tp1>&,
1097  const bitmap_allocator<_Tp2>&) throw()
1098  { return true; }
1099 
1100 #if __cpp_impl_three_way_comparison < 201907L
1101  template<typename _Tp1, typename _Tp2>
1102  bool
1103  operator!=(const bitmap_allocator<_Tp1>&,
1104  const bitmap_allocator<_Tp2>&) throw()
1105  { return false; }
1106 #endif
1107 
1108  // Static member definitions.
1109  template<typename _Tp>
1112 
1113  template<typename _Tp>
1115  = 2 * std::size_t(__detail::bits_per_block);
1116 
1117  template<typename _Tp>
1118  typename bitmap_allocator<_Tp>::_BPVector::size_type
1120 
1121  template<typename _Tp>
1125 
1126 #if defined __GTHREADS
1127  template<typename _Tp>
1128  typename bitmap_allocator<_Tp>::__mutex_type
1130 #endif
1131 
1132 _GLIBCXX_END_NAMESPACE_VERSION
1133 } // namespace __gnu_cxx
1134 
1135 #endif
std::size_t _Bit_scan_forward(std::size_t __num)
Generic Version of the bsf instruction.
Exception possibly thrown by new.bad_alloc (or classes derived from it) is used to report allocation ...
Definition: new:55
void __bit_free(std::size_t *__pbmap, std::size_t __pos)
Mark a memory address as free by setting the corresponding bit in the bit-map.
void __bit_allocate(std::size_t *__pbmap, std::size_t __pos)
Mark a memory address as allocated by re-setting the corresponding bit in the bit-map.
_T1 first
The first member.
Definition: stl_pair.h:193
void _M_insert(std::size_t *__addr)
This function returns the block of memory to the internal free list.
GNU extensions for public use.
std::size_t __num_blocks(_AddrPair __ap)
The number of Blocks pointed to by the address pair passed to the function.
void _M_deallocate_single_object(pointer __p)
Deallocates memory that belongs to a single object of size sizeof(_Tp).
std::size_t __num_bitmaps(_AddrPair __ap)
The number of Bit-maps pointed to by the address pair passed to the function.
__mini_vector<> is a stripped down version of the full-fledged std::vector<>.
ISO C++ entities toplevel namespace is std.
One of the comparison functors.
Definition: stl_function.h:365
The class which acts as a predicate for applying the first-fit memory allocation policy for the bitma...
constexpr _ForwardIterator __rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last, forward_iterator_tag)
This is a helper function for the rotate algorithm.
Definition: stl_algo.h:1199
pointer _M_allocate_single_object()
Allocates memory for a single object of size sizeof(_Tp).
Struct holding two objects of arbitrary type.
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition: move.h:49
One of the comparison functors.
Definition: stl_function.h:362
#define _BALLOC_ALIGN_BYTES
The constant in the expression below is the alignment required in bytes.
The free list class for managing chunks of memory to be given to and returned by the bitmap_allocator...
Definition: simd.h:286
Scoped lock idiom.
Definition: concurrence.h:228
Bitmap Allocator, primary template.
The bitmap counter which acts as the bitmap manipulator, and manages the bit-manipulation functions a...
integral_constant
Definition: type_traits:62