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> -> { 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(() -> { 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(() -> <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}