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.ImmutableList;
35import org.jf.dexlib2.writer.DexWriter;
36import org.jf.dexlib2.writer.TypeListSection;
37import org.jf.dexlib2.writer.pool.TypeListPool.Key;
38
39import javax.annotation.Nonnull;
40import javax.annotation.Nullable;
41import java.util.Collection;
42import java.util.Iterator;
43
44public class TypeListPool extends BaseNullableOffsetPool<Key<? extends Collection<? extends CharSequence>>>
45        implements TypeListSection<CharSequence, Key<? extends Collection<? extends CharSequence>>> {
46    @Nonnull private final TypePool typePool;
47
48    public TypeListPool(@Nonnull TypePool typePool) {
49        this.typePool = typePool;
50    }
51
52    public void intern(@Nonnull Collection<? extends CharSequence> types) {
53        if (types.size() > 0) {
54            Key<? extends Collection<? extends CharSequence>> key = new Key<Collection<? extends CharSequence>>(types);
55            Integer prev = internedItems.put(key, 0);
56            if (prev == null) {
57                for (CharSequence type: types) {
58                    typePool.intern(type);
59                }
60            }
61        }
62    }
63
64    @Nonnull @Override
65    public Collection<? extends CharSequence> getTypes(Key<? extends Collection<? extends CharSequence>> typesKey) {
66        if (typesKey == null) {
67            return ImmutableList.of();
68        }
69        return typesKey.types;
70    }
71
72    @Override public int getNullableItemOffset(@Nullable Key<? extends Collection<? extends CharSequence>> key) {
73        if (key == null || key.types.size() == 0) {
74            return DexWriter.NO_OFFSET;
75        } else {
76            return super.getNullableItemOffset(key);
77        }
78    }
79
80    public static class Key<TypeCollection extends Collection<? extends CharSequence>>
81            implements Comparable<Key<? extends Collection<? extends CharSequence>>> {
82        @Nonnull TypeCollection types;
83
84        public Key(@Nonnull TypeCollection types) {
85            this.types = types;
86        }
87
88        @Override
89        public int hashCode() {
90            int hashCode = 1;
91            for (CharSequence type: types) {
92                hashCode = hashCode*31 + type.toString().hashCode();
93            }
94            return hashCode;
95        }
96
97        @Override
98        public boolean equals(Object o) {
99            if (o instanceof Key) {
100                Key<? extends Collection<? extends CharSequence>> other =
101                        (Key<? extends Collection<? extends CharSequence>>)o;
102                if (types.size() != other.types.size()) {
103                    return false;
104                }
105                Iterator<? extends CharSequence> otherTypes = other.types.iterator();
106                for (CharSequence type: types) {
107                    if (!type.toString().equals(otherTypes.next().toString())) {
108                        return false;
109                    }
110                }
111                return true;
112            }
113            return false;
114        }
115
116        @Override
117        public String toString() {
118            StringBuilder sb = new StringBuilder();
119            for (CharSequence type: types) {
120                sb.append(type.toString());
121            }
122            return sb.toString();
123        }
124
125        @Override
126        public int compareTo(Key<? extends Collection<? extends CharSequence>> o) {
127            Iterator<? extends CharSequence> other = o.types.iterator();
128            for (CharSequence type: types) {
129                if (!other.hasNext()) {
130                    return 1;
131                }
132                int comparison = type.toString().compareTo(other.next().toString());
133                if (comparison != 0) {
134                    return comparison;
135                }
136            }
137            if (other.hasNext()) {
138                return -1;
139            }
140            return 0;
141        }
142    }
143}
144