View Javadoc
1   package org.djunits.value;
2   
3   import org.djunits.unit.Unit;
4   import org.djunits.value.base.Scalar;
5   import org.djunits.value.storage.Storage;
6   import org.djunits.value.storage.StorageType;
7   import org.djutils.exceptions.Throw;
8   
9   /**
10   * AbstractIndexedValue.java.
11   * <p>
12   * Copyright (c) 2019-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
13   * BSD-style license. See <a href="https://djunits.org/docs/license.html">DJUNITS License</a>.
14   * </p>
15   * @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a>
16   * @param <U> the unit type
17   * @param <S> the scalar type for the U unit
18   * @param <T> the value type for this unit
19   * @param <D> the data storage type
20   */
21  public abstract class IndexedValue<U extends Unit<U>, S extends Scalar<U, S>,
22          T extends IndexedValue<U, S, T, D>, D extends Storage<D>> implements Value<U, T>
23  {
24      /** */
25      private static final long serialVersionUID = 20190927L;
26  
27      /** The display unit of this AbstractValue. */
28      private U displayUnit;
29  
30      /** If set, any modification of the data must be preceded by replacing the data with a local copy. */
31      private boolean copyOnWrite = false;
32  
33      /** helper flag to indicate whether the data is mutable or not. */
34      private boolean mutable = false;
35  
36      /**
37       * Construct a new IndexedValue.
38       * @param displayUnit U; the unit of the new AbstractValue
39       */
40      public IndexedValue(final U displayUnit)
41      {
42          Throw.whenNull(displayUnit, "display unit cannot be null");
43          this.displayUnit = displayUnit;
44      }
45  
46      @Override
47      public final U getDisplayUnit()
48      {
49          return this.displayUnit;
50      }
51  
52      @Override
53      public void setDisplayUnit(final U newUnit)
54      {
55          Throw.whenNull(newUnit, "newUnit may not be null");
56          this.displayUnit = newUnit;
57      }
58  
59      /**
60       * Retrieve the data object. Method can only be used within package and by subclasses.
61       * @return D; the internal data
62       */
63      protected abstract D getData();
64  
65      /**
66       * Set the data object. Method can only be used within package and by subclasses.
67       * @param data D; the internal data
68       */
69      protected abstract void setData(D data);
70  
71      /**
72       * Return the StorageType (DENSE, SPARSE, etc.) for the stored vector.
73       * @return StorageType; the storage type (DENSE, SPARSE, etc.) for the stored vector
74       */
75      public final StorageType getStorageType()
76      {
77          return getData().getStorageType();
78      }
79  
80      /**
81       * Check the copyOnWrite flag and, if it is set, make a deep copy of the data and clear the flag.
82       * @throws ValueRuntimeException if the vector is immutable
83       */
84      protected final void checkCopyOnWrite()
85      {
86          Throw.when(!this.mutable, ValueRuntimeException.class, "Immutable Vector cannot be modified");
87          if (isCopyOnWrite())
88          {
89              setData(getData().copy());
90              setCopyOnWrite(false);
91          }
92      }
93  
94      /**
95       * Retrieve the value of the copyOnWrite flag.
96       * @return boolean
97       */
98      protected final boolean isCopyOnWrite()
99      {
100         return this.copyOnWrite;
101     }
102 
103     /**
104      * Change the copyOnWrite flag.
105      * @param copyOnWrite boolean; the new value for the copyOnWrite flag
106      */
107     protected final void setCopyOnWrite(final boolean copyOnWrite)
108     {
109         this.copyOnWrite = copyOnWrite;
110     }
111 
112     /**
113      * Return whether the data is mutable or not.
114      * @return boolean; whether the data is mutable or not
115      */
116     public final boolean isMutable()
117     {
118         return this.mutable;
119     }
120 
121     /**
122      * Set helper flag to indicate whether the data is mutable or not.
123      * @param mutable boolean; helper flag to indicate whether the data is mutable or not
124      */
125     protected final void setMutable(final boolean mutable)
126     {
127         this.mutable = mutable;
128     }
129 
130     /**
131      * Turn the immutable flag on for this vector.
132      * @return T; the vector with a raised immutable flag
133      */
134     public final T immutable()
135     {
136         if (isMutable())
137         {
138             setCopyOnWrite(true);
139         }
140         T result = clone();
141         result.setCopyOnWrite(false);
142         result.setMutable(false);
143         return result;
144     }
145 
146     /**
147      * Turn the immutable flag off for this internal storage.
148      * @return T; the internal storage with a cleared immutable flag
149      */
150     public final T mutable()
151     {
152         if (isMutable())
153         {
154             setCopyOnWrite(true);
155         }
156         T result = clone();
157         result.setCopyOnWrite(true);
158         result.setMutable(true);
159         return result;
160     }
161 
162     /**
163      * Return whether the internal storage type of the indexed value is dense or not.
164      * @return boolean; whether the internal storage type of the indexed value is dense or not
165      */
166     public final boolean isDense()
167     {
168         return getData().isDense();
169     }
170 
171     /**
172      * Return whether the internal storage type of the indexed value is sparse or not.
173      * @return boolean; whether the internal storage type of the indexed value is sparse or not
174      */
175     public final boolean isSparse()
176     {
177         return getData().isSparse();
178     }
179 
180     /**
181      * Count the number of cells that have a non-zero SI value.
182      * @return int; the number of cells having non-zero SI value
183      */
184     public final int cardinality()
185     {
186         return getData().cardinality();
187     }
188 
189     /**
190      * Create and return a dense version of this internal storage. When the data was already dense, the current version is
191      * returned and no copy will be made of the data.
192      * @return T; a dense version of this internal storage
193      */
194     public abstract T toDense();
195 
196     /**
197      * Create and return a sparse version of this internal storage. When the data was already sparse, the current version is
198      * returned and no copy will be made of the data.
199      * @return T; a sparse version of this internal storage
200      */
201     public abstract T toSparse();
202 
203     /**
204      * Return the class of the corresponding scalar.
205      * @return Class&lt;S&gt;; the class of the corresponding scalar
206      */
207     public abstract Class<S> getScalarClass();
208 
209     @SuppressWarnings("unchecked")
210     @Override
211     public T clone()
212     {
213         try
214         {
215             T result = (T) super.clone();
216             result.setData(getData().copy());
217             result.setCopyOnWrite(false);
218             return result;
219         }
220         catch (CloneNotSupportedException exception)
221         {
222             throw new RuntimeException(exception);
223         }
224     }
225 
226 }