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