Skip to content

Commit bfca3c4

Browse files
committed
Add OptionalBool utility for boolean ops
Introduce OptionalBool to wrap boolean values and provide Optional-like, functional-style operations. The class uses singleton instances for true/false, offers isTrue/isFalse checks, conditional executors (ifTrue, ifFalse, ifTrueOrElse) and mapping utilities (mapIfTrue, mapIfFalse, mapIfTrueOrElse) that return Optional or computed values. Also overrides equals, hashCode, and toString. Placed in games.negative.engine.util for use across the codebase.
1 parent bd985ab commit bfca3c4

1 file changed

Lines changed: 221 additions & 0 deletions

File tree

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
package games.negative.engine.util;
2+
3+
import java.util.Optional;
4+
5+
/**
6+
* A utility class that wraps a boolean value and provides functional-style operations
7+
* for conditional execution and value mapping based on the boolean state.
8+
*
9+
* <p>This class is similar to {@link Optional} but specifically designed for boolean values,
10+
* offering convenient methods for executing actions conditionally and mapping values
11+
* based on the true/false state.</p>
12+
*
13+
* <p>The class uses a singleton pattern for the two possible instances ({@code true} and {@code false})
14+
* to ensure memory efficiency and reference equality for instances with the same boolean value.</p>
15+
*
16+
* <h3>Usage Examples:</h3>
17+
* <pre>{@code
18+
* OptionalBool condition = OptionalBool.of(someCondition);
19+
*
20+
* // Conditional execution
21+
* condition.ifTrue(() -> System.out.println("Condition is true"));
22+
* condition.ifTrueOrElse(
23+
* () -> performTrueAction(),
24+
* () -> performFalseAction()
25+
* );
26+
*
27+
* // Value mapping
28+
* Optional<String> result = condition.mapIfTrue(() -> "Success");
29+
* String value = condition.mapIfTrueOrElse(
30+
* () -> "True value",
31+
* () -> "False value"
32+
* );
33+
* }</pre>
34+
*/
35+
public class OptionalBool {
36+
37+
private static final OptionalBool TRUE = new OptionalBool(true);
38+
private static final OptionalBool FALSE = new OptionalBool(false);
39+
40+
private final boolean value;
41+
42+
/**
43+
* Private constructor to enforce singleton pattern.
44+
*
45+
* @param value the boolean value to wrap
46+
*/
47+
private OptionalBool(boolean value) {
48+
this.value = value;
49+
}
50+
51+
/**
52+
* Creates an {@code OptionalBool} instance for the given boolean value.
53+
*
54+
* <p>This method returns one of two singleton instances to ensure memory efficiency
55+
* and allow reference equality comparisons.</p>
56+
*
57+
* @param value the boolean value to wrap
58+
* @return {@code OptionalBool.TRUE} if value is {@code true},
59+
* {@code OptionalBool.FALSE} if value is {@code false}
60+
*/
61+
public static OptionalBool of(boolean value) {
62+
return value ? TRUE : FALSE;
63+
}
64+
65+
/**
66+
* Checks if the wrapped boolean value is {@code true}.
67+
*
68+
* @return {@code true} if the wrapped value is {@code true}, {@code false} otherwise
69+
*/
70+
public boolean isTrue() {
71+
return value;
72+
}
73+
74+
/**
75+
* Checks if the wrapped boolean value is {@code false}.
76+
*
77+
* @return {@code true} if the wrapped value is {@code false}, {@code false} otherwise
78+
*/
79+
public boolean isFalse() {
80+
return !value;
81+
}
82+
83+
/**
84+
* Executes the given action if the wrapped boolean value is {@code true}.
85+
*
86+
* <p>If the value is {@code false}, no action is performed.</p>
87+
*
88+
* @param action the action to execute if the value is {@code true}
89+
* @throws NullPointerException if action is null and the value is {@code true}
90+
*/
91+
public void ifTrue(Runnable action) {
92+
if (value) action.run();
93+
}
94+
95+
/**
96+
* Executes the given action if the wrapped boolean value is {@code false}.
97+
*
98+
* <p>If the value is {@code true}, no action is performed.</p>
99+
*
100+
* @param action the action to execute if the value is {@code false}
101+
* @throws NullPointerException if action is null and the value is {@code false}
102+
*/
103+
public void ifFalse(Runnable action) {
104+
if (!value) action.run();
105+
}
106+
107+
/**
108+
* Executes one of two actions based on the wrapped boolean value.
109+
*
110+
* <p>If the value is {@code true}, the {@code trueAction} is executed.
111+
* If the value is {@code false}, the {@code falseAction} is executed.</p>
112+
*
113+
* @param trueAction the action to execute if the value is {@code true}
114+
* @param falseAction the action to execute if the value is {@code false}
115+
* @throws NullPointerException if the corresponding action is null
116+
*/
117+
public void ifTrueOrElse(Runnable trueAction, Runnable falseAction) {
118+
if (value) {
119+
trueAction.run();
120+
} else {
121+
falseAction.run();
122+
}
123+
}
124+
125+
/**
126+
* Maps the wrapped boolean to a value using the provided callback if the value is {@code true}.
127+
*
128+
* <p>If the wrapped value is {@code true}, the callback is executed and its result
129+
* is wrapped in an {@link Optional}. If the wrapped value is {@code false},
130+
* an empty {@code Optional} is returned.</p>
131+
*
132+
* @param <T> the type of the value to be returned
133+
* @param callback the callback to execute if the value is {@code true}
134+
* @return an {@code Optional} containing the callback result if value is {@code true},
135+
* or an empty {@code Optional} if value is {@code false}
136+
* @throws NullPointerException if callback is null and the value is {@code true}
137+
*/
138+
public <T> Optional<T> mapIfTrue(Callback<T> callback) {
139+
if (isFalse()) return Optional.empty();
140+
141+
return Optional.of(callback.apply());
142+
}
143+
144+
/**
145+
* Maps the wrapped boolean to a value using the provided callback if the value is {@code false}.
146+
*
147+
* <p>If the wrapped value is {@code false}, the callback is executed and its result
148+
* is wrapped in an {@link Optional}. If the wrapped value is {@code true},
149+
* an empty {@code Optional} is returned.</p>
150+
*
151+
* @param <T> the type of the value to be returned
152+
* @param callback the callback to execute if the value is {@code false}
153+
* @return an {@code Optional} containing the callback result if value is {@code false},
154+
* or an empty {@code Optional} if value is {@code true}
155+
* @throws NullPointerException if callback is null and the value is {@code false}
156+
*/
157+
public <T> Optional<T> mapIfFalse(Callback<T> callback) {
158+
if (isTrue()) return Optional.empty();
159+
160+
return Optional.of(callback.apply());
161+
}
162+
163+
/**
164+
* Maps the wrapped boolean to a value using one of two callbacks based on the boolean state.
165+
*
166+
* <p>If the wrapped value is {@code true}, the {@code trueCallback} is executed and its result returned.
167+
* If the wrapped value is {@code false}, the {@code falseCallback} is executed and its result returned.</p>
168+
*
169+
* @param <T> the type of the value to be returned
170+
* @param trueCallback the callback to execute if the value is {@code true}
171+
* @param falseCallback the callback to execute if the value is {@code false}
172+
* @return the result of the appropriate callback
173+
* @throws NullPointerException if the corresponding callback is null
174+
*/
175+
public <T> T mapIfTrueOrElse(Callback<T> trueCallback, Callback<T> falseCallback) {
176+
if (isTrue()) {
177+
return trueCallback.apply();
178+
} else {
179+
return falseCallback.apply();
180+
}
181+
}
182+
183+
/**
184+
* Indicates whether some other object is "equal to" this {@code OptionalBool}.
185+
*
186+
* <p>Two {@code OptionalBool} instances are considered equal if they wrap the same boolean value.</p>
187+
*
188+
* @param obj the reference object with which to compare
189+
* @return {@code true} if this object is the same as the obj argument; {@code false} otherwise
190+
*/
191+
@Override
192+
public boolean equals(Object obj) {
193+
return obj instanceof OptionalBool && ((OptionalBool) obj).value == value;
194+
}
195+
196+
/**
197+
* Returns a hash code value for this {@code OptionalBool}.
198+
*
199+
* <p>The hash code is based on the wrapped boolean value.</p>
200+
*
201+
* @return a hash code value for this object
202+
*/
203+
@Override
204+
public int hashCode() {
205+
return Boolean.hashCode(value);
206+
}
207+
208+
/**
209+
* Returns a string representation of this {@code OptionalBool}.
210+
*
211+
* <p>The string representation consists of the class name followed by
212+
* the wrapped boolean value in square brackets.</p>
213+
*
214+
* @return a string representation of this {@code OptionalBool}
215+
*/
216+
@Override
217+
public String toString() {
218+
return "OptionalBool[" + value + "]";
219+
}
220+
}
221+

0 commit comments

Comments
 (0)