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