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

jetbrains.exodus.tree.patricia.PatriciaTreeBase Maven / Gradle / Ivy

/**
 * Copyright 2010 - 2018 JetBrains s.r.o.
 *
 * 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 jetbrains.exodus.tree.patricia;

import jetbrains.exodus.ByteIterable;
import jetbrains.exodus.ByteIterator;
import jetbrains.exodus.log.DataIterator;
import jetbrains.exodus.log.Log;
import jetbrains.exodus.log.RandomAccessLoggable;
import jetbrains.exodus.tree.INode;
import jetbrains.exodus.tree.ITree;
import jetbrains.exodus.tree.LongIterator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.PrintStream;

public abstract class PatriciaTreeBase implements ITree {

    /**
     * Loggable types describing patricia tree nodes.
     * All types start from the NODE_WO_KEY_WO_VALUE_WO_CHILDREN which corresponds to a non-root node without key,
     * without value, without children and without back reference. All other patricia loggables' types are made
     * using additional 5 bits, giving additional 31 types. So maximum value of a patricia loggable type is 43.
     */
    public static final byte MAX_VALID_LOGGABLE_TYPE = 43;
    public static final byte NODE_WO_KEY_WO_VALUE_WO_CHILDREN = 12;
    public static final byte HAS_KEY_BIT = 1;
    public static final byte HAS_VALUE_BIT = 2;
    public static final byte HAS_CHILDREN_BIT = 4;
    public static final byte ROOT_BIT = 8;
    public static final byte ROOT_BIT_WITH_BACKREF = 16;

    @NotNull
    protected final Log log;
    @NotNull
    private final DataIterator dataIterator;
    protected final int structureId;
    protected long size;

    protected PatriciaTreeBase(@NotNull final Log log, final int structureId) {
        this.log = log;
        dataIterator = new DataIterator(log);
        this.structureId = structureId;
    }

    @NotNull
    @Override
    public Log getLog() {
        return log;
    }

    @NotNull
    @Override
    public DataIterator getDataIterator(long address) {
        dataIterator.checkPage(address);
        return dataIterator;
    }

    @Override
    public int getStructureId() {
        return structureId;
    }

    @Override
    @Nullable
    public ByteIterable get(@NotNull final ByteIterable key) {
        final NodeBase node = getNode(key);
        return node == null ? null : node.getValue();
    }

    @Override
    public boolean hasPair(@NotNull final ByteIterable key, @NotNull final ByteIterable value) {
        final ByteIterable val = get(key);
        return val != null && val.compareTo(value) == 0;
    }

    @Override
    public boolean hasKey(@NotNull final ByteIterable key) {
        return get(key) != null;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public long getSize() {
        return size;
    }

    @Override
    public void dump(PrintStream out) {
        dump(out, null);
    }

    @Override
    public void dump(PrintStream out, INode.ToString renderer) {
        new TreeAwareNodeDecorator(this, getRoot()).dump(out, 0, renderer);
    }

    @Override
    public LongIterator addressIterator() {
        if (isEmpty()) {
            return LongIterator.EMPTY;
        }
        return new AddressIterator(new PatriciaTraverser(this, getRoot()));
    }

    @NotNull
    final RandomAccessLoggable getLoggable(final long address) {
        return log.readNotNull(getDataIterator(address), address);
    }

    @NotNull
    final ImmutableNode loadNode(final long address) {
        final RandomAccessLoggable loggable = getLoggable(address);
        return new ImmutableNode(address, loggable.getType(), loggable.getData());
    }

    static boolean nodeHasKey(final byte type) {
        return ((type - NODE_WO_KEY_WO_VALUE_WO_CHILDREN) & HAS_KEY_BIT) != 0;
    }

    static boolean nodeHasValue(final byte type) {
        return ((type - NODE_WO_KEY_WO_VALUE_WO_CHILDREN) & HAS_VALUE_BIT) != 0;
    }

    static boolean nodeHasChildren(final byte type) {
        return ((type - NODE_WO_KEY_WO_VALUE_WO_CHILDREN) & HAS_CHILDREN_BIT) != 0;
    }

    static boolean nodeIsRoot(final byte type) {
        return ((type - NODE_WO_KEY_WO_VALUE_WO_CHILDREN) & ROOT_BIT) != 0;
    }

    static boolean nodeHasBackReference(final byte type) {
        return ((type - NODE_WO_KEY_WO_VALUE_WO_CHILDREN) & ROOT_BIT_WITH_BACKREF) != 0;
    }

    abstract NodeBase getRoot();

    @Nullable
    protected NodeBase getNode(@NotNull final ByteIterable key) {
        final ByteIterator it = key.iterator();
        NodeBase node = getRoot();
        do {
            if (NodeBase.MatchResult.getMatchingLength(node.matchesKeySequence(it)) < 0) {
                return null;
            }
            if (!it.hasNext()) {
                break;
            }
            node = node.getChild(this, it.next());
        } while (node != null);
        return node;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy