/* * 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.GuardedBy; import javax.annotation.concurrent.ThreadSafe; import java.io.InputStream; import com.facebook.common.internal.Preconditions; import com.facebook.common.internal.VisibleForTesting; import com.facebook.common.references.CloseableReference; /** * An implementation of {@link PooledByteBuffer} that uses native memory * ({@link NativeMemoryChunk}) to store data */ @ThreadSafe public class NativePooledByteBuffer implements PooledByteBuffer { private final int mSize; @GuardedBy("this") @VisibleForTesting CloseableReference<NativeMemoryChunk> mBufRef; public NativePooledByteBuffer(CloseableReference<NativeMemoryChunk> bufRef, int size) { Preconditions.checkNotNull(bufRef); Preconditions.checkArgument(size >= 0 && size <= bufRef.get().getSize()); mBufRef = bufRef.clone(); mSize = size; } /** * Gets the size of the bytebuffer if it is valid. Otherwise, an exception is raised * @return the size of the bytebuffer if it is not closed. * @throws {@link ClosedException} */ @Override public synchronized int size() { ensureValid(); return mSize; } /** * Get an input stream for this bytebuffer. * The bytebuffer must be valid (aka not closed); otherwise, a closedException is raised * @return a ByteArrayInputStream for this buf * @throws {@link ClosedException} */ @Override public synchronized InputStream getStream() { ensureValid(); return new NativeMemoryChunkInputStream(mBufRef.get(), 0, mSize); } @Override public synchronized byte read(int offset) { ensureValid(); Preconditions.checkArgument(offset >= 0); Preconditions.checkArgument(offset < mSize); return mBufRef.get().read(offset); } @Override public synchronized long getNativePtr() { ensureValid(); return mBufRef.get().getNativePtr(); } /** * Check if this bytebuffer is already closed * @return true if this bytebuffer is closed. */ @Override public synchronized boolean isClosed() { return !CloseableReference.isValid(mBufRef); } /** * Closes this instance, and releases the underlying buffer to the pool. * Once the bytebuffer has been closed, subsequent operations (especially {@code getStream()} will * fail. * Note: It is not an error to close an already closed bytebuffer */ @Override public synchronized void close() { CloseableReference.closeSafely(mBufRef); mBufRef = null; } /** * Validates that the bytebuffer instance is valid (aka not closed). If it is closed, then we * raise a ClosedException * This doesn't really need to be synchronized, but lint won't shut up otherwise * @throws ClosedException */ synchronized void ensureValid() { if (isClosed()) { throw new ClosedException(); } } }