/// <summary> /// Returns a buffer of the given size or greater. /// </summary> /// <exception cref="BufferAcquisitionException">If the buffer could /// not be taken from a pool, and the ActionOnBufferUnavailable /// is set to ThrowException, or if the specified size is greater /// than the maximum buffer size.</exception> /// <exception cref="ArgumentOutOfRangeException">If minimumSize is less than 0.</exception> public IBuffer GetBuffer(int minimumSize) { if (minimumSize < 0) { throw new ArgumentOutOfRangeException("minimumSize must be greater than or equal to 0"); } if (minimumSize > options.MaxBufferSize) { throw new BufferAcquisitionException("Requested buffer " + minimumSize + " is larger " + "than maximum buffer size " + options.MaxBufferSize); } // Work out the size of buffer to use, and where in the list to find // cached buffers int listIndex = 0; int size = options.MinBufferSize; while (size < minimumSize) { size = CalculateNextSizeBand(size); listIndex++; } // Loop in case we need to find the next size up while (true) { CachedBuffer ret = FindAvailableBuffer(listIndex, size); if (ret != null) { return(ret); } switch (options.ActionOnBufferUnavailable) { case Options.BufferUnavailableAction.ReturnUncached: return(new CachedBuffer(minimumSize, options.ClearAfterUse)); case Options.BufferUnavailableAction.ThrowException: throw new BufferAcquisitionException("No buffers available"); } // Must be "use bigger". Use an uncached buffer if we've reached the maximum size, // otherwise try the next size band if (size == options.MaxBufferSize) { return(new CachedBuffer(minimumSize, options.ClearAfterUse)); } size = CalculateNextSizeBand(size); listIndex++; } }
/// <summary> /// Finds an available buffer from the list, creating a new buffer /// where appropriate. /// </summary> /// <param name="listIndex">Index into the list of buffer slots</param> /// <param name="size">Size of buffer to create if necessary</param> /// <returns>An available buffer, or null if none are available in the given band.</returns> CachedBuffer FindAvailableBuffer(int listIndex, int size) { using (padlock.Lock()) { // Make sure there'll be an entry, even if it's null while (listIndex >= bufferBands.Count) { bufferBands.Add(null); } // Create a new array of buffers if necessary CachedBuffer[] buffers = bufferBands[listIndex]; if (buffers == null) { buffers = new CachedBuffer[options.MaxBuffersPerSizeBand]; bufferBands[listIndex] = buffers; } // Look through all the buffers in this band for an available one, or an unused slot for (int i = 0; i < buffers.Length; i++) { // No cached unused buffers. Create a new one. if (buffers[i] == null) { buffers[i] = new CachedBuffer(size, options.ClearAfterUse); return(buffers[i]); } if (buffers[i].Available) { buffers[i].Available = false; return(buffers[i]); } } return(null); } }
/// <summary> /// Finds an available buffer from the list, creating a new buffer /// where appropriate. /// </summary> /// <param name="listIndex">Index into the list of buffer slots</param> /// <param name="size">Size of buffer to create if necessary</param> /// <returns>An available buffer, or null if none are available in the given band.</returns> CachedBuffer FindAvailableBuffer(int listIndex, int size) { using (padlock.Lock()) { // Make sure there'll be an entry, even if it's null while (listIndex >= bufferBands.Count) { bufferBands.Add(null); } // Create a new array of buffers if necessary CachedBuffer[] buffers = bufferBands[listIndex]; if (buffers == null) { buffers = new CachedBuffer[options.MaxBuffersPerSizeBand]; bufferBands[listIndex] = buffers; } // Look through all the buffers in this band for an available one, or an unused slot for (int i = 0; i < buffers.Length; i++) { // No cached unused buffers. Create a new one. if (buffers[i] == null) { buffers[i] = new CachedBuffer(size, options.ClearAfterUse); return buffers[i]; } if (buffers[i].Available) { buffers[i].Available = false; return buffers[i]; } } return null; } }