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

io.parsingdata.metal.data.Selection Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2013-2024 Netherlands Forensic Institute
 * Copyright 2021-2024 Infix Technologies B.V.
 *
 * 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 io.parsingdata.metal.data;

import static io.parsingdata.metal.Trampoline.complete;
import static io.parsingdata.metal.Trampoline.intermediate;
import static io.parsingdata.metal.Util.checkNotNull;

import java.math.BigInteger;
import java.util.Optional;
import java.util.function.Predicate;

import io.parsingdata.metal.Trampoline;
import io.parsingdata.metal.token.Token;

public final class Selection {

    public static final int NO_LIMIT = -1;

    private Selection() {}

    public static Trampoline> findItemAtOffset(final ImmutableList items, final BigInteger offset, final Source source) {
        checkNotNull(items, "items");
        checkNotNull(source, "source");
        if (items.isEmpty()) {
            return complete(Optional::empty);
        }
        final ParseItem head = items.head;
        if (head.isValue() && matchesLocation(head.asValue(), offset, source)) {
            return complete(() -> Optional.of(head));
        }
        if (head.isGraph()) {
            final ParseValue value = getLowestOffsetValue(ImmutableList.create(head.asGraph()), null).computeResult();
            if (value != null && matchesLocation(value, offset, source)) {
                return complete(() -> Optional.of(head));
            }
        }
        return intermediate(() -> findItemAtOffset(items.tail, offset, source));
    }

    private static boolean matchesLocation(final ParseValue value, final BigInteger offset, final Source source) {
        return value.slice().offset.compareTo(offset) == 0 && value.slice().source.equals(source);
    }

    private static Trampoline getLowestOffsetValue(final ImmutableList graphList, final ParseValue lowest) {
        if (graphList.isEmpty()) {
            return complete(() -> lowest);
        }
        final ParseGraph graph = graphList.head;
        if (graph.isEmpty() || !graph.getDefinition().isLocal()) {
            return intermediate(() -> getLowestOffsetValue(graphList.tail, lowest));
        }
        return intermediate(() -> getLowestOffsetValue(addIfGraph(graphList.tail.add(graph.tail), graph.head),
                                                       compareIfValue(lowest, graph.head)));
    }

    private static ParseValue compareIfValue(final ParseValue lowest, final ParseItem head) {
        return head.isValue() ? getLowest(lowest, head.asValue()) : lowest;
    }

    private static ParseValue getLowest(final ParseValue lowest, final ParseValue value) {
        return lowest == null || lowest.slice().offset.compareTo(value.slice().offset) > 0 ? value : lowest;
    }

    private static ImmutableList addIfGraph(final ImmutableList graphList, final ParseItem head) {
        return head.isGraph() ? graphList.add(head.asGraph()) : graphList;
    }

    public static ImmutableList getAllValues(final ParseGraph graph, final Predicate predicate, final int limit) {
        return getAllValues(ImmutableList.create(graph), new ImmutableList<>(), predicate, limit).computeResult();
    }

    public static ImmutableList getAllValues(final ParseGraph graph, final Predicate predicate) {
        return getAllValues(graph, predicate, NO_LIMIT);
    }

    private static Trampoline> getAllValues(final ImmutableList graphList, final ImmutableList valueList, final Predicate predicate, final int limit) {
        if (graphList.isEmpty() || valueList.size == limit) {
            return complete(() -> valueList);
        }
        final ParseGraph graph = graphList.head;
        if (graph.isEmpty()) {
            return intermediate(() -> getAllValues(graphList.tail, valueList, predicate, limit));
        }
        return intermediate(() -> getAllValues(addIfGraph(graphList.tail.add(graph.tail), graph.head),
                                               addIfMatchingValue(valueList, graph.head, predicate),
                                               predicate,
                                               limit));
    }

    private static ImmutableList addIfMatchingValue(final ImmutableList valueList, final ParseItem item, final Predicate predicate) {
        if (item.isValue() && predicate.test(item.asValue())) {
            return valueList.add(item.asValue());
        }
        return valueList;
    }

    public static  ImmutableList reverse(final ImmutableList list) {
        if (list.isEmpty()) {
            return list;
        }
        return reverse(list.tail, ImmutableList.create(list.head)).computeResult();
    }

    private static  Trampoline> reverse(final ImmutableList oldList, final ImmutableList newList) {
        if (oldList.isEmpty()) {
            return complete(() -> newList);
        }
        return intermediate(() -> reverse(oldList.tail, newList.add(oldList.head)));
    }

    public static ImmutableList getAllRoots(final ParseGraph graph, final Token definition) {
        return getAllRootsRecursive(ImmutableList.create(new Pair(checkNotNull(graph, "graph"), null)), checkNotNull(definition, "definition"), new ImmutableList<>()).computeResult();
    }

    private static Trampoline> getAllRootsRecursive(final ImmutableList backlog, final Token definition, final ImmutableList rootList) {
        if (backlog.isEmpty()) {
            return complete(() -> rootList);
        }
        final ParseItem item = backlog.head.item;
        final ParseGraph parent = backlog.head.parent;
        final ImmutableList nextResult = item.getDefinition().equals(definition) && (parent == null || !parent.getDefinition().equals(definition)) ? rootList.add(item) : rootList;
        if (item.isGraph() && !item.asGraph().isEmpty()) {
            final ParseGraph itemGraph = item.asGraph();
            return intermediate(() -> getAllRootsRecursive(backlog.tail.add(new Pair(itemGraph.head, itemGraph))
                                                                       .add(new Pair(itemGraph.tail, itemGraph)),
                                                           definition,
                                                           nextResult));
        }
        return intermediate(() -> getAllRootsRecursive(backlog.tail, definition, nextResult));
    }

    static class Pair {
        public final ParseItem item;
        public final ParseGraph parent;

        Pair(final ParseItem item, final ParseGraph parent) {
            this.item = checkNotNull(item, "item");
            this.parent = parent;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy