All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tangosol.util.SortedBag Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2020, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */
package com.tangosol.util;


import com.tangosol.util.comparator.SafeComparator;

import java.util.AbstractCollection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NoSuchElementException;
import java.util.TreeMap;

import java.util.concurrent.atomic.AtomicLong;


/**
 * SortedBag is a 
 * multiset or bag implementation that supports sorted traversal
 * of the contained elements and is optimized for insertions and removals.
 * 

* This implementation is not thread-safe and does not support null elements. * * @author rhl 2013.04.24 */ public class SortedBag extends AbstractCollection { // ----- constructors --------------------------------------------------- /** * Default constructor. */ protected SortedBag() { this(SafeComparator.INSTANCE); } /** * Construct a SortedBag whose elements are to be ordered by the specified * comparator. * * @param comparator the comparator to use to order the elements */ public SortedBag(Comparator comparator) { m_atomicNonce = new AtomicLong(0L); m_comparator = comparator == null ? SafeComparator.INSTANCE : comparator; m_map = instantiateInternalMap(m_comparator); } // ----- accessors ------------------------------------------------------ /** * Return the internal sorted-map holding the bag contents. * * @return the internal sorted map holding the bag contents */ protected NavigableMap getInternalMap() { return m_map; } /** * Return the Comparator used to order the bag contents. * * @return the Comparator used to order the bag contents */ protected Comparator getComparator() { return m_comparator; } /** * Return the nonce counter used to assign unique element ids. * * @return the nonce counter */ protected AtomicLong getNonceCounter() { return m_atomicNonce; } // ----- Collection interface ------------------------------------------- /** * {@inheritDoc} */ public int size() { return getInternalMap().size(); } /** * {@inheritDoc} */ public boolean isEmpty() { return getInternalMap().isEmpty(); } /** * {@inheritDoc} */ public boolean contains(Object o) { Object oCeiling = getInternalMap().ceilingKey(o); return oCeiling != null && Base.equals(o, unwrap(oCeiling)); } /** * {@inheritDoc} */ public Iterator iterator() { final Iterator iter = getInternalMap().keySet().iterator(); return new Iterator() { public boolean hasNext() { return iter.hasNext(); } public E next() { return unwrap(iter.next()); } public void remove() { iter.remove(); } }; } /** * {@inheritDoc} */ public boolean add(E o) { // loop around a "conditional" put here to allow for a "safe" extension NavigableMap map = getInternalMap(); do { if (Base.equals(o, unwrap(map.ceilingKey(o)))) { // does not need to be "conditional", as all wrapped values are unique map.put(wrap(o), NO_VALUE); return true; } else if (map.put(o, NO_VALUE) == null) { return true; } } while (true); } /** * {@inheritDoc} */ public boolean remove(Object o) { // loop around a "conditional" remove here to allow for a "safe" extension NavigableMap map = getInternalMap(); do { Object oCeiling = map.ceilingKey(o); if (Base.equals(o, unwrap(oCeiling))) { if (map.remove(oCeiling) != null) { return true; } } else { return false; } } while (true); } // ----- SortedBag methods ---------------------------------------------- /** * Returns a view of the portion of this bag whose elements range * from fromElement, inclusive, to toElement, * exclusive. (If fromElement and toElement are * equal, the returned bag is empty.) The returned bag is backed * by this bag, so changes in the returned bag are reflected in * this bag, and vice-versa. The returned bag supports all * optional bag operations that this bag supports. * *

The returned bag will throw an IllegalArgumentException * on an attempt to insert an element outside its range. * * @param fromElement low endpoint (inclusive) of the returned bag * @param toElement high endpoint (exclusive) of the returned bag * * @return a view of the portion of this bag whose elements range from * fromElement, inclusive, to toElement, exclusive * * @throws ClassCastException if fromElement and * toElement cannot be compared to one another using this * bag's comparator (or, if the bag has no comparator, using * natural ordering). Implementations may, but are not required * to, throw this exception if fromElement or * toElement cannot be compared to elements currently in * the bag. * @throws NullPointerException if fromElement or * toElement is null and this bag does not permit null * elements * @throws IllegalArgumentException if fromElement is * greater than toElement; or if this bag itself * has a restricted range, and fromElement or * toElement lies outside the bounds of the range */ public SortedBag subBag(E fromElement, E toElement) { return new ViewBag(fromElement, toElement); } /** * Returns a view of the portion of this bag whose elements are * strictly less than toElement. The returned bag is * backed by this bag, so changes in the returned bag are * reflected in this bag, and vice-versa. The returned bag * supports all optional bag operations that this bag supports. * *

The returned bag will throw an IllegalArgumentException * on an attempt to insert an element outside its range. * * @param toElement high endpoint (exclusive) of the returned bag * * @return a view of the portion of this bag whose elements are strictly * less than toElement * * @throws ClassCastException if toElement is not compatible * with this bag's comparator (or, if the bag has no comparator, * if toElement does not implement {@link Comparable}). * Implementations may, but are not required to, throw this * exception if toElement cannot be compared to elements * currently in the bag. * @throws NullPointerException if toElement is null and * this bag does not permit null elements * @throws IllegalArgumentException if this bag itself has a * restricted range, and toElement lies outside the * bounds of the range */ public SortedBag headBag(E toElement) { return new ViewBag(null, toElement); } /** * Returns a view of the portion of this bag whose elements are * greater than or equal to fromElement. The returned * bag is backed by this bag, so changes in the returned bag are * reflected in this bag, and vice-versa. The returned bag * supports all optional bag operations that this bag supports. * *

The returned bag will throw an IllegalArgumentException * on an attempt to insert an element outside its range. * * @param fromElement low endpoint (inclusive) of the returned bag * * @return a view of the portion of this bag whose elements are greater * than or equal to fromElement * * @throws ClassCastException if fromElement is not compatible * with this bag's comparator (or, if the bag has no comparator, * if fromElement does not implement {@link Comparable}). * Implementations may, but are not required to, throw this * exception if fromElement cannot be compared to elements * currently in the bag. * @throws NullPointerException if fromElement is null * and this bag does not permit null elements * @throws IllegalArgumentException if this bag itself has a * restricted range, and fromElement lies outside the * bounds of the range */ public SortedBag tailBag(E fromElement) { return new ViewBag(fromElement, null); } /** * Returns the first (lowest) element currently in this bag. * * @return the first (lowest) element currently in this bag * * @throws NoSuchElementException if this bag is empty */ public E first() { return unwrap(getInternalMap().firstKey()); } /** * Returns the last (highest) element currently in this bag. * * @return the last (highest) element currently in this bag * * @throws NoSuchElementException if this bag is empty */ public E last() { return unwrap(getInternalMap().lastKey()); } /** * Remove and return the least element in this bag, or null if empty. * * @return the removed first element of this bag, or null if empty */ public E removeFirst() { Map.Entry entryRemoved = getInternalMap().pollFirstEntry(); return entryRemoved == null ? null : unwrap(entryRemoved.getKey()); } /** * Remove and return the greatest element in this bag, or null if empty. * * @return the removed last element of this bag, or null if empty */ public E removeLast() { Map.Entry entryRemoved = getInternalMap().pollLastEntry(); return entryRemoved == null ? null : unwrap(entryRemoved.getKey()); } // ----- internal helpers ----------------------------------------------- /** * Factory for the sorted internal map to use to hold the bag elements. * * @param comparator the comparator to use to sort the bag elements * * @return a sorted map */ protected NavigableMap instantiateInternalMap(Comparator comparator) { return new TreeMap(new WrapperComparator(comparator)); } /** * Wrap the specified element to ensure uniqueness. * * @param o the element to wrap * * @return a unique element representing the specified element */ protected UniqueElement wrap(E o) { return new UniqueElement<>(o); } /** * Unwrap the specified element (which could be a {@link UniqueElement * wrapped} or an "actual") element. * * @param o the element to unwrap * * @return the unwrapped element */ protected E unwrap(Object o) { return (E) (o instanceof UniqueElement ? ((UniqueElement) o).f_elem : o); } // ----- inner class: WrapperComparator --------------------------------- /** * WrapperComparator is a Comparator implementation that is aware of * {@link UniqueElement} wrappers and will delegate the comparison of the * elements in both forms to the wrapped comparator. */ protected class WrapperComparator implements Comparator { // ----- constructors ----------------------------------------------- /** * Construct a WrapperComparator around the specified comparator. * * @param comparator the underlying comparator */ public WrapperComparator(Comparator comparator) { f_comparator = comparator; } // ----- Comparator methods ----------------------------------------- /** * {@inheritDoc} */ public int compare(Object o1, Object o2) { if (o1 instanceof UniqueElement) { return ((UniqueElement) o1).compareTo(o2); } else if (o2 instanceof UniqueElement) { return -((UniqueElement) o2).compareTo(o1); } else // o1 and o2 are both "real" elements { return f_comparator.compare(o1, o2); } } // ----- data members ----------------------------------------------- /** * The underlying "logical" comparator. */ protected final Comparator f_comparator; } // ----- inner class: ViewBag ------------------------------------------- /** * A range-limited view of the SortedBag. This view is backed by the * SortedBag, so any modifications made to it are visible to the underlying * bag, and vice-versa. */ protected class ViewBag extends SortedBag { // ----- constructors ----------------------------------------------- /** * Construct a view of the SortedBag, constrained to the range [from, to). * * @param from the "from" element (inclusive), or null * @param to the "to" element (exclusive), or null */ public ViewBag(E from, E to) { super(); NavigableMap mapInternal = SortedBag.this.getInternalMap(); m_map = from == null ? mapInternal.headMap(to, false) : to == null ? mapInternal.tailMap(from, true) : mapInternal.subMap(from, true, to, false); m_atomicNonce = SortedBag.this.getNonceCounter(); m_comparator = SortedBag.this.getComparator(); f_oFrom = from; f_oTo = to; } // ----- SortedBag methods ------------------------------------------ /** * {@inheritDoc} */ public boolean add(E o) { checkRange(o); return super.add(o); } /** * {@inheritDoc} */ public SortedBag subBag(E fromElement, E toElement) { checkRange(fromElement); checkRange(toElement); return super.subBag(fromElement, toElement); } /** * {@inheritDoc} */ public SortedBag headBag(E toElement) { checkRange(toElement); return super.headBag(toElement); } /** * {@inheritDoc} */ public SortedBag tailBag(E fromElement) { checkRange(fromElement); return super.tailBag(fromElement); } // ----- helper methods --------------------------------------------- /** * Check that the specified object is within the range of this view. * * @param o the object to check */ protected void checkRange(Object o) { Comparator comparator = getComparator(); if ((f_oFrom != null && comparator.compare(o, f_oFrom) < 0) || (f_oTo != null && comparator.compare(o, f_oTo) >= 0)) { throw new IllegalArgumentException(); } } // ----- data members ----------------------------------------------- /** * The (inclusive) lower bound of this view. */ protected final Object f_oFrom; /** * The (exclusive) upper bound of this view. */ protected final Object f_oTo; } // ----- inner class: UniqueElement ------------------------------------- /** * UniqueElement represents a unique instance of a logical element in the bag. */ protected class UniqueElement implements Comparable { // ----- constructors ----------------------------------------------- /** * Create a UniqueElement to represent the specified element. * * @param elem the element */ public UniqueElement(E elem) { f_elem = elem; f_nUniqueId = getNonceCounter().incrementAndGet(); } // ----- Comparable interface --------------------------------------- /** * {@inheritDoc} */ public int compareTo(Object o) { Comparator comparator = getComparator(); if (o instanceof UniqueElement) { UniqueElement that = (UniqueElement) o; int nCompare = comparator.compare(this.f_elem, that.f_elem); long nIdThis = this.f_nUniqueId; long nIdThat = that.f_nUniqueId; return nCompare == 0 ? nIdThis == nIdThat ? 0 : nIdThis < nIdThat ? -1 : 1 : nCompare; } else { int nCompare = comparator.compare(this.f_elem, o); // this must be comparing to a "plain" or "actual" element; // order the actual elements first if they are equivalent return nCompare < 0 ? -1 : 1; } } // ----- data members ----------------------------------------------- /** * The unique "id" for this element. */ protected final long f_nUniqueId; /** * The "actual" element. */ protected final E f_elem; } // ----- constants and data members ------------------------------------- /** * Marker value object. */ protected static final Object NO_VALUE = new Object(); /** * The nonce used to increment the unique element ids. */ protected AtomicLong m_atomicNonce; /** * The internal sorted map holding the bag contents. */ protected NavigableMap m_map; /** * The comparator used to compare logical elements. */ protected Comparator m_comparator; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy