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

org.javimmutable.collections.array.trie32.MultiBranchTrieNode Maven / Gradle / Ivy

Go to download

Library providing immutable/persistent collection classes for Java. While collections are immutable they provide methods for adding and removing values by creating new modified copies of themselves. Each copy shares almost all of its structure with other copies to minimize memory consumption.

There is a newer version: 3.2.1
Show newest version
///###////////////////////////////////////////////////////////////////////////
//
// Burton Computer Corporation
// http://www.burton-computer.com
//
// Copyright (c) 2017, Burton Computer Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     Redistributions of source code must retain the above copyright
//     notice, this list of conditions and the following disclaimer.
//
//     Redistributions in binary form must reproduce the above copyright
//     notice, this list of conditions and the following disclaimer in
//     the documentation and/or other materials provided with the
//     distribution.
//
//     Neither the name of the Burton Computer Corporation nor the names
//     of its contributors may be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package org.javimmutable.collections.array.trie32;

import org.javimmutable.collections.Cursor;
import org.javimmutable.collections.Holder;
import org.javimmutable.collections.Holders;
import org.javimmutable.collections.Indexed;
import org.javimmutable.collections.JImmutableMap;
import org.javimmutable.collections.SplitableIterator;
import org.javimmutable.collections.common.MutableDelta;
import org.javimmutable.collections.cursors.LazyMultiCursor;
import org.javimmutable.collections.indexed.IndexedArray;
import org.javimmutable.collections.iterators.LazyMultiIterator;

import javax.annotation.concurrent.Immutable;

@Immutable
public class MultiBranchTrieNode
    extends TrieNode
{
    // used by SignedOrderCursorSource to determine which index to use next
    private static final int[] SIGNED_INDEX_BITS = new int[]{
        0b0100, 0b1000, 0b0001, 0b0010
    };

    private final int shift;
    private final int bitmask;
    private final TrieNode[] entries;

    private MultiBranchTrieNode(int shift,
                                int bitmask,
                                TrieNode[] entries)
    {
        assert shift >= 0;
        this.shift = shift;
        this.bitmask = bitmask;
        this.entries = entries;
    }

    static  MultiBranchTrieNode forTesting(int shift)
    {
        TrieNode[] entries = allocate(0);
        return new MultiBranchTrieNode<>(shift, 0, entries);
    }

    static  MultiBranchTrieNode forIndex(int shift,
                                               int index,
                                               TrieNode child)
    {
        int branchIndex = ((index >>> shift) & 0x1f);
        return forBranchIndex(shift, branchIndex, child);
    }

    static  MultiBranchTrieNode forBranchIndex(int shift,
                                                     int branchIndex,
                                                     TrieNode child)
    {
        assert (branchIndex >= 0) && (branchIndex < 32);
        TrieNode[] entries = allocate(1);
        entries[0] = child;
        return new MultiBranchTrieNode<>(shift, 1 << branchIndex, entries);
    }

    static  MultiBranchTrieNode forEntries(int shift,
                                                 TrieNode[] entries)
    {
        final int length = entries.length;
        final int bitmask = (length == 32) ? -1 : ((1 << length) - 1);
        return new MultiBranchTrieNode<>(shift, bitmask, entries.clone());
    }

    static  MultiBranchTrieNode forSource(int index,
                                                int size,
                                                Indexed source,
                                                int offset)
    {
        final TrieNode[] entries = allocate(size);
        for (int i = 0; i < size; ++i) {
            entries[i] = LeafTrieNode.of(index++, source.get(offset++));
        }
        final int bitmask = (size == 32) ? -1 : ((1 << size) - 1);
        return new MultiBranchTrieNode<>(0, bitmask, entries);
    }

    static  MultiBranchTrieNode fullWithout(int shift,
                                                  TrieNode[] entries,
                                                  int withoutIndex)
    {
        assert entries.length == 32;
        final TrieNode[] newEntries = allocate(31);
        System.arraycopy(entries, 0, newEntries, 0, withoutIndex);
        System.arraycopy(entries, withoutIndex + 1, newEntries, withoutIndex, 31 - withoutIndex);
        final int newMask = ~(1 << withoutIndex);
        return new MultiBranchTrieNode<>(shift, newMask, newEntries);
    }

    @Override
    public boolean isEmpty()
    {
        return entries.length == 0;
    }

    @Override
    public T getValueOr(int shift,
                        int index,
                        T defaultValue)
    {
        assert this.shift == shift;
        final int bit = 1 << ((index >>> shift) & 0x1f);
        final int bitmask = this.bitmask;
        if ((bitmask & bit) == 0) {
            return defaultValue;
        } else {
            final int childIndex = realIndex(bitmask, bit);
            return entries[childIndex].getValueOr(shift - 5, index, defaultValue);
        }
    }

    @Override
    public  V getValueOr(int shift,
                               int index,
                               K key,
                               Transforms transforms,
                               V defaultValue)
    {
        assert this.shift == shift;
        final int bit = 1 << ((index >>> shift) & 0x1f);
        final int bitmask = this.bitmask;
        if ((bitmask & bit) == 0) {
            return defaultValue;
        } else {
            final int childIndex = realIndex(bitmask, bit);
            return entries[childIndex].getValueOr(shift - 5, index, key, transforms, defaultValue);
        }
    }

    @Override
    public Holder find(int shift,
                          int index)
    {
        assert this.shift == shift;
        final int bit = 1 << ((index >>> shift) & 0x1f);
        final int bitmask = this.bitmask;
        if ((bitmask & bit) == 0) {
            return Holders.of();
        } else {
            final int childIndex = realIndex(bitmask, bit);
            return entries[childIndex].find(shift - 5, index);
        }
    }

    @Override
    public  Holder find(int shift,
                                 int index,
                                 K key,
                                 Transforms transforms)
    {
        assert this.shift == shift;
        final int bit = 1 << ((index >>> shift) & 0x1f);
        final int bitmask = this.bitmask;
        if ((bitmask & bit) == 0) {
            return Holders.of();
        } else {
            final int childIndex = realIndex(bitmask, bit);
            return entries[childIndex].find(shift - 5, index, key, transforms);
        }
    }

    @Override
    public TrieNode assign(int shift,
                              int index,
                              T value,
                              MutableDelta sizeDelta)
    {
        assert this.shift == shift;
        final int bit = 1 << ((index >>> shift) & 0x1f);
        final int bitmask = this.bitmask;
        final int childIndex = realIndex(bitmask, bit);
        final TrieNode[] entries = this.entries;
        if ((bitmask & bit) == 0) {
            final TrieNode newChild = LeafTrieNode.of(index, value);
            sizeDelta.add(1);
            return selectNodeForInsertResult(shift, bit, bitmask, childIndex, entries, newChild);
        } else {
            final TrieNode child = entries[childIndex];
            final TrieNode newChild = child.assign(shift - 5, index, value, sizeDelta);
            return selectNodeForUpdateResult(shift, bitmask, childIndex, entries, child, newChild);
        }
    }

    @Override
    public  TrieNode assign(int shift,
                                     int index,
                                     K key,
                                     V value,
                                     Transforms transforms,
                                     MutableDelta sizeDelta)
    {
        assert this.shift == shift;
        final int bit = 1 << ((index >>> shift) & 0x1f);
        final int bitmask = this.bitmask;
        final int childIndex = realIndex(bitmask, bit);
        final TrieNode[] entries = this.entries;
        if ((bitmask & bit) == 0) {
            final TrieNode newChild = LeafTrieNode.of(index, transforms.update(Holders.of(), key, value, sizeDelta));
            return selectNodeForInsertResult(shift, bit, bitmask, childIndex, entries, newChild);
        } else {
            final TrieNode child = entries[childIndex];
            final TrieNode newChild = child.assign(shift - 5, index, key, value, transforms, sizeDelta);
            return selectNodeForUpdateResult(shift, bitmask, childIndex, entries, child, newChild);
        }
    }

    @Override
    public TrieNode delete(int shift,
                              int index,
                              MutableDelta sizeDelta)
    {
        assert this.shift == shift;
        final int bit = 1 << ((index >>> shift) & 0x1f);
        final int bitmask = this.bitmask;
        final TrieNode[] entries = this.entries;
        if ((bitmask & bit) == 0) {
            return this;
        } else {
            final int childIndex = realIndex(bitmask, bit);
            final TrieNode child = entries[childIndex];
            final TrieNode newChild = child.delete(shift - 5, index, sizeDelta);
            return selectNodeForDeleteResult(shift, bit, bitmask, entries, childIndex, child, newChild);
        }
    }

    @Override
    public  TrieNode delete(int shift,
                                     int index,
                                     K key,
                                     Transforms transforms,
                                     MutableDelta sizeDelta)
    {
        assert this.shift == shift;
        final int bit = 1 << ((index >>> shift) & 0x1f);
        final int bitmask = this.bitmask;
        final TrieNode[] entries = this.entries;
        if ((bitmask & bit) == 0) {
            return this;
        } else {
            final int childIndex = realIndex(bitmask, bit);
            final TrieNode child = entries[childIndex];
            TrieNode newChild = child.delete(shift - 5, index, key, transforms, sizeDelta);
            return selectNodeForDeleteResult(shift, bit, bitmask, entries, childIndex, child, newChild);
        }
    }

    @Override
    public int getShift()
    {
        return shift;
    }

    @Override
    public boolean isLeaf()
    {
        return false;
    }

    @Override
    public TrieNode trimmedToMinimumDepth()
    {
        return (bitmask == 1) ? entries[0].trimmedToMinimumDepth() : this;
    }

    @Override
    public Cursor> anyOrderEntryCursor()
    {
        return LazyMultiCursor.transformed(IndexedArray.retained(entries), node -> () -> node.anyOrderEntryCursor());
    }

    @Override
    public  Cursor> anyOrderEntryCursor(final Transforms transforms)
    {
        return LazyMultiCursor.transformed(IndexedArray.retained(entries), node -> () -> node.anyOrderEntryCursor(transforms));
    }

    @Override
    public Cursor anyOrderValueCursor()
    {
        return LazyMultiCursor.transformed(IndexedArray.retained(entries), node -> () -> node.anyOrderValueCursor());
    }

    @Override
    public Cursor> signedOrderEntryCursor()
    {
        if (shift != ROOT_SHIFT) {
            return anyOrderEntryCursor();
        } else {
            return LazyMultiCursor.transformed(indexedForSignedOrder(), node -> () -> node.anyOrderEntryCursor());
        }
    }

    @Override
    public  Cursor> signedOrderEntryCursor(Transforms transforms)
    {
        if (shift != ROOT_SHIFT) {
            return anyOrderEntryCursor(transforms);
        } else {
            return LazyMultiCursor.transformed(indexedForSignedOrder(), node -> () -> node.anyOrderEntryCursor(transforms));
        }
    }

    @Override
    public Cursor signedOrderValueCursor()
    {
        if (shift != ROOT_SHIFT) {
            return anyOrderValueCursor();
        } else {
            return LazyMultiCursor.transformed(indexedForSignedOrder(), node -> () -> node.anyOrderValueCursor());
        }
    }

    @Override
    public SplitableIterator> anyOrderEntryIterator()
    {
        return LazyMultiIterator.transformed(IndexedArray.retained(entries), node -> () -> node.anyOrderEntryIterator());
    }

    @Override
    public  SplitableIterator> anyOrderEntryIterator(Transforms transforms)
    {
        return LazyMultiIterator.transformed(IndexedArray.retained(entries), node -> () -> node.anyOrderEntryIterator(transforms));
    }

    @Override
    public SplitableIterator anyOrderValueIterator()
    {
        return LazyMultiIterator.transformed(IndexedArray.retained(entries), node -> () -> node.anyOrderValueIterator());
    }

    @Override
    public SplitableIterator> signedOrderEntryIterator()
    {
        if (shift != ROOT_SHIFT) {
            return anyOrderEntryIterator();
        } else {
            return LazyMultiIterator.transformed(indexedForSignedOrder(), node -> () -> node.anyOrderEntryIterator());
        }
    }

    @Override
    public  SplitableIterator> signedOrderEntryIterator(Transforms transforms)
    {
        if (shift != ROOT_SHIFT) {
            return anyOrderEntryIterator(transforms);
        } else {
            return LazyMultiIterator.transformed(indexedForSignedOrder(), node -> () -> node.anyOrderEntryIterator(transforms));
        }
    }

    @Override
    public SplitableIterator signedOrderValueIterator()
    {
        if (shift != ROOT_SHIFT) {
            return anyOrderValueIterator();
        } else {
            return LazyMultiIterator.transformed(indexedForSignedOrder(), node -> () -> node.anyOrderValueIterator());
        }
    }

    // for use by unit tests
    int getBitmask()
    {
        return bitmask;
    }

    // for use by unit tests
    TrieNode[] getEntries()
    {
        return entries.clone();
    }

    private TrieNode selectNodeForUpdateResult(int shift,
                                                  int bitmask,
                                                  int childIndex,
                                                  TrieNode[] entries,
                                                  TrieNode child,
                                                  TrieNode newChild)
    {
        if (newChild == child) {
            return this;
        } else {
            assert newChild.isLeaf() || (newChild.getShift() == (shift - 5));
            final TrieNode[] newEntries = entries.clone();
            newEntries[childIndex] = newChild;
            return new MultiBranchTrieNode<>(shift, bitmask, newEntries);
        }
    }

    private TrieNode selectNodeForInsertResult(int shift,
                                                  int bit,
                                                  int bitmask,
                                                  int childIndex,
                                                  TrieNode[] entries,
                                                  TrieNode newChild)
    {
        final int oldLength = entries.length;
        final TrieNode[] newEntries = allocate(oldLength + 1);
        if (bitmask != 0) {
            System.arraycopy(entries, 0, newEntries, 0, childIndex);
            System.arraycopy(entries, childIndex, newEntries, childIndex + 1, oldLength - childIndex);
        }
        newEntries[childIndex] = newChild;
        if (newEntries.length == 32) {
            return new FullBranchTrieNode<>(shift, newEntries);
        } else {
            return new MultiBranchTrieNode<>(shift, bitmask | bit, newEntries);
        }
    }

    private TrieNode selectNodeForDeleteResult(int shift,
                                                  int bit,
                                                  int bitmask,
                                                  TrieNode[] entries,
                                                  int childIndex,
                                                  TrieNode child,
                                                  TrieNode newChild)
    {
        if (newChild.isEmpty()) {
            switch (entries.length) {
            case 1:
                return of();
            case 2: {
                final int newBitmask = bitmask & ~bit;
                final int remainingIndex = Integer.numberOfTrailingZeros(newBitmask);
                final TrieNode remainingChild = entries[realIndex(bitmask, 1 << remainingIndex)];
                if (remainingChild.isLeaf()) {
                    return remainingChild;
                } else {
                    return SingleBranchTrieNode.forBranchIndex(shift, remainingIndex, remainingChild);
                }
            }
            default: {
                final int newLength = entries.length - 1;
                final TrieNode[] newArray = allocate(newLength);
                System.arraycopy(entries, 0, newArray, 0, childIndex);
                System.arraycopy(entries, childIndex + 1, newArray, childIndex, newLength - childIndex);
                return new MultiBranchTrieNode<>(shift, bitmask & ~bit, newArray);
            }
            }
        } else {
            return selectNodeForUpdateResult(shift, bitmask, childIndex, entries, child, newChild);
        }
    }

    private Indexed> indexedForSignedOrder()
    {
        final TrieNode[] nodes = allocate(entries.length);
        int offset = 0;
        for (int bit : SIGNED_INDEX_BITS) {
            if ((bitmask & bit) != 0) {
                nodes[offset++] = entries[realIndex(bitmask, bit)];
            }
        }
        assert offset == nodes.length;
        return IndexedArray.retained(nodes);
    }

    private static int realIndex(int bitmask,
                                 int bit)
    {
        return Integer.bitCount(bitmask & (bit - 1));
    }

    @SuppressWarnings("unchecked")
    static  TrieNode[] allocate(int size)
    {
        return (TrieNode[])new TrieNode[size];
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy