1 /*******************************************************************************
2 
3     Pool class template which stores class instances, has the
4     following features:
5         * Get and recycle items. Recycled items will be re-used before creating
6           new items.
7         * The total number of items, as well as the number of idle or busy items
8           in the pool can be queried.
9         * A limit can be applied to the pool, which prevents more than the
10           specified number of items from being created.
11         * A specified number of items can be pre-allocated in the pool using the
12           fill() method.
13         * The entire pool can be emptied, returning all items to the idle state,
14           with clear().
15         * Iteration over all items in the pool, or all busy or idle items. (See
16           further notes in the super class.)
17         * For classes with a default (parameterless) constructor, get() and
18           fill() methods exist which automatically create new pool items,
19           without requiring them to be passed via a lazy argument.
20 
21     An additional class template exists, the AutoCtorPool, which automatically
22     creates new instances of the specified class by calling the constructor
23     with a fixed set of parameters.
24 
25     Also see: ocean.util.container.pool.model.IAggregatePool, for more detailed
26     documentation and usage examples.
27 
28     Copyright:
29         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
30         All rights reserved.
31 
32     License:
33         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
34         Alternatively, this file may be distributed under the terms of the Tango
35         3-Clause BSD License (see LICENSE_BSD.txt for details).
36 
37 *******************************************************************************/
38 
39 module ocean.util.container.pool.ObjectPool;
40 
41 
42 
43 
44 import ocean.util.container.pool.model.IAggregatePool;
45 import ocean.util.container.pool.model.IResettable;
46 
47 import ocean.transition;
48 
49 /*******************************************************************************
50 
51     Manages a pool of class instances of type T.
52 
53     Does not create the items ("new T") internally but receives them as lazy
54     arguments in get().
55 
56     Params:
57         T = type stored in pool
58 
59 *******************************************************************************/
60 
61 public class ObjectPool ( T ) : IAggregatePool!(T)
62 {
63     /***************************************************************************
64 
65         Asserts that T is a class.
66 
67     ***************************************************************************/
68 
69     static assert(is(T == class));
70 
71     /***************************************************************************
72 
73         Resets item.
74 
75         Params:
76             item = item to reset
77 
78     ***************************************************************************/
79 
80     protected override void resetItem ( Item item )
81     {
82         static if (is(T : Resettable))
83         {
84             this.fromItem(item).reset();
85         }
86     }
87 }
88 
89 
90 
91 /*******************************************************************************
92 
93     Extends ObjectPool by creating items (instances of T) automatically with
94     "new T(Args)".
95 
96     Params:
97         T = type stored in pool
98         Args = tuple of T constructor argument types.
99 
100 *******************************************************************************/
101 
102 public class AutoCtorPool ( T, Args ... ) : ObjectPool!(T)
103 {
104     /***************************************************************************
105 
106         Asserts that at least one constructor argument is specified in the Args
107         tuple.
108 
109     ***************************************************************************/
110 
111     static assert(Args.length > 0, "if you want to use a constructor with no arguments, just use ObjectPool");
112 
113     /***************************************************************************
114 
115         Arguments used to construct pool items. These items are set in the
116         class' constructor and are then used to construct all requested pool
117         items.
118 
119     ***************************************************************************/
120 
121     private Args args;
122 
123     /***************************************************************************
124 
125         Constructor
126 
127         Params:
128             args = T constructor arguments to be used each time an
129                    object is created
130 
131     ***************************************************************************/
132 
133     public this ( Args args )
134     {
135         this.args = args;
136     }
137 
138     /**************************************************************************
139 
140         Gets an object from the object pool.
141 
142         Returns:
143             object from the object pool
144 
145      **************************************************************************/
146 
147     public ItemType get ( )
148     {
149         return super.get(new T(args));
150     }
151 
152     /**************************************************************************
153 
154         Ensures that the pool contains at least the specified number of items.
155         Useful to pre-allocate a pool of a certain size.
156 
157         Params:
158             num = minimum number of items desired in pool
159 
160         Returns:
161             this
162 
163         Throws:
164             LimitExceededException if the requested number of items exceeds
165             the previously specified limit.
166 
167      **************************************************************************/
168 
169     public typeof(this) fill ( size_t num )
170     {
171         super.fill_(num, this.toItem(new T(args)));
172         return this;
173     }
174 
175     /**************************************************************************
176 
177         Creates a new instance.
178 
179         Params:
180             args = T constructor arguments to be used each time an object is
181                    created
182 
183      **************************************************************************/
184 
185     static typeof (this) newPool ( Args args )
186     {
187         return new typeof (this)(args);
188     }
189 }
190 
191 
192 
193 version ( UnitTest )
194 {
195     class Class
196     {
197         size_t object_pool_index;
198 
199         mixin(genOpEquals(`
200         {
201             auto crhs = cast(typeof(this)) rhs;
202             return this.i == crhs.i && this.s == crhs.s;
203         }`));
204 
205         size_t i;
206         char[] s;
207     }
208 
209     import ocean.core.Test;
210 
211     alias ObjectPool!(Class) MyPool;
212     class ObjectPoolTester : IAggregatePoolTester!(Class)
213     {
214 
215         public this ( )
216         {
217             super(new MyPool);
218         }
219 
220         protected override Item newItem ( )
221         {
222             return new Class;
223         }
224 
225         protected override void setItem ( ref Item item, size_t i )
226         {
227             item.i = i;
228             item.s.length = 1;
229             item.s[0] = cast(char)(i + 32);
230         }
231 
232         protected override void checkItem ( ref Item item, size_t i )
233         {
234             .test!("==")(item.i, i, "item integer wrong");
235             .test!("==")(item.s.length, 1, "item string length wrong");
236             .test!("==")(item.s[0], cast(char)(i + 32), "item string content wrong");
237         }
238     }
239 }
240 
241 unittest
242 {
243     scope op = new ObjectPoolTester;
244     op.test();
245 }
246