001package io.ebean.common;
002
003import java.io.Serializable;
004import java.util.AbstractList;
005import java.util.ArrayList;
006import java.util.Collection;
007import java.util.Comparator;
008import java.util.List;
009import java.util.function.Predicate;
010import java.util.function.UnaryOperator;
011
012/**
013 * List that copies itself on first write access. Needed to keep memory footprint low and the ability
014 * to modify lists from cache.
015 * 
016 * @author Roland Praml, FOCONIS AG
017 */
018public final class CopyOnFirstWriteList<E> extends AbstractList<E> implements List<E>, Serializable {
019
020  private static final long serialVersionUID = 1L;
021
022  /**
023   * The underlying List implementation.
024   */
025  private List<E> list;
026  
027  
028  public CopyOnFirstWriteList(List<E> list) {
029    super();
030    this.list = list;
031  }
032
033  private volatile boolean copied = false;
034
035  @Override
036  public int size() {
037    return list.size();
038  }
039
040  @Override
041  public boolean isEmpty() {
042    return list.isEmpty();
043  }
044
045  @Override
046  public boolean contains(Object o) {
047    return list.contains(o);
048  }
049
050  @Override
051  public Object[] toArray() {
052    return list.toArray();
053  }
054
055  @Override
056  public <T> T[] toArray(T[] a) {
057    return list.toArray(a);
058  }
059
060  @Override
061  public boolean add(E e) {
062    checkCopyOnWrite();
063    return list.add(e);
064  }
065
066  @Override
067  public boolean remove(Object o) {
068    checkCopyOnWrite();
069    return list.remove(o);
070  }
071
072  @Override
073  public boolean containsAll(Collection<?> c) {
074    return list.containsAll(c);
075  }
076
077  @Override
078  public boolean addAll(Collection<? extends E> c) {
079    checkCopyOnWrite();
080    return list.addAll(c);
081  }
082
083  @Override
084  public boolean addAll(int index, Collection<? extends E> c) {
085    checkCopyOnWrite();
086    return list.addAll(index, c);
087  }
088
089  @Override
090  public boolean removeAll(Collection<?> c) {
091    checkCopyOnWrite();
092    return list.removeAll(c);
093  }
094
095  @Override
096  public boolean retainAll(Collection<?> c) {
097    checkCopyOnWrite();
098    return list.retainAll(c);
099  }
100
101  @Override
102  public void replaceAll(UnaryOperator<E> operator) {
103    checkCopyOnWrite();
104    list.replaceAll(operator);
105  }
106
107  @Override
108  public boolean removeIf(Predicate<? super E> filter) {
109    checkCopyOnWrite();
110    return list.removeIf(filter);
111  }
112
113  @Override
114  public void sort(Comparator<? super E> c) {
115    checkCopyOnWrite();
116    list.sort(c);
117  }
118
119  @Override
120  public void clear() {
121    if (!copied) {
122      list = new ArrayList<>();
123      copied = true;
124    }
125  }
126
127  @Override
128  public boolean equals(Object o) {
129    return list.equals(o);
130  }
131
132  @Override
133  public int hashCode() {
134    return list.hashCode();
135  }
136
137  @Override
138  public E get(int index) {
139    return list.get(index);
140  }
141
142  @Override
143  public E set(int index, E element) {
144    checkCopyOnWrite();
145    return list.set(index, element);
146  }
147
148  @Override
149  public void add(int index, E element) {
150    checkCopyOnWrite();
151    list.add(index, element);
152  }
153
154  @Override
155  public E remove(int index) {
156    checkCopyOnWrite();
157    return list.remove(index);
158  }
159
160  @Override
161  public int indexOf(Object o) {
162    return list.indexOf(o);
163  }
164
165  @Override
166  public int lastIndexOf(Object o) {
167    return list.lastIndexOf(o);
168  }
169  
170  private void checkCopyOnWrite() {
171    if (!copied) {
172      synchronized (this) {
173        if (!copied) {
174          list = new ArrayList<>(list);
175          copied = true;
176        }
177      }
178    }
179  }
180}