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