• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // http://code.google.com/p/protobuf/
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.List;
34 import java.util.AbstractList;
35 import java.util.ArrayList;
36 import java.util.Collection;
37 import java.util.Collections;
38 import java.util.RandomAccess;
39 
40 /**
41  * An implementation of {@link LazyStringList} that wraps an ArrayList. Each
42  * element is either a ByteString or a String. It caches the last one requested
43  * which is most likely the one needed next. This minimizes memory usage while
44  * satisfying the most common use cases.
45  * <p>
46  * <strong>Note that this implementation is not synchronized.</strong>
47  * If multiple threads access an <tt>ArrayList</tt> instance concurrently,
48  * and at least one of the threads modifies the list structurally, it
49  * <i>must</i> be synchronized externally.  (A structural modification is
50  * any operation that adds or deletes one or more elements, or explicitly
51  * resizes the backing array; merely setting the value of an element is not
52  * a structural modification.)  This is typically accomplished by
53  * synchronizing on some object that naturally encapsulates the list.
54  * <p>
55  * If the implementation is accessed via concurrent reads, this is thread safe.
56  * Conversions are done in a thread safe manner. It's possible that the
57  * conversion may happen more than once if two threads attempt to access the
58  * same element and the modifications were not visible to each other, but this
59  * will not result in any corruption of the list or change in behavior other
60  * than performance.
61  *
62  * @author jonp@google.com (Jon Perlow)
63  */
64 public class LazyStringArrayList extends AbstractList<String>
65     implements LazyStringList, RandomAccess {
66 
67   public final static LazyStringList EMPTY = new UnmodifiableLazyStringList(
68       new LazyStringArrayList());
69 
70   private final List<Object> list;
71 
LazyStringArrayList()72   public LazyStringArrayList() {
73     list = new ArrayList<Object>();
74   }
75 
LazyStringArrayList(LazyStringList from)76   public LazyStringArrayList(LazyStringList from) {
77     list = new ArrayList<Object>(from.size());
78     addAll(from);
79   }
80 
LazyStringArrayList(List<String> from)81   public LazyStringArrayList(List<String> from) {
82     list = new ArrayList<Object>(from);
83   }
84 
85   @Override
get(int index)86   public String get(int index) {
87     Object o = list.get(index);
88     if (o instanceof String) {
89       return (String) o;
90     } else {
91       ByteString bs = (ByteString) o;
92       String s = bs.toStringUtf8();
93       if (bs.isValidUtf8()) {
94         list.set(index, s);
95       }
96       return s;
97     }
98   }
99 
100   @Override
size()101   public int size() {
102     return list.size();
103   }
104 
105   @Override
set(int index, String s)106   public String set(int index, String s) {
107     Object o = list.set(index, s);
108     return asString(o);
109   }
110 
111   @Override
add(int index, String element)112   public void add(int index, String element) {
113     list.add(index, element);
114     modCount++;
115   }
116 
117   @Override
addAll(Collection<? extends String> c)118   public boolean addAll(Collection<? extends String> c) {
119     // The default implementation of AbstractCollection.addAll(Collection)
120     // delegates to add(Object). This implementation instead delegates to
121     // addAll(int, Collection), which makes a special case for Collections
122     // which are instances of LazyStringList.
123     return addAll(size(), c);
124   }
125 
126   @Override
addAll(int index, Collection<? extends String> c)127   public boolean addAll(int index, Collection<? extends String> c) {
128     // When copying from another LazyStringList, directly copy the underlying
129     // elements rather than forcing each element to be decoded to a String.
130     Collection<?> collection = c instanceof LazyStringList
131         ? ((LazyStringList) c).getUnderlyingElements() : c;
132     boolean ret = list.addAll(index, collection);
133     modCount++;
134     return ret;
135   }
136 
137   @Override
remove(int index)138   public String remove(int index) {
139     Object o = list.remove(index);
140     modCount++;
141     return asString(o);
142   }
143 
clear()144   public void clear() {
145     list.clear();
146     modCount++;
147   }
148 
149   // @Override
add(ByteString element)150   public void add(ByteString element) {
151     list.add(element);
152     modCount++;
153   }
154 
155   // @Override
getByteString(int index)156   public ByteString getByteString(int index) {
157     Object o = list.get(index);
158     if (o instanceof String) {
159       ByteString b = ByteString.copyFromUtf8((String) o);
160       list.set(index, b);
161       return b;
162     } else {
163       return (ByteString) o;
164     }
165   }
166 
asString(Object o)167   private String asString(Object o) {
168     if (o instanceof String) {
169       return (String) o;
170     } else {
171       return ((ByteString) o).toStringUtf8();
172     }
173   }
174 
getUnderlyingElements()175   public List<?> getUnderlyingElements() {
176     return Collections.unmodifiableList(list);
177   }
178 }
179