// 
// Decompiled by Procyon v0.6.0
// 

package io.netty.buffer;

import io.netty.util.internal.SystemPropertyUtil;
import io.netty.util.internal.logging.InternalLoggerFactory;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.logging.InternalLogger;

public final class AdaptiveByteBufAllocator extends AbstractByteBufAllocator implements ByteBufAllocatorMetricProvider, ByteBufAllocatorMetric
{
    private static final InternalLogger logger;
    private static final boolean DEFAULT_USE_CACHED_MAGAZINES_FOR_NON_EVENT_LOOP_THREADS;
    private final AdaptivePoolingAllocator direct;
    private final AdaptivePoolingAllocator heap;
    
    public AdaptiveByteBufAllocator() {
        this(!PlatformDependent.isExplicitNoPreferDirect());
    }
    
    public AdaptiveByteBufAllocator(final boolean preferDirect) {
        this(preferDirect, AdaptiveByteBufAllocator.DEFAULT_USE_CACHED_MAGAZINES_FOR_NON_EVENT_LOOP_THREADS);
    }
    
    public AdaptiveByteBufAllocator(final boolean preferDirect, final boolean useCacheForNonEventLoopThreads) {
        super(preferDirect);
        this.direct = new AdaptivePoolingAllocator(new DirectChunkAllocator((ByteBufAllocator)this), useCacheForNonEventLoopThreads);
        this.heap = new AdaptivePoolingAllocator(new HeapChunkAllocator((ByteBufAllocator)this), useCacheForNonEventLoopThreads);
    }
    
    @Override
    protected ByteBuf newHeapBuffer(final int initialCapacity, final int maxCapacity) {
        return AbstractByteBufAllocator.toLeakAwareBuffer(this.heap.allocate(initialCapacity, maxCapacity));
    }
    
    @Override
    protected ByteBuf newDirectBuffer(final int initialCapacity, final int maxCapacity) {
        return AbstractByteBufAllocator.toLeakAwareBuffer(this.direct.allocate(initialCapacity, maxCapacity));
    }
    
    @Override
    public boolean isDirectBufferPooled() {
        return true;
    }
    
    @Override
    public long usedHeapMemory() {
        return this.heap.usedMemory();
    }
    
    @Override
    public long usedDirectMemory() {
        return this.direct.usedMemory();
    }
    
    @Override
    public ByteBufAllocatorMetric metric() {
        return this;
    }
    
    static {
        logger = InternalLoggerFactory.getInstance(AdaptiveByteBufAllocator.class);
        DEFAULT_USE_CACHED_MAGAZINES_FOR_NON_EVENT_LOOP_THREADS = SystemPropertyUtil.getBoolean("io.netty.allocator.useCachedMagazinesForNonEventLoopThreads", false);
        AdaptiveByteBufAllocator.logger.debug("-Dio.netty.allocator.useCachedMagazinesForNonEventLoopThreads: {}", (Object)AdaptiveByteBufAllocator.DEFAULT_USE_CACHED_MAGAZINES_FOR_NON_EVENT_LOOP_THREADS);
    }
    
    private static final class HeapChunkAllocator implements AdaptivePoolingAllocator.ChunkAllocator
    {
        private final ByteBufAllocator allocator;
        
        private HeapChunkAllocator(final ByteBufAllocator allocator) {
            this.allocator = allocator;
        }
        
        @Override
        public AbstractByteBuf allocate(final int initialCapacity, final int maxCapacity) {
            return PlatformDependent.hasUnsafe() ? new UnpooledUnsafeHeapByteBuf(this.allocator, initialCapacity, maxCapacity) : new UnpooledHeapByteBuf(this.allocator, initialCapacity, maxCapacity);
        }
    }
    
    private static final class DirectChunkAllocator implements AdaptivePoolingAllocator.ChunkAllocator
    {
        private final ByteBufAllocator allocator;
        
        private DirectChunkAllocator(final ByteBufAllocator allocator) {
            this.allocator = allocator;
        }
        
        @Override
        public AbstractByteBuf allocate(final int initialCapacity, final int maxCapacity) {
            return PlatformDependent.hasUnsafe() ? UnsafeByteBufUtil.newUnsafeDirectByteBuf(this.allocator, initialCapacity, maxCapacity, false) : new UnpooledDirectByteBuf(this.allocator, initialCapacity, maxCapacity, false);
        }
    }
}
