001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.util; 019 020import java.util.ArrayList; 021import java.util.Collection; 022import java.util.Collections; 023import java.util.Comparator; 024import java.util.Iterator; 025import java.util.List; 026import java.util.ListIterator; 027import java.util.RandomAccess; 028import org.apache.yetus.audience.InterfaceAudience; 029 030/** 031 * Simple sorted list implementation that uses {@link java.util.ArrayList} as the underlying 032 * collection so we can support RandomAccess. All mutations create a new copy of the 033 * <code>ArrayList</code> instance, so can be expensive. This class is only intended for use on 034 * small, very rarely written collections that expect highly concurrent reads. 035 * <p> 036 * Read operations are performed on a reference to the internal list at the time of invocation, so 037 * will not see any mutations to the collection during their operation. Iterating over list elements 038 * manually using the RandomAccess pattern involves multiple operations. For this to be safe get a 039 * reference to the internal list first using get(). 040 * <p> 041 * If constructed with a {@link java.util.Comparator}, the list will be sorted using the comparator. 042 * Adding or changing an element using an index will trigger a resort. 043 * <p> 044 * Iterators are read-only. They cannot be used to remove elements. 045 */ 046@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "UG_SYNC_SET_UNSYNC_GET", 047 justification = "TODO: synchronization in here needs review!!!") 048@InterfaceAudience.Private 049public class SortedList<E> implements List<E>, RandomAccess { 050 private volatile List<E> list; 051 private final Comparator<? super E> comparator; 052 053 /** 054 * Constructs an empty list with the default initial capacity that will be sorted using the given 055 * comparator. 056 * @param comparator the comparator 057 */ 058 public SortedList(Comparator<? super E> comparator) { 059 this.list = Collections.emptyList(); 060 this.comparator = comparator; 061 } 062 063 /** 064 * Constructs a list containing the elements of the given collection, in the order returned by the 065 * collection's iterator, that will be sorted with the given comparator. 066 * @param c the collection 067 * @param comparator the comparator 068 */ 069 public SortedList(Collection<? extends E> c, Comparator<? super E> comparator) { 070 this.list = Collections.unmodifiableList(new ArrayList<E>(c)); 071 this.comparator = comparator; 072 } 073 074 /** 075 * Returns a reference to the unmodifiable list currently backing the SortedList. Changes to the 076 * SortedList will not be reflected in this list. Use this method to get a reference for iterating 077 * over using the RandomAccess pattern. 078 */ 079 public List<E> get() { // FindBugs: UG_SYNC_SET_UNSYNC_GET complaint. Fix!! 080 return list; 081 } 082 083 @Override 084 public int size() { 085 return list.size(); 086 } 087 088 @Override 089 public boolean isEmpty() { 090 return list.isEmpty(); 091 } 092 093 @Override 094 public boolean contains(Object o) { 095 return list.contains(o); 096 } 097 098 @Override 099 public Iterator<E> iterator() { 100 return list.iterator(); 101 } 102 103 @Override 104 public Object[] toArray() { 105 return list.toArray(); 106 } 107 108 @Override 109 public <T> T[] toArray(T[] a) { 110 return list.toArray(a); 111 } 112 113 @Override 114 public synchronized boolean add(E e) { 115 ArrayList<E> newList = new ArrayList<>(list); 116 boolean changed = newList.add(e); 117 if (changed) { 118 Collections.sort(newList, comparator); 119 } 120 list = Collections.unmodifiableList(newList); 121 return changed; 122 } 123 124 @Override 125 public synchronized boolean remove(Object o) { 126 ArrayList<E> newList = new ArrayList<>(list); 127 // Removals in ArrayList won't break sorting 128 boolean changed = newList.remove(o); 129 list = Collections.unmodifiableList(newList); 130 return changed; 131 } 132 133 @Override 134 public boolean containsAll(Collection<?> c) { 135 return list.containsAll(c); 136 } 137 138 @Override 139 public synchronized boolean addAll(Collection<? extends E> c) { 140 ArrayList<E> newList = new ArrayList<>(list); 141 boolean changed = newList.addAll(c); 142 if (changed) { 143 Collections.sort(newList, comparator); 144 } 145 list = Collections.unmodifiableList(newList); 146 return changed; 147 } 148 149 @Override 150 public synchronized boolean addAll(int index, Collection<? extends E> c) { 151 ArrayList<E> newList = new ArrayList<>(list); 152 boolean changed = newList.addAll(index, c); 153 if (changed) { 154 Collections.sort(newList, comparator); 155 } 156 list = Collections.unmodifiableList(newList); 157 return changed; 158 } 159 160 @Override 161 public synchronized boolean removeAll(Collection<?> c) { 162 ArrayList<E> newList = new ArrayList<>(list); 163 // Removals in ArrayList won't break sorting 164 boolean changed = newList.removeAll(c); 165 list = Collections.unmodifiableList(newList); 166 return changed; 167 } 168 169 @Override 170 public synchronized boolean retainAll(Collection<?> c) { 171 ArrayList<E> newList = new ArrayList<>(list); 172 // Removals in ArrayList won't break sorting 173 boolean changed = newList.retainAll(c); 174 list = Collections.unmodifiableList(newList); 175 return changed; 176 } 177 178 @Override 179 public synchronized void clear() { 180 list = Collections.emptyList(); 181 } 182 183 @Override 184 public synchronized E get(int index) { 185 return list.get(index); 186 } 187 188 @Override 189 public synchronized E set(int index, E element) { 190 ArrayList<E> newList = new ArrayList<>(list); 191 E result = newList.set(index, element); 192 Collections.sort(list, comparator); 193 list = Collections.unmodifiableList(newList); 194 return result; 195 } 196 197 @Override 198 public synchronized void add(int index, E element) { 199 ArrayList<E> newList = new ArrayList<>(list); 200 newList.add(index, element); 201 Collections.sort(list, comparator); 202 list = Collections.unmodifiableList(newList); 203 } 204 205 @Override 206 public synchronized E remove(int index) { 207 ArrayList<E> newList = new ArrayList<>(list); 208 // Removals in ArrayList won't break sorting 209 E result = newList.remove(index); 210 list = Collections.unmodifiableList(newList); 211 return result; 212 } 213 214 @Override 215 public int indexOf(Object o) { 216 return list.indexOf(o); 217 } 218 219 @Override 220 public int lastIndexOf(Object o) { 221 return list.lastIndexOf(o); 222 } 223 224 @Override 225 public ListIterator<E> listIterator() { 226 return list.listIterator(); 227 } 228 229 @Override 230 public ListIterator<E> listIterator(int index) { 231 return list.listIterator(index); 232 } 233 234 @Override 235 public List<E> subList(int fromIndex, int toIndex) { 236 return list.subList(fromIndex, toIndex); 237 } 238}