ProtoPool.java revision 42627b850c8f68a594f105e04b97c512b292b698
1/*
2 * Copyright 2013, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32package org.jf.dexlib2.writer.pool;
33
34import com.google.common.collect.Ordering;
35import org.jf.dexlib2.iface.reference.MethodReference;
36import org.jf.dexlib2.util.MethodUtil;
37import org.jf.dexlib2.writer.pool.ProtoPool.Key;
38import org.jf.dexlib2.writer.ProtoSection;
39import org.jf.util.CharSequenceUtils;
40import org.jf.util.CollectionUtils;
41
42import javax.annotation.Nonnull;
43import javax.annotation.Nullable;
44import java.util.Collection;
45import java.util.List;
46
47public class ProtoPool extends BaseIndexPool<Key>
48        implements ProtoSection<CharSequence, CharSequence, Key, TypeListPool.Key<? extends Collection<? extends CharSequence>>> {
49    @Nonnull private final StringPool stringPool;
50    @Nonnull private final TypePool typePool;
51    @Nonnull private final TypeListPool typeListPool;
52
53    public ProtoPool(@Nonnull StringPool stringPool, @Nonnull TypePool typePool,
54                     @Nonnull TypeListPool typeListPool) {
55        this.stringPool = stringPool;
56        this.typePool = typePool;
57        this.typeListPool = typeListPool;
58    }
59
60    public void intern(@Nonnull MethodReference method) {
61        // We can't use method directly, because it is likely a full MethodReference. We use a wrapper that computes
62        // hashCode and equals based only on the prototype fields
63        Key key = new Key(method);
64        Integer prev = internedItems.put(key, 0);
65        if (prev == null) {
66            stringPool.intern(key.getShorty());
67            typePool.intern(method.getReturnType());
68            typeListPool.intern(method.getParameterTypes());
69        }
70    }
71
72    @Nonnull @Override public CharSequence getShorty(@Nonnull Key key) {
73        return key.getShorty();
74    }
75
76    @Nonnull @Override public CharSequence getReturnType(@Nonnull Key key) {
77        return key.getReturnType();
78    }
79
80    @Nullable @Override public TypeListPool.Key<List<? extends CharSequence>> getParameters(@Nonnull Key key) {
81        return new TypeListPool.Key<List<? extends CharSequence>>(key.getParameters());
82    }
83
84    public static class Key implements Comparable<Key> {
85        @Nonnull private final MethodReference method;
86
87        public Key(@Nonnull MethodReference method) {
88            this.method = method;
89        }
90
91        @Nonnull public String getReturnType() { return method.getReturnType(); }
92        @Nonnull public List<? extends CharSequence> getParameters() {
93            return method.getParameterTypes();
94        }
95
96        public String getShorty() {
97            return MethodUtil.getShorty(method.getParameterTypes(), method.getReturnType());
98        }
99
100        public String toString() {
101            StringBuilder sb = new StringBuilder();
102            sb.append('(');
103            for (CharSequence paramType: getParameters()) {
104                sb.append(paramType);
105            }
106            sb.append(')');
107            sb.append(getReturnType());
108            return sb.toString();
109        }
110
111        @Override
112        public int hashCode() {
113            int hashCode = getReturnType().hashCode();
114            return hashCode*31 + CharSequenceUtils.listHashCode(getParameters());
115        }
116
117        @Override
118        public boolean equals(@Nullable Object o) {
119            if (o instanceof Key) {
120                Key other = (Key)o;
121                return getReturnType().equals(other.getReturnType()) &&
122                        CharSequenceUtils.listEquals(getParameters(), other.getParameters());
123            }
124            return false;
125        }
126
127        @Override
128        public int compareTo(@Nonnull Key o) {
129            int res = getReturnType().compareTo(o.getReturnType());
130            if (res != 0) return res;
131            return CollectionUtils.compareAsIterable(Ordering.usingToString(), getParameters(), o.getParameters());
132        }
133    }
134}
135