View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.util;
20  
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.Comparator;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.ListIterator;
28  import java.util.RandomAccess;
29  
30  /**
31   * Simple sorted list implementation that uses {@link java.util.ArrayList} as
32   * the underlying collection so we can support RandomAccess. All mutations
33   * create a new copy of the <code>ArrayList</code> instance, so can be
34   * expensive. This class is only intended for use on small, very rarely
35   * written collections that expect highly concurrent reads.
36   * <p>
37   * Read operations are performed on a reference to the internal list at the
38   * time of invocation, so will not see any mutations to the collection during
39   * their operation. Iterating over list elements manually using the
40   * RandomAccess pattern involves multiple operations. For this to be safe get
41   * a reference to the internal list first using get(). 
42   * <p>
43   * If constructed with a {@link java.util.Comparator}, the list will be sorted
44   * using the comparator. Adding or changing an element using an index will
45   * trigger a resort.
46   * <p>
47   * Iterators are read-only. They cannot be used to remove elements.
48   */
49  public class SortedList<E> implements List<E>, RandomAccess {
50    private volatile List<E> list;
51    private final Comparator<? super E> comparator;
52  
53    /**
54     * Constructs an empty list with the default initial capacity that will be
55     * sorted using the given comparator.
56     *
57     * @param comparator the comparator
58     */
59    public SortedList(Comparator<? super E> comparator) {
60      this.list = Collections.emptyList();
61      this.comparator = comparator;
62    }
63  
64    /**
65     * Constructs a list containing the elements of the given collection, in the
66     * order returned by the collection's iterator, that will be sorted with the
67     * given comparator.
68     *
69     * @param c the collection
70     * @param comparator the comparator
71     */
72    public SortedList(Collection<? extends E> c, Comparator<? super E> comparator) {
73      this.list = Collections.unmodifiableList(new ArrayList<E>(c));
74      this.comparator = comparator;
75    }
76  
77    /**
78     * Returns a reference to the unmodifiable list currently backing the SortedList.
79     * Changes to the SortedList will not be reflected in this list. Use this
80     * method to get a reference for iterating over using the RandomAccess
81     * pattern.
82     */
83    public List<E> get() {
84      return list;
85    }
86  
87    @Override
88    public int size() {
89      return list.size();
90    }
91  
92    @Override
93    public boolean isEmpty() {
94      return list.isEmpty();
95    }
96  
97    @Override
98    public boolean contains(Object o) {
99      return list.contains(o);
100   }
101 
102   @Override
103   public Iterator<E> iterator() {
104     return list.iterator();
105   }
106 
107   @Override
108   public Object[] toArray() {
109     return list.toArray();
110   }
111 
112   @Override
113   public <T> T[] toArray(T[] a) {
114     return list.toArray(a);
115   }
116 
117   @Override
118   public synchronized boolean add(E e) {
119     ArrayList<E> newList = new ArrayList<E>(list);
120     boolean changed = newList.add(e);
121     if (changed) {
122       Collections.sort(newList, comparator);
123     }
124     list = Collections.unmodifiableList(newList);
125     return changed;
126   }
127 
128   @Override
129   public synchronized boolean remove(Object o) {
130     ArrayList<E> newList = new ArrayList<E>(list);
131     // Removals in ArrayList won't break sorting
132     boolean changed = newList.remove(o);
133     list = Collections.unmodifiableList(newList);
134     return changed;
135   }
136 
137   @Override
138   public boolean containsAll(Collection<?> c) {
139     return list.containsAll(c);
140   }
141 
142   @Override
143   public synchronized boolean addAll(Collection<? extends E> c) {
144     ArrayList<E> newList = new ArrayList<E>(list);
145     boolean changed = newList.addAll(c);
146     if (changed) {
147       Collections.sort(newList, comparator);
148     }
149     list = Collections.unmodifiableList(newList);
150     return changed;
151   }
152 
153   @Override
154   public synchronized boolean addAll(int index, Collection<? extends E> c) {
155     ArrayList<E> newList = new ArrayList<E>(list);
156     boolean changed = newList.addAll(index, c);
157     if (changed) {
158       Collections.sort(newList, comparator);
159     }
160     list = Collections.unmodifiableList(newList);
161     return changed;
162   }
163 
164   @Override
165   public synchronized boolean removeAll(Collection<?> c) {
166     ArrayList<E> newList = new ArrayList<E>(list);
167     // Removals in ArrayList won't break sorting
168     boolean changed = newList.removeAll(c);
169     list = Collections.unmodifiableList(newList);
170     return changed;
171   }
172 
173   @Override
174   public synchronized boolean retainAll(Collection<?> c) {
175     ArrayList<E> newList = new ArrayList<E>(list);
176     // Removals in ArrayList won't break sorting
177     boolean changed = newList.retainAll(c);
178     list = Collections.unmodifiableList(newList);
179     return changed;
180   }
181 
182   @Override
183   public synchronized void clear() {
184     list = Collections.emptyList();
185   }
186 
187   @Override
188   public E get(int index) {
189     return list.get(index);
190   }
191 
192   @Override
193   public synchronized E set(int index, E element) {
194     ArrayList<E> newList = new ArrayList<E>(list);
195     E result = newList.set(index, element);
196     Collections.sort(list, comparator);
197     list = Collections.unmodifiableList(newList);
198     return result;
199   }
200 
201   @Override
202   public synchronized void add(int index, E element) {
203     ArrayList<E> newList = new ArrayList<E>(list);
204     newList.add(index, element);
205     Collections.sort(list, comparator);
206     list = Collections.unmodifiableList(newList);
207   }
208 
209   @Override
210   public synchronized E remove(int index) {
211     ArrayList<E> newList = new ArrayList<E>(list);
212     // Removals in ArrayList won't break sorting
213     E result = newList.remove(index);
214     list = Collections.unmodifiableList(newList);
215     return result;
216   }
217 
218   @Override
219   public int indexOf(Object o) {
220     return list.indexOf(o);
221   }
222 
223   @Override
224   public int lastIndexOf(Object o) {
225     return list.lastIndexOf(o);
226   }
227 
228   @Override
229   public ListIterator<E> listIterator() {
230     return list.listIterator();
231   }
232 
233   @Override
234   public ListIterator<E> listIterator(int index) {
235     return list.listIterator(index);
236   }
237 
238   @Override
239   public List<E> subList(int fromIndex, int toIndex) {
240     return list.subList(fromIndex, toIndex);
241   }
242 }