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

org.gradle.execution.plan.ValuedVfsHierarchy Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021 the original author or authors.
 *
 * 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 org.gradle.execution.plan;

import com.google.common.collect.ImmutableList;
import org.gradle.internal.collect.PersistentList;
import org.gradle.internal.snapshot.CaseSensitivity;
import org.gradle.internal.snapshot.ChildMap;
import org.gradle.internal.snapshot.ChildMapFactory;
import org.gradle.internal.snapshot.EmptyChildMap;
import org.gradle.internal.snapshot.VfsRelativePath;

import javax.annotation.CheckReturnValue;
import java.util.function.BiConsumer;
import java.util.function.Supplier;

/**
 * A hierarchy of relative paths with attached values.
 *
 * This is an immutable data structure.
 */
public final class ValuedVfsHierarchy {
    private final PersistentList values;

    private final ChildMap> children;
    private final CaseSensitivity caseSensitivity;

    public ValuedVfsHierarchy(PersistentList values, ChildMap> children, CaseSensitivity caseSensitivity) {
        this.values = values;
        this.children = children;
        this.caseSensitivity = caseSensitivity;
    }

    /**
     * Returns an empty {@link ValuedVfsHierarchy} with the same case sensitivity.
     */
    @CheckReturnValue
    public ValuedVfsHierarchy empty() {
        return new ValuedVfsHierarchy<>(PersistentList.of(), EmptyChildMap.getInstance(), caseSensitivity);
    }

    /**
     * Visits the values which are attached to ancestors and children of the given location.
     */
    public void visitValuesRelatedTo(VfsRelativePath location, ValueVisitor visitor) {
        values.forEach(value -> visitor.visitAncestor(value, location));
        children.withNode(location, caseSensitivity, new ChildMap.NodeHandler, String>() {
            @Override
            public String handleAsDescendantOfChild(VfsRelativePath pathInChild, ValuedVfsHierarchy child) {
                child.visitValuesRelatedTo(pathInChild, visitor);
                return "";
            }

            @Override
            public String handleAsAncestorOfChild(String childPathFromAncestor, ValuedVfsHierarchy child) {
                visitor.visitChildren(
                    child.getValues(),
                    () -> childPathFromAncestor.substring(location.length() + 1));
                child.visitAllChildren((nodes, relativePath) ->
                    visitor.visitChildren(nodes, () -> joinRelativePaths(
                        childPathFromAncestor.substring(location.length() + 1),
                        relativePath.get())
                    ));
                return "";
            }

            @Override
            public String handleExactMatchWithChild(ValuedVfsHierarchy child) {
                child.visitAllValues(visitor);
                return "";
            }

            @Override
            public String handleUnrelatedToAnyChild() {
                return "";
            }
        });
    }

    /**
     * Visits all values relative to the root.
     */
    public void visitAllValues(ValueVisitor valueVisitor) {
        getValues().forEach(valueVisitor::visitExact);
        visitAllChildren(valueVisitor::visitChildren);
    }

    public interface ValueVisitor {
        /**
         * The visited value is attached to the given location.
         */
        void visitExact(T value);

        /**
         * The visited value is an ancestor of the visited location
         */
        void visitAncestor(T value, VfsRelativePath pathToVisitedLocation);

        /**
         * The visited value is a child of the visited location.
         *
         * @param relativePathSupplier provides the relative path from the visited location to the path with the attached values.
         */
        void visitChildren(PersistentList values, Supplier relativePathSupplier);
    }

    /**
     * Returns a new {@link ValuedVfsHierarchy} with the value attached to the location.
     */
    @CheckReturnValue
    public ValuedVfsHierarchy recordValue(VfsRelativePath location, T value) {
        if (location.length() == 0) {
            return new ValuedVfsHierarchy<>(values.plus(value), children, caseSensitivity);
        }
        ChildMap> newChildren = children.store(location, caseSensitivity, new ChildMap.StoreHandler>() {
            @Override
            public ValuedVfsHierarchy handleAsDescendantOfChild(VfsRelativePath pathInChild, ValuedVfsHierarchy child) {
                return child.recordValue(pathInChild, value);
            }

            @Override
            public ValuedVfsHierarchy handleAsAncestorOfChild(String childPath, ValuedVfsHierarchy child) {
                ChildMap> singletonChild = ChildMapFactory.childMapFromSorted(ImmutableList.of(new ChildMap.Entry<>(VfsRelativePath.of(childPath).suffixStartingFrom(location.length() + 1).getAsString(), child)));
                return new ValuedVfsHierarchy<>(PersistentList.of(value), singletonChild, caseSensitivity);
            }

            @Override
            public ValuedVfsHierarchy mergeWithExisting(ValuedVfsHierarchy child) {
                return new ValuedVfsHierarchy<>(child.getValues().plus(value), child.getChildren(), caseSensitivity);
            }

            @Override
            public ValuedVfsHierarchy createChild() {
                return new ValuedVfsHierarchy<>(PersistentList.of(value), EmptyChildMap.getInstance(), caseSensitivity);
            }

            @Override
            public ValuedVfsHierarchy createNodeFromChildren(ChildMap> children) {
                return new ValuedVfsHierarchy<>(PersistentList.of(), children, caseSensitivity);
            }
        });
        return new ValuedVfsHierarchy<>(values, newChildren, caseSensitivity);
    }

    private PersistentList getValues() {
        return values;
    }

    private void visitAllChildren(BiConsumer, Supplier> childConsumer) {
        children.visitChildren((childPath, child) -> {
            childConsumer.accept(
                child.getValues(),
                () -> childPath
            );
            child.visitAllChildren((grandChildren, relativePath) -> childConsumer.accept(grandChildren, () -> joinRelativePaths(
                childPath,
                relativePath.get())
            ));
        });
    }

    private ChildMap> getChildren() {
        return children;
    }

    private static String joinRelativePaths(String first, String second) {
        return first + "/" + second;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy