1 2 /* 3 * Copyright 2011 JogAmp Community. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, are 6 * permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this list of 9 * conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 * of conditions and the following disclaimer in the documentation and/or other materials 13 * provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED 16 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 17 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 22 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 * The views and conclusions contained in the software and documentation are those of the 26 * authors and should not be interpreted as representing official policies, either expressed 27 * or implied, of JogAmp Community. 28 */ 29 30 /* 31 * Created on Sunday, February 13 2011 15:17 32 */ 33 package com.jogamp.common.nio; 34 35 import java.nio.ByteBuffer; 36 import java.nio.CharBuffer; 37 import java.nio.DoubleBuffer; 38 import java.nio.FloatBuffer; 39 import java.nio.IntBuffer; 40 import java.nio.LongBuffer; 41 import java.nio.ShortBuffer; 42 43 /** 44 * Buffer factory attempting to reduce buffer creation overhead. 45 * Direct ByteBuffers must be page aligned which increases creation overhead of 46 * small buffers significantly. 47 * This factory can be used as fixed size static or or dynamic allocating 48 * factory. The initial size and allocation size is configurable. 49 * <p> 50 * Fixed size factories may be used in systems with hard realtime requirements 51 * and/or predictable memory usage. 52 * </p> 53 * <p> 54 * concurrency info:<br/> 55 * <ul> 56 * <li>all create methods are threadsafe</li> 57 * <li>factories created with create(...) are <b>not</b> threadsafe</li> 58 * <li>factories created with createSynchronized(...) are threadsafe</li> 59 * </ul> 60 * </p> 61 * 62 * @author Michael Bien 63 */ 64 public class CachedBufferFactory { 65 66 /** 67 * default size for internal buffer allocation. 68 */ 69 public static final int DEFAULT_ALLOCATION_SIZE = 1024 * 1024; 70 71 private final int ALLOCATION_SIZE; 72 private ByteBuffer currentBuffer; 73 CachedBufferFactory()74 private CachedBufferFactory() { 75 this(DEFAULT_ALLOCATION_SIZE, DEFAULT_ALLOCATION_SIZE); 76 } 77 CachedBufferFactory(final int initialSize, final int allocationSize)78 private CachedBufferFactory(final int initialSize, final int allocationSize) { 79 currentBuffer = Buffers.newDirectByteBuffer(initialSize); 80 ALLOCATION_SIZE = allocationSize; 81 } 82 83 84 /** 85 * Creates a factory with initial size and allocation size set to 86 * {@link #DEFAULT_ALLOCATION_SIZE}. 87 */ create()88 public static CachedBufferFactory create() { 89 return new CachedBufferFactory(); 90 } 91 92 /** 93 * Creates a factory with the specified initial size. The allocation size is set to 94 * {@link #DEFAULT_ALLOCATION_SIZE}. 95 */ create(final int initialSize)96 public static CachedBufferFactory create(final int initialSize) { 97 return new CachedBufferFactory(initialSize, DEFAULT_ALLOCATION_SIZE); 98 } 99 100 /** 101 * Creates a factory with the specified initial size. The allocation size is set to 102 * {@link #DEFAULT_ALLOCATION_SIZE}. 103 * @param fixed Creates a fixed size factory which will handle overflows (initial size) 104 * with RuntimeExceptions. 105 */ create(final int initialSize, final boolean fixed)106 public static CachedBufferFactory create(final int initialSize, final boolean fixed) { 107 return new CachedBufferFactory(initialSize, fixed?-1:DEFAULT_ALLOCATION_SIZE); 108 } 109 110 /** 111 * Creates a factory with the specified initial size and allocation size. 112 */ create(final int initialSize, final int allocationSize)113 public static CachedBufferFactory create(final int initialSize, final int allocationSize) { 114 return new CachedBufferFactory(initialSize, allocationSize); 115 } 116 117 118 /** 119 * Synchronized version of {@link #create()}. 120 */ createSynchronized()121 public static CachedBufferFactory createSynchronized() { 122 return new SynchronizedCachedBufferFactory(); 123 } 124 125 /** 126 * Synchronized version of {@link #create(int)}. 127 */ createSynchronized(final int initialSize)128 public static CachedBufferFactory createSynchronized(final int initialSize) { 129 return new SynchronizedCachedBufferFactory(initialSize, DEFAULT_ALLOCATION_SIZE); 130 } 131 132 /** 133 * Synchronized version of {@link #create(int, boolean)}. 134 */ createSynchronized(final int initialSize, final boolean fixed)135 public static CachedBufferFactory createSynchronized(final int initialSize, final boolean fixed) { 136 return new SynchronizedCachedBufferFactory(initialSize, fixed?-1:DEFAULT_ALLOCATION_SIZE); 137 } 138 139 /** 140 * Synchronized version of {@link #create(int, int)}. 141 */ createSynchronized(final int initialSize, final int allocationSize)142 public static CachedBufferFactory createSynchronized(final int initialSize, final int allocationSize) { 143 return new CachedBufferFactory(initialSize, allocationSize); 144 } 145 146 /** 147 * Returns true only if this factory does not allow to allocate more buffers 148 * as limited by the initial size. 149 */ isFixed()150 public boolean isFixed() { 151 return ALLOCATION_SIZE == -1; 152 } 153 154 /** 155 * Returns the allocation size used to create new internal buffers. 156 * 0 means that the buffer will not grows, see {@link #isFixed()}. 157 */ getAllocationSize()158 public int getAllocationSize() { 159 return ALLOCATION_SIZE; 160 } 161 162 /** 163 * @return true if buffer cannot grow, otherwise false 164 */ checkIfFixed()165 private void checkIfFixed() { 166 if(ALLOCATION_SIZE == 0) { 167 throw new RuntimeException("fixed size buffer factory ran out ouf bounds."); 168 } 169 } 170 destroy()171 public void destroy() { 172 if(null != currentBuffer) { 173 currentBuffer.clear(); 174 currentBuffer = null; 175 } 176 } newDirectByteBuffer(final int size)177 public ByteBuffer newDirectByteBuffer(final int size) { 178 179 // if large enough... just create it 180 if (size > currentBuffer.capacity()) { 181 checkIfFixed(); 182 return Buffers.newDirectByteBuffer(size); 183 } 184 185 // create new internal buffer if the old is running full 186 if (size > currentBuffer.remaining()) { 187 checkIfFixed(); 188 currentBuffer = Buffers.newDirectByteBuffer(ALLOCATION_SIZE); 189 } 190 191 currentBuffer.limit(currentBuffer.position() + size); 192 final ByteBuffer result = currentBuffer.slice().order(currentBuffer.order()); 193 currentBuffer.position(currentBuffer.limit()); 194 currentBuffer.limit(currentBuffer.capacity()); 195 return result; 196 } 197 198 newDirectByteBuffer(final byte[] values, final int offset, final int lenght)199 public ByteBuffer newDirectByteBuffer(final byte[] values, final int offset, final int lenght) { 200 return (ByteBuffer)newDirectByteBuffer(lenght).put(values, offset, lenght).rewind(); 201 } 202 newDirectByteBuffer(final byte[] values, final int offset)203 public ByteBuffer newDirectByteBuffer(final byte[] values, final int offset) { 204 return newDirectByteBuffer(values, offset, values.length-offset); 205 } 206 newDirectByteBuffer(final byte[] values)207 public ByteBuffer newDirectByteBuffer(final byte[] values) { 208 return newDirectByteBuffer(values, 0); 209 } 210 newDirectDoubleBuffer(final int numElements)211 public DoubleBuffer newDirectDoubleBuffer(final int numElements) { 212 return newDirectByteBuffer(numElements * Buffers.SIZEOF_DOUBLE).asDoubleBuffer(); 213 } 214 newDirectDoubleBuffer(final double[] values, final int offset, final int lenght)215 public DoubleBuffer newDirectDoubleBuffer(final double[] values, final int offset, final int lenght) { 216 return (DoubleBuffer)newDirectDoubleBuffer(lenght).put(values, offset, lenght).rewind(); 217 } 218 newDirectDoubleBuffer(final double[] values, final int offset)219 public DoubleBuffer newDirectDoubleBuffer(final double[] values, final int offset) { 220 return newDirectDoubleBuffer(values, offset, values.length - offset); 221 } 222 newDirectDoubleBuffer(final double[] values)223 public DoubleBuffer newDirectDoubleBuffer(final double[] values) { 224 return newDirectDoubleBuffer(values, 0); 225 } 226 newDirectFloatBuffer(final int numElements)227 public FloatBuffer newDirectFloatBuffer(final int numElements) { 228 return newDirectByteBuffer(numElements * Buffers.SIZEOF_FLOAT).asFloatBuffer(); 229 } 230 newDirectFloatBuffer(final float[] values, final int offset, final int lenght)231 public FloatBuffer newDirectFloatBuffer(final float[] values, final int offset, final int lenght) { 232 return (FloatBuffer)newDirectFloatBuffer(lenght).put(values, offset, lenght).rewind(); 233 } 234 newDirectFloatBuffer(final float[] values, final int offset)235 public FloatBuffer newDirectFloatBuffer(final float[] values, final int offset) { 236 return newDirectFloatBuffer(values, offset, values.length - offset); 237 } 238 newDirectFloatBuffer(final float[] values)239 public FloatBuffer newDirectFloatBuffer(final float[] values) { 240 return newDirectFloatBuffer(values, 0); 241 } 242 newDirectIntBuffer(final int numElements)243 public IntBuffer newDirectIntBuffer(final int numElements) { 244 return newDirectByteBuffer(numElements * Buffers.SIZEOF_INT).asIntBuffer(); 245 } 246 newDirectIntBuffer(final int[] values, final int offset, final int lenght)247 public IntBuffer newDirectIntBuffer(final int[] values, final int offset, final int lenght) { 248 return (IntBuffer)newDirectIntBuffer(lenght).put(values, offset, lenght).rewind(); 249 } 250 newDirectIntBuffer(final int[] values, final int offset)251 public IntBuffer newDirectIntBuffer(final int[] values, final int offset) { 252 return newDirectIntBuffer(values, offset, values.length - offset); 253 } 254 newDirectIntBuffer(final int[] values)255 public IntBuffer newDirectIntBuffer(final int[] values) { 256 return newDirectIntBuffer(values, 0); 257 } 258 newDirectLongBuffer(final int numElements)259 public LongBuffer newDirectLongBuffer(final int numElements) { 260 return newDirectByteBuffer(numElements * Buffers.SIZEOF_LONG).asLongBuffer(); 261 } 262 newDirectLongBuffer(final long[] values, final int offset, final int lenght)263 public LongBuffer newDirectLongBuffer(final long[] values, final int offset, final int lenght) { 264 return (LongBuffer)newDirectLongBuffer(lenght).put(values, offset, lenght).rewind(); 265 } 266 newDirectLongBuffer(final long[] values, final int offset)267 public LongBuffer newDirectLongBuffer(final long[] values, final int offset) { 268 return newDirectLongBuffer(values, offset, values.length - offset); 269 } 270 newDirectLongBuffer(final long[] values)271 public LongBuffer newDirectLongBuffer(final long[] values) { 272 return newDirectLongBuffer(values, 0); 273 } 274 newDirectShortBuffer(final int numElements)275 public ShortBuffer newDirectShortBuffer(final int numElements) { 276 return newDirectByteBuffer(numElements * Buffers.SIZEOF_SHORT).asShortBuffer(); 277 } 278 newDirectShortBuffer(final short[] values, final int offset, final int lenght)279 public ShortBuffer newDirectShortBuffer(final short[] values, final int offset, final int lenght) { 280 return (ShortBuffer)newDirectShortBuffer(lenght).put(values, offset, lenght).rewind(); 281 } 282 newDirectShortBuffer(final short[] values, final int offset)283 public ShortBuffer newDirectShortBuffer(final short[] values, final int offset) { 284 return newDirectShortBuffer(values, offset, values.length - offset); 285 } 286 newDirectShortBuffer(final short[] values)287 public ShortBuffer newDirectShortBuffer(final short[] values) { 288 return newDirectShortBuffer(values, 0); 289 } 290 newDirectCharBuffer(final int numElements)291 public CharBuffer newDirectCharBuffer(final int numElements) { 292 return newDirectByteBuffer(numElements * Buffers.SIZEOF_SHORT).asCharBuffer(); 293 } 294 newDirectCharBuffer(final char[] values, final int offset, final int lenght)295 public CharBuffer newDirectCharBuffer(final char[] values, final int offset, final int lenght) { 296 return (CharBuffer)newDirectCharBuffer(lenght).put(values, offset, lenght).rewind(); 297 } 298 newDirectCharBuffer(final char[] values, final int offset)299 public CharBuffer newDirectCharBuffer(final char[] values, final int offset) { 300 return newDirectCharBuffer(values, offset, values.length - offset); 301 } 302 newDirectCharBuffer(final char[] values)303 public CharBuffer newDirectCharBuffer(final char[] values) { 304 return newDirectCharBuffer(values, 0); 305 } 306 307 @Override equals(final Object obj)308 public boolean equals(final Object obj) { 309 if (obj == null) { 310 return false; 311 } 312 if (getClass() != obj.getClass()) { 313 return false; 314 } 315 final CachedBufferFactory other = (CachedBufferFactory) obj; 316 if (this.ALLOCATION_SIZE != other.ALLOCATION_SIZE) { 317 return false; 318 } 319 if (this.currentBuffer != other.currentBuffer && (this.currentBuffer == null || !this.currentBuffer.equals(other.currentBuffer))) { 320 return false; 321 } 322 return true; 323 } 324 325 @Override toString()326 public String toString() { 327 return getClass().getName()+"[static:"+isFixed()+" alloc size:"+getAllocationSize()+"]"; 328 } 329 330 331 // nothing special, just synchronized 332 private static class SynchronizedCachedBufferFactory extends CachedBufferFactory { 333 SynchronizedCachedBufferFactory()334 private SynchronizedCachedBufferFactory() { 335 super(); 336 } 337 SynchronizedCachedBufferFactory(final int size, final int step)338 private SynchronizedCachedBufferFactory(final int size, final int step) { 339 super(size, step); 340 } 341 342 @Override newDirectByteBuffer(final int size)343 public synchronized ByteBuffer newDirectByteBuffer(final int size) { 344 return super.newDirectByteBuffer(size); 345 } 346 347 } 348 349 } 350