• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
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 package com.google.protobuf;
32 
33 import java.util.AbstractList;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Collection;
37 import java.util.Collections;
38 import java.util.List;
39 import java.util.RandomAccess;
40 
41 /**
42  * An implementation of {@link LazyStringList} that wraps an ArrayList. Each
43  * element is one of String, ByteString, or byte[]. It caches the last one
44  * requested which is most likely the one needed next. This minimizes memory
45  * usage while satisfying the most common use cases.
46  * <p>
47  * <strong>Note that this implementation is not synchronized.</strong>
48  * If multiple threads access an <tt>ArrayList</tt> instance concurrently,
49  * and at least one of the threads modifies the list structurally, it
50  * <i>must</i> be synchronized externally.  (A structural modification is
51  * any operation that adds or deletes one or more elements, or explicitly
52  * resizes the backing array; merely setting the value of an element is not
53  * a structural modification.)  This is typically accomplished by
54  * synchronizing on some object that naturally encapsulates the list.
55  * <p>
56  * If the implementation is accessed via concurrent reads, this is thread safe.
57  * Conversions are done in a thread safe manner. It's possible that the
58  * conversion may happen more than once if two threads attempt to access the
59  * same element and the modifications were not visible to each other, but this
60  * will not result in any corruption of the list or change in behavior other
61  * than performance.
62  *
63  * @author jonp@google.com (Jon Perlow)
64  */
65 public class LazyStringArrayList extends AbstractProtobufList<String>
66     implements LazyStringList, RandomAccess {
67 
68   private static final LazyStringArrayList EMPTY_LIST = new LazyStringArrayList();
69   static {
EMPTY_LIST.makeImmutable()70     EMPTY_LIST.makeImmutable();
71   }
72 
emptyList()73   static LazyStringArrayList emptyList() {
74     return EMPTY_LIST;
75   }
76 
77   // For compatibility with older runtimes.
78   public static final LazyStringList EMPTY = EMPTY_LIST;
79 
80   private final List<Object> list;
81 
LazyStringArrayList()82   public LazyStringArrayList() {
83     this(DEFAULT_CAPACITY);
84   }
85 
LazyStringArrayList(int intialCapacity)86   public LazyStringArrayList(int intialCapacity) {
87     this(new ArrayList<Object>(intialCapacity));
88   }
89 
LazyStringArrayList(LazyStringList from)90   public LazyStringArrayList(LazyStringList from) {
91     list = new ArrayList<Object>(from.size());
92     addAll(from);
93   }
94 
LazyStringArrayList(List<String> from)95   public LazyStringArrayList(List<String> from) {
96     this(new ArrayList<Object>(from));
97   }
98 
LazyStringArrayList(ArrayList<Object> list)99   private LazyStringArrayList(ArrayList<Object> list) {
100     this.list = list;
101   }
102 
103   @Override
mutableCopyWithCapacity(int capacity)104   public LazyStringArrayList mutableCopyWithCapacity(int capacity) {
105     if (capacity < size()) {
106       throw new IllegalArgumentException();
107     }
108     ArrayList<Object> newList = new ArrayList<Object>(capacity);
109     newList.addAll(list);
110     return new LazyStringArrayList(newList);
111   }
112 
113   @Override
get(int index)114   public String get(int index) {
115     Object o = list.get(index);
116     if (o instanceof String) {
117       return (String) o;
118     } else if (o instanceof ByteString) {
119       ByteString bs = (ByteString) o;
120       String s = bs.toStringUtf8();
121       if (bs.isValidUtf8()) {
122         list.set(index, s);
123       }
124       return s;
125     } else {
126       byte[] ba = (byte[]) o;
127       String s = Internal.toStringUtf8(ba);
128       if (Internal.isValidUtf8(ba)) {
129         list.set(index, s);
130       }
131       return s;
132     }
133   }
134 
135   @Override
size()136   public int size() {
137     return list.size();
138   }
139 
140   @Override
set(int index, String s)141   public String set(int index, String s) {
142     ensureIsMutable();
143     Object o = list.set(index, s);
144     return asString(o);
145   }
146 
147   @Override
add(int index, String element)148   public void add(int index, String element) {
149     ensureIsMutable();
150     list.add(index, element);
151     modCount++;
152   }
153 
add(int index, ByteString element)154   private void add(int index, ByteString element) {
155     ensureIsMutable();
156     list.add(index, element);
157     modCount++;
158   }
159 
add(int index, byte[] element)160   private void add(int index, byte[] element) {
161     ensureIsMutable();
162     list.add(index, element);
163     modCount++;
164   }
165 
166   @Override
addAll(Collection<? extends String> c)167   public boolean addAll(Collection<? extends String> c) {
168     // The default implementation of AbstractCollection.addAll(Collection)
169     // delegates to add(Object). This implementation instead delegates to
170     // addAll(int, Collection), which makes a special case for Collections
171     // which are instances of LazyStringList.
172     return addAll(size(), c);
173   }
174 
175   @Override
addAll(int index, Collection<? extends String> c)176   public boolean addAll(int index, Collection<? extends String> c) {
177     ensureIsMutable();
178     // When copying from another LazyStringList, directly copy the underlying
179     // elements rather than forcing each element to be decoded to a String.
180     Collection<?> collection = c instanceof LazyStringList
181         ? ((LazyStringList) c).getUnderlyingElements() : c;
182     boolean ret = list.addAll(index, collection);
183     modCount++;
184     return ret;
185   }
186 
187   @Override
addAllByteString(Collection<? extends ByteString> values)188   public boolean addAllByteString(Collection<? extends ByteString> values) {
189     ensureIsMutable();
190     boolean ret = list.addAll(values);
191     modCount++;
192     return ret;
193   }
194 
195   @Override
addAllByteArray(Collection<byte[]> c)196   public boolean addAllByteArray(Collection<byte[]> c) {
197     ensureIsMutable();
198     boolean ret = list.addAll(c);
199     modCount++;
200     return ret;
201   }
202 
203   @Override
remove(int index)204   public String remove(int index) {
205     ensureIsMutable();
206     Object o = list.remove(index);
207     modCount++;
208     return asString(o);
209   }
210 
211   @Override
clear()212   public void clear() {
213     ensureIsMutable();
214     list.clear();
215     modCount++;
216   }
217 
218   @Override
add(ByteString element)219   public void add(ByteString element) {
220     ensureIsMutable();
221     list.add(element);
222     modCount++;
223   }
224 
225   @Override
add(byte[] element)226   public void add(byte[] element) {
227     ensureIsMutable();
228     list.add(element);
229     modCount++;
230   }
231 
232   @Override
getRaw(int index)233   public Object getRaw(int index) {
234     return list.get(index);
235   }
236 
237   @Override
getByteString(int index)238   public ByteString getByteString(int index) {
239     Object o = list.get(index);
240     ByteString b = asByteString(o);
241     if (b != o) {
242       list.set(index, b);
243     }
244     return b;
245   }
246 
247   @Override
getByteArray(int index)248   public byte[] getByteArray(int index) {
249     Object o = list.get(index);
250     byte[] b = asByteArray(o);
251     if (b != o) {
252       list.set(index, b);
253     }
254     return b;
255   }
256 
257   @Override
set(int index, ByteString s)258   public void set(int index, ByteString s) {
259     setAndReturn(index, s);
260   }
261 
setAndReturn(int index, ByteString s)262   private Object setAndReturn(int index, ByteString s) {
263     ensureIsMutable();
264     return list.set(index, s);
265   }
266 
267   @Override
set(int index, byte[] s)268   public void set(int index, byte[] s) {
269     setAndReturn(index, s);
270   }
271 
setAndReturn(int index, byte[] s)272   private Object setAndReturn(int index, byte[] s) {
273     ensureIsMutable();
274     return list.set(index, s);
275   }
276 
asString(Object o)277   private static String asString(Object o) {
278     if (o instanceof String) {
279       return (String) o;
280     } else if (o instanceof ByteString) {
281       return ((ByteString) o).toStringUtf8();
282     } else {
283       return Internal.toStringUtf8((byte[]) o);
284     }
285   }
286 
asByteString(Object o)287   private static ByteString asByteString(Object o) {
288     if (o instanceof ByteString) {
289       return (ByteString) o;
290     } else if (o instanceof String) {
291       return ByteString.copyFromUtf8((String) o);
292     } else {
293       return ByteString.copyFrom((byte[]) o);
294     }
295   }
296 
asByteArray(Object o)297   private static byte[] asByteArray(Object o) {
298     if (o instanceof byte[]) {
299       return (byte[]) o;
300     } else if (o instanceof String) {
301       return Internal.toByteArray((String) o);
302     } else {
303       return ((ByteString) o).toByteArray();
304     }
305   }
306 
307   @Override
getUnderlyingElements()308   public List<?> getUnderlyingElements() {
309     return Collections.unmodifiableList(list);
310   }
311 
312   @Override
mergeFrom(LazyStringList other)313   public void mergeFrom(LazyStringList other) {
314     ensureIsMutable();
315     for (Object o : other.getUnderlyingElements()) {
316       if (o instanceof byte[]) {
317         byte[] b = (byte[]) o;
318         // Byte array's content is mutable so they should be copied rather than
319         // shared when merging from one message to another.
320         list.add(Arrays.copyOf(b, b.length));
321       } else {
322         list.add(o);
323       }
324     }
325   }
326 
327   private static class ByteArrayListView extends AbstractList<byte[]>
328       implements RandomAccess {
329     private final LazyStringArrayList list;
330 
ByteArrayListView(LazyStringArrayList list)331     ByteArrayListView(LazyStringArrayList list) {
332       this.list = list;
333     }
334 
335     @Override
get(int index)336     public byte[] get(int index) {
337       return list.getByteArray(index);
338     }
339 
340     @Override
size()341     public int size() {
342       return list.size();
343     }
344 
345     @Override
set(int index, byte[] s)346     public byte[] set(int index, byte[] s) {
347       Object o = list.setAndReturn(index, s);
348       modCount++;
349       return asByteArray(o);
350     }
351 
352     @Override
add(int index, byte[] s)353     public void add(int index, byte[] s) {
354       list.add(index, s);
355       modCount++;
356     }
357 
358     @Override
remove(int index)359     public byte[] remove(int index) {
360       Object o = list.remove(index);
361       modCount++;
362       return asByteArray(o);
363     }
364   }
365 
366   @Override
asByteArrayList()367   public List<byte[]> asByteArrayList() {
368     return new ByteArrayListView(this);
369   }
370 
371   private static class ByteStringListView extends AbstractList<ByteString>
372       implements RandomAccess {
373     private final LazyStringArrayList list;
374 
ByteStringListView(LazyStringArrayList list)375     ByteStringListView(LazyStringArrayList list) {
376       this.list = list;
377     }
378 
379     @Override
get(int index)380     public ByteString get(int index) {
381       return list.getByteString(index);
382     }
383 
384     @Override
size()385     public int size() {
386       return list.size();
387     }
388 
389     @Override
set(int index, ByteString s)390     public ByteString set(int index, ByteString s) {
391       Object o = list.setAndReturn(index, s);
392       modCount++;
393       return asByteString(o);
394     }
395 
396     @Override
add(int index, ByteString s)397     public void add(int index, ByteString s) {
398       list.add(index, s);
399       modCount++;
400     }
401 
402     @Override
remove(int index)403     public ByteString remove(int index) {
404       Object o = list.remove(index);
405       modCount++;
406       return asByteString(o);
407     }
408   }
409 
410   @Override
asByteStringList()411   public List<ByteString> asByteStringList() {
412     return new ByteStringListView(this);
413   }
414 
415   @Override
getUnmodifiableView()416   public LazyStringList getUnmodifiableView() {
417     if (isModifiable()) {
418       return new UnmodifiableLazyStringList(this);
419     }
420     return this;
421   }
422 
423 }
424