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

org.apache.cassandra.utils.btree.BTreeSet Maven / Gradle / Ivy

Go to download

The Apache Cassandra Project develops a highly scalable second-generation distributed database, bringing together Dynamo's fully distributed design and Bigtable's ColumnFamily-based data model.

There is a newer version: 5.0.2
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.cassandra.utils.btree;

import java.util.*;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering;

import org.apache.cassandra.utils.btree.BTree.Dir;

import static org.apache.cassandra.utils.btree.BTree.findIndex;
import static org.apache.cassandra.utils.btree.BTree.lower;
import static org.apache.cassandra.utils.btree.BTree.toArray;

public class BTreeSet implements NavigableSet, List
{
    protected final Comparator comparator;
    protected final Object[] tree;

    public BTreeSet(Object[] tree, Comparator comparator)
    {
        this.tree = tree;
        this.comparator = comparator;
    }

    public BTreeSet update(Collection updateWith)
    {
        return new BTreeSet<>(BTree.update(tree, comparator, updateWith, UpdateFunction.noOp()), comparator);
    }

    @Override
    public Comparator comparator()
    {
        return comparator;
    }

    protected BTreeSearchIterator slice(Dir dir)
    {
        return BTree.slice(tree, comparator, dir);
    }

    public Object[] tree()
    {
        return tree;
    }

    /**
     * The index of the item within the list, or its insertion point otherwise. i.e. binarySearch semantics
     */
    public int indexOf(Object item)
    {
        return findIndex(tree, comparator, (V) item);
    }

    /**
     * The converse of indexOf: provided an index between 0 and size, returns the i'th item, in set order.
     */
    public V get(int index)
    {
        return BTree.findByIndex(tree, index);
    }

    public int lastIndexOf(Object o)
    {
        return indexOf(o);
    }

    public BTreeSet subList(int fromIndex, int toIndex)
    {
        return new BTreeRange(tree, comparator, fromIndex, toIndex - 1);
    }

    @Override
    public int size()
    {
        return BTree.size(tree);
    }

    @Override
    public boolean isEmpty()
    {
        return BTree.isEmpty(tree);
    }

    @Override
    public BTreeSearchIterator iterator()
    {
        return slice(Dir.ASC);
    }

    @Override
    public BTreeSearchIterator descendingIterator()
    {
        return slice(Dir.DESC);
    }

    @Override
    public Object[] toArray()
    {
        return toArray(new Object[0]);
    }

    @Override
    public  T[] toArray(T[] a)
    {
        return toArray(a, 0);
    }

    public  T[] toArray(T[] a, int offset)
    {
        int size = size();
        if (a.length < size + offset)
            a = Arrays.copyOf(a, size);
        BTree.toArray(tree, a, offset);
        return a;
    }

    public Spliterator spliterator()
    {
        return Spliterators.spliterator(this, Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.SIZED);
    }

    @Override
    public BTreeSet subSet(V fromElement, boolean fromInclusive, V toElement, boolean toInclusive)
    {
        return new BTreeRange<>(tree, comparator, fromElement, fromInclusive, toElement, toInclusive);
    }

    @Override
    public BTreeSet headSet(V toElement, boolean inclusive)
    {
        return new BTreeRange<>(tree, comparator, null, true, toElement, inclusive);
    }

    @Override
    public BTreeSet tailSet(V fromElement, boolean inclusive)
    {
        return new BTreeRange<>(tree, comparator, fromElement, inclusive, null, true);
    }

    @Override
    public SortedSet subSet(V fromElement, V toElement)
    {
        return subSet(fromElement, true, toElement, false);
    }

    @Override
    public SortedSet headSet(V toElement)
    {
        return headSet(toElement, false);
    }

    @Override
    public SortedSet tailSet(V fromElement)
    {
        return tailSet(fromElement, true);
    }

    @Override
    public BTreeSet descendingSet()
    {
        return new BTreeRange(this.tree, this.comparator).descendingSet();
    }

    @Override
    public V first()
    {
        return get(0);
    }

    @Override
    public V last()
    {
        return get(size() - 1);
    }

    @Override
    public V lower(V v)
    {
        return BTree.lower(tree, comparator, v);
    }

    @Override
    public V floor(V v)
    {
        return BTree.floor(tree, comparator, v);
    }

    @Override
    public V ceiling(V v)
    {
        return BTree.ceil(tree, comparator, v);
    }

    @Override
    public V higher(V v)
    {
        return BTree.higher(tree, comparator, v);
    }

    @Override
    public boolean contains(Object o)
    {
        return indexOf((V) o) >= 0;
    }

    @Override
    public boolean containsAll(Collection c)
    {
        // TODO: if we ever use this method, it can be specialized quite easily for SortedSet arguments
        for (Object o : c)
            if (!contains(o))
                return false;
        return true;
    }

    public int hashCode()
    {
        // we can't just delegate to Arrays.deepHashCode(),
        // because two equivalent sets may be represented by differently shaped trees
        int result = 1;
        for (V v : this)
            result = 31 * result + Objects.hashCode(v);
        return result;
    }

    @Override
    public boolean addAll(Collection c)
    {
        throw new UnsupportedOperationException();
    }

    public boolean addAll(int index, Collection c)
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean retainAll(Collection c)
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean removeAll(Collection c)
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public void clear()
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public V pollFirst()
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public V pollLast()
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean add(V v)
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean remove(Object o)
    {
        throw new UnsupportedOperationException();
    }

    public V set(int index, V element)
    {
        throw new UnsupportedOperationException();
    }

    public void add(int index, V element)
    {
        throw new UnsupportedOperationException();
    }

    public V remove(int index)
    {
        throw new UnsupportedOperationException();
    }

    public ListIterator listIterator()
    {
        throw new UnsupportedOperationException();
    }

    public ListIterator listIterator(int index)
    {
        throw new UnsupportedOperationException();
    }

    public static class BTreeRange extends BTreeSet
    {
        // both inclusive
        protected final int lowerBound, upperBound;
        BTreeRange(Object[] tree, Comparator comparator)
        {
            this(tree, comparator, null, true, null, true);
        }

        BTreeRange(BTreeRange from)
        {
            super(from.tree, from.comparator);
            this.lowerBound = from.lowerBound;
            this.upperBound = from.upperBound;
        }

        BTreeRange(Object[] tree, Comparator comparator, int lowerBound, int upperBound)
        {
            super(tree, comparator);
            if (upperBound < lowerBound - 1)
                upperBound = lowerBound - 1;
            this.lowerBound = lowerBound;
            this.upperBound = upperBound;
        }

        BTreeRange(Object[] tree, Comparator comparator, V lowerBound, boolean inclusiveLowerBound, V upperBound, boolean inclusiveUpperBound)
        {
            this(tree, comparator,
                 lowerBound == null ? 0 : inclusiveLowerBound ? BTree.ceilIndex(tree, comparator, lowerBound)
                                                              : BTree.higherIndex(tree, comparator, lowerBound),
                 upperBound == null ? BTree.size(tree) - 1 : inclusiveUpperBound ? BTree.floorIndex(tree, comparator, upperBound)
                                                                                 : BTree.lowerIndex(tree, comparator, upperBound));
        }

        // narrowing range constructor - makes this the intersection of the two ranges over the same tree b
        BTreeRange(BTreeRange a, BTreeRange b)
        {
            this(a.tree, a.comparator, Math.max(a.lowerBound, b.lowerBound), Math.min(a.upperBound, b.upperBound));
            assert a.tree == b.tree;
        }

        @Override
        protected BTreeSearchIterator slice(Dir dir)
        {
            return new BTreeSearchIterator<>(tree, comparator, dir, lowerBound, upperBound);
        }

        @Override
        public boolean isEmpty()
        {
            return upperBound < lowerBound;
        }

        public int size()
        {
            return (upperBound - lowerBound) + 1;
        }

        boolean outOfBounds(int i)
        {
            return (i < lowerBound) | (i > upperBound);
        }

        public V get(int index)
        {
            index += lowerBound;
            if (outOfBounds(index))
                throw new NoSuchElementException();
            return super.get(index);
        }

        public int indexOf(Object item)
        {
            int i = super.indexOf(item);
            boolean negate = i < 0;
            if (negate)
                i = -1 - i;
            if (outOfBounds(i))
                return i < lowerBound ? -1 : -1 - size();
            i = i - lowerBound;
            if (negate)
                i = -1 -i;
            return i;
        }

        public V lower(V v)
        {
            return maybe(Math.min(upperBound, BTree.lowerIndex(tree, comparator, v)));
        }

        public V floor(V v)
        {
            return maybe(Math.min(upperBound, BTree.floorIndex(tree, comparator, v)));
        }

        public V ceiling(V v)
        {
            return maybe(Math.max(lowerBound, BTree.ceilIndex(tree, comparator, v)));
        }

        public V higher(V v)
        {
            return maybe(Math.max(lowerBound, BTree.higherIndex(tree, comparator, v)));
        }

        private V maybe(int i)
        {
            if (outOfBounds(i))
                return null;
            return super.get(i);
        }

        @Override
        public BTreeSet subSet(V fromElement, boolean fromInclusive, V toElement, boolean toInclusive)
        {
            return new BTreeRange<>(this, new BTreeRange<>(tree, comparator, fromElement, fromInclusive, toElement, toInclusive));
        }

        @Override
        public BTreeSet headSet(V toElement, boolean inclusive)
        {
            return new BTreeRange<>(this, new BTreeRange<>(tree, comparator, null, true, toElement, inclusive));
        }

        @Override
        public BTreeSet tailSet(V fromElement, boolean inclusive)
        {
            return new BTreeRange<>(this, new BTreeRange<>(tree, comparator, fromElement, inclusive, null, true));
        }

        @Override
        public BTreeSet descendingSet()
        {
            return new BTreeDescRange<>(this);
        }

        public BTreeSet subList(int fromIndex, int toIndex)
        {
            if (fromIndex < 0 || toIndex > size())
                throw new IndexOutOfBoundsException();
            return new BTreeRange(tree, comparator, lowerBound + fromIndex, lowerBound + toIndex - 1);
        }

        @Override
        public  T[] toArray(T[] a)
        {
            return toArray(a, 0);
        }

        public  T[] toArray(T[] a, int offset)
        {
            if (size() + offset < a.length)
                a = Arrays.copyOf(a, size() + offset);

            BTree.toArray(tree, lowerBound, upperBound + 1, a, offset);
            return a;
        }
    }

    public static class BTreeDescRange extends BTreeRange
    {
        BTreeDescRange(BTreeRange from)
        {
            super(from.tree, from.comparator, from.lowerBound, from.upperBound);
        }

        @Override
        protected BTreeSearchIterator slice(Dir dir)
        {
            return super.slice(dir.invert());
        }

        /* Flip the methods we call for inequality searches */

        public V higher(V v)
        {
            return super.lower(v);
        }

        public V ceiling(V v)
        {
            return super.floor(v);
        }

        public V floor(V v)
        {
            return super.ceiling(v);
        }

        public V lower(V v)
        {
            return super.higher(v);
        }

        public V get(int index)
        {
            index = upperBound - index;
            if (outOfBounds(index))
                throw new NoSuchElementException();
            return BTree.findByIndex(tree, index);
        }

        public int indexOf(Object item)
        {
            int i = super.indexOf(item);
            // i is in range [-1 - size()..size())
            // so we just need to invert by adding/subtracting from size
            return i < 0 ? -2 - size() - i  : size() - (i + 1);
        }

        public BTreeSet subList(int fromIndex, int toIndex)
        {
            if (fromIndex < 0 || toIndex > size())
                throw new IndexOutOfBoundsException();
            return new BTreeDescRange(new BTreeRange(tree, comparator, upperBound - (toIndex - 1), upperBound - fromIndex));
        }

        @Override
        public BTreeSet subSet(V fromElement, boolean fromInclusive, V toElement, boolean toInclusive)
        {
            return super.subSet(toElement, toInclusive, fromElement, fromInclusive).descendingSet();
        }

        @Override
        public BTreeSet headSet(V toElement, boolean inclusive)
        {
            return super.tailSet(toElement, inclusive).descendingSet();
        }

        @Override
        public BTreeSet tailSet(V fromElement, boolean inclusive)
        {
            return super.headSet(fromElement, inclusive).descendingSet();
        }

        @Override
        public BTreeSet descendingSet()
        {
            return new BTreeRange<>(this);
        }

        public Comparator comparator()
        {
            return (a, b) -> comparator.compare(b, a);
        }

        public  T[] toArray(T[] a, int offset)
        {
            a = super.toArray(a, offset);
            int count = size();
            int flip = count / 2;
            for (int i = 0 ; i < flip ; i++)
            {
                int j = count - (i + 1);
                T t = a[i + offset];
                a[i + offset] = a[j + offset];
                a[j + offset] = t;
            }
            return a;
        }
    }

    public static class Builder
    {
        final BTree.Builder builder;
        protected Builder(Comparator comparator)
        {
            builder= BTree.builder(comparator);
        }

        public Builder add(V v)
        {
            builder.add(v);
            return this;
        }

        public Builder addAll(Collection iter)
        {
            builder.addAll(iter);
            return this;
        }

        public boolean isEmpty()
        {
            return builder.isEmpty();
        }
        public BTreeSet build()
        {
            return new BTreeSet<>(builder.build(), builder.comparator);
        }
    }

    public static  Builder builder(Comparator comparator)
    {
        return new Builder<>(comparator);
    }

    public static  BTreeSet wrap(Object[] btree, Comparator comparator)
    {
        return new BTreeSet<>(btree, comparator);
    }

    public static > BTreeSet of(Collection sortedValues)
    {
        return new BTreeSet<>(BTree.build(sortedValues, UpdateFunction.noOp()), Ordering.natural());
    }

    public static > BTreeSet of(V value)
    {
        return new BTreeSet<>(BTree.build(ImmutableList.of(value), UpdateFunction.noOp()), Ordering.natural());
    }

    public static  BTreeSet empty(Comparator comparator)
    {
        return new BTreeSet<>(BTree.empty(), comparator);
    }

    public static  BTreeSet of(Comparator comparator, V value)
    {
        return new BTreeSet<>(BTree.build(ImmutableList.of(value), UpdateFunction.noOp()), comparator);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy