org.magicwerk.brownies.collections.KeyListImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of brownies-collections Show documentation
Show all versions of brownies-collections Show documentation
Brownies Collections complements the Java Collections Framework.
GapList combines the strengths of both ArrayList and LinkedList.
BigList is a list optimized for storing large number of elements.
There are specialized List implementations for all primitive data types (IntGapList, IntBigList, IntObjGapList, IntObjBigList).
The key collection classes offer support for keys and constraints for lists and collections
(KeyList, KeyCollection, KeySet, Key1List, Key1Collection, Key1Set, Key2List, Key2Collection, Key2Set).
/*
* Copyright 2012 by Thomas Mauch
*
* 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.
*
* $Id: KeyListImpl.java 3081 2016-01-05 00:29:01Z origo $
*/
package org.magicwerk.brownies.collections;
import java.util.Comparator;
import java.util.Set;
import org.magicwerk.brownies.collections.function.IFunction;
import org.magicwerk.brownies.collections.helper.Option;
/**
* A KeyList add key handling features to GapList.
* It is the abstract base class for both SetList and MapList.
*
* @author Thomas Mauch
* @version $Id: KeyListImpl.java 3081 2016-01-05 00:29:01Z origo $
*
* @see GapList
* @param type of elements stored in the list
*/
@SuppressWarnings("serial")
public abstract class KeyListImpl extends IList {
/**
* Key collection used for key storage (never null).
*/
KeyCollectionImpl keyColl;
/**
* List where the list content of this KeyListImpl is stored (never null).
* If this is list sorted by element (key 0), keyColl.keyMaps[0].keysList will also reference this list.
*/
IList list;
/** If true the invariants are checked for debugging */
private static final boolean DEBUG_CHECK = false;
/**
* Private method to check invariant of GapList.
* It is only used for debugging.
*/
private void debugCheck() {
keyColl.debugCheck();
//list.debugCheck();
assert(keyColl.keyList == this);
assert(list.size() == keyColl.size() || (keyColl.size() == 0 && keyColl.keyMaps == null));
}
/**
* Constructor.
*/
KeyListImpl() {
}
protected KeyListImpl(boolean copy, KeyListImpl that) {
if (copy) {
doAssign(that);
}
}
@Override
protected void doAssign(IList that) {
KeyListImpl list = (KeyListImpl) that;
this.keyColl = list.keyColl;
this.list = list.list;
}
@Override
public Object clone() {
return copy();
}
@Override
public KeyListImpl copy() {
@SuppressWarnings("unchecked")
KeyListImpl copy = (KeyListImpl) super.clone();
copy.initCopy(this);
return copy;
}
/**
* Returns a copy this list but without elements.
* The new list will use the same comparator, ordering, etc.
*
* @return an empty copy of this list
*/
public KeyListImpl crop() {
@SuppressWarnings("unchecked")
KeyListImpl crop = (KeyListImpl) super.clone();
crop.initCrop(this);
return crop;
}
/**
* Initialize object for crop() operation.
*
* @param that source object
*/
@SuppressWarnings("unchecked")
void initCrop(KeyListImpl that) {
// KeyCollectionImpl
keyColl = new KeyCollectionImpl();
keyColl.initCrop(that.keyColl);
if (keyColl.keyList != null) {
keyColl.keyList = this;
}
// List
if (that.keyColl.keyMaps != null && that.keyColl.keyMaps[0] != null && that.list == that.keyColl.keyMaps[0].keysList) {
list = (IList) keyColl.keyMaps[0].keysList;
} else {
list = that.list.doCreate(-1);
}
if (DEBUG_CHECK) debugCheck();
}
/**
* Initialize object for copy() operation.
*
* @param that source object
*/
@SuppressWarnings("unchecked")
void initCopy(KeyListImpl that) {
// KeyCollectionImpl
keyColl = new KeyCollectionImpl();
keyColl.initCopy(that.keyColl);
if (keyColl.keyList != null) {
keyColl.keyList = this;
}
// List
if (that.keyColl.keyMaps != null && that.keyColl.keyMaps[0] != null && that.list == that.keyColl.keyMaps[0].keysList) {
list = (IList) keyColl.keyMaps[0].keysList;
} else {
list = that.list.doCreate(-1);
list.addAll(that.list);
}
if (DEBUG_CHECK) debugCheck();
}
@Override
protected void doClone(IList that) {
}
/**
* Returns a Set view of the element set.
*
* @return set view
* @throws IllegalArgumentException if the element set cannot be viewed as Set
*/
public Set asSet() {
return new CollectionAsSet(this, false);
}
//-- Read
/**
* Determines whether this list is sorted or not.
*
* @return true if this a sorted list, false if not
*/
public boolean isSorted() {
return keyColl.isSorted();
}
@Override
public int capacity() {
return list.capacity();
}
@Override
public int size() {
return list.size();
}
@Override
public E get(int index) {
return list.get(index);
}
@Override
protected E doGet(int index) {
return list.doGet(index);
}
@Override
protected void doGetAll(T[] array, int index, int len) {
list.doGetAll(array, index, len);
}
@Override
public boolean contains(Object elem) {
if (keyColl.hasElemSet()) {
return keyColl.contains(elem);
} else {
return super.contains(elem);
}
}
//--
/**
* {@inheritDoc}
*
* Note that the behavior of the operation depends on the defined constraints.
*
*/
// This method is only overwritten to change the Javadoc comment.
@Override
public boolean add(E elem) {
return super.add(elem);
}
/**
* Adds element if allowed and returns true.
* If the element cannot be added (constraint violation like duplicated key),
* false is returned.
*
* @param elem element to add
* @return true if element has been added, false otherwise
*/
public boolean addIf(E elem) {
try {
return super.add(elem);
}
catch (Exception e) {
return false;
}
}
/**
* {@inheritDoc}
*
* Note that the behavior of the operation depends on the defined constraints.
*
*/
// This method is only overwritten to change the Javadoc comment.
@Override
public void add(int index, E elem) {
super.add(index, elem);
}
/**
* {@inheritDoc}
*
* Note that the behavior of the operation depends on the defined constraints.
*
*/
// This method is only overwritten to change the Javadoc comment.
@Override
public E set(int index, E elem) {
return super.set(index, elem);
}
@Override
public void clear() {
keyColl.clear();
list.clear();
}
@Override
public void ensureCapacity(int minCapacity) {
// Make sure that we never allocate more slots than needed.
// The add methods make sure that we never use to many slots.
if (keyColl.maxSize != 0) {
minCapacity = Math.min(minCapacity, keyColl.maxSize);
}
super.ensureCapacity(minCapacity);
}
@Override
protected boolean doAdd(int index, E elem) {
// This method is also called by doAdd(E)
keyColl.checkElemAllowed(elem);
// Handle maximum size and window
if (keyColl.maxSize != 0 && size() >= keyColl.maxSize) {
if (keyColl.movingWindow) {
if (index == 0) {
// the element inserted at position 0 will be removed again due to the limited size
return false;
}
if (index == -1) {
index = size();
}
doRemove(0);
index = index-1;
} else {
KeyCollectionImpl.errorMaxSize();
}
}
// Add element
if (keyColl.isSorted()) {
// Sorted list
if (index == -1) {
index = keyColl.binarySearchSorted(elem);
if (index < 0) {
index = -index-1;
}
}
keyColl.addSorted(index, elem);
// If list is sorted by element, keyColl points to list so no explicit call to its add method is needed
if (!keyColl.isSortedByElem()) {
list.doAdd(index, elem);
}
} else {
// Unsorted list
keyColl.addUnsorted(elem);
if (index == -1) {
// Element is already added to keyColl
index = list.size();
}
list.doAdd(index, elem);
}
if (DEBUG_CHECK) debugCheck();
return true;
}
@Override
protected E doSet(int index, E elem) {
keyColl.checkElemAllowed(elem);
E remove = doGet(index);
if (keyColl.isSorted()) {
keyColl.setSorted(index, elem, remove);
} else {
keyColl.remove(remove);
try {
keyColl.add(elem);
}
catch (RuntimeException e) {
keyColl.add(remove);
throw e;
}
}
list.doSet(index, elem);
if (DEBUG_CHECK) debugCheck();
return remove;
}
@Override
protected E doRemove(int index) {
E removed = list.get(index);
keyColl.remove(removed);
if (!keyColl.isSortedByElem()) {
list.remove(index);
}
if (DEBUG_CHECK) debugCheck();
return removed;
}
@Override
protected void doRemoveAll(int index, int len) {
if (keyColl.isSortedByElem()) {
for (int i=0; i getKeyMapper(int keyIndex) {
return keyColl.getKeyMapper(keyIndex);
}
/**
* Returns value for given key.
* If there are several values for this key, the first is returned.
* If the key is not found, null is returned.
*
* @param keyIndex key index
* @param key key to find
* @return value of specified key or null
*/
public E getByKey(int keyIndex, Object key) {
return (E) keyColl.getByKey(keyIndex, key);
}
/**
* Returns a list with all elements with the specified key.
*
* @param keyIndex key index
* @param key key which elements must have
* @return list with all elements
*/
public GapList getAllByKey(int keyIndex, Object key) {
return keyColl.getAllByKey(keyIndex, key);
}
/**
* Returns number of elements with specified key.
*
* @param keyIndex key index
* @param key key which elements must have
* @return number of elements with key
*/
public int getCountByKey(int keyIndex, Object key) {
return keyColl.getCountByKey(keyIndex, key);
}
/**
* Removes element by key.
* If there are duplicates, only one element is removed.
*
* @param keyIndex key index
* @param key key of element to remove
* @return removed element or null if no element has been removed
*/
protected E removeByKey(int keyIndex, Object key) {
Option removed = keyColl.doRemoveByKey(keyIndex, key);
if (removed.hasValue()) {
int index = list.indexOf(removed.getValue());
if (index == -1) {
KeyCollectionImpl.errorInvalidData();
}
list.doRemove(index);
}
if (DEBUG_CHECK) debugCheck();
return removed.getValueOrNull();
}
protected E putByKey(int keyIndex, E elem) {
int index;
if (keyIndex == 0 && (keyColl.keyMaps == null || keyColl.keyMaps[0] == null)) {
index = indexOf(elem);
} else {
Object key = keyColl.getKey(keyIndex, elem);
index = indexOfKey(keyIndex, key);
}
E replaced = null;
if (index == -1) {
doAdd(-1, elem);
} else {
replaced = doSet(index, elem);
}
if (DEBUG_CHECK) debugCheck();
return replaced;
}
/**
* Removes element by key.
* If there are duplicates, all elements are removed.
*
* @param keyIndex key index
* @param key key of element to remove
* @return true if elements have been removed, false otherwise
*/
protected GapList removeAllByKey(int keyIndex, Object key) {
GapList removeds = keyColl.removeAllByKey(keyIndex, key);
if (!removeds.isEmpty()) {
if (!keyColl.isSortedByElem()) {
if (!list.removeAll(removeds)) {
KeyCollectionImpl.errorInvalidData();
}
}
}
if (DEBUG_CHECK) debugCheck();
return removeds;
}
/**
* Returns list containing all keys in element order.
*
* @param keyIndex key index
* @return list containing all keys
*/
protected GapList