/* * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.util.containers; import org.jetbrains.annotations.NotNull; import java.util.*; /** * A base class for immutable list implementations. * <p/> * Copied from {@link java.util.AbstractList} with modCount field removed, because the implementations are supposed to be immutable, so * it makes no sense to waste memory on modCount. */ public abstract class ImmutableList<E> extends AbstractCollection<E> implements List<E> { @NotNull @Override public Iterator<E> iterator() { return new Itr(); } @Override public boolean addAll(int index, @NotNull Collection<? extends E> c) { throw new UnsupportedOperationException(); } @Override public E set(int index, E element) { throw new UnsupportedOperationException(); } @Override public void add(int index, E element) { throw new UnsupportedOperationException(); } @Override public E remove(int index) { throw new UnsupportedOperationException(); } public int indexOf(Object o) { ListIterator<E> it = listIterator(); if (o == null) { while (it.hasNext()) { if (it.next() == null) { return it.previousIndex(); } } } else { while (it.hasNext()) { if (o.equals(it.next())) { return it.previousIndex(); } } } return -1; } @Override public int lastIndexOf(Object o) { ListIterator<E> it = listIterator(size()); if (o == null) { while (it.hasPrevious()) { if (it.previous() == null) { return it.nextIndex(); } } } else { while (it.hasPrevious()) { if (o.equals(it.previous())) { return it.nextIndex(); } } } return -1; } @NotNull @Override public ListIterator<E> listIterator() { return listIterator(0); } @NotNull @Override public ListIterator<E> listIterator(int index) { return new ListItr(index); } @NotNull @Override public List<E> subList(int fromIndex, int toIndex) { return new SubList<E>(this, fromIndex, toIndex); } @Override public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof List)) { return false; } ListIterator<E> e1 = listIterator(); ListIterator e2 = ((List)o).listIterator(); while (e1.hasNext() && e2.hasNext()) { E o1 = e1.next(); Object o2 = e2.next(); if (!(o1 == null ? o2 == null : o1.equals(o2))) { return false; } } return !(e1.hasNext() || e2.hasNext()); } @Override public int hashCode() { int hashCode = 1; for (E e : this) { hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode()); } return hashCode; } private class Itr implements Iterator<E> { /** * Index of element to be returned by subsequent call to next. */ int cursor = 0; /** * Index of element returned by most recent call to next or * previous. Reset to -1 if this element is deleted by a call * to remove. */ int lastRet = -1; public boolean hasNext() { return cursor != size(); } public E next() { try { int i = cursor; E next = get(i); lastRet = i; cursor = i + 1; return next; } catch (IndexOutOfBoundsException e) { throw new NoSuchElementException(); } } public void remove() { throw new UnsupportedOperationException(); } } private class ListItr extends Itr implements ListIterator<E> { ListItr(int index) { cursor = index; } public boolean hasPrevious() { return cursor != 0; } public E previous() { try { int i = cursor - 1; E previous = get(i); lastRet = cursor = i; return previous; } catch (IndexOutOfBoundsException e) { throw new NoSuchElementException(); } } public int nextIndex() { return cursor; } public int previousIndex() { return cursor - 1; } public void set(E e) { throw new UnsupportedOperationException(); } public void add(E e) { throw new UnsupportedOperationException(); } } private static class SubList<E> extends ImmutableList<E> { private final List<E> l; private final int offset; private int size; SubList(List<E> list, int fromIndex, int toIndex) { if (fromIndex < 0) { throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); } if (toIndex > list.size()) { throw new IndexOutOfBoundsException("toIndex = " + toIndex); } if (fromIndex > toIndex) { throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); } l = list; offset = fromIndex; size = toIndex - fromIndex; } public E get(int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); } return l.get(index + offset); } public int size() { return size; } } }