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