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