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.*;
020
021import org.apache.juneau.commons.utils.*;
022
023/**
024 * A simple mutable byte value.
025 *
026 * <p>
027 * This class extends {@link Holder}&lt;{@link Byte}&gt; and adds convenience methods for incrementing,
028 * decrementing, and testing byte values, which are useful in lambdas and byte manipulation operations.
029 *
030 * <h5 class='section'>Notes:</h5><ul>
031 *    <li class='note'>
032 *       This class is <b>not thread-safe</b>. For concurrent access, use synchronization or atomic classes.
033 * </ul>
034 *
035 * <h5 class='section'>Example:</h5>
036 * <p class='bjava'>
037 *    <jc>// Create a counter</jc>
038 *    ByteHolder <jv>counter</jv> = ByteHolder.<jsm>create</jsm>();
039 *
040 *    <jc>// Use in a lambda to count items</jc>
041 *    list.forEach(<jv>x</jv> -&gt; {
042 *       <jk>if</jk> (<jv>x</jv>.isValid()) {
043 *          <jv>counter</jv>.increment();
044 *       }
045 *    });
046 *
047 *    <jsm>log</jsm>(<js>"Count: "</js> + <jv>counter</jv>.get());
048 * </p>
049 *
050 * <h5 class='section'>See Also:</h5><ul>
051 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsLang">Lang Package</a>
052 * </ul>
053 */
054@SuppressWarnings({
055   "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants
056})
057public class ByteHolder extends Holder<Byte> {
058
059   /**
060    * Creates a new byte value initialized to <c>0</c>.
061    *
062    * <h5 class='section'>Example:</h5>
063    * <p class='bjava'>
064    *    ByteHolder <jv>counter</jv> = ByteHolder.<jsm>create</jsm>();
065    *    <jsm>assertEquals</jsm>(0, <jv>counter</jv>.get());
066    * </p>
067    *
068    * @return A new byte value.
069    */
070   public static ByteHolder create() {
071      return of((byte)0);
072   }
073
074   /**
075    * Creates a new byte value with the specified initial value.
076    *
077    * <h5 class='section'>Example:</h5>
078    * <p class='bjava'>
079    *    ByteHolder <jv>value</jv> = ByteHolder.<jsm>of</jsm>((<jk>byte</jk>)42);
080    *    <jsm>assertEquals</jsm>(42, <jv>value</jv>.get());
081    * </p>
082    *
083    * @param value The initial value.  Can be <jk>null</jk> (treated as <c>0</c>).
084    * @return A new byte value.
085    */
086   public static ByteHolder of(Byte value) {
087      return new ByteHolder(value);
088   }
089
090   /**
091    * Constructor.
092    */
093   public ByteHolder() {
094      super((byte)0);
095   }
096
097   /**
098    * Constructor.
099    *
100    * @param value The initial value.  Can be <jk>null</jk> (treated as <c>0</c>).
101    */
102   public ByteHolder(Byte value) {
103      super(value == null ? 0 : value);
104   }
105
106   /**
107    * Adds the specified value to the current value.
108    *
109    * <h5 class='section'>Example:</h5>
110    * <p class='bjava'>
111    *    ByteHolder <jv>value</jv> = ByteHolder.<jsm>of</jsm>((<jk>byte</jk>)10);
112    *    <jv>value</jv>.add((<jk>byte</jk>)5);
113    *    <jsm>assertEquals</jsm>(15, <jv>value</jv>.get());
114    * </p>
115    *
116    * @param x The value to add.  Can be <jk>null</jk> (treated as <c>0</c>).
117    * @return This object.
118    */
119   public ByteHolder add(Byte x) {
120      var v = get();
121      set((byte)((v == null ? 0 : v) + (x == null ? 0 : x)));
122      return this;
123   }
124
125   /**
126    * Adds the specified value to the current value and returns the new value.
127    *
128    * <h5 class='section'>Example:</h5>
129    * <p class='bjava'>
130    *    ByteHolder <jv>value</jv> = ByteHolder.<jsm>of</jsm>((<jk>byte</jk>)10);
131    *    <jk>byte</jk> <jv>result</jv> = <jv>value</jv>.addAndGet((<jk>byte</jk>)5);  <jc>// Returns 15</jc>
132    *    <jsm>assertEquals</jsm>(15, <jv>value</jv>.get());
133    * </p>
134    *
135    * @param x The value to add.  Can be <jk>null</jk> (treated as <c>0</c>).
136    * @return The new value after addition.
137    */
138   public Byte addAndGet(Byte x) {
139      var v = get();
140      var result = (byte)((v == null ? 0 : v) + (x == null ? 0 : x));
141      set(result);
142      return result;
143   }
144
145   /**
146    * Decrements the value by 1.
147    *
148    * <h5 class='section'>Example:</h5>
149    * <p class='bjava'>
150    *    ByteHolder <jv>counter</jv> = ByteHolder.<jsm>of</jsm>((<jk>byte</jk>)5);
151    *    <jv>counter</jv>.decrement();
152    *    <jsm>assertEquals</jsm>(4, <jv>counter</jv>.get());
153    * </p>
154    *
155    * @return This object.
156    */
157   public ByteHolder decrement() {
158      var v = get();
159      set((byte)((v == null ? 0 : v) - 1));
160      return this;
161   }
162
163   /**
164    * Decrements the value by 1 and returns the new value.
165    *
166    * <h5 class='section'>Example:</h5>
167    * <p class='bjava'>
168    *    ByteHolder <jv>counter</jv> = ByteHolder.<jsm>of</jsm>((<jk>byte</jk>)5);
169    *    <jk>byte</jk> <jv>result</jv> = <jv>counter</jv>.decrementAndGet();  <jc>// Returns 4</jc>
170    *    <jsm>assertEquals</jsm>(4, <jv>counter</jv>.get());
171    * </p>
172    *
173    * @return The decremented value.
174    */
175   public Byte decrementAndGet() {
176      var v = get();
177      var result = (byte)((v == null ? 0 : v) - 1);
178      set(result);
179      return result;
180   }
181
182   /**
183    * Increments the value by 1.
184    *
185    * <h5 class='section'>Example:</h5>
186    * <p class='bjava'>
187    *    ByteHolder <jv>counter</jv> = ByteHolder.<jsm>of</jsm>((<jk>byte</jk>)5);
188    *    <jv>counter</jv>.increment();
189    *    <jsm>assertEquals</jsm>(6, <jv>counter</jv>.get());
190    * </p>
191    *
192    * @return This object.
193    */
194   public ByteHolder increment() {
195      var v = get();
196      set((byte)((v == null ? 0 : v) + 1));
197      return this;
198   }
199
200   /**
201    * Increments the value by 1 and returns the new value.
202    *
203    * <h5 class='section'>Example:</h5>
204    * <p class='bjava'>
205    *    ByteHolder <jv>counter</jv> = ByteHolder.<jsm>of</jsm>((<jk>byte</jk>)5);
206    *    <jk>byte</jk> <jv>result</jv> = <jv>counter</jv>.incrementAndGet();  <jc>// Returns 6</jc>
207    *    <jsm>assertEquals</jsm>(6, <jv>counter</jv>.get());
208    * </p>
209    *
210    * @return The incremented value.
211    */
212   public Byte incrementAndGet() {
213      var v = get();
214      var result = (byte)((v == null ? 0 : v) + 1);
215      set(result);
216      return result;
217   }
218
219   /**
220    * Checks if the current value is equal to the specified value.
221    *
222    * <p>
223    * Uses {@link Shorts#eq(Object, Object)} for deep equality comparison, which handles nulls safely.
224    *
225    * <h5 class='section'>Example:</h5>
226    * <p class='bjava'>
227    *    ByteHolder <jv>value</jv> = ByteHolder.<jsm>of</jsm>((<jk>byte</jk>)42);
228    *    <jsm>assertTrue</jsm>(<jv>value</jv>.is((<jk>byte</jk>)42));
229    *    <jsm>assertFalse</jsm>(<jv>value</jv>.is((<jk>byte</jk>)43));
230    * </p>
231    *
232    * @param value The value to compare to.  Can be <jk>null</jk>.
233    * @return <jk>true</jk> if the current value is equal to the specified value.
234    */
235   @Override
236   public boolean is(Byte value) {
237      return eq(get(), value);
238   }
239
240   /**
241    * Checks if the current value matches any of the specified values.
242    *
243    * <p>
244    * Uses {@link Shorts#eq(Object, Object)} for deep equality comparison of each value.
245    *
246    * <h5 class='section'>Example:</h5>
247    * <p class='bjava'>
248    *    ByteHolder <jv>value</jv> = ByteHolder.<jsm>of</jsm>((<jk>byte</jk>)5);
249    *    <jsm>assertTrue</jsm>(<jv>value</jv>.isAny((<jk>byte</jk>)3, (<jk>byte</jk>)5, (<jk>byte</jk>)7));
250    *    <jsm>assertFalse</jsm>(<jv>value</jv>.isAny((<jk>byte</jk>)1, (<jk>byte</jk>)2));
251    * </p>
252    *
253    * @param values The values to compare to.  Must not be <jk>null</jk>.
254    * @return <jk>true</jk> if the current value matches any of the specified values.
255    */
256   public boolean isAny(Byte...values) {
257      reqnn("values", values);
258      var current = get();
259      for (var value : values)
260         if (eq(current, value))
261            return true;
262      return false;
263   }
264}