/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * 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 org.optaplanner.core.impl.domain.variable.listener.support; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; /** * An ordered {@link Set} which is implemented as a {@link ArrayList} for a small {@link Set#size()} * and a {@link LinkedHashSet} for a big {@link Set#size()}. * <p> * This speeds up {@link #add(Object)} performance (in some cases by 20%) if most instances have a small size * because no {@link Object#hashCode()} need to be calculated. * @param <E> */ public final class SmallScalingOrderedSet<E> implements Set<E> { protected static final int LIST_SIZE_THRESHOLD = 16; private boolean belowThreshold; private List<E> list; private Set<E> set; public SmallScalingOrderedSet() { belowThreshold = true; list = new ArrayList<>(LIST_SIZE_THRESHOLD); set = null; } @Override public int size() { return belowThreshold ? list.size() : set.size(); } @Override public boolean isEmpty() { return belowThreshold ? list.isEmpty() : set.isEmpty(); } @Override public boolean contains(Object o) { return belowThreshold ? list.contains(o) : set.contains(o); } @Override public boolean containsAll(Collection<?> c) { return belowThreshold ? list.containsAll(c) : set.containsAll(c); } @Override public Iterator<E> iterator() { final Iterator<E> childIterator = belowThreshold ? list.iterator() : set.iterator(); return new Iterator<E>() { @Override public boolean hasNext() { return childIterator.hasNext(); } @Override public E next() { return childIterator.next(); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } @Override public Object[] toArray() { return belowThreshold ? list.toArray() : set.toArray(); } @Override public <T> T[] toArray(T[] a) { return belowThreshold ? list.toArray(a) : set.toArray(a); } @Override public boolean add(E e) { if (belowThreshold) { int newSize = list.size() + 1; if (newSize > LIST_SIZE_THRESHOLD) { set = new LinkedHashSet<>(list); list = null; belowThreshold = false; return set.add(e); } else { if (list.contains(e)) { return false; } return list.add(e); } } else { return set.add(e); } } @Override public boolean addAll(Collection<? extends E> c) { if (belowThreshold) { int newSize = list.size() + c.size(); if (newSize > LIST_SIZE_THRESHOLD) { set = new LinkedHashSet<>(newSize); set.addAll(list); list = null; belowThreshold = false; return set.addAll(c); } else { boolean changed = false; for (E e : c) { if (!list.contains(e)) { changed = true; list.add(e); } } return changed; } } else { return set.addAll(c); } } @Override public boolean remove(Object o) { if (belowThreshold) { return list.remove(o); } else { int newSize = set.size() - 1; if (newSize <= LIST_SIZE_THRESHOLD) { set.remove(o); list = new ArrayList<>(set); set = null; belowThreshold = true; return true; } else { return set.remove(o); } } } @Override public boolean retainAll(Collection<?> c) { throw new UnsupportedOperationException("retainAll() not yet implemented"); } @Override public boolean removeAll(Collection<?> c) { throw new UnsupportedOperationException("removeAll() not yet implemented"); } @Override public void clear() { if (belowThreshold) { list.clear(); } else { list = new ArrayList<>(LIST_SIZE_THRESHOLD); set = null; belowThreshold = true; } } }