001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  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 */
017package org.apache.juneau.commons.lang;
018
019import static org.apache.juneau.commons.utils.Utils.*;
020
021import org.apache.juneau.commons.function.*;
022
023/**
024 * A simple mutable boolean flag.
025 *
026 * <p>
027 * This class provides a thread-unsafe alternative to {@link java.util.concurrent.atomic.AtomicBoolean} for cases
028 * where atomic operations are not required. It is useful in situations where you need to pass a mutable boolean
029 * reference to lambdas, inner classes, or methods.
030 *
031 * <h5 class='section'>Notes:</h5><ul>
032 *    <li class='note'>
033 *       This class is <b>not thread-safe</b>. For concurrent access, use {@link java.util.concurrent.atomic.AtomicBoolean} instead.
034 *    <li class='note'>
035 *       This class supports only two states (<c>true</c>/<c>false</c>). If you need to represent three states
036 *       (<c>true</c>/<c>false</c>/<c>null</c>), use {@link BooleanValue} instead.
037 * </ul>
038 *
039 * <h5 class='section'>Example:</h5>
040 * <p class='bjava'>
041 *    <jc>// Create a flag to track if an operation was performed</jc>
042 *    Flag <jv>processed</jv> = Flag.<jsm>create</jsm>();
043 *
044 *    <jc>// Use in a lambda</jc>
045 *    list.forEach(<jv>x</jv> -&gt; {
046 *       <jk>if</jk> (<jv>x</jv>.needsProcessing()) {
047 *          <jv>processed</jv>.set();
048 *          process(<jv>x</jv>);
049 *       }
050 *    });
051 *
052 *    <jk>if</jk> (<jv>processed</jv>.isSet()) {
053 *       <jsm>log</jsm>(<js>"Processing completed"</js>);
054 *    }
055 * </p>
056 *
057 * <h5 class='section'>See Also:</h5><ul>
058 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsLang">Lang Package</a>
059 *    <li class='jc'>{@link BooleanValue}
060 * </ul>
061 */
062public class Flag {
063
064   /**
065    * Creates a new flag initialized to <jk>false</jk>.
066    *
067    * <h5 class='section'>Example:</h5>
068    * <p class='bjava'>
069    *    Flag <jv>flag</jv> = Flag.<jsm>create</jsm>();
070    *    <jsm>assertTrue</jsm>(<jv>flag</jv>.isUnset());
071    * </p>
072    *
073    * @return A new flag.
074    */
075   public static Flag create() {
076      return of(false);
077   }
078
079   /**
080    * Creates a new flag with the specified initial state.
081    *
082    * <h5 class='section'>Example:</h5>
083    * <p class='bjava'>
084    *    Flag <jv>flag</jv> = Flag.<jsm>of</jsm>(<jk>true</jk>);
085    *    <jsm>assertTrue</jsm>(<jv>flag</jv>.isSet());
086    * </p>
087    *
088    * @param value The initial state of the flag.
089    * @return A new flag.
090    */
091   public static Flag of(boolean value) {
092      return new Flag(value);
093   }
094
095   private boolean value;
096
097   private Flag(boolean value) {
098      this.value = value;
099   }
100
101   /**
102    * Sets the flag to <jk>true</jk> and returns the previous value.
103    *
104    * <h5 class='section'>Example:</h5>
105    * <p class='bjava'>
106    *    Flag <jv>flag</jv> = Flag.<jsm>create</jsm>();
107    *    <jk>boolean</jk> <jv>wasSet</jv> = <jv>flag</jv>.getAndSet();  <jc>// Returns false, flag is now true</jc>
108    *    <jk>boolean</jk> <jv>wasSet2</jv> = <jv>flag</jv>.getAndSet(); <jc>// Returns true, flag remains true</jc>
109    * </p>
110    *
111    * @return The value before it was set to <jk>true</jk>.
112    */
113   public boolean getAndSet() {
114      var b = value;
115      value = true;
116      return b;
117   }
118
119   /**
120    * Sets the flag to <jk>false</jk> and returns the previous value.
121    *
122    * <h5 class='section'>Example:</h5>
123    * <p class='bjava'>
124    *    Flag <jv>flag</jv> = Flag.<jsm>of</jsm>(<jk>true</jk>);
125    *    <jk>boolean</jk> <jv>wasSet</jv> = <jv>flag</jv>.getAndUnset();  <jc>// Returns true, flag is now false</jc>
126    *    <jk>boolean</jk> <jv>wasSet2</jv> = <jv>flag</jv>.getAndUnset(); <jc>// Returns false, flag remains false</jc>
127    * </p>
128    *
129    * @return The value before it was set to <jk>false</jk>.
130    */
131   public boolean getAndUnset() {
132      var v = value;
133      value = false;
134      return v;
135   }
136
137   /**
138    * Executes a code snippet if the flag is <jk>false</jk>.
139    *
140    * <p>
141    * This method is useful for conditional execution based on the flag state, particularly in lambda expressions
142    * or method chains.
143    *
144    * <h5 class='section'>Example:</h5>
145    * <p class='bjava'>
146    *    Flag <jv>initialized</jv> = Flag.<jsm>create</jsm>();
147    *
148    *    <jc>// Initialize only once</jc>
149    *    <jv>initialized</jv>.ifNotSet(() -&gt; {
150    *       <jsm>initialize</jsm>();
151    *       <jv>initialized</jv>.set();
152    *    });
153    * </p>
154    *
155    * @param snippet The code snippet to execute if the flag is <jk>false</jk>.
156    * @return This object.
157    */
158   public Flag ifNotSet(Snippet snippet) {
159      if (! value)
160         safe(snippet);
161      return this;
162   }
163
164   /**
165    * Executes a code snippet if the flag is <jk>true</jk>.
166    *
167    * <p>
168    * This method is useful for conditional execution based on the flag state, particularly in lambda expressions
169    * or method chains.
170    *
171    * <h5 class='section'>Example:</h5>
172    * <p class='bjava'>
173    *    Flag <jv>hasErrors</jv> = Flag.<jsm>create</jsm>();
174    *
175    *    <jc>// Log only if errors occurred</jc>
176    *    <jv>hasErrors</jv>.ifSet(() -&gt; <jsm>logErrors</jsm>());
177    * </p>
178    *
179    * @param snippet The code snippet to execute if the flag is <jk>true</jk>.
180    * @return This object.
181    */
182   public Flag ifSet(Snippet snippet) {
183      if (value)
184         safe(snippet);
185      return this;
186   }
187
188   /**
189    * Returns <jk>true</jk> if the flag is set.
190    *
191    * <h5 class='section'>Example:</h5>
192    * <p class='bjava'>
193    *    Flag <jv>flag</jv> = Flag.<jsm>of</jsm>(<jk>true</jk>);
194    *    <jsm>assertTrue</jsm>(<jv>flag</jv>.isSet());
195    * </p>
196    *
197    * @return <jk>true</jk> if the flag is set, <jk>false</jk> otherwise.
198    */
199   public boolean isSet() { return value; }
200
201   /**
202    * Returns <jk>true</jk> if the flag is not set.
203    *
204    * <h5 class='section'>Example:</h5>
205    * <p class='bjava'>
206    *    Flag <jv>flag</jv> = Flag.<jsm>create</jsm>();
207    *    <jsm>assertTrue</jsm>(<jv>flag</jv>.isUnset());
208    * </p>
209    *
210    * @return <jk>true</jk> if the flag is not set, <jk>false</jk> otherwise.
211    */
212   public boolean isUnset() { return ! value; }
213
214   /**
215    * Sets the flag to <jk>true</jk>.
216    *
217    * <h5 class='section'>Example:</h5>
218    * <p class='bjava'>
219    *    Flag <jv>flag</jv> = Flag.<jsm>create</jsm>();
220    *    <jv>flag</jv>.set();
221    *    <jsm>assertTrue</jsm>(<jv>flag</jv>.isSet());
222    * </p>
223    *
224    * @return This object.
225    */
226   public Flag set() {
227      value = true;
228      return this;
229   }
230
231   /**
232    * Sets the flag to <jk>true</jk> if the specified value is <jk>true</jk>.
233    *
234    * <p>
235    * This method uses a logical OR operation, so once the flag is set, it remains set regardless of subsequent
236    * calls with <jk>false</jk>.
237    *
238    * <h5 class='section'>Example:</h5>
239    * <p class='bjava'>
240    *    Flag <jv>flag</jv> = Flag.<jsm>create</jsm>();
241    *    <jv>flag</jv>.setIf(<jk>false</jk>);  <jc>// Flag remains false</jc>
242    *    <jv>flag</jv>.setIf(<jk>true</jk>);   <jc>// Flag becomes true</jc>
243    *    <jv>flag</jv>.setIf(<jk>false</jk>);  <jc>// Flag remains true</jc>
244    * </p>
245    *
246    * @param value If <jk>true</jk>, the flag will be set to <jk>true</jk>.
247    * @return This object.
248    */
249   public Flag setIf(boolean value) {
250      this.value |= value;
251      return this;
252   }
253
254   /**
255    * Sets the flag to <jk>false</jk>.
256    *
257    * <h5 class='section'>Example:</h5>
258    * <p class='bjava'>
259    *    Flag <jv>flag</jv> = Flag.<jsm>of</jsm>(<jk>true</jk>);
260    *    <jv>flag</jv>.unset();
261    *    <jsm>assertTrue</jsm>(<jv>flag</jv>.isUnset());
262    * </p>
263    *
264    * @return This object.
265    */
266   public Flag unset() {
267      value = false;
268      return this;
269   }
270
271   /**
272    * Returns a string representation of this flag.
273    *
274    * <p>
275    * The format is simply the string representation of the boolean value.
276    *
277    * @return A string representation of this flag.
278    */
279   @Override
280   public String toString() {
281      return String.valueOf(value);
282   }
283
284   /**
285    * Compares the specified object with this flag for equality.
286    *
287    * <p>
288    * Returns <jk>true</jk> if and only if the specified object is also a <c>Flag</c> and both flags
289    * have the same boolean value.
290    *
291    * @param o The object to be compared for equality with this flag.
292    * @return <jk>true</jk> if the specified object is equal to this flag.
293    */
294   @Override
295   public boolean equals(Object o) {
296      return (o instanceof Flag o2) && eq(this, o2, (x, y) -> x.value == y.value);
297   }
298
299   /**
300    * Returns the hash code value for this flag.
301    *
302    * <p>
303    * The hash code is computed from the boolean value using the standard <c>Boolean.hashCode(boolean)</c>
304    * method, which returns <c>1231</c> for <c>true</c> and <c>1237</c> for <c>false</c>.
305    *
306    * <p>
307    * This ensures that <c>flag1.equals(flag2)</c> implies that <c>flag1.hashCode()==flag2.hashCode()</c>
308    * for any two flags <c>flag1</c> and <c>flag2</c>, as required by the general contract of
309    * {@link Object#hashCode()}.
310    *
311    * @return The hash code value for this flag.
312    */
313   @Override
314   public int hashCode() {
315      return Boolean.hashCode(value);
316   }
317}