001/*
002*   SizedObjectFactory -- A class that holds factories to produce objects that require variable size inputs.
003*
004*   Copyright (C) 2011-2025 by Joseph A. Huwaldt. All rights reserved.
005*   
006*   This library is free software; you can redistribute it and/or
007*   modify it under the terms of the GNU Lesser General Public
008*   License as published by the Free Software Foundation; either
009*   version 2 of the License, or (at your option) any later version.
010*   
011*   This library is distributed in the hope that it will be useful,
012*   but WITHOUT ANY WARRANTY; without even the implied warranty of
013*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014*   Lesser General Public License for more details.
015*
016*   You should have received a copy of the GNU Lesser General Public License
017*   along with this program; if not, write to the Free Software
018*   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
019*   Or visit:  http://www.gnu.org/licenses/lgpl.html
020**/
021package jahuwaldt.js.util;
022
023import javolution.context.ObjectFactory;
024
025
026/**
027* <p> This class holds factories to produces objects of variable size/length.
028*     It allows for object recycling, pre-allocation and stack allocations:
029*
030*   <pre>
031*   {@code
032*     static SizedObjectFactory<BinomialCoef> BINOMIAL_FACTORY = new SizedObjectFactory<BinomialCoef> {
033*         protected BinomialCoef create(int size) {
034*             return new BinomialCoef(size);
035*         }
036*     };
037*     ...
038*     BinomialCoef bin = BINOMIAL_FACTORY.array(256);
039*   }
040*   </pre>
041*          
042*  @author  Joseph A. Huwaldt   Date: May 11, 2011
043*  @version February 22, 2025
044**/
045public abstract class SizedObjectFactory<T extends SizedObject> {
046
047    /**
048     * Holds factory for arrays up to size 4.
049     */
050    private final ObjectFactory _factory4 = new ObjectFactory() {
051        @Override
052        protected Object create() {
053            return SizedObjectFactory.this.create(4);
054        }
055    };
056
057    /**
058     * Holds factory for arrays up to size 8.
059     */
060    private final ObjectFactory _factory8 = new ObjectFactory() {
061        @Override
062        protected Object create() {
063            return SizedObjectFactory.this.create(8);
064        }
065    };
066
067    /**
068     * Holds factory for arrays up to size 16.
069     */
070    private final ObjectFactory _factory16 = new ObjectFactory() {
071        @Override
072        protected Object create() {
073            return SizedObjectFactory.this.create(16);
074        }
075    };
076
077    /**
078     * Holds factory for arrays up to size 32.
079     */
080    private final ObjectFactory _factory32 = new ObjectFactory() {
081        @Override
082        protected Object create() {
083            return SizedObjectFactory.this.create(32);
084        }
085    };
086
087    /**
088     * Holds factory for arrays up to size 64.
089     */
090    private final ObjectFactory _factory64 = new ObjectFactory() {
091        @Override
092        protected Object create() {
093            return SizedObjectFactory.this.create(64);
094        }
095    };
096
097    /**
098     * Holds factory for arrays up to size 128.
099     */
100    private final ObjectFactory _factory128 = new ObjectFactory() {
101        @Override
102        protected Object create() {
103            return SizedObjectFactory.this.create(128);
104        }
105    };
106
107    /**
108     * Holds factory for arrays up to size 256.
109     */
110    private final ObjectFactory _factory256 = new ObjectFactory() {
111        @Override
112        protected Object create() {
113            return SizedObjectFactory.this.create(256);
114        }
115    };
116
117    /**
118     * Holds factory for arrays up to size 512.
119     */
120    private final ObjectFactory _factory512 = new ObjectFactory() {
121        @Override
122        protected Object create() {
123            return SizedObjectFactory.this.create(512);
124        }
125    };
126
127    /**
128     * Holds factory for arrays up to size 1024.
129     */
130    private final ObjectFactory _factory1024 = new ObjectFactory() {
131        @Override
132        protected Object create() {
133            return SizedObjectFactory.this.create(1024);
134        }
135    };
136
137    /**
138     * Holds factory for arrays up to size 2048.
139     */
140    private final ObjectFactory _factory2048 = new ObjectFactory() {
141        @Override
142        protected Object create() {
143            return SizedObjectFactory.this.create(2048);
144        }
145    };
146
147    /**
148     * Holds factory for arrays up to size 4096.
149     */
150    private final ObjectFactory _factory4096 = new ObjectFactory() {
151        @Override
152        protected Object create() {
153            return SizedObjectFactory.this.create(4096);
154        }
155    };
156
157    /**
158     * Holds factory for arrays up to size 8192.
159     */
160    private final ObjectFactory _factory8192 = new ObjectFactory() {
161        @Override
162        protected Object create() {
163            return SizedObjectFactory.this.create(8192);
164        }
165    };
166
167    /**
168     * Holds factory for arrays up to size 16384.
169     */
170    private final ObjectFactory _factory16384 = new ObjectFactory() {
171        @Override
172        protected Object create() {
173            return SizedObjectFactory.this.create(16384);
174        }
175    };
176
177    /**
178     * Holds factory for arrays up to size 32768.
179     */
180    private final ObjectFactory _factory32768 = new ObjectFactory() {
181        @Override
182        protected Object create() {
183            return SizedObjectFactory.this.create(32768);
184        }
185    };
186
187    /**
188     * Holds factory for arrays up to size 65536.
189     */
190    private final ObjectFactory _factory65536 = new ObjectFactory() {
191        @Override
192        protected Object create() {
193            return SizedObjectFactory.this.create(65536);
194        }
195    };
196
197    // Above 65536 we use the heap exclusively. 
198
199    /**
200     * Default constructor.
201     */
202    public SizedObjectFactory() { }
203
204    /**
205     * Returns an sized object possibly recycled or preallocated of specified 
206     * minimum size.
207     * 
208     * @param capacity the minimum size of the array to be returned.
209     * @return a recycled, pre-allocated or new factory array.
210     */
211    public final T object(int capacity) {
212        return (capacity <= 4) ? (T) _factory4.object()
213                : largeArray(capacity);
214    }
215
216    private T largeArray(int capacity) {
217        if (capacity <= 8)
218            return (T) _factory8.object();
219        if (capacity <= 16)
220            return (T) _factory16.object();
221        if (capacity <= 32)
222            return (T) _factory32.object();
223        if (capacity <= 64)
224            return (T) _factory64.object();
225        if (capacity <= 128)
226            return (T) _factory128.object();
227        if (capacity <= 256)
228            return (T) _factory256.object();
229        if (capacity <= 512)
230            return (T) _factory512.object();
231        if (capacity <= 1024)
232            return (T) _factory1024.object();
233        if (capacity <= 2048)
234            return (T) _factory2048.object();
235        if (capacity <= 4096)
236            return (T) _factory4096.object();
237        if (capacity <= 8192)
238            return (T) _factory8192.object();
239        if (capacity <= 16384)
240            return (T) _factory16384.object();
241        if (capacity <= 32768)
242            return (T) _factory32768.object();
243        if (capacity <= 65536)
244            return (T) _factory65536.object();
245        return create(capacity);
246    }
247
248    /**
249     * Recycles the specified sized object.
250     * 
251     * @param object the SizedObject to be recycled.
252     */
253    public void recycle(SizedObject object) {
254        recycle(object, object.size());
255    }
256
257    final void recycle(SizedObject array, int length) {
258        if (length <= 4) {
259            _factory4.recycle(array);
260        } else if (length <= 8) {
261            _factory8.recycle(array);
262        } else if (length <= 16) {
263            _factory16.recycle(array);
264        } else if (length <= 32) {
265            _factory32.recycle(array);
266        } else if (length <= 64) {
267            _factory64.recycle(array);
268        } else if (length <= 128) {
269            _factory128.recycle(array);
270        } else if (length <= 256) {
271            _factory256.recycle(array);
272        } else if (length <= 512) {
273            _factory512.recycle(array);
274        } else if (length <= 1024) {
275            _factory1024.recycle(array);
276        } else if (length <= 2048) {
277            _factory2048.recycle(array);
278        } else if (length <= 4096) {
279            _factory4096.recycle(array);
280        } else if (length <= 8192) {
281            _factory8192.recycle(array);
282        } else if (length <= 16384) {
283            _factory16384.recycle(array);
284        } else if (length <= 32768) {
285            _factory32768.recycle(array);
286        } else if (length <= 65536) {
287            _factory65536.recycle(array);
288        }
289    }
290
291    /**
292     * Constructs a new sized object of specified size from this factory 
293     * (using the <code>new</code> keyword).
294     *
295     * @param size the size of the array.
296     * @return a new factory array.
297     */
298    protected abstract T create(int size);
299
300}