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