001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.internal;
014
015import java.lang.reflect.*;
016import java.util.*;
017
018/**
019 * Simple read-only wrapper around an object array.
020 *
021 * <p>
022 * Allows for forward or reverse access to elements of an array without being able to modify the array and without
023 * involving copying the array.
024 *
025 * @param <T> Array element type.
026 */
027public class UnmodifiableArray<T> implements List<T> {
028
029   final T[] array;
030   final int length;
031   private final boolean reversed;
032
033   /**
034    * Constructor.
035    *
036    * @param array The array being wrapped.
037    */
038   public UnmodifiableArray(T[] array) {
039      this(array, false);
040   }
041
042   /**
043    * Constructor.
044    *
045    * @param array The array being wrapped.
046    * @param reversed <jk>true</jk> if elements of array should be addressed in reverse.
047    */
048   @SuppressWarnings("unchecked")
049   public UnmodifiableArray(T[] array, boolean reversed) {
050      this.array = array == null ? (T[])new Object[0] : array;
051      this.length = this.array.length;
052      this.reversed = reversed;
053   }
054
055   @Override
056   public int size() {
057      return array.length;
058   }
059
060   @Override
061   public boolean isEmpty() {
062      return array.length == 0;
063   }
064
065   @Override
066   public boolean contains(Object o) {
067      return indexOf(o) != -1;
068   }
069
070   @Override
071   public Iterator<T> iterator() {
072      if (reversed) {
073         return new Iterator<T>() {
074            int i = length-1;
075
076            @Override
077            public boolean hasNext() {
078               return i > -1;
079            }
080
081            @Override
082            public T next() {
083               return array[i--];
084            }
085         };
086      }
087      return new Iterator<T>() {
088         int i = 0;
089
090         @Override
091         public boolean hasNext() {
092            return i < length;
093         }
094
095         @Override
096         public T next() {
097            return array[i++];
098         }
099      };
100   }
101
102   @Override
103   public Object[] toArray() {
104      Object[] o2 = (Object[])Array.newInstance(array.getClass().getComponentType(), array.length);
105      for (int i = 0; i < array.length; i++)
106         o2[i] = reversed ? array[length-i-1] : array[i];
107      return o2;
108   }
109
110   @Override
111   @SuppressWarnings({ "unchecked", "hiding" })
112   public <T> T[] toArray(T[] a) {
113      if (a.length < length)
114         return (T[])toArray();
115      for (int i = 0; i < array.length; i++)
116         a[i] = reversed ? (T)array[length-i-1] : (T)array[i];
117      return a;
118   }
119
120   @Override
121   public boolean add(T e) {
122      throw new UnsupportedOperationException("Cannot modify read-only list.");
123   }
124
125   @Override
126   public boolean remove(Object o) {
127      throw new UnsupportedOperationException("Cannot modify read-only list.");
128   }
129
130   @Override
131   public boolean containsAll(Collection<?> c) {
132      for (Object o : c)
133         if (! contains(o))
134            return false;
135      return true;
136   }
137
138   @Override
139   public boolean addAll(Collection<? extends T> c) {
140      throw new UnsupportedOperationException("Cannot modify read-only list.");
141   }
142
143   @Override
144   public boolean addAll(int index, Collection<? extends T> c) {
145      throw new UnsupportedOperationException("Cannot modify read-only list.");
146   }
147
148   @Override
149   public boolean removeAll(Collection<?> c) {
150      throw new UnsupportedOperationException("Cannot modify read-only list.");
151   }
152
153   @Override
154   public boolean retainAll(Collection<?> c) {
155      throw new UnsupportedOperationException("Cannot modify read-only list.");
156   }
157
158   @Override
159   public void clear() {
160      throw new UnsupportedOperationException("Cannot modify read-only list.");
161   }
162
163   @Override
164   public T get(int index) {
165      return reversed ? array[length-index-1] : array[index];
166   }
167
168   @Override
169   public T set(int index, T element) {
170      throw new UnsupportedOperationException("Cannot modify read-only list.");
171   }
172
173   @Override
174   public void add(int index, T element) {
175      throw new UnsupportedOperationException("Cannot modify read-only list.");
176   }
177
178   @Override
179   public T remove(int index) {
180      throw new UnsupportedOperationException("Cannot modify read-only list.");
181   }
182
183   @Override
184   public int indexOf(Object o) {
185      for (int i = 0; i < length; i++) {
186         int j = reversed ? length-i-1 : i;
187         T t = array[j];
188         if ((o == t) || (o != null && o.equals(t)))
189            return j;
190      }
191      return -1;
192   }
193
194   @Override
195   public int lastIndexOf(Object o) {
196      for (int i = length-1; i >= 0; i--) {
197         int j = reversed ? length-i-1 : i;
198         T t = array[j];
199         if ((o == t) || (o != null && o.equals(t)))
200            return j;
201      }
202      return -1;
203   }
204
205   @Override
206   public ListIterator<T> listIterator() {
207      throw new UnsupportedOperationException("Unsupported method on ReadOnlyArrayList class.");
208   }
209
210   @Override
211   public ListIterator<T> listIterator(int index) {
212      throw new UnsupportedOperationException("Unsupported method on ReadOnlyArrayList class.");
213   }
214
215   @Override
216   public List<T> subList(int fromIndex, int toIndex) {
217      if (reversed) {
218         List<T> l = Arrays.asList(array);
219         Collections.reverse(l);
220         return l.subList(fromIndex, toIndex);
221      }
222      return Arrays.asList(array).subList(fromIndex, toIndex);
223   }
224}