/*
 * Copyright 2013 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.util;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.IdentityHashMap;
import java.util.Map;

/**
 * Light-weight object pool based on a thread-local stack.
 *
 * @param <T> the type of the pooled object
 */
public abstract class Recycler<T> {

    private final ThreadLocal<Stack<T>> threadLocal = new ThreadLocal<Stack<T>>() {
        @Override
        protected Stack<T> initialValue() {
            return new Stack<T>(Recycler.this, Thread.currentThread());
        }
    };

    public final T get() {
        Stack<T> stack = threadLocal.get();
        T o = stack.pop();
        if (o == null) {
            o = newObject(stack);
        }
        return o;
    }

    public final boolean recycle(T o, Handle handle) {
        @SuppressWarnings("unchecked")
        Stack<T> stack = (Stack<T>) handle;
        if (stack.parent != this) {
            return false;
        }

        if (Thread.currentThread() != stack.thread) {
            return false;
        }

        stack.push(o);
        return true;
    }

    protected abstract T newObject(Handle handle);

    public interface Handle { }

    static final class Stack<T> implements Handle {
        final Recycler<T> parent;
        final Thread thread;
        private final Deque<T> deque = new ArrayDeque<T>();
        private final Map<T, Boolean> map = new IdentityHashMap<T, Boolean>();

        Stack(Recycler<T> parent, Thread thread) {
            this.parent = parent;
            this.thread = thread;
        }

        T pop() {
            T ret = deque.pollLast();
            map.remove(ret);
            return ret;
        }

        void push(T o) {
            if (map.put(o, Boolean.TRUE) != null) {
                throw new IllegalStateException("recycled already");
            }
            deque.addLast(o);
        }
    }
}

@@ -657,61 +657,8 @@
 l;%0A%0A
-import java.util.ArrayDeque;%0Aimport java.util.Deque;%0A
 impo
@@ -1779,16 +1779,75 @@
 andle %7B%0A
+%0A        private static final int INITIAL_CAPACITY = 256;%0A%0A
         
@@ -1921,50 +1921,46 @@
 ate 
-final Deque%3CT%3E deque = new ArrayDeque%3CT%3E()
+T%5B%5D elements;%0A        private int size
 ;%0A  
@@ -2033,19 +2033,101 @@
 oolean%3E(
-);%0A
+INITIAL_CAPACITY);%0A%0A        @SuppressWarnings(%7B %22unchecked%22, %22SuspiciousArrayCast%22 %7D)
 %0A       
@@ -2250,94 +2250,335 @@
     
-%7D%0A%0A        T pop() %7B%0A            T ret = deque.pollLast();%0A            map.remove(ret)
+    elements = newArray(INITIAL_CAPACITY);%0A        %7D%0A%0A        T pop() %7B%0A            int size = this.size;%0A            if (size == 0) %7B%0A                return null;%0A            %7D%0A            size --;%0A            T ret = elements%5Bsize%5D;%0A            elements%5Bsize%5D = null;%0A            map.remove(ret);%0A            this.size = size
 ;%0A  
@@ -2762,32 +2762,33 @@
 ;%0A            %7D%0A
+%0A
             dequ
@@ -2787,24 +2787,492 @@
     
-deque.addLast(o)
+int size = this.size;%0A            if (size == elements.length) %7B%0A                T%5B%5D newElements = newArray(size %3C%3C 1);%0A                System.arraycopy(elements, 0, newElements, 0, size);%0A                elements = newElements;%0A            %7D%0A%0A            elements%5Bsize%5D = o;%0A            this.size = size + 1;%0A        %7D%0A%0A        @SuppressWarnings(%7B %22unchecked%22, %22SuspiciousArrayCast%22 %7D)%0A        private static %3CT%3E T%5B%5D newArray(int length) %7B%0A            return (T%5B%5D) new Object%5Blength%5D
 ;%0A  

Optimize Recycler.Stack