1 /****************************************************************************
2 * Core Library Version 1.7, August 2004
3 * Copyright (c) 1995-2004 Exact Computation Project
4 * All rights reserved.
5 *
6 * This file is part of CGAL (www.cgal.org).
7 *
8 * File: MemoryPool.h
9 * Synopsis:
10 * a memory pool template class.
11 *
12 * Written by
13 * Zilin Du <zilin@cs.nyu.edu>
14 * Chee Yap <yap@cs.nyu.edu>
15 * Sylvain Pion <pion@cs.nyu.edu>
16 *
17 * WWW URL: http://cs.nyu.edu/exact/
18 * Email: exact@cs.nyu.edu
19 *
20 * $URL: https://github.com/CGAL/cgal/blob/v5.3/CGAL_Core/include/CGAL/CORE/MemoryPool.h $
21 * $Id: MemoryPool.h 8a7d3fa 2020-07-21T17:32:30+02:00 Laurent Rineau
22 * SPDX-License-Identifier: LGPL-3.0-or-later
23 ***************************************************************************/
24 #ifndef _CORE_MEMORYPOOL_H_
25 #define _CORE_MEMORYPOOL_H_
26
27 #include <CGAL/config.h>
28 #include <CGAL/tss.h>
29
30 #include <new> // for placement new
31 #include <cassert>
32 #include <CGAL/assertions.h>
33 #include <vector>
34
35 namespace CORE {
36
37 #define CORE_EXPANSION_SIZE 1024
38 template< class T, int nObjects = CORE_EXPANSION_SIZE >
39 class MemoryPool {
40 private:
41 struct Thunk {
42 T object;
43 Thunk* next;
44 };
45
46 typedef MemoryPool<T,nObjects> Self;
47 public:
MemoryPool()48 MemoryPool() : head( 0 ) {}
49
~MemoryPool()50 ~MemoryPool()
51 {
52 //CGAL_warning_code(
53 std::size_t count = 0;
54 Thunk* t = head;
55 while(t!=0){
56 ++count;
57 t = t->next;
58 }
59 //);
60 //CGAL_warning_msg(count == nObjects * blocks.size(),
61 // "Cannot delete memory as there are cyclic references");
62
63 if(count == nObjects * blocks.size()){
64 for(std::size_t i=0; i < blocks.size();i++){
65 ::operator delete(blocks[i]);
66 }
67 }
68 // un-commenting the following line can help reproduce on Linux the
69 // assertion !blocks.empty() that is sometimes triggered with MSVC
70 // or AppleClang
71 // blocks.clear();
72 }
73
74
75 void* allocate(std::size_t size);
76 void free(void* p);
77
78 // Access the corresponding static global allocator.
global_allocator()79 static MemoryPool<T,nObjects>& global_allocator() {
80 #if defined(CGAL_HAS_THREADS) // use the C++11 implementation
81 static thread_local Self memPool;
82 #else // not CGAL_HAS_THREADS
83 static Self memPool;
84 #endif // not CGAL_HAS_THREADS
85 return memPool;
86 }
87
88 private:
89 Thunk* head; // next available block in the pool
90 std::vector<void*> blocks;
91 };
92
93 template< class T, int nObjects >
allocate(std::size_t)94 void* MemoryPool< T, nObjects >::allocate(std::size_t) {
95 if ( head == 0 ) { // if no more memory in the pool
96 const int last = nObjects - 1;
97
98 // use the global operator new to allocate a block for the pool
99 Thunk* pool = reinterpret_cast<Thunk*>(
100 ::operator new(nObjects * sizeof(Thunk)));
101
102 blocks.push_back(pool);
103 // initialize the chain (one-directional linked list)
104 head = pool;
105 for (int i = 0; i < last; ++i ) {
106 pool[i].next = &pool[i+1];
107 }
108 pool[last].next = 0;
109 }
110
111 // set head to point to the next object in the list
112 Thunk* currentThunk = head;
113 head = currentThunk->next;
114
115 return currentThunk;
116 }
117
118 template< class T, int nObjects >
free(void * t)119 void MemoryPool< T, nObjects >::free(void* t) {
120 CGAL_assertion(t != 0);
121 if (t == 0) return; // for safety
122 if(blocks.empty()){
123 std::cerr << typeid(T).name() << std::endl;
124 }
125 CGAL_assertion (! blocks.empty());
126
127 // recycle the object memory, by putting it back into the chain
128 reinterpret_cast<Thunk*>(t)->next = head;
129 head = reinterpret_cast<Thunk*>(t);
130 }
131
132 } //namespace CORE
133
134 #endif // _CORE_MEMORYPOOL_H_
135