001/*
002 * Java Genetic Algorithm Library (jenetics-8.3.0).
003 * Copyright (c) 2007-2025 Franz Wilhelmstötter
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 * Author:
018 *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019 */
020package io.jenetics;
021
022import static java.util.Objects.requireNonNull;
023import static io.jenetics.internal.util.Hashes.hash;
024import static io.jenetics.util.RandomRegistry.random;
025
026import java.util.Objects;
027import java.util.function.Predicate;
028import java.util.function.Supplier;
029
030import io.jenetics.util.ISeq;
031import io.jenetics.util.IntRange;
032import io.jenetics.util.MSeq;
033
034/**
035 * {@code Gene} implementation, which allows creating genes without explicit
036 * implementing the {@code Gene} interface.
037 * {@snippet lang="java":
038 * class Main {
039 *     // First Monday of 2015.
040 *     private static final LocalDate MIN_MONDAY = LocalDate.of(2015, 1, 5);
041 *
042 *     // Supplier of random 'LocalDate' objects. The implementation is responsible
043 *     // for guaranteeing the desired allele restriction. In this case, we will
044 *     // generate only mondays.
045 *     static LocalDate nextRandomMonday() {
046 *         return MIN_MONDAY.plusWeeks(RandomRegistry.getRandom().nextInt(1000));
047 *     }
048 *
049 *     // Create a new 'LocalDate' gene. All other genes, created with
050 *     // gene.newInstance(), are calling the 'newRandomMonday' method.
051 *     final AnyGene<LocalDate> gene = AnyGene.of(Main::nextRandomMonday);
052 * }
053 * }
054 * The example above shows how to create {@code LocalDate} genes from a random
055 * {@code LocalDate} supplier. It also shows how to implement a restriction on
056 * the created dates. The usage of the {@code AnyGene} class is useful for
057 * supporting custom allele types without explicit implementation of the
058 * {@code Gene} interface. But the {@code AnyGene} can only be used for a subset
059 * of the existing alterers.
060 *
061 * @see AnyChromosome
062 *
063 * @implNote
064 * This class is immutable and thread-safe.
065 *
066 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
067 * @version 6.0
068 * @since 3.3
069 */
070public final class AnyGene<A> implements Gene<A, AnyGene<A>> {
071
072        private final A _allele;
073        private final Supplier<? extends A> _supplier;
074        private final Predicate<? super A> _validator;
075
076        private AnyGene(
077                final A allele,
078                final Supplier<? extends A> supplier,
079                final Predicate<? super A> validator
080        ) {
081                _allele = allele;
082                _supplier = requireNonNull(supplier);
083                _validator = requireNonNull(validator);
084        }
085
086        @Override
087        public A allele() {
088                return _allele;
089        }
090
091        @Override
092        public AnyGene<A> newInstance() {
093                return new AnyGene<>(_supplier.get(), _supplier, _validator);
094        }
095
096        @Override
097        public AnyGene<A> newInstance(final A value) {
098                return new AnyGene<>(value, _supplier, _validator);
099        }
100
101        @Override
102        public boolean isValid() {
103                return _validator.test(_allele);
104        }
105
106        @Override
107        public int hashCode() {
108                return hash(_allele, hash(AnyGene.class));
109        }
110
111        @Override
112        public boolean equals(final Object obj) {
113                return obj instanceof AnyGene<?> other &&
114                        Objects.equals(other._allele, _allele);
115        }
116
117        @Override
118        public String toString() {
119                return Objects.toString(_allele);
120        }
121
122
123        /* *************************************************************************
124         *  Static factory methods.
125         * ************************************************************************/
126
127        /**
128         * Create a new {@code AnyGene} instance with the given parameters. New
129         * (random) genes are created with the given allele {@code supplier}.
130         *
131         * @param <A> the allele type
132         * @param allele the actual allele instance the created gene represents.
133         *        {@code null} values are allowed.
134         * @param supplier the allele-supplier which is used for creating new,
135         *        random alleles
136         * @param validator the validator used for validating the created gene. This
137         *        predicate is used in the {@link #isValid()} method.
138         * @return a new {@code AnyGene} with the given parameters
139         * @throws NullPointerException if the {@code supplier} or {@code validator}
140         *         is {@code null}
141         */
142        public static <A> AnyGene<A> of(
143                final A allele,
144                final Supplier<? extends A> supplier,
145                final Predicate<? super A> validator
146        ) {
147                return new AnyGene<>(allele, supplier, validator);
148        }
149
150        /**
151         * Create a new {@code AnyGene} instance with the given parameters. New
152         * (random) genes are created with the given allele {@code supplier}. The
153         * {@code validator} predicate of the generated gene will always return
154         * {@code true}.
155         *
156         * @param <A> the allele type
157         * @param allele the actual allele instance the created gene represents.
158         *        {@code null} values are allowed.
159         * @param supplier the allele-supplier which is used for creating new,
160         *        random alleles
161         * @return a new {@code AnyGene} with the given parameters
162         * @throws NullPointerException if the {@code suppler} is {@code null}
163         */
164        public static <A> AnyGene<A> of(
165                final A allele,
166                final Supplier<? extends A> supplier
167        ) {
168                return new AnyGene<>(allele, supplier, a -> true);
169        }
170
171        /**
172         * Create a new {@code AnyGene} instance with the given allele
173         * {@code supplier}. The {@code validator} predicate of the generated gene
174         * will always return {@code true}.
175         *
176         * @param <A> the allele type
177         * @param supplier the allele-supplier which is used for creating new,
178         *        random alleles
179         * @return a new {@code AnyGene} with the given parameters
180         * @throws NullPointerException if one of the parameters is {@code null}
181         */
182        public static <A> AnyGene<A> of(final Supplier<? extends A> supplier) {
183                return new AnyGene<>(supplier.get(), supplier, a -> true);
184        }
185
186        /**
187         * Create a new {@code AnyGene} instance with the given parameters. New
188         * (random) genes are created with the given allele {@code supplier}.
189         *
190         * @param <A> the allele type
191         * @param supplier the allele-supplier which is used for creating new,
192         *        random alleles
193         * @param validator the validator used for validating the created gene. This
194         *        predicate is used in the {@link #isValid()} method.
195         * @return a new {@code AnyGene} with the given parameters
196         * @throws NullPointerException if one of the parameters is {@code null}
197         */
198        public static <A> AnyGene<A> of(
199                final Supplier<? extends A> supplier,
200                final Predicate<? super A> validator
201        ) {
202                return new AnyGene<>(supplier.get(), supplier, validator);
203        }
204
205        // Create gene sequence.
206        static <A> ISeq<AnyGene<A>> seq(
207                final IntRange lengthRange,
208                final Supplier<? extends A> supplier,
209                final Predicate<? super A> validator
210        ) {
211                final var random = random();
212                final var length = random.nextInt(lengthRange.min(), lengthRange.max());
213
214                return MSeq.<AnyGene<A>>ofLength(length)
215                        .fill(() -> of(supplier.get(), supplier, validator))
216                        .toISeq();
217        }
218
219}