001 /*
002 * Java Genetic Algorithm Library (jenetics-6.0.0).
003 * Copyright (c) 2007-2020 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 */
020 package io.jenetics.prog.op;
021
022 import static java.lang.String.format;
023 import static java.util.Objects.requireNonNull;
024 import static io.jenetics.internal.util.SerialIO.readNullableString;
025 import static io.jenetics.internal.util.SerialIO.writeNullableString;
026
027 import java.io.IOException;
028 import java.io.InvalidObjectException;
029 import java.io.ObjectInput;
030 import java.io.ObjectInputStream;
031 import java.io.ObjectOutput;
032 import java.io.Serializable;
033 import java.util.Objects;
034 import java.util.function.Supplier;
035
036 import io.jenetics.internal.util.Lazy;
037
038 /**
039 * Implementation of an <em>ephemeral</em> constant. It causes the insertion of
040 * a <em>mutable</em> constant into the operation tree. Every time this terminal
041 * is chosen a, different value is generated which is then used for that
042 * particular terminal, and which will remain fixed for the given tree. The main
043 * usage would be to introduce random terminal values.
044 *
045 * <pre>{@code
046 * final Random random = ...;
047 * final Op<Double> val = EphemeralConst.of(random::nextDouble);
048 * }</pre>
049 *
050 * <b>Serialization</b>
051 * Although the {@code EphemeralConst} class implements the {@link Serializable}
052 * interface, the serialization will fail if the <em>const</em> supplier is not
053 * <em>serializable</em> as well. This can be achieved by <em>casting</em> the
054 * supplier to a {@link Serializable}.
055 * <pre>{@code
056 * final Random random = new Random();
057 * final EphemeralConst<Integer> object = EphemeralConst.of(
058 * "R",
059 * (Supplier<Integer> & Serializable)random::nextInt
060 * );
061 * }</pre>
062 * The serialization of the <em>constant</em> will fail, if the lambda has to
063 * capture variables form a <em>non</em>-serializable context (class). In such a
064 * case it is advisable to create a dedicated supplier class.
065 * <pre>{@code
066 * final class RandomInt implements Supplier<Integer>, Serializable {
067 * private final Random rnd = new Random();
068 * private final int min;
069 * private final int max;
070 *
071 * private RandomInt(final int min, final int max) {
072 * this.min = min;
073 * this.max = max;
074 * }
075 *
076 * \@Override
077 * public Integer get() {
078 * return rnd.nextInt(max - min) + min;
079 * }
080 * }
081 * }</pre>
082 *
083 *
084 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
085 * @version 5.0
086 * @since 3.9
087 */
088 public final class EphemeralConst<T>
089 extends Val<T>
090 implements Op<T>, Serializable
091 {
092
093 private static final long serialVersionUID = 1L;
094
095 private final Lazy<T> _value;
096 private final Supplier<T> _supplier;
097
098 private EphemeralConst(
099 final String name,
100 final Lazy<T> value,
101 final Supplier<T> supplier
102 ) {
103 super(name);
104 _value = requireNonNull(value);
105 _supplier = requireNonNull(supplier);
106 }
107
108 private EphemeralConst(final String name, final Supplier<T> supplier) {
109 this(name, Lazy.of(supplier), supplier);
110 }
111
112 /**
113 * Return a newly created, uninitialized constant of type {@code T}.
114 *
115 * @return a newly created, uninitialized constant of type {@code T}
116 */
117 @Override
118 public Op<T> get() {
119 return new EphemeralConst<>(name(), _supplier);
120 }
121
122 /**
123 * Fixes and returns the constant value.
124 *
125 * @since 5.0
126 *
127 * @return the constant value
128 */
129 @Override
130 public T value() {
131 return _value.get();
132 }
133
134 @Override
135 public String toString() {
136 return name() != null
137 ? format("%s(%s)", name(), value())
138 : Objects.toString(value());
139 }
140
141 /**
142 * Create a new ephemeral constant with the given {@code name} and value
143 * {@code supplier}. For every newly created operation tree, a new constant
144 * value is chosen for this terminal operation. The value is than kept
145 * constant for this tree.
146 *
147 * @param name the name of the ephemeral constant
148 * @param supplier the value supplier
149 * @param <T> the constant type
150 * @return a new ephemeral constant
151 * @throws NullPointerException if one of the arguments is {@code null}
152 */
153 public static <T> EphemeralConst<T> of(
154 final String name,
155 final Supplier<T> supplier
156 ) {
157 return new EphemeralConst<>(requireNonNull(name), supplier);
158 }
159
160 /**
161 * Create a new ephemeral constant with the given value {@code supplier}.
162 * For every newly created operation tree, a new constant value is chosen
163 * for this terminal operation. The value is than kept constant for this tree.
164 *
165 * @param supplier the value supplier
166 * @param <T> the constant type
167 * @return a new ephemeral constant
168 * @throws NullPointerException if the {@code supplier} is {@code null}
169 */
170 public static <T> EphemeralConst<T> of(final Supplier<T> supplier) {
171 return new EphemeralConst<>(null, supplier);
172 }
173
174
175 /* *************************************************************************
176 * Java object serialization
177 * ************************************************************************/
178
179 private Object writeReplace() {
180 return new Serial(Serial.EPHEMERAL_CONST, this);
181 }
182
183 private void readObject(final ObjectInputStream stream)
184 throws InvalidObjectException
185 {
186 throw new InvalidObjectException("Serialization proxy required.");
187 }
188
189 void write(final ObjectOutput out) throws IOException {
190 writeNullableString(name(), out);
191 out.writeObject(value());
192 out.writeObject(_supplier);
193 }
194
195 @SuppressWarnings({"unchecked", "rawtypes"})
196 static EphemeralConst read(final ObjectInput in)
197 throws IOException, ClassNotFoundException
198 {
199 final String name = readNullableString(in);
200 final Object value = in.readObject();
201 final Supplier supplier = (Supplier)in.readObject();
202
203 return new EphemeralConst(name, Lazy.ofValue(value), supplier);
204 }
205
206 }
|