/* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.imagepipeline.memory; import javax.annotation.concurrent.ThreadSafe; import android.util.SparseIntArray; import com.facebook.common.internal.Preconditions; import com.facebook.common.memory.MemoryTrimmableRegistry; /** * Manages a pool of native memory chunks ({@link NativeMemoryChunk}) */ @ThreadSafe public class NativeMemoryChunkPool extends BasePool<NativeMemoryChunk> { private final int[] mBucketSizes; /** * Creates a new instance of the NativeMemoryChunkPool class * @param memoryTrimmableRegistry the memory manager to register with * @param poolParams provider for pool parameters * @param nativeMemoryChunkPoolStatsTracker */ public NativeMemoryChunkPool( MemoryTrimmableRegistry memoryTrimmableRegistry, PoolParams poolParams, PoolStatsTracker nativeMemoryChunkPoolStatsTracker) { super(memoryTrimmableRegistry, poolParams, nativeMemoryChunkPoolStatsTracker); SparseIntArray bucketSizes = poolParams.bucketSizes; mBucketSizes = new int[bucketSizes.size()]; for (int i = 0; i < mBucketSizes.length; ++i) { mBucketSizes[i] = bucketSizes.keyAt(i); } initialize(); } /** * Gets the smallest size supported by the pool * @return the smallest size supported by the pool */ public int getMinBufferSize() { return mBucketSizes[0]; } /** * Allocate a native memory chunk larger than or equal to the specified size * @param bucketedSize size of the buffer requested * @return a native memory chunk of the specified or larger size. Null if the size is invalid */ @Override protected NativeMemoryChunk alloc(int bucketedSize) { return new NativeMemoryChunk(bucketedSize); } /** * Frees the 'value' * @param value the value to free */ @Override protected void free(NativeMemoryChunk value) { Preconditions.checkNotNull(value); value.close(); } /** * Gets the size in bytes for the given 'bucketed' size * @param bucketedSize the bucketed size * @return size in bytes */ @Override protected int getSizeInBytes(int bucketedSize) { return bucketedSize; } /** * Get the 'bucketed' size for the given request size. The 'bucketed' size is a size that is * the same or larger than the request size. We walk through our list of pre-defined bucket * sizes, and use that to determine the smallest bucket size that is larger than the requested * size. * If no such 'bucketedSize' is found, then we simply return "requestSize" * @param requestSize the logical request size * @return the bucketed size * @throws InvalidSizeException, if the requested size was invalid */ @Override protected int getBucketedSize(int requestSize) { int intRequestSize = requestSize; if (intRequestSize <= 0) { throw new InvalidSizeException(requestSize); } // find the smallest bucketed size that is larger than the requested size for (int bucketedSize : mBucketSizes) { if (bucketedSize >= intRequestSize) { return bucketedSize; } } // requested size doesn't match our existing buckets - just return the requested size // this will eventually translate into a plain alloc/free paradigm return requestSize; } /** * Gets the bucketed size of the value * @param value the value * @return just the length of the value */ @Override protected int getBucketedSizeForValue(NativeMemoryChunk value) { Preconditions.checkNotNull(value); return value.getSize(); } /** * Checks if the value is reusable (for subseequent {@link #get(int)} operations. * The value is reusable, if * - it hasn't already been freed * @param value the value to test for reusability * @return true, if the value is reusable */ @Override protected boolean isReusable(NativeMemoryChunk value) { Preconditions.checkNotNull(value); return !value.isClosed(); } }