001/*
002 * Hypo, an extensible and pluggable Java bytecode analytical model.
003 *
004 * Copyright (C) 2021  Kyle Wood (DemonWav)
005 *
006 * This program is free software: you can redistribute it and/or modify
007 * it under the terms of the Lesser GNU General Public License as published by
008 * the Free Software Foundation, version 3 of the License only.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU Lesser General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License
016 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
017 */
018
019package com.demonwav.hypo.core;
020
021import com.demonwav.hypo.model.ClassDataDecorator;
022import com.demonwav.hypo.model.ClassDataProvider;
023import com.google.errorprone.annotations.CanIgnoreReturnValue;
024import com.google.errorprone.annotations.Immutable;
025import java.util.function.Function;
026import org.jetbrains.annotations.Contract;
027import org.jetbrains.annotations.NotNull;
028
029/**
030 * Core global configuration for Hypo executions.
031 *
032 * <p>Create new instances of this class using {@link #builder()}.
033 */
034@Immutable
035public final class HypoConfig {
036
037    private final int parallelism;
038    @SuppressWarnings("Immutable")
039    private final @NotNull Function<ClassDataProvider, ClassDataDecorator> decorator;
040
041    /**
042     * Create a new instance of {@link HypoConfig}. Use {@link #builder()} instead.
043     *
044     * @param parallelism The parallelism level to use for Hypo executions.
045     * @param decorator The decorator to use for {@link ClassDataProvider#setDecorator(ClassDataDecorator)}.
046     */
047    HypoConfig(
048        final int parallelism,
049        final @NotNull Function<ClassDataProvider, ClassDataDecorator> decorator
050    ) {
051        this.parallelism = parallelism;
052        this.decorator = decorator;
053    }
054
055    /**
056     * Returns the parallelism level to use for Hypo executions.
057     * @return The parallelism level to use for Hypo executions.
058     */
059    public int getParallelism() {
060        return this.parallelism;
061    }
062
063    /**
064     * Returns the {@link ClassDataDecorator decorator} constructor to use for
065     * {@link ClassDataProvider#setDecorator(ClassDataDecorator)}.
066     *
067     * @return The {@link ClassDataDecorator decorator} constructor to use.
068     */
069    public @NotNull Function<ClassDataProvider, ClassDataDecorator> getDecorator() {
070        return this.decorator;
071    }
072
073    /**
074     * Create a new {@link Builder builder} for creating new instances of {@link HypoConfig}.
075     *
076     * @return A new {@link Builder} instance.
077     */
078    @Contract(value = "-> new ", pure = true)
079    public static @NotNull Builder builder() {
080        return new Builder();
081    }
082
083    /**
084     * Builder class for creating new instances of {@link HypoConfig}. Create new instances of this builder with
085     * {@link HypoConfig#builder()}.
086     *
087     * <p>This class is structured as the write-only version of {@link HypoConfig}, which is read-only.
088     */
089    public static final class Builder {
090
091        private int parallelism = -1;
092        private @NotNull Function<ClassDataProvider, ClassDataDecorator> decorator = DefaultClassDataDecorator::new;
093
094        /**
095         * Constructor for {@link Builder}. Use {@link HypoConfig#builder()} instead.
096         */
097        Builder() {}
098
099        /**
100         * Set the level of parallelism to use for Hypo executions.
101         *
102         * <p>Defaults to {@code -1}, which means to use {@link Runtime#availableProcessors()}.
103         *
104         * @param parallelism The level of parallelism to use for Hypo executions.
105         * @return {@code this} for chaining.
106         */
107        @CanIgnoreReturnValue
108        @Contract(value = "_ -> this", mutates = "this")
109        public @NotNull Builder withParallelism(final int parallelism) {
110            this.parallelism = parallelism;
111            return this;
112        }
113
114        /**
115         * Set the {@link ClassDataDecorator decorator} constructor to use for
116         * {@link ClassDataProvider#setDecorator(ClassDataDecorator)}.
117         *
118         * <p>Defaults to {@link DefaultClassDataDecorator#DefaultClassDataDecorator(ClassDataProvider)
119         * DefaultClassDataDecorator::new}.
120         *
121         * @param decorator The {@link ClassDataDecorator decorator} constructor to use.
122         * @return {@code this} for chaining.
123         */
124        @CanIgnoreReturnValue
125        @Contract(value = "_ -> this", mutates = "this")
126        public @NotNull Builder withDecorator(
127            final @NotNull Function<ClassDataProvider, ClassDataDecorator> decorator
128        ) {
129            this.decorator = decorator;
130            return this;
131        }
132
133        /**
134         * Use the current values of this builder to create a new instance of {@link HypoConfig} and return it.
135         *
136         * @return The new instance of {@link HypoConfig} using the value set in this builder.
137         */
138        @CanIgnoreReturnValue
139        @Contract(value = "-> new", pure = true)
140        public @NotNull HypoConfig build() {
141            return new HypoConfig(this.parallelism, this.decorator);
142        }
143    }
144}