/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package io.netty.buffer; import io.netty.util.ResourceLeak; import io.netty.util.ResourceLeakDetector; import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.StringUtil; /** * Skeletal {@link ByteBufAllocator} implementation to extend. */ public abstract class AbstractByteBufAllocator implements ByteBufAllocator { private static final int DEFAULT_INITIAL_CAPACITY = 256; private static final int DEFAULT_MAX_COMPONENTS = 16; protected static ByteBuf toLeakAwareBuffer(ByteBuf buf) { ResourceLeak leak; switch (ResourceLeakDetector.getLevel()) { case SIMPLE: leak = AbstractByteBuf.leakDetector.open(buf); if (leak != null) { buf = new SimpleLeakAwareByteBuf(buf, leak); } break; case ADVANCED: case PARANOID: leak = AbstractByteBuf.leakDetector.open(buf); if (leak != null) { buf = new AdvancedLeakAwareByteBuf(buf, leak); } break; } return buf; } private final boolean directByDefault; private final ByteBuf emptyBuf; /** * Instance use heap buffers by default */ protected AbstractByteBufAllocator() { this(false); } /** * Create new instance * * @param preferDirect {@code true} if {@link #buffer(int)} should try to allocate a direct buffer rather than * a heap buffer */ protected AbstractByteBufAllocator(boolean preferDirect) { directByDefault = preferDirect && PlatformDependent.hasUnsafe(); emptyBuf = new EmptyByteBuf(this); } @Override public ByteBuf buffer() { if (directByDefault) { return directBuffer(); } return heapBuffer(); } @Override public ByteBuf buffer(int initialCapacity) { if (directByDefault) { return directBuffer(initialCapacity); } return heapBuffer(initialCapacity); } @Override public ByteBuf buffer(int initialCapacity, int maxCapacity) { if (directByDefault) { return directBuffer(initialCapacity, maxCapacity); } return heapBuffer(initialCapacity, maxCapacity); } @Override public ByteBuf ioBuffer() { if (PlatformDependent.hasUnsafe()) { return directBuffer(DEFAULT_INITIAL_CAPACITY); } return heapBuffer(DEFAULT_INITIAL_CAPACITY); } @Override public ByteBuf ioBuffer(int initialCapacity) { if (PlatformDependent.hasUnsafe()) { return directBuffer(initialCapacity); } return heapBuffer(initialCapacity); } @Override public ByteBuf ioBuffer(int initialCapacity, int maxCapacity) { if (PlatformDependent.hasUnsafe()) { return directBuffer(initialCapacity, maxCapacity); } return heapBuffer(initialCapacity, maxCapacity); } @Override public ByteBuf heapBuffer() { return heapBuffer(DEFAULT_INITIAL_CAPACITY, Integer.MAX_VALUE); } @Override public ByteBuf heapBuffer(int initialCapacity) { return heapBuffer(initialCapacity, Integer.MAX_VALUE); } @Override public ByteBuf heapBuffer(int initialCapacity, int maxCapacity) { if (initialCapacity == 0 && maxCapacity == 0) { return emptyBuf; } validate(initialCapacity, maxCapacity); return newHeapBuffer(initialCapacity, maxCapacity); } @Override public ByteBuf directBuffer() { return directBuffer(DEFAULT_INITIAL_CAPACITY, Integer.MAX_VALUE); } @Override public ByteBuf directBuffer(int initialCapacity) { return directBuffer(initialCapacity, Integer.MAX_VALUE); } @Override public ByteBuf directBuffer(int initialCapacity, int maxCapacity) { if (initialCapacity == 0 && maxCapacity == 0) { return emptyBuf; } validate(initialCapacity, maxCapacity); return newDirectBuffer(initialCapacity, maxCapacity); } @Override public CompositeByteBuf compositeBuffer() { if (directByDefault) { return compositeDirectBuffer(); } return compositeHeapBuffer(); } @Override public CompositeByteBuf compositeBuffer(int maxNumComponents) { if (directByDefault) { return compositeDirectBuffer(maxNumComponents); } return compositeHeapBuffer(maxNumComponents); } @Override public CompositeByteBuf compositeHeapBuffer() { return compositeHeapBuffer(DEFAULT_MAX_COMPONENTS); } @Override public CompositeByteBuf compositeHeapBuffer(int maxNumComponents) { return new CompositeByteBuf(this, false, maxNumComponents); } @Override public CompositeByteBuf compositeDirectBuffer() { return compositeDirectBuffer(DEFAULT_MAX_COMPONENTS); } @Override public CompositeByteBuf compositeDirectBuffer(int maxNumComponents) { return new CompositeByteBuf(this, true, maxNumComponents); } private static void validate(int initialCapacity, int maxCapacity) { if (initialCapacity < 0) { throw new IllegalArgumentException("initialCapacity: " + initialCapacity + " (expectd: 0+)"); } if (initialCapacity > maxCapacity) { throw new IllegalArgumentException(String.format( "initialCapacity: %d (expected: not greater than maxCapacity(%d)", initialCapacity, maxCapacity)); } } /** * Create a heap {@link ByteBuf} with the given initialCapacity and maxCapacity. */ protected abstract ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity); /** * Create a direct {@link ByteBuf} with the given initialCapacity and maxCapacity. */ protected abstract ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity); @Override public String toString() { return StringUtil.simpleClassName(this) + "(directByDefault: " + directByDefault + ')'; } }