package org.parboiled.transform;

import org.objectweb.asm.Type;
import org.parboiled.annotations.Cached;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static org.parboiled.common.Utils.toObjectArray;

/**
 * Runtime cache arguments for generated parsers
 *
 * <p>This class is used by generated parsers for rules taking arguments and
 * annotated with {@link Cached}. In this case, a {@link Map} is generated whose
 * keys are instances of this class, and values are already generated rules.</p>
 *
 * <p>What this class basically does is generate a "digest" of rule
 * arguments (as an {@code Object[]}.</p>
 */
public final class CacheArguments
{
    private final Object[] params;

    public CacheArguments(final Object... params)
    {
        // we need to "unroll" all inner Object arrays
        final List<Object> list = new ArrayList<Object>(params.length);
        unroll(params, list);
        this.params = list.toArray();
    }

    private static void unroll(final Object[] params, final List<Object> list)
    {
        Class<?> c;
        int type;
        for (final Object param: params) {
            if (param == null)
                continue;
            c = param.getClass();
            if (!c.isArray()) {
                list.add(param);
                continue;
            }
            type = Type.getType(c.getComponentType()).getSort();
            switch (type)
            {
                case Type.BOOLEAN:
                    unroll(toObjectArray((boolean[]) param), list);
                    continue;
                case Type.BYTE:
                    unroll(toObjectArray((byte[]) param), list);
                    continue;
                case Type.CHAR:
                    unroll(toObjectArray((char[]) param), list);
                    continue;
                case Type.DOUBLE:
                    unroll(toObjectArray((double[]) param), list);
                    continue;
                case Type.FLOAT:
                    unroll(toObjectArray((float[]) param), list);
                    continue;
                case Type.INT:
                    unroll(toObjectArray((int[]) param), list);
                    continue;
                case Type.LONG:
                    unroll(toObjectArray((long[]) param), list);
                    continue;
                case Type.SHORT:
                    unroll(toObjectArray((short[]) param), list);
                    continue;
                case Type.OBJECT:
                case Type.ARRAY:
                    unroll((Object[]) param, list);
                    continue;
                default:
                    throw new IllegalStateException();
            }
        }
    }

    @Override
    public boolean equals(final Object o)
    {
        if (o == null)
            return false;
        if (this == o)
            return true;
        if (getClass() != o.getClass())
            return false;
        final CacheArguments other = (CacheArguments) o;
        return Arrays.equals(params, other.params);
    }

    @Override
    public int hashCode()
    {
        return Arrays.hashCode(params);
    }
}

@@ -31,39 +31,8 @@
 m;%0A%0A
-import org.objectweb.asm.Type;%0A
 impo
@@ -95,139 +95,31 @@
 rray
-List;%0Aimport java.util.Arrays;%0Aimport java.util.List;%0Aimport java.util.Map;%0A%0Aimport static org.parboiled.common.Utils.toObjectArray
+s;%0Aimport java.util.Map
 ;%0A%0A/
@@ -669,1949 +669,59 @@
     
-// we need to %22unroll%22 all inner Object arrays%0A        final List%3CObject%3E list = new ArrayList%3CObject%3E(params.length);%0A        unroll(params, list);%0A        this.params = list.toArray();%0A    %7D%0A%0A    private static void unroll(final Object%5B%5D params, final List%3CObject%3E list)%0A    %7B%0A        Class%3C?%3E c;%0A        int type;%0A        for (final Object param: params) %7B%0A            if (param == null)%0A                continue;%0A            c = param.getClass();%0A            if (!c.isArray()) %7B%0A                list.add(param);%0A                continue;%0A            %7D%0A            type = Type.getType(c.getComponentType()).getSort();%0A            switch (type)%0A            %7B%0A                case Type.BOOLEAN:%0A                    unroll(toObjectArray((boolean%5B%5D) param), list);%0A                    continue;%0A                case Type.BYTE:%0A                    unroll(toObjectArray((byte%5B%5D) param), list);%0A                    continue;%0A                case Type.CHAR:%0A                    unroll(toObjectArray((char%5B%5D) param), list);%0A                    continue;%0A                case Type.DOUBLE:%0A                    unroll(toObjectArray((double%5B%5D) param), list);%0A                    continue;%0A                case Type.FLOAT:%0A                    unroll(toObjectArray((float%5B%5D) param), list);%0A                    continue;%0A                case Type.INT:%0A                    unroll(toObjectArray((int%5B%5D) param), list);%0A                    continue;%0A                case Type.LONG:%0A                    unroll(toObjectArray((long%5B%5D) param), list);%0A                    continue;%0A                case Type.SHORT:%0A                    unroll(toObjectArray((short%5B%5D) param), list);%0A                    continue;%0A                case Type.OBJECT:%0A                case Type.ARRAY:%0A                    unroll((Object%5B%5D) param, list);%0A                    continue;%0A                default:%0A                    throw new IllegalStateException();%0A            %7D%0A        %7D
+this.params = Arrays.copyOf(params, params.length);
 %0A   
@@ -778,16 +778,18 @@
 Object o
+bj
 )%0A    %7B%0A
@@ -801,16 +801,18 @@
    if (o
+bj
  == null
@@ -860,16 +860,18 @@
 his == o
+bj
 )%0A      
@@ -916,16 +916,18 @@
 s() != o
+bj
 .getClas
@@ -1012,16 +1012,18 @@
 ments) o
+bj
 ;%0A      
@@ -1038,17 +1038,21 @@
  Arrays.
-e
+deepE
 quals(pa
@@ -1147,17 +1147,21 @@
  Arrays.
-h
+deepH
 ashCode(

simplify logic