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