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}