1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file or at 6 // https://developers.google.com/open-source/licenses/bsd 7 8 package com.google.protobuf; 9 10 import com.google.protobuf.Internal.ProtobufList; 11 import java.util.AbstractList; 12 import java.util.Collection; 13 import java.util.List; 14 import java.util.RandomAccess; 15 16 /** 17 * An abstract implementation of {@link ProtobufList} which manages mutability semantics. All mutate 18 * methods must check if the list is mutable before proceeding. Subclasses must invoke {@link 19 * #ensureIsMutable()} manually when overriding those methods. 20 * 21 * <p>This implementation assumes all subclasses are array based, supporting random access. 22 */ 23 abstract class AbstractProtobufList<E> extends AbstractList<E> implements ProtobufList<E> { 24 25 protected static final int DEFAULT_CAPACITY = 10; 26 27 /** Whether or not this list is modifiable. */ 28 private boolean isMutable; 29 30 /** Constructs a mutable list by default. */ AbstractProtobufList()31 AbstractProtobufList() { 32 this(true); 33 } 34 35 /** Constructs an immutable list for EMPTY lists */ AbstractProtobufList(boolean isMutable)36 AbstractProtobufList(boolean isMutable) { 37 this.isMutable = isMutable; 38 } 39 40 @Override equals(Object o)41 public boolean equals(Object o) { 42 if (o == this) { 43 return true; 44 } 45 if (!(o instanceof List)) { 46 return false; 47 } 48 // Handle lists that do not support RandomAccess as efficiently as possible by using an iterator 49 // based approach in our super class. Otherwise our index based approach will avoid those 50 // allocations. 51 if (!(o instanceof RandomAccess)) { 52 return super.equals(o); 53 } 54 55 List<?> other = (List<?>) o; 56 final int size = size(); 57 if (size != other.size()) { 58 return false; 59 } 60 for (int i = 0; i < size; i++) { 61 if (!get(i).equals(other.get(i))) { 62 return false; 63 } 64 } 65 return true; 66 } 67 68 @Override hashCode()69 public int hashCode() { 70 final int size = size(); 71 int hashCode = 1; 72 for (int i = 0; i < size; i++) { 73 hashCode = (31 * hashCode) + get(i).hashCode(); 74 } 75 return hashCode; 76 } 77 78 @Override add(E e)79 public boolean add(E e) { 80 ensureIsMutable(); 81 return super.add(e); 82 } 83 84 @Override add(int index, E element)85 public void add(int index, E element) { 86 ensureIsMutable(); 87 super.add(index, element); 88 } 89 90 @Override addAll(Collection<? extends E> c)91 public boolean addAll(Collection<? extends E> c) { 92 ensureIsMutable(); 93 return super.addAll(c); 94 } 95 96 @Override addAll(int index, Collection<? extends E> c)97 public boolean addAll(int index, Collection<? extends E> c) { 98 ensureIsMutable(); 99 return super.addAll(index, c); 100 } 101 102 @Override clear()103 public void clear() { 104 ensureIsMutable(); 105 super.clear(); 106 } 107 108 @Override isModifiable()109 public boolean isModifiable() { 110 return isMutable; 111 } 112 113 @Override makeImmutable()114 public final void makeImmutable() { 115 if (isMutable) { 116 isMutable = false; 117 } 118 } 119 120 @Override remove(int index)121 public E remove(int index) { 122 ensureIsMutable(); 123 return super.remove(index); 124 } 125 126 @Override remove(Object o)127 public boolean remove(Object o) { 128 ensureIsMutable(); 129 int index = indexOf(o); 130 if (index == -1) { 131 return false; 132 } 133 remove(index); 134 return true; 135 } 136 137 @Override removeAll(Collection<?> c)138 public boolean removeAll(Collection<?> c) { 139 ensureIsMutable(); 140 return super.removeAll(c); 141 } 142 143 @Override retainAll(Collection<?> c)144 public boolean retainAll(Collection<?> c) { 145 ensureIsMutable(); 146 return super.retainAll(c); 147 } 148 149 @Override set(int index, E element)150 public E set(int index, E element) { 151 ensureIsMutable(); 152 return super.set(index, element); 153 } 154 155 /** 156 * Throws an {@link UnsupportedOperationException} if the list is immutable. Subclasses are 157 * responsible for invoking this method on mutate operations. 158 */ ensureIsMutable()159 protected void ensureIsMutable() { 160 if (!isMutable) { 161 throw new UnsupportedOperationException(); 162 } 163 } 164 } 165