1 | // |
2 | // Redistribution and use in source and binary forms, with or without |
3 | // modification, are permitted provided that the following conditions |
4 | // are met: |
5 | // * Redistributions of source code must retain the above copyright |
6 | // notice, this list of conditions and the following disclaimer. |
7 | // * Redistributions in binary form must reproduce the above copyright |
8 | // notice, this list of conditions and the following disclaimer in the |
9 | // documentation and/or other materials provided with the distribution. |
10 | // * Neither the name of NVIDIA CORPORATION nor the names of its |
11 | // contributors may be used to endorse or promote products derived |
12 | // from this software without specific prior written permission. |
13 | // |
14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY |
15 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
17 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
18 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
19 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
20 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
21 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
22 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
24 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 | // |
26 | // Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved. |
27 | // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. |
28 | // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. |
29 | |
30 | #ifndef PSFOUNDATION_PSPOOL_H |
31 | #define PSFOUNDATION_PSPOOL_H |
32 | |
33 | #include "PsArray.h" |
34 | #include "PsSort.h" |
35 | #include "PsBasicTemplates.h" |
36 | #include "PsInlineArray.h" |
37 | |
38 | namespace physx |
39 | { |
40 | namespace shdfnd |
41 | { |
42 | |
43 | /*! |
44 | Simple allocation pool |
45 | */ |
46 | template <class T, class Alloc = typename AllocatorTraits<T>::Type> |
47 | class PoolBase : public UserAllocated, public Alloc |
48 | { |
49 | PX_NOCOPY(PoolBase) |
50 | protected: |
51 | PoolBase(const Alloc& alloc, uint32_t elementsPerSlab, uint32_t slabSize) |
52 | : Alloc(alloc), mSlabs(alloc), mElementsPerSlab(elementsPerSlab), mUsed(0), mSlabSize(slabSize), mFreeElement(0) |
53 | { |
54 | PX_COMPILE_TIME_ASSERT(sizeof(T) >= sizeof(size_t)); |
55 | } |
56 | |
57 | public: |
58 | ~PoolBase() |
59 | { |
60 | if(mUsed) |
61 | disposeElements(); |
62 | |
63 | for(void** slabIt = mSlabs.begin(), *slabEnd = mSlabs.end(); slabIt != slabEnd; ++slabIt) |
64 | Alloc::deallocate(*slabIt); |
65 | } |
66 | |
67 | // Allocate space for single object |
68 | PX_INLINE T* allocate() |
69 | { |
70 | if(mFreeElement == 0) |
71 | allocateSlab(); |
72 | T* p = reinterpret_cast<T*>(mFreeElement); |
73 | mFreeElement = mFreeElement->mNext; |
74 | mUsed++; |
75 | /** |
76 | Mark a specified amount of memory with 0xcd pattern. This is used to check that the meta data |
77 | definition for serialized classes is complete in checked builds. |
78 | */ |
79 | #if PX_CHECKED |
80 | for(uint32_t i = 0; i < sizeof(T); ++i) |
81 | reinterpret_cast<uint8_t*>(p)[i] = 0xcd; |
82 | #endif |
83 | return p; |
84 | } |
85 | |
86 | // Put space for a single element back in the lists |
87 | PX_INLINE void deallocate(T* p) |
88 | { |
89 | if(p) |
90 | { |
91 | PX_ASSERT(mUsed); |
92 | mUsed--; |
93 | push(p: reinterpret_cast<FreeList*>(p)); |
94 | } |
95 | } |
96 | |
97 | PX_INLINE T* construct() |
98 | { |
99 | T* t = allocate(); |
100 | return t ? new (t) T() : 0; |
101 | } |
102 | |
103 | template <class A1> |
104 | PX_INLINE T* construct(A1& a) |
105 | { |
106 | T* t = allocate(); |
107 | return t ? new (t) T(a) : 0; |
108 | } |
109 | |
110 | template <class A1, class A2> |
111 | PX_INLINE T* construct(A1& a, A2& b) |
112 | { |
113 | T* t = allocate(); |
114 | return t ? new (t) T(a, b) : 0; |
115 | } |
116 | |
117 | template <class A1, class A2, class A3> |
118 | PX_INLINE T* construct(A1& a, A2& b, A3& c) |
119 | { |
120 | T* t = allocate(); |
121 | return t ? new (t) T(a, b, c) : 0; |
122 | } |
123 | |
124 | template <class A1, class A2, class A3> |
125 | PX_INLINE T* construct(A1* a, A2& b, A3& c) |
126 | { |
127 | T* t = allocate(); |
128 | return t ? new (t) T(a, b, c) : 0; |
129 | } |
130 | |
131 | template <class A1, class A2, class A3, class A4> |
132 | PX_INLINE T* construct(A1& a, A2& b, A3& c, A4& d) |
133 | { |
134 | T* t = allocate(); |
135 | return t ? new (t) T(a, b, c, d) : 0; |
136 | } |
137 | |
138 | template <class A1, class A2, class A3, class A4, class A5> |
139 | PX_INLINE T* construct(A1& a, A2& b, A3& c, A4& d, A5& e) |
140 | { |
141 | T* t = allocate(); |
142 | return t ? new (t) T(a, b, c, d, e) : 0; |
143 | } |
144 | |
145 | PX_INLINE void destroy(T* const p) |
146 | { |
147 | if(p) |
148 | { |
149 | p->~T(); |
150 | deallocate(p); |
151 | } |
152 | } |
153 | |
154 | protected: |
155 | struct FreeList |
156 | { |
157 | FreeList* mNext; |
158 | }; |
159 | |
160 | // All the allocated slabs, sorted by pointer |
161 | InlineArray<void*, 64, Alloc> mSlabs; |
162 | |
163 | uint32_t mElementsPerSlab; |
164 | uint32_t mUsed; |
165 | uint32_t mSlabSize; |
166 | |
167 | FreeList* mFreeElement; // Head of free-list |
168 | |
169 | // Helper function to get bitmap of allocated elements |
170 | |
171 | void push(FreeList* p) |
172 | { |
173 | p->mNext = mFreeElement; |
174 | mFreeElement = p; |
175 | } |
176 | |
177 | // Allocate a slab and segregate it into the freelist |
178 | void allocateSlab() |
179 | { |
180 | T* slab = reinterpret_cast<T*>(Alloc::allocate(mSlabSize, __FILE__, __LINE__)); |
181 | |
182 | mSlabs.pushBack(slab); |
183 | |
184 | // Build a chain of nodes for the freelist |
185 | T* it = slab + mElementsPerSlab; |
186 | while(--it >= slab) |
187 | push(p: reinterpret_cast<FreeList*>(it)); |
188 | } |
189 | |
190 | /* |
191 | Cleanup method. Go through all active slabs and call destructor for live objects, |
192 | then free their memory |
193 | */ |
194 | void disposeElements() |
195 | { |
196 | Array<void*, Alloc> freeNodes(*this); |
197 | while(mFreeElement) |
198 | { |
199 | freeNodes.pushBack(mFreeElement); |
200 | mFreeElement = mFreeElement->mNext; |
201 | } |
202 | Alloc& alloc(*this); |
203 | sort(freeNodes.begin(), freeNodes.size(), Less<void*>(), alloc); |
204 | sort(mSlabs.begin(), mSlabs.size(), Less<void*>(), alloc); |
205 | |
206 | typename Array<void*, Alloc>::Iterator slabIt = mSlabs.begin(), slabEnd = mSlabs.end(); |
207 | for(typename Array<void*, Alloc>::Iterator freeIt = freeNodes.begin(); slabIt != slabEnd; ++slabIt) |
208 | { |
209 | for(T* tIt = reinterpret_cast<T*>(*slabIt), *tEnd = tIt + mElementsPerSlab; tIt != tEnd; ++tIt) |
210 | { |
211 | if(freeIt != freeNodes.end() && *freeIt == tIt) |
212 | ++freeIt; |
213 | else |
214 | tIt->~T(); |
215 | } |
216 | } |
217 | } |
218 | }; |
219 | |
220 | // original pool implementation |
221 | template <class T, class Alloc = typename AllocatorTraits<T>::Type> |
222 | class Pool : public PoolBase<T, Alloc> |
223 | { |
224 | public: |
225 | Pool(const Alloc& alloc = Alloc(), uint32_t elementsPerSlab = 32) |
226 | : PoolBase<T, Alloc>(alloc, elementsPerSlab, elementsPerSlab * sizeof(T)) |
227 | { |
228 | } |
229 | }; |
230 | |
231 | // allows specification of the slab size instead of the occupancy |
232 | template <class T, uint32_t slabSize, class Alloc = typename AllocatorTraits<T>::Type> |
233 | class Pool2 : public PoolBase<T, Alloc> |
234 | { |
235 | public: |
236 | Pool2(const Alloc& alloc = Alloc()) : PoolBase<T, Alloc>(alloc, slabSize / sizeof(T), slabSize) |
237 | { |
238 | } |
239 | }; |
240 | |
241 | } // namespace shdfnd |
242 | } // namespace physx |
243 | |
244 | #endif // #ifndef PSFOUNDATION_PSPOOL_H |
245 | |