pool.hpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. // Copyright (C) 2000, 2001 Stephen Cleary
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // See http://www.boost.org for updates, documentation, and revision history.
  8. #ifndef BOOST_POOL_HPP
  9. #define BOOST_POOL_HPP
  10. #include <boost/config.hpp> // for workarounds
  11. // std::less, std::less_equal, std::greater
  12. #include <functional>
  13. // new[], delete[], std::nothrow
  14. #include <new>
  15. // std::size_t, std::ptrdiff_t
  16. #include <cstddef>
  17. // std::malloc, std::free
  18. #include <cstdlib>
  19. // std::invalid_argument
  20. #include <exception>
  21. // std::max
  22. #include <algorithm>
  23. #include <boost/pool/poolfwd.hpp>
  24. // boost::integer::static_lcm
  25. #include <boost/integer/common_factor_ct.hpp>
  26. // boost::simple_segregated_storage
  27. #include <boost/pool/simple_segregated_storage.hpp>
  28. // boost::alignment_of
  29. #include <boost/type_traits/alignment_of.hpp>
  30. // BOOST_ASSERT
  31. #include <boost/assert.hpp>
  32. #ifdef BOOST_POOL_INSTRUMENT
  33. #include <iostream>
  34. #include<iomanip>
  35. #endif
  36. #ifdef BOOST_POOL_VALGRIND
  37. #include <set>
  38. #include <valgrind/memcheck.h>
  39. #endif
  40. #ifdef BOOST_NO_STDC_NAMESPACE
  41. namespace std { using ::malloc; using ::free; }
  42. #endif
  43. // There are a few places in this file where the expression "this->m" is used.
  44. // This expression is used to force instantiation-time name lookup, which I am
  45. // informed is required for strict Standard compliance. It's only necessary
  46. // if "m" is a member of a base class that is dependent on a template
  47. // parameter.
  48. // Thanks to Jens Maurer for pointing this out!
  49. /*!
  50. \file
  51. \brief Provides class \ref pool: a fast memory allocator that guarantees proper alignment of all allocated chunks,
  52. and which extends and generalizes the framework provided by the simple segregated storage solution.
  53. Also provides two UserAllocator classes which can be used in conjuction with \ref pool.
  54. */
  55. /*!
  56. \mainpage Boost.Pool Memory Allocation Scheme
  57. \section intro_sec Introduction
  58. Pool allocation is a memory allocation scheme that is very fast, but limited in its usage.
  59. This Doxygen-style documentation is complementary to the
  60. full Quickbook-generated html and pdf documentation at www.boost.org.
  61. This page generated from file pool.hpp.
  62. */
  63. #ifdef BOOST_MSVC
  64. #pragma warning(push)
  65. #pragma warning(disable:4127) // Conditional expression is constant
  66. #endif
  67. namespace boost
  68. {
  69. //! \brief Allocator used as the default template parameter for
  70. //! a <a href="boost_pool/pool/pooling.html#boost_pool.pool.pooling.user_allocator">UserAllocator</a>
  71. //! template parameter. Uses new and delete.
  72. struct default_user_allocator_new_delete
  73. {
  74. typedef std::size_t size_type; //!< An unsigned integral type that can represent the size of the largest object to be allocated.
  75. typedef std::ptrdiff_t difference_type; //!< A signed integral type that can represent the difference of any two pointers.
  76. static char * malloc BOOST_PREVENT_MACRO_SUBSTITUTION(const size_type bytes)
  77. { //! Attempts to allocate n bytes from the system. Returns 0 if out-of-memory
  78. return new (std::nothrow) char[bytes];
  79. }
  80. static void free BOOST_PREVENT_MACRO_SUBSTITUTION(char * const block)
  81. { //! Attempts to de-allocate block.
  82. //! \pre Block must have been previously returned from a call to UserAllocator::malloc.
  83. delete [] block;
  84. }
  85. };
  86. //! \brief <a href="boost_pool/pool/pooling.html#boost_pool.pool.pooling.user_allocator">UserAllocator</a>
  87. //! used as template parameter for \ref pool and \ref object_pool.
  88. //! Uses malloc and free internally.
  89. struct default_user_allocator_malloc_free
  90. {
  91. typedef std::size_t size_type; //!< An unsigned integral type that can represent the size of the largest object to be allocated.
  92. typedef std::ptrdiff_t difference_type; //!< A signed integral type that can represent the difference of any two pointers.
  93. static char * malloc BOOST_PREVENT_MACRO_SUBSTITUTION(const size_type bytes)
  94. { return static_cast<char *>((std::malloc)(bytes)); }
  95. static void free BOOST_PREVENT_MACRO_SUBSTITUTION(char * const block)
  96. { (std::free)(block); }
  97. };
  98. namespace details
  99. { //! Implemention only.
  100. template <typename SizeType>
  101. class PODptr
  102. { //! PODptr is a class that pretends to be a "pointer" to different class types
  103. //! that don't really exist. It provides member functions to access the "data"
  104. //! of the "object" it points to. Since these "class" types are of variable
  105. //! size, and contains some information at the *end* of its memory
  106. //! (for alignment reasons),
  107. //! PODptr must contain the size of this "class" as well as the pointer to this "object".
  108. /*! \details A PODptr holds the location and size of a memory block allocated from the system.
  109. Each memory block is split logically into three sections:
  110. <b>Chunk area</b>. This section may be different sizes. PODptr does not care what the size of the chunks is,
  111. but it does care (and keep track of) the total size of the chunk area.
  112. <b>Next pointer</b>. This section is always the same size for a given SizeType. It holds a pointer
  113. to the location of the next memory block in the memory block list, or 0 if there is no such block.
  114. <b>Next size</b>. This section is always the same size for a given SizeType. It holds the size of the
  115. next memory block in the memory block list.
  116. The PODptr class just provides cleaner ways of dealing with raw memory blocks.
  117. A PODptr object is either valid or invalid. An invalid PODptr is analogous to a null pointer.
  118. The default constructor for PODptr will result in an invalid object.
  119. Calling the member function invalidate will result in that object becoming invalid.
  120. The member function valid can be used to test for validity.
  121. */
  122. public:
  123. typedef SizeType size_type;
  124. private:
  125. char * ptr;
  126. size_type sz;
  127. char * ptr_next_size() const
  128. {
  129. return (ptr + sz - sizeof(size_type));
  130. }
  131. char * ptr_next_ptr() const
  132. {
  133. return (ptr_next_size() -
  134. integer::static_lcm<sizeof(size_type), sizeof(void *)>::value);
  135. }
  136. public:
  137. PODptr(char * const nptr, const size_type nsize)
  138. :ptr(nptr), sz(nsize)
  139. {
  140. //! A PODptr may be created to point to a memory block by passing
  141. //! the address and size of that memory block into the constructor.
  142. //! A PODptr constructed in this way is valid.
  143. }
  144. PODptr()
  145. : ptr(0), sz(0)
  146. { //! default constructor for PODptr will result in an invalid object.
  147. }
  148. bool valid() const
  149. { //! A PODptr object is either valid or invalid.
  150. //! An invalid PODptr is analogous to a null pointer.
  151. //! \returns true if PODptr is valid, false if invalid.
  152. return (begin() != 0);
  153. }
  154. void invalidate()
  155. { //! Make object invalid.
  156. begin() = 0;
  157. }
  158. char * & begin()
  159. { //! Each PODptr keeps the address and size of its memory block.
  160. //! \returns The address of its memory block.
  161. return ptr;
  162. }
  163. char * begin() const
  164. { //! Each PODptr keeps the address and size of its memory block.
  165. //! \return The address of its memory block.
  166. return ptr;
  167. }
  168. char * end() const
  169. { //! \returns begin() plus element_size (a 'past the end' value).
  170. return ptr_next_ptr();
  171. }
  172. size_type total_size() const
  173. { //! Each PODptr keeps the address and size of its memory block.
  174. //! The address may be read or written by the member functions begin.
  175. //! The size of the memory block may only be read,
  176. //! \returns size of the memory block.
  177. return sz;
  178. }
  179. size_type element_size() const
  180. { //! \returns size of element pointer area.
  181. return static_cast<size_type>(sz - sizeof(size_type) -
  182. integer::static_lcm<sizeof(size_type), sizeof(void *)>::value);
  183. }
  184. size_type & next_size() const
  185. { //!
  186. //! \returns next_size.
  187. return *(static_cast<size_type *>(static_cast<void*>((ptr_next_size()))));
  188. }
  189. char * & next_ptr() const
  190. { //! \returns pointer to next pointer area.
  191. return *(static_cast<char **>(static_cast<void*>(ptr_next_ptr())));
  192. }
  193. PODptr next() const
  194. { //! \returns next PODptr.
  195. return PODptr<size_type>(next_ptr(), next_size());
  196. }
  197. void next(const PODptr & arg) const
  198. { //! Sets next PODptr.
  199. next_ptr() = arg.begin();
  200. next_size() = arg.total_size();
  201. }
  202. }; // class PODptr
  203. } // namespace details
  204. #ifndef BOOST_POOL_VALGRIND
  205. /*!
  206. \brief A fast memory allocator that guarantees proper alignment of all allocated chunks.
  207. \details Whenever an object of type pool needs memory from the system,
  208. it will request it from its UserAllocator template parameter.
  209. The amount requested is determined using a doubling algorithm;
  210. that is, each time more system memory is allocated,
  211. the amount of system memory requested is doubled.
  212. Users may control the doubling algorithm by using the following extensions:
  213. Users may pass an additional constructor parameter to pool.
  214. This parameter is of type size_type,
  215. and is the number of chunks to request from the system
  216. the first time that object needs to allocate system memory.
  217. The default is 32. This parameter may not be 0.
  218. Users may also pass an optional third parameter to pool's
  219. constructor. This parameter is of type size_type,
  220. and sets a maximum size for allocated chunks. When this
  221. parameter takes the default value of 0, then there is no upper
  222. limit on chunk size.
  223. Finally, if the doubling algorithm results in no memory
  224. being allocated, the pool will backtrack just once, halving
  225. the chunk size and trying again.
  226. <b>UserAllocator type</b> - the method that the Pool will use to allocate memory from the system.
  227. There are essentially two ways to use class pool: the client can call \ref malloc() and \ref free() to allocate
  228. and free single chunks of memory, this is the most efficient way to use a pool, but does not allow for
  229. the efficient allocation of arrays of chunks. Alternatively, the client may call \ref ordered_malloc() and \ref
  230. ordered_free(), in which case the free list is maintained in an ordered state, and efficient allocation of arrays
  231. of chunks are possible. However, this latter option can suffer from poor performance when large numbers of
  232. allocations are performed.
  233. */
  234. template <typename UserAllocator>
  235. class pool: protected simple_segregated_storage < typename UserAllocator::size_type >
  236. {
  237. public:
  238. typedef UserAllocator user_allocator; //!< User allocator.
  239. typedef typename UserAllocator::size_type size_type; //!< An unsigned integral type that can represent the size of the largest object to be allocated.
  240. typedef typename UserAllocator::difference_type difference_type; //!< A signed integral type that can represent the difference of any two pointers.
  241. private:
  242. BOOST_STATIC_CONSTANT(size_type, min_alloc_size =
  243. (::boost::integer::static_lcm<sizeof(void *), sizeof(size_type)>::value) );
  244. BOOST_STATIC_CONSTANT(size_type, min_align =
  245. (::boost::integer::static_lcm< ::boost::alignment_of<void *>::value, ::boost::alignment_of<size_type>::value>::value) );
  246. //! \returns 0 if out-of-memory.
  247. //! Called if malloc/ordered_malloc needs to resize the free list.
  248. void * malloc_need_resize(); //! Called if malloc needs to resize the free list.
  249. void * ordered_malloc_need_resize(); //! Called if ordered_malloc needs to resize the free list.
  250. protected:
  251. details::PODptr<size_type> list; //!< List structure holding ordered blocks.
  252. simple_segregated_storage<size_type> & store()
  253. { //! \returns pointer to store.
  254. return *this;
  255. }
  256. const simple_segregated_storage<size_type> & store() const
  257. { //! \returns pointer to store.
  258. return *this;
  259. }
  260. const size_type requested_size;
  261. size_type next_size;
  262. size_type start_size;
  263. size_type max_size;
  264. //! finds which POD in the list 'chunk' was allocated from.
  265. details::PODptr<size_type> find_POD(void * const chunk) const;
  266. // is_from() tests a chunk to determine if it belongs in a block.
  267. static bool is_from(void * const chunk, char * const i,
  268. const size_type sizeof_i)
  269. { //! \param chunk chunk to check if is from this pool.
  270. //! \param i memory chunk at i with element sizeof_i.
  271. //! \param sizeof_i element size (size of the chunk area of that block, not the total size of that block).
  272. //! \returns true if chunk was allocated or may be returned.
  273. //! as the result of a future allocation.
  274. //!
  275. //! Returns false if chunk was allocated from some other pool,
  276. //! or may be returned as the result of a future allocation from some other pool.
  277. //! Otherwise, the return value is meaningless.
  278. //!
  279. //! Note that this function may not be used to reliably test random pointer values.
  280. // We use std::less_equal and std::less to test 'chunk'
  281. // against the array bounds because standard operators
  282. // may return unspecified results.
  283. // This is to ensure portability. The operators < <= > >= are only
  284. // defined for pointers to objects that are 1) in the same array, or
  285. // 2) subobjects of the same object [5.9/2].
  286. // The functor objects guarantee a total order for any pointer [20.3.3/8]
  287. std::less_equal<void *> lt_eq;
  288. std::less<void *> lt;
  289. return (lt_eq(i, chunk) && lt(chunk, i + sizeof_i));
  290. }
  291. size_type alloc_size() const
  292. { //! Calculated size of the memory chunks that will be allocated by this Pool.
  293. //! \returns allocated size.
  294. // For alignment reasons, this used to be defined to be lcm(requested_size, sizeof(void *), sizeof(size_type)),
  295. // but is now more parsimonious: just rounding up to the minimum required alignment of our housekeeping data
  296. // when required. This works provided all alignments are powers of two.
  297. size_type s = (std::max)(requested_size, min_alloc_size);
  298. size_type rem = s % min_align;
  299. if(rem)
  300. s += min_align - rem;
  301. BOOST_ASSERT(s >= min_alloc_size);
  302. BOOST_ASSERT(s % min_align == 0);
  303. return s;
  304. }
  305. static void * & nextof(void * const ptr)
  306. { //! \returns Pointer dereferenced.
  307. //! (Provided and used for the sake of code readability :)
  308. return *(static_cast<void **>(ptr));
  309. }
  310. public:
  311. // pre: npartition_size != 0 && nnext_size != 0
  312. explicit pool(const size_type nrequested_size,
  313. const size_type nnext_size = 32,
  314. const size_type nmax_size = 0)
  315. :
  316. list(0, 0), requested_size(nrequested_size), next_size(nnext_size), start_size(nnext_size),max_size(nmax_size)
  317. { //! Constructs a new empty Pool that can be used to allocate chunks of size RequestedSize.
  318. //! \param nrequested_size Requested chunk size
  319. //! \param nnext_size parameter is of type size_type,
  320. //! is the number of chunks to request from the system
  321. //! the first time that object needs to allocate system memory.
  322. //! The default is 32. This parameter may not be 0.
  323. //! \param nmax_size is the maximum number of chunks to allocate in one block.
  324. }
  325. ~pool()
  326. { //! Destructs the Pool, freeing its list of memory blocks.
  327. purge_memory();
  328. }
  329. // Releases memory blocks that don't have chunks allocated
  330. // pre: lists are ordered
  331. // Returns true if memory was actually deallocated
  332. bool release_memory();
  333. // Releases *all* memory blocks, even if chunks are still allocated
  334. // Returns true if memory was actually deallocated
  335. bool purge_memory();
  336. size_type get_next_size() const
  337. { //! Number of chunks to request from the system the next time that object needs to allocate system memory. This value should never be 0.
  338. //! \returns next_size;
  339. return next_size;
  340. }
  341. void set_next_size(const size_type nnext_size)
  342. { //! Set number of chunks to request from the system the next time that object needs to allocate system memory. This value should never be set to 0.
  343. //! \returns nnext_size.
  344. next_size = start_size = nnext_size;
  345. }
  346. size_type get_max_size() const
  347. { //! \returns max_size.
  348. return max_size;
  349. }
  350. void set_max_size(const size_type nmax_size)
  351. { //! Set max_size.
  352. max_size = nmax_size;
  353. }
  354. size_type get_requested_size() const
  355. { //! \returns the requested size passed into the constructor.
  356. //! (This value will not change during the lifetime of a Pool object).
  357. return requested_size;
  358. }
  359. // Both malloc and ordered_malloc do a quick inlined check first for any
  360. // free chunks. Only if we need to get another memory block do we call
  361. // the non-inlined *_need_resize() functions.
  362. // Returns 0 if out-of-memory
  363. void * malloc BOOST_PREVENT_MACRO_SUBSTITUTION()
  364. { //! Allocates a chunk of memory. Searches in the list of memory blocks
  365. //! for a block that has a free chunk, and returns that free chunk if found.
  366. //! Otherwise, creates a new memory block, adds its free list to pool's free list,
  367. //! \returns a free chunk from that block.
  368. //! If a new memory block cannot be allocated, returns 0. Amortized O(1).
  369. // Look for a non-empty storage
  370. if (!store().empty())
  371. return (store().malloc)();
  372. return malloc_need_resize();
  373. }
  374. void * ordered_malloc()
  375. { //! Same as malloc, only merges the free lists, to preserve order. Amortized O(1).
  376. //! \returns a free chunk from that block.
  377. //! If a new memory block cannot be allocated, returns 0. Amortized O(1).
  378. // Look for a non-empty storage
  379. if (!store().empty())
  380. return (store().malloc)();
  381. return ordered_malloc_need_resize();
  382. }
  383. // Returns 0 if out-of-memory
  384. // Allocate a contiguous section of n chunks
  385. void * ordered_malloc(size_type n);
  386. //! Same as malloc, only allocates enough contiguous chunks to cover n * requested_size bytes. Amortized O(n).
  387. //! \returns a free chunk from that block.
  388. //! If a new memory block cannot be allocated, returns 0. Amortized O(1).
  389. // pre: 'chunk' must have been previously
  390. // returned by *this.malloc().
  391. void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const chunk)
  392. { //! Deallocates a chunk of memory. Note that chunk may not be 0. O(1).
  393. //!
  394. //! Chunk must have been previously returned by t.malloc() or t.ordered_malloc().
  395. //! Assumes that chunk actually refers to a block of chunks
  396. //! spanning n * partition_sz bytes.
  397. //! deallocates each chunk in that block.
  398. //! Note that chunk may not be 0. O(n).
  399. (store().free)(chunk);
  400. }
  401. // pre: 'chunk' must have been previously
  402. // returned by *this.malloc().
  403. void ordered_free(void * const chunk)
  404. { //! Same as above, but is order-preserving.
  405. //!
  406. //! Note that chunk may not be 0. O(N) with respect to the size of the free list.
  407. //! chunk must have been previously returned by t.malloc() or t.ordered_malloc().
  408. store().ordered_free(chunk);
  409. }
  410. // pre: 'chunk' must have been previously
  411. // returned by *this.malloc(n).
  412. void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const chunks, const size_type n)
  413. { //! Assumes that chunk actually refers to a block of chunks.
  414. //!
  415. //! chunk must have been previously returned by t.ordered_malloc(n)
  416. //! spanning n * partition_sz bytes.
  417. //! Deallocates each chunk in that block.
  418. //! Note that chunk may not be 0. O(n).
  419. const size_type partition_size = alloc_size();
  420. const size_type total_req_size = n * requested_size;
  421. const size_type num_chunks = total_req_size / partition_size +
  422. ((total_req_size % partition_size) ? true : false);
  423. store().free_n(chunks, num_chunks, partition_size);
  424. }
  425. // pre: 'chunk' must have been previously
  426. // returned by *this.malloc(n).
  427. void ordered_free(void * const chunks, const size_type n)
  428. { //! Assumes that chunk actually refers to a block of chunks spanning n * partition_sz bytes;
  429. //! deallocates each chunk in that block.
  430. //!
  431. //! Note that chunk may not be 0. Order-preserving. O(N + n) where N is the size of the free list.
  432. //! chunk must have been previously returned by t.malloc() or t.ordered_malloc().
  433. const size_type partition_size = alloc_size();
  434. const size_type total_req_size = n * requested_size;
  435. const size_type num_chunks = total_req_size / partition_size +
  436. ((total_req_size % partition_size) ? true : false);
  437. store().ordered_free_n(chunks, num_chunks, partition_size);
  438. }
  439. // is_from() tests a chunk to determine if it was allocated from *this
  440. bool is_from(void * const chunk) const
  441. { //! \returns Returns true if chunk was allocated from u or
  442. //! may be returned as the result of a future allocation from u.
  443. //! Returns false if chunk was allocated from some other pool or
  444. //! may be returned as the result of a future allocation from some other pool.
  445. //! Otherwise, the return value is meaningless.
  446. //! Note that this function may not be used to reliably test random pointer values.
  447. return (find_POD(chunk).valid());
  448. }
  449. };
  450. #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
  451. template <typename UserAllocator>
  452. typename pool<UserAllocator>::size_type const pool<UserAllocator>::min_alloc_size;
  453. template <typename UserAllocator>
  454. typename pool<UserAllocator>::size_type const pool<UserAllocator>::min_align;
  455. #endif
  456. template <typename UserAllocator>
  457. bool pool<UserAllocator>::release_memory()
  458. { //! pool must be ordered. Frees every memory block that doesn't have any allocated chunks.
  459. //! \returns true if at least one memory block was freed.
  460. // ret is the return value: it will be set to true when we actually call
  461. // UserAllocator::free(..)
  462. bool ret = false;
  463. // This is a current & previous iterator pair over the memory block list
  464. details::PODptr<size_type> ptr = list;
  465. details::PODptr<size_type> prev;
  466. // This is a current & previous iterator pair over the free memory chunk list
  467. // Note that "prev_free" in this case does NOT point to the previous memory
  468. // chunk in the free list, but rather the last free memory chunk before the
  469. // current block.
  470. void * free_p = this->first;
  471. void * prev_free_p = 0;
  472. const size_type partition_size = alloc_size();
  473. // Search through all the all the allocated memory blocks
  474. while (ptr.valid())
  475. {
  476. // At this point:
  477. // ptr points to a valid memory block
  478. // free_p points to either:
  479. // 0 if there are no more free chunks
  480. // the first free chunk in this or some next memory block
  481. // prev_free_p points to either:
  482. // the last free chunk in some previous memory block
  483. // 0 if there is no such free chunk
  484. // prev is either:
  485. // the PODptr whose next() is ptr
  486. // !valid() if there is no such PODptr
  487. // If there are no more free memory chunks, then every remaining
  488. // block is allocated out to its fullest capacity, and we can't
  489. // release any more memory
  490. if (free_p == 0)
  491. break;
  492. // We have to check all the chunks. If they are *all* free (i.e., present
  493. // in the free list), then we can free the block.
  494. bool all_chunks_free = true;
  495. // Iterate 'i' through all chunks in the memory block
  496. // if free starts in the memory block, be careful to keep it there
  497. void * saved_free = free_p;
  498. for (char * i = ptr.begin(); i != ptr.end(); i += partition_size)
  499. {
  500. // If this chunk is not free
  501. if (i != free_p)
  502. {
  503. // We won't be able to free this block
  504. all_chunks_free = false;
  505. // free_p might have travelled outside ptr
  506. free_p = saved_free;
  507. // Abort searching the chunks; we won't be able to free this
  508. // block because a chunk is not free.
  509. break;
  510. }
  511. // We do not increment prev_free_p because we are in the same block
  512. free_p = nextof(free_p);
  513. }
  514. // post: if the memory block has any chunks, free_p points to one of them
  515. // otherwise, our assertions above are still valid
  516. const details::PODptr<size_type> next = ptr.next();
  517. if (!all_chunks_free)
  518. {
  519. if (is_from(free_p, ptr.begin(), ptr.element_size()))
  520. {
  521. std::less<void *> lt;
  522. void * const end = ptr.end();
  523. do
  524. {
  525. prev_free_p = free_p;
  526. free_p = nextof(free_p);
  527. } while (free_p && lt(free_p, end));
  528. }
  529. // This invariant is now restored:
  530. // free_p points to the first free chunk in some next memory block, or
  531. // 0 if there is no such chunk.
  532. // prev_free_p points to the last free chunk in this memory block.
  533. // We are just about to advance ptr. Maintain the invariant:
  534. // prev is the PODptr whose next() is ptr, or !valid()
  535. // if there is no such PODptr
  536. prev = ptr;
  537. }
  538. else
  539. {
  540. // All chunks from this block are free
  541. // Remove block from list
  542. if (prev.valid())
  543. prev.next(next);
  544. else
  545. list = next;
  546. // Remove all entries in the free list from this block
  547. if (prev_free_p != 0)
  548. nextof(prev_free_p) = free_p;
  549. else
  550. this->first = free_p;
  551. // And release memory
  552. (UserAllocator::free)(ptr.begin());
  553. ret = true;
  554. }
  555. // Increment ptr
  556. ptr = next;
  557. }
  558. next_size = start_size;
  559. return ret;
  560. }
  561. template <typename UserAllocator>
  562. bool pool<UserAllocator>::purge_memory()
  563. { //! pool must be ordered.
  564. //! Frees every memory block.
  565. //!
  566. //! This function invalidates any pointers previously returned
  567. //! by allocation functions of t.
  568. //! \returns true if at least one memory block was freed.
  569. details::PODptr<size_type> iter = list;
  570. if (!iter.valid())
  571. return false;
  572. do
  573. {
  574. // hold "next" pointer
  575. const details::PODptr<size_type> next = iter.next();
  576. // delete the storage
  577. (UserAllocator::free)(iter.begin());
  578. // increment iter
  579. iter = next;
  580. } while (iter.valid());
  581. list.invalidate();
  582. this->first = 0;
  583. next_size = start_size;
  584. return true;
  585. }
  586. template <typename UserAllocator>
  587. void * pool<UserAllocator>::malloc_need_resize()
  588. { //! No memory in any of our storages; make a new storage,
  589. //! Allocates chunk in newly malloc aftert resize.
  590. //! \returns pointer to chunk.
  591. size_type partition_size = alloc_size();
  592. size_type POD_size = static_cast<size_type>(next_size * partition_size +
  593. integer::static_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type));
  594. char * ptr = (UserAllocator::malloc)(POD_size);
  595. if (ptr == 0)
  596. {
  597. if(next_size > 4)
  598. {
  599. next_size >>= 1;
  600. partition_size = alloc_size();
  601. POD_size = static_cast<size_type>(next_size * partition_size +
  602. integer::static_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type));
  603. ptr = (UserAllocator::malloc)(POD_size);
  604. }
  605. if(ptr == 0)
  606. return 0;
  607. }
  608. const details::PODptr<size_type> node(ptr, POD_size);
  609. BOOST_USING_STD_MIN();
  610. if(!max_size)
  611. next_size <<= 1;
  612. else if( next_size*partition_size/requested_size < max_size)
  613. next_size = min BOOST_PREVENT_MACRO_SUBSTITUTION(next_size << 1, max_size*requested_size/ partition_size);
  614. // initialize it,
  615. store().add_block(node.begin(), node.element_size(), partition_size);
  616. // insert it into the list,
  617. node.next(list);
  618. list = node;
  619. // and return a chunk from it.
  620. return (store().malloc)();
  621. }
  622. template <typename UserAllocator>
  623. void * pool<UserAllocator>::ordered_malloc_need_resize()
  624. { //! No memory in any of our storages; make a new storage,
  625. //! \returns pointer to new chunk.
  626. size_type partition_size = alloc_size();
  627. size_type POD_size = static_cast<size_type>(next_size * partition_size +
  628. integer::static_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type));
  629. char * ptr = (UserAllocator::malloc)(POD_size);
  630. if (ptr == 0)
  631. {
  632. if(next_size > 4)
  633. {
  634. next_size >>= 1;
  635. partition_size = alloc_size();
  636. POD_size = static_cast<size_type>(next_size * partition_size +
  637. integer::static_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type));
  638. ptr = (UserAllocator::malloc)(POD_size);
  639. }
  640. if(ptr == 0)
  641. return 0;
  642. }
  643. const details::PODptr<size_type> node(ptr, POD_size);
  644. BOOST_USING_STD_MIN();
  645. if(!max_size)
  646. next_size <<= 1;
  647. else if( next_size*partition_size/requested_size < max_size)
  648. next_size = min BOOST_PREVENT_MACRO_SUBSTITUTION(next_size << 1, max_size*requested_size/ partition_size);
  649. // initialize it,
  650. // (we can use "add_block" here because we know that
  651. // the free list is empty, so we don't have to use
  652. // the slower ordered version)
  653. store().add_ordered_block(node.begin(), node.element_size(), partition_size);
  654. // insert it into the list,
  655. // handle border case
  656. if (!list.valid() || std::greater<void *>()(list.begin(), node.begin()))
  657. {
  658. node.next(list);
  659. list = node;
  660. }
  661. else
  662. {
  663. details::PODptr<size_type> prev = list;
  664. while (true)
  665. {
  666. // if we're about to hit the end or
  667. // if we've found where "node" goes
  668. if (prev.next_ptr() == 0
  669. || std::greater<void *>()(prev.next_ptr(), node.begin()))
  670. break;
  671. prev = prev.next();
  672. }
  673. node.next(prev.next());
  674. prev.next(node);
  675. }
  676. // and return a chunk from it.
  677. return (store().malloc)();
  678. }
  679. template <typename UserAllocator>
  680. void * pool<UserAllocator>::ordered_malloc(const size_type n)
  681. { //! Gets address of a chunk n, allocating new memory if not already available.
  682. //! \returns Address of chunk n if allocated ok.
  683. //! \returns 0 if not enough memory for n chunks.
  684. const size_type partition_size = alloc_size();
  685. const size_type total_req_size = n * requested_size;
  686. const size_type num_chunks = total_req_size / partition_size +
  687. ((total_req_size % partition_size) ? true : false);
  688. void * ret = store().malloc_n(num_chunks, partition_size);
  689. #ifdef BOOST_POOL_INSTRUMENT
  690. std::cout << "Allocating " << n << " chunks from pool of size " << partition_size << std::endl;
  691. #endif
  692. if ((ret != 0) || (n == 0))
  693. return ret;
  694. #ifdef BOOST_POOL_INSTRUMENT
  695. std::cout << "Cache miss, allocating another chunk...\n";
  696. #endif
  697. // Not enough memory in our storages; make a new storage,
  698. BOOST_USING_STD_MAX();
  699. next_size = max BOOST_PREVENT_MACRO_SUBSTITUTION(next_size, num_chunks);
  700. size_type POD_size = static_cast<size_type>(next_size * partition_size +
  701. integer::static_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type));
  702. char * ptr = (UserAllocator::malloc)(POD_size);
  703. if (ptr == 0)
  704. {
  705. if(num_chunks < next_size)
  706. {
  707. // Try again with just enough memory to do the job, or at least whatever we
  708. // allocated last time:
  709. next_size >>= 1;
  710. next_size = max BOOST_PREVENT_MACRO_SUBSTITUTION(next_size, num_chunks);
  711. POD_size = static_cast<size_type>(next_size * partition_size +
  712. integer::static_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type));
  713. ptr = (UserAllocator::malloc)(POD_size);
  714. }
  715. if(ptr == 0)
  716. return 0;
  717. }
  718. const details::PODptr<size_type> node(ptr, POD_size);
  719. // Split up block so we can use what wasn't requested.
  720. if (next_size > num_chunks)
  721. store().add_ordered_block(node.begin() + num_chunks * partition_size,
  722. node.element_size() - num_chunks * partition_size, partition_size);
  723. BOOST_USING_STD_MIN();
  724. if(!max_size)
  725. next_size <<= 1;
  726. else if( next_size*partition_size/requested_size < max_size)
  727. next_size = min BOOST_PREVENT_MACRO_SUBSTITUTION(next_size << 1, max_size*requested_size/ partition_size);
  728. // insert it into the list,
  729. // handle border case.
  730. if (!list.valid() || std::greater<void *>()(list.begin(), node.begin()))
  731. {
  732. node.next(list);
  733. list = node;
  734. }
  735. else
  736. {
  737. details::PODptr<size_type> prev = list;
  738. while (true)
  739. {
  740. // if we're about to hit the end, or if we've found where "node" goes.
  741. if (prev.next_ptr() == 0
  742. || std::greater<void *>()(prev.next_ptr(), node.begin()))
  743. break;
  744. prev = prev.next();
  745. }
  746. node.next(prev.next());
  747. prev.next(node);
  748. }
  749. // and return it.
  750. return node.begin();
  751. }
  752. template <typename UserAllocator>
  753. details::PODptr<typename pool<UserAllocator>::size_type>
  754. pool<UserAllocator>::find_POD(void * const chunk) const
  755. { //! find which PODptr storage memory that this chunk is from.
  756. //! \returns the PODptr that holds this chunk.
  757. // Iterate down list to find which storage this chunk is from.
  758. details::PODptr<size_type> iter = list;
  759. while (iter.valid())
  760. {
  761. if (is_from(chunk, iter.begin(), iter.element_size()))
  762. return iter;
  763. iter = iter.next();
  764. }
  765. return iter;
  766. }
  767. #else // BOOST_POOL_VALGRIND
  768. template<typename UserAllocator>
  769. class pool
  770. {
  771. public:
  772. // types
  773. typedef UserAllocator user_allocator; // User allocator.
  774. typedef typename UserAllocator::size_type size_type; // An unsigned integral type that can represent the size of the largest object to be allocated.
  775. typedef typename UserAllocator::difference_type difference_type; // A signed integral type that can represent the difference of any two pointers.
  776. // construct/copy/destruct
  777. explicit pool(const size_type s, const size_type = 32, const size_type m = 0) : chunk_size(s), max_alloc_size(m) {}
  778. ~pool()
  779. {
  780. purge_memory();
  781. }
  782. bool release_memory()
  783. {
  784. bool ret = free_list.empty() ? false : true;
  785. for(std::set<void*>::iterator pos = free_list.begin(); pos != free_list.end(); ++pos)
  786. {
  787. (user_allocator::free)(static_cast<char*>(*pos));
  788. }
  789. free_list.clear();
  790. return ret;
  791. }
  792. bool purge_memory()
  793. {
  794. bool ret = free_list.empty() && used_list.empty() ? false : true;
  795. for(std::set<void*>::iterator pos = free_list.begin(); pos != free_list.end(); ++pos)
  796. {
  797. (user_allocator::free)(static_cast<char*>(*pos));
  798. }
  799. free_list.clear();
  800. for(std::set<void*>::iterator pos = used_list.begin(); pos != used_list.end(); ++pos)
  801. {
  802. (user_allocator::free)(static_cast<char*>(*pos));
  803. }
  804. used_list.clear();
  805. return ret;
  806. }
  807. size_type get_next_size() const
  808. {
  809. return 1;
  810. }
  811. void set_next_size(const size_type){}
  812. size_type get_max_size() const
  813. {
  814. return max_alloc_size;
  815. }
  816. void set_max_size(const size_type s)
  817. {
  818. max_alloc_size = s;
  819. }
  820. size_type get_requested_size() const
  821. {
  822. return chunk_size;
  823. }
  824. void * malloc BOOST_PREVENT_MACRO_SUBSTITUTION()
  825. {
  826. void* ret;
  827. if(free_list.empty())
  828. {
  829. ret = (user_allocator::malloc)(chunk_size);
  830. VALGRIND_MAKE_MEM_UNDEFINED(ret, chunk_size);
  831. }
  832. else
  833. {
  834. ret = *free_list.begin();
  835. free_list.erase(free_list.begin());
  836. VALGRIND_MAKE_MEM_UNDEFINED(ret, chunk_size);
  837. }
  838. used_list.insert(ret);
  839. return ret;
  840. }
  841. void * ordered_malloc()
  842. {
  843. return (this->malloc)();
  844. }
  845. void * ordered_malloc(size_type n)
  846. {
  847. if(max_alloc_size && (n > max_alloc_size))
  848. return 0;
  849. void* ret = (user_allocator::malloc)(chunk_size * n);
  850. used_list.insert(ret);
  851. return ret;
  852. }
  853. void free BOOST_PREVENT_MACRO_SUBSTITUTION(void *const chunk)
  854. {
  855. BOOST_ASSERT(used_list.count(chunk) == 1);
  856. BOOST_ASSERT(free_list.count(chunk) == 0);
  857. used_list.erase(chunk);
  858. free_list.insert(chunk);
  859. VALGRIND_MAKE_MEM_NOACCESS(chunk, chunk_size);
  860. }
  861. void ordered_free(void *const chunk)
  862. {
  863. return (this->free)(chunk);
  864. }
  865. void free BOOST_PREVENT_MACRO_SUBSTITUTION(void *const chunk, const size_type)
  866. {
  867. BOOST_ASSERT(used_list.count(chunk) == 1);
  868. BOOST_ASSERT(free_list.count(chunk) == 0);
  869. used_list.erase(chunk);
  870. (user_allocator::free)(static_cast<char*>(chunk));
  871. }
  872. void ordered_free(void *const chunk, const size_type n)
  873. {
  874. (this->free)(chunk, n);
  875. }
  876. bool is_from(void *const chunk) const
  877. {
  878. return used_list.count(chunk) || free_list.count(chunk);
  879. }
  880. protected:
  881. size_type chunk_size, max_alloc_size;
  882. std::set<void*> free_list, used_list;
  883. };
  884. #endif
  885. } // namespace boost
  886. #ifdef BOOST_MSVC
  887. #pragma warning(pop)
  888. #endif
  889. #endif // #ifdef BOOST_POOL_HPP