View Javadoc
1   package org.djunits.value.vfloat.vector.base;
2   
3   import java.io.Serializable;
4   import java.lang.reflect.Array;
5   import java.util.Iterator;
6   import java.util.NoSuchElementException;
7   
8   import org.djunits.unit.Unit;
9   import org.djunits.value.Absolute;
10  import org.djunits.value.ValueRuntimeException;
11  import org.djunits.value.base.Vector;
12  import org.djunits.value.formatter.Format;
13  import org.djunits.value.storage.StorageType;
14  import org.djunits.value.util.ValueUtil;
15  import org.djunits.value.vfloat.function.FloatFunction;
16  import org.djunits.value.vfloat.function.FloatMathFunctions;
17  import org.djunits.value.vfloat.scalar.base.FloatScalar;
18  import org.djunits.value.vfloat.vector.data.FloatVectorData;
19  import org.djutils.exceptions.Throw;
20  
21  /**
22   * The most basic abstract class for the FloatVector.
23   * <p>
24   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
25   * BSD-style license. See <a href="https://djunits.org/docs/license.html">DJUNITS License</a>.
26   * </p>
27   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
28   * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
29   * @param <U> the unit
30   * @param <S> the scalar with unit U
31   * @param <V> the generic vector type
32   */
33  public abstract class FloatVector<U extends Unit<U>, S extends FloatScalar<U, S>, V extends FloatVector<U, S, V>>
34          extends Vector<U, S, V, FloatVectorData>
35  {
36      /** */
37      private static final long serialVersionUID = 20161015L;
38  
39      /** The stored data as an object, can be sparse or dense. */
40      @SuppressWarnings("checkstyle:visibilitymodifier")
41      protected FloatVectorData data;
42  
43      /**
44       * Construct a new FloatVector.
45       * @param data FloatVectorData; an internal data object
46       * @param unit U; the unit
47       */
48      FloatVector(final FloatVectorData data, final U unit)
49      {
50          super(unit);
51          Throw.whenNull(data, "data cannot be null");
52          this.data = data;
53      }
54  
55      /**
56       * Instantiate a new vector of the class of this vector. This can be used instead of the FloatVector.instiantiate() methods
57       * in case another vector of this class is known. The method is faster than FloatVector.instantiate, and it will also work
58       * if the vector is user-defined.
59       * @param fvd FloatVectorData; the data used to instantiate the vector
60       * @param displayUnit U; the display unit of the vector
61       * @return V; a vector of the correct type
62       */
63      public abstract V instantiateVector(FloatVectorData fvd, U displayUnit);
64  
65      /**
66       * Instantiate a new scalar for the class of this vector. This can be used instead of the FloatScalar.instiantiate() methods
67       * in case a vector of this class is known. The method is faster than FloatScalar.instantiate, and it will also work if the
68       * vector and/or scalar are user-defined.
69       * @param valueSI float; the SI value of the scalar
70       * @param displayUnit U; the unit in which the value will be displayed
71       * @return S; a scalar of the correct type, belonging to the vector type
72       */
73      public abstract S instantiateScalarSI(float valueSI, U displayUnit);
74  
75      @Override
76      protected final FloatVectorData getData()
77      {
78          return this.data;
79      }
80  
81      @Override
82      protected void setData(final FloatVectorData data)
83      {
84          this.data = data;
85      }
86  
87      /**
88       * Create a float[] array filled with the values in the standard SI unit.
89       * @return float[]; array of values in the standard SI unit
90       */
91      public final float[] getValuesSI()
92      {
93          return getData().getDenseVectorSI();
94      }
95  
96      /**
97       * Create a float[] array filled with the values in the original unit.
98       * @return float[]; the values in the original unit
99       */
100     public final float[] getValuesInUnit()
101     {
102         return getValuesInUnit(getDisplayUnit());
103     }
104 
105     /**
106      * Create a float[] array filled with the values converted into a specified unit.
107      * @param targetUnit U; the unit into which the values are converted for use
108      * @return float[]; the values converted into the specified unit
109      */
110     public final float[] getValuesInUnit(final U targetUnit)
111     {
112         float[] values = getValuesSI();
113         for (int i = values.length; --i >= 0;)
114         {
115             values[i] = (float) ValueUtil.expressAsUnit(values[i], targetUnit);
116         }
117         return values;
118     }
119 
120     @Override
121     public final int size()
122     {
123         return getData().size();
124     }
125 
126     /**
127      * Check that a provided index is valid.
128      * @param index int; the value to check
129      * @throws IndexOutOfBoundsException when index is invalid
130      */
131     protected final void checkIndex(final int index) throws IndexOutOfBoundsException
132     {
133         if (index < 0 || index >= size())
134         {
135             throw new IndexOutOfBoundsException(
136                     "index out of range (valid range is 0.." + (size() - 1) + ", got " + index + ")");
137         }
138     }
139 
140     /**
141      * Retrieve the value stored at a specified position in the standard SI unit.
142      * @param index int; index of the value to retrieve
143      * @return float; value at position index in the standard SI unit
144      * @throws IndexOutOfBoundsException when index out of range (index &lt; 0 or index &gt;= size())
145      */
146     public final float getSI(final int index) throws IndexOutOfBoundsException
147     {
148         checkIndex(index);
149         return getData().getSI(index);
150     }
151 
152     @Override
153     public S get(final int index) throws IndexOutOfBoundsException
154     {
155         return FloatScalar.instantiateSI(getSI(index), getDisplayUnit());
156     }
157 
158     /**
159      * Retrieve the value stored at a specified position in the original unit.
160      * @param index int; index of the value to retrieve
161      * @return float; value at position index in the original unit
162      * @throws IndexOutOfBoundsException when index out of range (index &lt; 0 or index &gt;= size())
163      */
164     public final float getInUnit(final int index) throws IndexOutOfBoundsException
165     {
166         return (float) ValueUtil.expressAsUnit(getSI(index), getDisplayUnit());
167     }
168 
169     /**
170      * Retrieve the value stored at a specified position converted into a specified unit.
171      * @param index int; index of the value to retrieve
172      * @param targetUnit U; the unit for the result
173      * @return float; value at position index converted into the specified unit
174      * @throws IndexOutOfBoundsException when index out of range (index &lt; 0 or index &gt;= size())
175      */
176     public final float getInUnit(final int index, final U targetUnit) throws IndexOutOfBoundsException
177     {
178         return (float) ValueUtil.expressAsUnit(getSI(index), targetUnit);
179     }
180 
181     /**
182      * Set the value, specified in the standard SI unit, at the specified position.
183      * @param index int; the index of the value to set
184      * @param valueSI float; the value, specified in the standard SI unit
185      * @throws IndexOutOfBoundsException when index out of range (index &lt; 0 or index &gt;= size())
186      */
187     public final void setSI(final int index, final float valueSI) throws IndexOutOfBoundsException
188     {
189         checkIndex(index);
190         checkCopyOnWrite();
191         getData().setSI(index, valueSI);
192     }
193 
194     /**
195      * Set the value, specified in the (current) display unit, at the specified position.
196      * @param index int; the index of the value to set
197      * @param valueInUnit float; the value, specified in the (current) display unit
198      * @throws IndexOutOfBoundsException when index out of range (index &lt; 0 or index &gt;= size())
199      */
200     public void setInUnit(final int index, final float valueInUnit) throws IndexOutOfBoundsException
201     {
202         setSI(index, (float) ValueUtil.expressAsSIUnit(valueInUnit, getDisplayUnit()));
203     }
204 
205     /**
206      * Set the value, specified in the <code>valueUnit</code>, at the specified position.
207      * @param index int; the index of the value to set
208      * @param valueInUnit float; the value, specified in the (current) display unit
209      * @param valueUnit U; the unit in which the <code>valueInUnit</code> is expressed
210      * @throws IndexOutOfBoundsException when index out of range (index &lt; 0 or index &gt;= size())
211      */
212     public void setInUnit(final int index, final float valueInUnit, final U valueUnit) throws IndexOutOfBoundsException
213     {
214         setSI(index, (float) ValueUtil.expressAsSIUnit(valueInUnit, valueUnit));
215     }
216 
217     /**
218      * Set the scalar value at the specified position.
219      * @param index int; the index of the value to set
220      * @param value S; the value to set
221      * @throws IndexOutOfBoundsException when index out of range (index &lt; 0 or index &gt;= size())
222      */
223     public void set(final int index, final S value) throws IndexOutOfBoundsException
224     {
225         setSI(index, value.si);
226     }
227 
228     @SuppressWarnings("unchecked")
229     @Override
230     public S[] getScalars()
231     {
232         S[] array = (S[]) Array.newInstance(getScalarClass(), size());
233         for (int i = 0; i < size(); i++)
234         {
235             array[i] = get(i);
236         }
237         return array;
238     }
239 
240     @SuppressWarnings("unchecked")
241     @Override
242     public V toSparse()
243     {
244         V result;
245         if (getStorageType().equals(StorageType.SPARSE))
246         {
247             result = (V) this;
248             result.setDisplayUnit(getDisplayUnit());
249         }
250         else
251         {
252             result = instantiateVector(getData().toSparse(), getDisplayUnit());
253         }
254         result.setDisplayUnit(getDisplayUnit());
255         return result;
256     }
257 
258     @SuppressWarnings("unchecked")
259     @Override
260     public V toDense()
261     {
262         V result;
263         if (getStorageType().equals(StorageType.DENSE))
264         {
265             result = (V) this;
266             result.setDisplayUnit(getDisplayUnit());
267         }
268         else
269         {
270             result = instantiateVector(getData().toDense(), getDisplayUnit());
271         }
272         return result;
273     }
274 
275     /**
276      * Execute a function on a cell by cell basis. Note: May be expensive when used on sparse data.
277      * @param floatFunction FloatFunction; the function to apply
278      * @return V; this updated vector
279      */
280     @SuppressWarnings("unchecked")
281     public final V assign(final FloatFunction floatFunction)
282     {
283         checkCopyOnWrite();
284         this.data.assign(floatFunction);
285         return (V) this;
286     }
287 
288     @Override
289     public final V abs()
290     {
291         return assign(FloatMathFunctions.ABS);
292     }
293 
294     @Override
295     public final V ceil()
296     {
297         return assign(FloatMathFunctions.CEIL);
298     }
299 
300     @Override
301     public final V floor()
302     {
303         return assign(FloatMathFunctions.FLOOR);
304     }
305 
306     @Override
307     public final V neg()
308     {
309         return assign(FloatMathFunctions.NEG);
310     }
311 
312     @Override
313     public final V rint()
314     {
315         return assign(FloatMathFunctions.RINT);
316     }
317 
318     @Override
319     public String toString()
320     {
321         return toString(getDisplayUnit(), false, true);
322     }
323 
324     @Override
325     public String toString(final U displayUnit)
326     {
327         return toString(displayUnit, false, true);
328     }
329 
330     @Override
331     public String toString(final boolean verbose, final boolean withUnit)
332     {
333         return toString(getDisplayUnit(), verbose, withUnit);
334     }
335 
336     @Override
337     public String toString(final U displayUnit, final boolean verbose, final boolean withUnit)
338     {
339         StringBuffer buf = new StringBuffer();
340         if (verbose)
341         {
342             String ar = this instanceof Absolute ? "Abs " : "Rel ";
343             String ds = getData().isDense() ? "Dense  " : getData().isSparse() ? "Sparse " : "?????? ";
344             if (isMutable())
345             {
346                 buf.append("Mutable   " + ar + ds);
347             }
348             else
349             {
350                 buf.append("Immutable " + ar + ds);
351             }
352         }
353         buf.append("[");
354         for (int i = 0; i < size(); i++)
355         {
356             try
357             {
358                 float f = (float) ValueUtil.expressAsUnit(getSI(i), displayUnit);
359                 buf.append(" " + Format.format(f));
360             }
361             catch (IndexOutOfBoundsException ve)
362             {
363                 buf.append(" " + "********************".substring(0, Format.DEFAULTSIZE));
364             }
365         }
366         buf.append("]");
367         if (withUnit)
368         {
369             buf.append(" " + displayUnit.getLocalizedDisplayAbbreviation());
370         }
371         return buf.toString();
372     }
373 
374     /**
375      * Centralized size equality check.
376      * @param other FloatVector&lt;?, ?, ?&gt;; other FloatVector
377      * @throws NullPointerException when other vector is null
378      * @throws ValueRuntimeException when vectors have unequal size
379      */
380     protected final void checkSize(final FloatVector<?, ?, ?> other) throws ValueRuntimeException
381     {
382         Throw.whenNull(other, "Other vector is null");
383         Throw.when(size() != other.size(), ValueRuntimeException.class, "The vectors have different sizes: %d != %d", size(),
384                 other.size());
385     }
386 
387     @Override
388     @SuppressWarnings("checkstyle:designforextension")
389     public int hashCode()
390     {
391         final int prime = 31;
392         int result = getDisplayUnit().getStandardUnit().hashCode();
393         result = prime * result + ((this.data == null) ? 0 : this.data.hashCode());
394         return result;
395     }
396 
397     @Override
398     @SuppressWarnings({"checkstyle:designforextension", "checkstyle:needbraces"})
399     public boolean equals(final Object obj)
400     {
401         if (this == obj)
402             return true;
403         if (obj == null)
404             return false;
405         if (getClass() != obj.getClass())
406             return false;
407         FloatVector<?, ?, ?> other = (FloatVector<?, ?, ?>) obj;
408         if (!getDisplayUnit().getStandardUnit().equals(other.getDisplayUnit().getStandardUnit()))
409             return false;
410         if (this.data == null)
411         {
412             if (other.data != null)
413                 return false;
414         }
415         else if (!this.data.equals(other.data))
416             return false;
417         return true;
418     }
419 
420     /* ============================================================================================ */
421     /* =============================== ITERATOR METHODS AND CLASS ================================= */
422     /* ============================================================================================ */
423 
424     @Override
425     public Iterator<S> iterator()
426     {
427         return new Itr();
428     }
429 
430     /**
431      * The iterator class is loosely based in AbstractList.Itr. It does not throw a ConcurrentModificationException, because the
432      * size of the vector does not change. Normal (non-mutable) vectors cannot change their size, nor their content. The only
433      * thing for the MutableVector that can change is its content, not its length.
434      */
435     protected class Itr implements Iterator<S>, Serializable
436     {
437         /** ... */
438         private static final long serialVersionUID = 20191018L;
439 
440         /** index of next element to return. */
441         private int cursor = 0;
442 
443         @Override
444         public boolean hasNext()
445         {
446             return this.cursor != size();
447         }
448 
449         @Override
450         public S next()
451         {
452             if (this.cursor >= size())
453             {
454                 throw new NoSuchElementException();
455             }
456             try
457             {
458                 int i = this.cursor;
459                 S next = get(i);
460                 this.cursor = i + 1;
461                 return next;
462             }
463             catch (IndexOutOfBoundsException exception)
464             {
465                 throw new RuntimeException(exception);
466             }
467         }
468 
469         @Override
470         public void remove()
471         {
472             throw new RuntimeException("Remove function cannot be applied on fixed-size DJUNITS Vector");
473         }
474 
475         @Override
476         public String toString()
477         {
478             return "Itr [cursor=" + this.cursor + "]";
479         }
480 
481     }
482 
483 }