1 /*******************************************************************************
2 3 Free list of dynamically allocated objects.
4 Implemented as a linked list; a subclass must get and set the next one of
5 a given object.
6 7 Copyright:
8 Copyright (c) 2009-2016 dunnhumby Germany GmbH.
9 All rights reserved.
10 11 License:
12 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
13 Alternatively, this file may be distributed under the terms of the Tango
14 3-Clause BSD License (see LICENSE_BSD.txt for details).
15 16 *******************************************************************************/17 18 moduleocean.util.container.map.model.BucketElementFreeList;
19 20 21 importocean.util.container.map.model.IAllocator;
22 23 importocean.core.Array: clear;
24 25 /*******************************************************************************
26 27 Free list of currently unused bucket elements.
28 29 *******************************************************************************/30 31 classBucketElementFreeList ( BucketElement ) : IBucketElementFreeList32 {
33 staticassert(is(BucketElement == struct),
34 "BucketElement type needs to be a struct, which " ~
35 BucketElement.stringof ~ " is not");
36 37 staticif(is(typeof(BucketElement.next) Next))
38 {
39 staticassert(is(Next == BucketElement*),
40 BucketElement.stringof ~ ".next needs to be of type " ~
41 (BucketElement*).stringof ~ ", not " ~ Next.stringof);
42 }
43 else44 {
45 staticassert(false, "need " ~ (BucketElement*).stringof ~ " " ~
46 BucketElement.stringof ~ ".next");
47 }
48 49 /***************************************************************************
50 51 Constructor.
52 53 ***************************************************************************/54 55 publicthis ( )
56 {
57 super(BucketElement.sizeof);
58 }
59 60 /**************************************************************************
61 62 Obtains the next element of element.
63 64 Params:
65 element = bucket element of which to obtain the next one
66 67 Returns:
68 the next bucket element (which may be null).
69 70 **************************************************************************/71 72 protectedoverridevoid* getNext ( void* element )
73 {
74 return (cast(BucketElement*)element).next;
75 }
76 77 /**************************************************************************
78 79 Sets the next element of element.
80 81 Params:
82 element = bucket element to which to set the next one
83 next = next bucket element for element (nay be null)
84 85 **************************************************************************/86 87 protectedoverridevoidsetNext ( void* element, void* next )
88 {
89 (cast(BucketElement*)element).next = cast(BucketElement*)next;
90 }
91 92 /**************************************************************************
93 94 Allocates a bucket element.
95 96 Returns:
97 a new bucket element.
98 99 **************************************************************************/100 101 protectedoverridevoid* newElement ( )
102 {
103 returnnewBucketElement;
104 }
105 }
106 107 /*******************************************************************************
108 109 Creates an instance of BucketElementFreeList which is suitable for usage
110 with the Map type passed as a template parameter.
111 112 Params:
113 Map = the type to create the allocator according to
114 115 Returns:
116 an instance of type BucketElementFreeList class
117 118 *******************************************************************************/119 120 publicBucketElementFreeList!(Map.Bucket.Element) instantiateAllocator ( Map ) ( )
121 {
122 returnnewBucketElementFreeList!(Map.Bucket.Element);
123 }
124 125 126 /*******************************************************************************
127 128 Type generic BucketElementFreeList base class.
129 130 *******************************************************************************/131 132 abstractclassIBucketElementFreeList: IAllocator133 {
134 importocean.core.Verify;
135 136 /**************************************************************************
137 138 First free element.
139 140 **************************************************************************/141 142 privatevoid* first = null;
143 144 /**************************************************************************
145 146 Free list length.
147 148 **************************************************************************/149 150 privatesize_tn_free = 0;
151 152 /**************************************************************************
153 154 True while a ParkingStack instance for this instance exists.
155 156 **************************************************************************/157 158 privateboolparking_stack_open = false;
159 160 /**************************************************************************
161 162 Consistency check and assertion that at most one ParkingStack instance
163 for this instance exists at a time.
164 165 **************************************************************************/166 167 invariant ( )
168 {
169 if (this.first)
170 {
171 assert (this.n_free);
172 }
173 else174 {
175 assert (!this.n_free);
176 }
177 178 assert (!this.parking_stack_open, "attempted to use the outer " ~
179 typeof (this).stringof ~ " instance of an existing " ~
180 ParkingStack.stringof ~ " instance");
181 }
182 183 /***************************************************************************
184 185 Constructor.
186 187 Params:
188 bucket_element_sizeof = the amount of memory used by each allocated
189 element.
190 191 ***************************************************************************/192 193 publicthis( size_tbucket_element_sizeof )
194 {
195 super(bucket_element_sizeof);
196 }
197 198 /**************************************************************************
199 200 Obtains an object either from the free list, if available, or from
201 new_object if the free list is empty.
202 203 Returns:
204 new object
205 206 Out:
207 The returned object cannot be null.
208 209 **************************************************************************/210 211 protectedoverridevoid* allocate ( )
212 out (object)
213 {
214 assert (object !isnull);
215 }
216 body217 {
218 if (this.first)
219 {
220 returnthis.get_();
221 }
222 else223 {
224 returnthis.newElement();
225 }
226 }
227 228 /**************************************************************************
229 230 Allocates a new object. Called by get() if the list is empty.
231 232 Returns:
233 a new object.
234 235 **************************************************************************/236 237 abstractprotectedvoid* newElement ( );
238 239 /**************************************************************************
240 241 Appends old_object to the free list.
242 243 Params:
244 old_object = object to recycle
245 246 In:
247 old_object must not be null.
248 249 **************************************************************************/250 251 protectedoverridevoiddeallocate ( void* old_object )
252 {
253 verify (old_object !isnull);
254 255 scope (success) this.n_free++;
256 257 this.recycle_(old_object);
258 }
259 260 /**************************************************************************
261 262 Returns:
263 the number of objects in the free list.
264 265 **************************************************************************/266 267 publicsize_tlength ( )
268 {
269 returnthis.n_free;
270 }
271 272 /**************************************************************************
273 274 Obtains the next object of object. object is never null but the next
275 object may be.
276 277 Params:
278 object = object of which to obtain the next object (is never null)
279 280 Returns:
281 the next object (which may be null).
282 283 **************************************************************************/284 285 abstractprotectedvoid* getNext ( void* object );
286 287 /**************************************************************************
288 289 Sets the next object of object. object is never null but next may be.
290 291 Params:
292 object = object to which to set the next object (is never null)
293 next = next object for object (nay be null)
294 295 **************************************************************************/296 297 abstractprotectedvoidsetNext ( void* object, void* next );
298 299 /**************************************************************************
300 301 Obtains free_list[n] and sets free_list[n] to null.
302 303 Params:
304 n = free list index
305 306 Returns:
307 free_list[n]
308 309 **************************************************************************/310 311 privatevoid* get_ ( )
312 {
313 verify (this.first !isnull);
314 315 void* element = this.first;
316 317 this.first = this.getNext(element);
318 this.n_free--;
319 this.setNext(element, null);
320 321 returnelement;
322 }
323 324 /**************************************************************************
325 326 Appends object to the free list using n as insertion index. n is
327 expected to refer to the position immediately after the last object in
328 the free list, which may be free_list.length.
329 330 Params:
331 n = free list insertion index
332 333 Returns:
334 free_list[n]
335 336 **************************************************************************/337 338 privatevoid* recycle_ ( void* object )
339 {
340 this.setNext(object, this.first);
341 342 returnthis.first = object;
343 }
344 345 /***************************************************************************
346 347 Calls dg with an IParkingStack instance that is set up to keep n
348 elements.
349 350 Params:
351 n = number of elements to park
352 dg = delegate to call with the IParkingStack instance
353 354 ***************************************************************************/355 356 publicoverridevoidparkElements (size_tn,
357 scopevoiddelegate ( IParkingStackpark ) dg)
358 {
359 scopeparking_stack = this.newParkingStack(n);
360 361 dg(parking_stack);
362 }
363 364 /**************************************************************************
365 366 Allows using the free list as a stack to park objects without marking
367 them as free. The parked object are appended to the free list after the
368 free objects currently in the list.
369 At most one ParkingStack instance may exist at a time. While a
370 ParkingStack instance exists, no public FreeList method may be used.
371 372 **************************************************************************/373 374 scopeclassParkingStack: IParkingStack375 {
376 /**********************************************************************
377 378 Constructor.
379 380 Params:
381 max_length = maximum number of objects that will be stored
382 383 **********************************************************************/384 385 privatethis ( size_tmax_length )
386 {
387 verify (!this.outer.parking_stack_open);
388 389 this.outer.parking_stack_open = true;
390 super(max_length);
391 }
392 393 /**********************************************************************
394 395 Destructor; removes the remaining stack elements, if any.
396 397 **********************************************************************/398 399 ~this ( )
400 {
401 scope ( exit ) this.outer.parking_stack_open = false;
402 while (this.pop()) { }
403 }
404 405 /**********************************************************************
406 407 Pushes an object on the stack.
408 409 Params:
410 object = object to push
411 n = number of parked objects before object is pushed
412 (guaranteed to be less than max_length)
413 414 **********************************************************************/415 416 protectedoverridevoidpush_ ( void* object, size_tn )
417 {
418 this.outer.recycle_(object);
419 }
420 421 /**********************************************************************
422 423 Pops an object from the stack. This method is never called if the
424 stack is empty.
425 426 Params:
427 n = number of parked objects after object is popped (guaranteed
428 to be less than max_length)
429 430 Returns:
431 object popped from the stack or null if the stack is empty.
432 433 **********************************************************************/434 435 protectedoverridevoid* pop_ ( size_tn )
436 {
437 returnthis.outer.get_();
438 }
439 }
440 }