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