1 /******************************************************************************* 2 3 Interfaces to manage and get information about a free list. 4 5 Copyright: 6 Copyright (c) 2009-2016 dunnhumby Germany GmbH. 7 All rights reserved. 8 9 License: 10 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 11 Alternatively, this file may be distributed under the terms of the Tango 12 3-Clause BSD License (see LICENSE_BSD.txt for details). 13 14 *******************************************************************************/ 15 16 module ocean.util.container.pool.model.IFreeList; 17 18 import ocean.meta.types.Qualifiers; 19 20 /******************************************************************************* 21 22 Informational interface to a free list. 23 24 *******************************************************************************/ 25 26 public interface IFreeListInfo 27 { 28 /*************************************************************************** 29 30 Returns the number of idle items in pool. 31 32 Returns: 33 the number of idle items in pool 34 35 ***************************************************************************/ 36 37 size_t num_idle ( ); 38 } 39 40 41 /******************************************************************************* 42 43 Management interface to a free list. 44 45 *******************************************************************************/ 46 47 public interface IFreeList ( T ) : IFreeListInfo 48 { 49 /*************************************************************************** 50 51 Gets an item from the free list. 52 53 Params: 54 new_item = new item, will only be evaluated in the case when no 55 items are available in the free list 56 57 Returns: 58 new item (either popped from free list or new_item) 59 60 ***************************************************************************/ 61 62 T get ( lazy T new_item ); 63 64 65 /*************************************************************************** 66 67 Ensures that the free list contains at least the specified number of 68 (idle) items. Useful to pre-allocate a free list of a certain size. 69 70 Params: 71 num = minimum number of idle items desired in free list 72 new_item = expression that creates a new instance of T 73 74 Returns: 75 this 76 77 ***************************************************************************/ 78 79 typeof(this) fill ( size_t num, lazy T new_item ); 80 81 82 /*************************************************************************** 83 84 Recycles an item into the free list. 85 86 Params: 87 item = item to be put into the free list 88 89 ***************************************************************************/ 90 91 void recycle ( T item ); 92 93 94 /*************************************************************************** 95 96 Ensures that the free list contains at most the specified number of 97 items. 98 99 Params: 100 num = maximum number of items desired in free list 101 102 Returns: 103 this 104 105 ***************************************************************************/ 106 107 typeof(this) minimize ( size_t num = 0 ); 108 } 109 110 111 112 version (unittest) 113 { 114 import ocean.core.Test; 115 import ocean.core.Array : pop; 116 117 118 /*************************************************************************** 119 120 Free list tester base class. Tests all methods of IFreeList. 121 122 Params: 123 I = type of item stored in free list 124 125 ***************************************************************************/ 126 127 abstract class FreeListTester ( I ) 128 { 129 /*********************************************************************** 130 131 Free list being tested. 132 133 ***********************************************************************/ 134 135 private alias IFreeList!(I) FL; 136 137 private FL fl; 138 139 140 /*********************************************************************** 141 142 Alias for type of item stored in free list. 143 144 ***********************************************************************/ 145 146 protected alias I Item; 147 148 149 /*********************************************************************** 150 151 Number of items to use in tests. 152 153 ***********************************************************************/ 154 155 protected static immutable num_items = 10; 156 157 158 /*********************************************************************** 159 160 Constructor. 161 162 Params: 163 fl = free list to test 164 165 ***********************************************************************/ 166 167 public this ( FL fl ) 168 { 169 this.fl = fl; 170 } 171 172 173 /*********************************************************************** 174 175 Unittest for internal free list. 176 177 ***********************************************************************/ 178 179 public void test ( ) 180 { 181 Item[] busy_items; 182 size_t idle_count; 183 184 // Get some items (initial creation) 185 for ( int i; i < this.num_items; i++ ) 186 { 187 busy_items ~= this.fl.get(this.newItem()); 188 this.lengthCheck(busy_items.length, idle_count); 189 } 190 .test!("==")(idle_count, 0, "idle count mismatch"); 191 192 // Recycle them 193 this.recycle(busy_items, idle_count); 194 .test!("==")(idle_count, this.num_items); 195 196 // Get some items and store something in them 197 for ( int i; i < this.num_items; i++ ) 198 { 199 auto item = this.fl.get(this.newItem()); 200 201 this.setItem(item, i); 202 busy_items ~= item; 203 204 this.lengthCheck(busy_items.length, --idle_count); 205 } 206 .test!("==")(idle_count, 0, "idle count mismatch"); 207 208 // Recycle them 209 this.recycle(busy_items, idle_count); 210 .test!("==")(idle_count, this.num_items, "idle count mismatch"); 211 212 // Get them again and check the contents are as expected 213 for ( int i; i < this.num_items; i++ ) 214 { 215 auto item = this.fl.get(this.newItem()); 216 217 this.checkItem(item, i); 218 busy_items ~= item; 219 220 this.lengthCheck(busy_items.length, --idle_count); 221 } 222 .test!("==")(idle_count, 0, "idle count mismatch"); 223 224 // Recycle them 225 this.recycle(busy_items, idle_count); 226 .test!("==")(idle_count, this.num_items, "idle count mismatch"); 227 228 // Fill 229 this.fl.fill(this.num_items * 2, this.newItem()); 230 this.lengthCheck(busy_items.length, this.num_items * 2); 231 232 // Minimize 233 this.fl.minimize(this.num_items); 234 this.lengthCheck(busy_items.length, this.num_items); 235 236 this.fl.minimize(); 237 this.lengthCheck(busy_items.length, 0); 238 } 239 240 241 /*********************************************************************** 242 243 Checks that the contents of the free list match the expected values. 244 Derived classes can add additional checks by overriding. 245 246 Params: 247 expected_busy = expected number of busy items 248 expected_idle = expected number of idle items 249 250 ***********************************************************************/ 251 252 protected void lengthCheck ( size_t expected_busy, size_t expected_idle ) 253 { 254 .test!("==")(this.fl.num_idle, expected_idle, "FreeList idle items wrong"); 255 } 256 257 258 /*********************************************************************** 259 260 Returns: 261 a new item of the type stored in the free list. 262 263 ***********************************************************************/ 264 265 protected abstract Item newItem ( ); 266 267 268 /*********************************************************************** 269 270 Sets the value of the passed item, using the passed integer to 271 deterministically decide its contents. 272 273 Params: 274 item = item to set value of 275 i = integer to determine contents of item 276 277 ***********************************************************************/ 278 279 protected abstract void setItem ( ref Item item, size_t i ); 280 281 282 /*********************************************************************** 283 284 Checks the value of the passed item against the value which can be 285 deterministically derived from the passed integer. The method should 286 throw TestException on failure. 287 288 Params: 289 item = item to check value of 290 i = integer to determine contents of item 291 292 ***********************************************************************/ 293 294 protected abstract void checkItem ( ref Item item, size_t i ); 295 296 297 /*********************************************************************** 298 299 Recycles all of the passed items into the free list, checking 300 consistency along the way. 301 302 Params: 303 busy_items = items to recycle 304 idle_count = count of idle items 305 306 ***********************************************************************/ 307 308 private void recycle ( ref Item[] busy_items, ref size_t idle_count ) 309 { 310 while ( busy_items.length ) 311 { 312 Item item; 313 auto popped = busy_items.pop(item); 314 .test(popped, "pop from list of busy items failed"); 315 316 this.fl.recycle(item); 317 this.lengthCheck(busy_items.length, ++idle_count); 318 } 319 320 assumeSafeAppend(busy_items); 321 } 322 } 323 }