001/* 002 * @author Francesco.Kriegel@gmx.de 003 */ 004package conexp.fx.core.collections.setlist; 005 006/* 007 * #%L 008 * Concept Explorer FX 009 * %% 010 * Copyright (C) 2010 - 2019 Francesco Kriegel 011 * %% 012 * This program is free software: you can redistribute it and/or modify 013 * it under the terms of the GNU General Public License as 014 * published by the Free Software Foundation, either version 3 of the 015 * License, or (at your option) any later version. 016 * 017 * This program is distributed in the hope that it will be useful, 018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 020 * GNU General Public License for more details. 021 * 022 * You should have received a copy of the GNU General Public 023 * License along with this program. If not, see 024 * <http://www.gnu.org/licenses/gpl-3.0.html>. 025 * #L% 026 */ 027 028import java.util.ArrayList; 029import java.util.Arrays; 030import java.util.Collection; 031import java.util.Comparator; 032import java.util.HashSet; 033import java.util.ListIterator; 034import java.util.Spliterator; 035 036public class HashSetArrayList<E> extends AbstractSetList<E> { 037 038 private final HashSet<E> s = new HashSet<E>(); 039 private final ArrayList<E> l = new ArrayList<E>(); 040 041 public HashSetArrayList() { 042 super(); 043 } 044 045 public HashSetArrayList(final Collection<? extends E> c) { 046 super(); 047 addAll(c); 048 } 049 050 private final void checkIndex(final int i) throws IndexOutOfBoundsException { 051 if (i < 0 || i > size()) 052 throw new IndexOutOfBoundsException(); 053 } 054 055 public boolean add(final E e) { 056 return s.add(e) && l.add(e); 057 } 058 059 public void add(final int i, final E e) { 060 // checkIndex(i); 061 // if (s.add(e)) 062 // l.add(i, e); 063 // else 064 if (!_add(i, e)) 065 throw new IllegalArgumentException(); 066 } 067 068 public boolean _add(final int i, final E e) { 069 checkIndex(i); 070 if (s.add(e)) { 071 l.add(i, e); 072 return true; 073 } 074 return false; 075 } 076 077 public boolean addAll(final Collection<? extends E> c) { 078 // return c.stream().map(this::add).reduce(false, Boolean::logicalOr); 079 boolean changed = false; 080 for (E e : c) 081 changed |= s.add(e) && l.add(e); 082 return changed; 083 } 084 085 public boolean addAll(final int i, final Collection<? extends E> c) { 086 if (i < 0 || i > size()) 087 throw new IndexOutOfBoundsException(); 088 // final AtomicInteger j = new AtomicInteger(i); 089 // return c.stream().map(e -> this._add(j.getAndIncrement(), 090 // e)).reduce(false, Boolean::logicalOr); 091 boolean changed = false; 092 int j = i; 093 for (E e : c) 094 if (s.add(e)) { 095 l.add(j++, e); 096 changed = true; 097 } 098 return changed; 099 } 100 101 public E set(final int i, final E e) { 102 if (i < 0 || i > size()) 103 throw new IndexOutOfBoundsException(); 104 if (s.add(e)) { 105 final E x = l.set(i, e); 106 s.remove(x); 107 return x; 108 } 109 return e; 110 } 111 112 public boolean remove(final Object o) { 113 return l.remove(o) && s.remove(o); 114 } 115 116 public E remove(final int i) { 117 final E e = l.remove(i); 118 s.remove(e); 119 return e; 120 } 121 122 public boolean removeAll(final Collection<?> c) { 123 return l.removeAll(c) && s.removeAll(c); 124 } 125 126 public boolean retainAll(final Collection<?> c) { 127 return l.retainAll(c) && s.retainAll(c); 128 } 129 130 public boolean contains(final Object o) { 131 return s.contains(o); 132 } 133 134 public boolean containsAll(final Collection<?> c) { 135 return s.containsAll(c); 136 } 137 138 public E get(final int i) { 139 return l.get(i); 140 } 141 142 public int indexOf(final Object o) { 143 return l.indexOf(o); 144 } 145 146 public ListIterator<E> listIterator(final int i) { 147 return new ListIterator<E>() { 148 149 private final ListIterator<E> it = l.listIterator(i); 150 private E pointer = null; 151 private boolean illegal = true; 152 153 public final boolean hasNext() { 154 return it.hasNext(); 155 } 156 157 public final E next() { 158 pointer = it.next(); 159 illegal = false; 160 return pointer; 161 } 162 163 public final boolean hasPrevious() { 164 return it.hasPrevious(); 165 } 166 167 public final E previous() { 168 pointer = it.previous(); 169 illegal = false; 170 return pointer; 171 } 172 173 public final int nextIndex() { 174 return it.nextIndex(); 175 } 176 177 public final int previousIndex() { 178 return it.previousIndex(); 179 } 180 181 public final void remove() { 182 if (illegal) 183 throw new IllegalStateException(); 184 s.remove(pointer); 185 it.remove(); 186 illegal = true; 187 pointer = null; 188 } 189 190 public final void set(final E e) { 191 if (illegal) 192 throw new IllegalStateException(); 193 if (pointer.equals(e)) 194 return; 195 if (!s.add(e)) 196 throw new IllegalArgumentException(); 197 s.remove(pointer); 198 it.set(e); 199 pointer = e; 200 } 201 202 public final void add(final E e) { 203 if (!s.add(e)) 204 throw new IllegalArgumentException(); 205 it.add(e); 206 illegal = true; 207 pointer = null; 208 } 209 }; 210 } 211 212 @Override 213 @SuppressWarnings({ "unchecked", "rawtypes" }) 214 public void sort(Comparator<? super E> c) { 215 Object[] a = this.toArray(); 216 s.clear(); 217 Arrays.sort(a, (Comparator) c); 218 ListIterator<E> i = this.listIterator(); 219 for (Object e : a) { 220 i.next(); 221 i.set((E) e); 222 } 223 } 224 225 @Override 226 public Spliterator<E> spliterator() { 227 return l.spliterator(); 228 } 229 230 public boolean isEmpty() { 231 return s.isEmpty(); 232 } 233 234 public int size() { 235 return l.size(); 236 } 237 238 public void clear() { 239 s.clear(); 240 l.clear(); 241 } 242 243 @Override 244 public int hashCode() { 245 return s.hashCode() + l.hashCode(); 246 } 247 248 public Object[] toArray() { 249 return l.toArray(); 250 } 251 252 public <T> T[] toArray(final T[] a) { 253 return l.toArray(a); 254 } 255}