1+ /* -
2+ * Copyright (c) 2013 Cosku Acay, http://www.coskuacay.com
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a
5+ * copy of this software and associated documentation files (the "Software"),
6+ * to deal in the Software without restriction, including without limitation
7+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+ * and/or sell copies of the Software, and to permit persons to whom the
9+ * Software is furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20+ * IN THE SOFTWARE.
21+ */
22+
23+ #ifndef MEMORY_POOL_HPP
24+ #define MEMORY_POOL_HPP
25+
26+ #include < climits>
27+ #include < cstddef>
28+
29+ template <typename T, size_t BlockSize = 4096 >
30+ class MemoryPool {
31+ public:
32+ /* Member types */
33+ typedef T value_type;
34+ typedef T* pointer;
35+ typedef T& reference;
36+ typedef const T* const_pointer;
37+ typedef const T& const_reference;
38+ typedef size_t size_type;
39+ typedef ptrdiff_t difference_type;
40+ typedef std::false_type propagate_on_container_copy_assignment;
41+ typedef std::true_type propagate_on_container_move_assignment;
42+ typedef std::true_type propagate_on_container_swap;
43+
44+ template <typename U>
45+ struct rebind {
46+ typedef MemoryPool<U> other;
47+ };
48+
49+ /* Member functions */
50+ MemoryPool () noexcept ;
51+ MemoryPool (const MemoryPool& memoryPool) noexcept ;
52+ MemoryPool (MemoryPool&& memoryPool) noexcept ;
53+ template <class U >
54+ MemoryPool (const MemoryPool<U>& memoryPool) noexcept ;
55+
56+ ~MemoryPool () noexcept ;
57+
58+ MemoryPool& operator =(const MemoryPool& memoryPool) = delete ;
59+ MemoryPool& operator =(MemoryPool&& memoryPool) noexcept ;
60+
61+ pointer address (reference x) const noexcept ;
62+ const_pointer address (const_reference x) const noexcept ;
63+
64+ // Can only allocate one object at a time. n and hint are ignored
65+ pointer allocate (size_type n = 1 , const_pointer hint = 0 );
66+ void deallocate (pointer p, size_type n = 1 );
67+
68+ size_type max_size () const noexcept ;
69+
70+ template <class U , class ... Args>
71+ void construct (U* p, Args&&... args);
72+ template <class U >
73+ void destroy (U* p);
74+
75+ template <class ... Args>
76+ pointer newElement (Args&&... args);
77+ void deleteElement (pointer p);
78+
79+ static MemoryPool* getInstance () {
80+ thread_local static MemoryPool instance;
81+ return &instance;
82+ }
83+
84+ private:
85+ union Slot_ {
86+ value_type element;
87+ Slot_* next;
88+ };
89+
90+ typedef char * data_pointer_;
91+ typedef Slot_ slot_type_;
92+ typedef Slot_* slot_pointer_;
93+
94+ slot_pointer_ currentBlock_;
95+ slot_pointer_ currentSlot_;
96+ slot_pointer_ lastSlot_;
97+ slot_pointer_ freeSlots_;
98+
99+ size_type padPointer (data_pointer_ p, size_type align) const noexcept ;
100+ void allocateBlock ();
101+
102+ static_assert (BlockSize >= 2 * sizeof (slot_type_), " BlockSize too small." );
103+ };
104+
105+ template <typename T, size_t BlockSize>
106+ inline typename MemoryPool<T, BlockSize>::size_type MemoryPool<T, BlockSize>::padPointer(
107+ data_pointer_ p, size_type align) const noexcept {
108+ uintptr_t result = reinterpret_cast <uintptr_t >(p);
109+ return ((align - result) % align);
110+ }
111+
112+ template <typename T, size_t BlockSize>
113+ MemoryPool<T, BlockSize>::MemoryPool() noexcept {
114+ currentBlock_ = nullptr ;
115+ currentSlot_ = nullptr ;
116+ lastSlot_ = nullptr ;
117+ freeSlots_ = nullptr ;
118+ }
119+
120+ template <typename T, size_t BlockSize>
121+ MemoryPool<T, BlockSize>::MemoryPool(const MemoryPool& memoryPool) noexcept : MemoryPool() {}
122+
123+ template <typename T, size_t BlockSize>
124+ MemoryPool<T, BlockSize>::MemoryPool(MemoryPool&& memoryPool) noexcept {
125+ currentBlock_ = memoryPool.currentBlock_ ;
126+ memoryPool.currentBlock_ = nullptr ;
127+ currentSlot_ = memoryPool.currentSlot_ ;
128+ lastSlot_ = memoryPool.lastSlot_ ;
129+ freeSlots_ = memoryPool.freeSlots ;
130+ }
131+
132+ template <typename T, size_t BlockSize>
133+ template <class U >
134+ MemoryPool<T, BlockSize>::MemoryPool(const MemoryPool<U>& memoryPool) noexcept : MemoryPool() {}
135+
136+ template <typename T, size_t BlockSize>
137+ MemoryPool<T, BlockSize>& MemoryPool<T, BlockSize>::operator =(MemoryPool&& memoryPool) noexcept {
138+ if (this != &memoryPool) {
139+ std::swap (currentBlock_, memoryPool.currentBlock_ );
140+ currentSlot_ = memoryPool.currentSlot_ ;
141+ lastSlot_ = memoryPool.lastSlot_ ;
142+ freeSlots_ = memoryPool.freeSlots ;
143+ }
144+ return *this ;
145+ }
146+
147+ template <typename T, size_t BlockSize>
148+ MemoryPool<T, BlockSize>::~MemoryPool () noexcept {
149+ slot_pointer_ curr = currentBlock_;
150+ while (curr != nullptr ) {
151+ slot_pointer_ prev = curr->next ;
152+ operator delete (reinterpret_cast <void *>(curr));
153+ curr = prev;
154+ }
155+ }
156+
157+ template <typename T, size_t BlockSize>
158+ inline typename MemoryPool<T, BlockSize>::pointer MemoryPool<T, BlockSize>::address(reference x) const noexcept {
159+ return &x;
160+ }
161+
162+ template <typename T, size_t BlockSize>
163+ inline typename MemoryPool<T, BlockSize>::const_pointer MemoryPool<T, BlockSize>::address(
164+ const_reference x) const noexcept {
165+ return &x;
166+ }
167+
168+ template <typename T, size_t BlockSize>
169+ void MemoryPool<T, BlockSize>::allocateBlock() {
170+ // Allocate space for the new block and store a pointer to the previous one
171+ data_pointer_ newBlock = reinterpret_cast <data_pointer_>(operator new (BlockSize));
172+ reinterpret_cast <slot_pointer_>(newBlock)->next = currentBlock_;
173+ currentBlock_ = reinterpret_cast <slot_pointer_>(newBlock);
174+ // Pad block body to staisfy the alignment requirements for elements
175+ data_pointer_ body = newBlock + sizeof (slot_pointer_);
176+ size_type bodyPadding = padPointer (body, alignof (slot_type_));
177+ currentSlot_ = reinterpret_cast <slot_pointer_>(body + bodyPadding);
178+ lastSlot_ = reinterpret_cast <slot_pointer_>(newBlock + BlockSize - sizeof (slot_type_) + 1 );
179+ }
180+
181+ template <typename T, size_t BlockSize>
182+ inline typename MemoryPool<T, BlockSize>::pointer MemoryPool<T, BlockSize>::allocate(size_type n, const_pointer hint) {
183+ if (freeSlots_ != nullptr ) {
184+ pointer result = reinterpret_cast <pointer>(freeSlots_);
185+ freeSlots_ = freeSlots_->next ;
186+ return result;
187+ } else {
188+ if (currentSlot_ >= lastSlot_) allocateBlock ();
189+ return reinterpret_cast <pointer>(currentSlot_++);
190+ }
191+ }
192+
193+ template <typename T, size_t BlockSize>
194+ inline void MemoryPool<T, BlockSize>::deallocate(pointer p, size_type n) {
195+ if (p != nullptr ) {
196+ reinterpret_cast <slot_pointer_>(p)->next = freeSlots_;
197+ freeSlots_ = reinterpret_cast <slot_pointer_>(p);
198+ }
199+ }
200+
201+ template <typename T, size_t BlockSize>
202+ inline typename MemoryPool<T, BlockSize>::size_type MemoryPool<T, BlockSize>::max_size() const noexcept {
203+ size_type maxBlocks = -1 / BlockSize;
204+ return (BlockSize - sizeof (data_pointer_)) / sizeof (slot_type_) * maxBlocks;
205+ }
206+
207+ template <typename T, size_t BlockSize>
208+ template <class U , class ... Args>
209+ inline void MemoryPool<T, BlockSize>::construct(U* p, Args&&... args) {
210+ new (p) U (std::forward<Args>(args)...);
211+ }
212+
213+ template <typename T, size_t BlockSize>
214+ template <class U >
215+ inline void MemoryPool<T, BlockSize>::destroy(U* p) {
216+ p->~U ();
217+ }
218+
219+ template <typename T, size_t BlockSize>
220+ template <class ... Args>
221+ inline typename MemoryPool<T, BlockSize>::pointer MemoryPool<T, BlockSize>::newElement(Args&&... args) {
222+ pointer result = allocate ();
223+ construct<value_type>(result, std::forward<Args>(args)...);
224+ return result;
225+ }
226+
227+ template <typename T, size_t BlockSize>
228+ inline void MemoryPool<T, BlockSize>::deleteElement(pointer p) {
229+ if (p != nullptr ) {
230+ p->~value_type ();
231+ deallocate (p);
232+ }
233+ }
234+
235+ #endif // MEMORY_POOL_HPP
0 commit comments