View Javadoc
1   package org.djutils.serialization.serializers;
2   
3   import java.lang.reflect.Constructor;
4   import java.lang.reflect.InvocationTargetException;
5   import java.util.HashMap;
6   import java.util.Map;
7   
8   import org.djunits.unit.SIUnit;
9   import org.djunits.unit.Unit;
10  import org.djunits.unit.scale.IdentityScale;
11  import org.djunits.unit.util.UnitRuntimeException;
12  import org.djunits.value.ValueRuntimeException;
13  import org.djunits.value.storage.StorageType;
14  import org.djunits.value.vdouble.matrix.SIMatrix;
15  import org.djunits.value.vdouble.matrix.base.DoubleMatrix;
16  import org.djunits.value.vdouble.matrix.data.DoubleMatrixData;
17  import org.djunits.value.vdouble.scalar.base.DoubleScalar;
18  import org.djunits.value.vdouble.vector.base.DoubleVector;
19  import org.djutils.serialization.EndianUtil;
20  import org.djutils.serialization.FieldTypes;
21  import org.djutils.serialization.SerializationException;
22  
23  /**
24   * (De)serializes a DJUNITS DoubleMatrix.
25   * <p>
26   * Copyright (c) 2019-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
27   * BSD-style license. See <a href="https://djunits.org/docs/license.html">DJUNITS License</a>.
28   * </p>
29   * @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a>
30   * @param <U> the unit type
31   * @param <S> the scalar type
32   * @param <V> the vector type
33   * @param <M> the matrix type
34   */
35  public class DoubleMatrixSerializer<U extends Unit<U>, S extends DoubleScalar<U, S>, V extends DoubleVector<U, S, V>,
36          M extends DoubleMatrix<U, S, V, M>> extends ArrayOrMatrixWithUnitSerializer<U, M>
37  {
38      /** The cache to make the lookup of the constructor for a Vevtor belonging to a unit faster. */
39      private static final Map<Unit<?>, Constructor<? extends DoubleMatrix<?, ?, ?, ?>>> CACHE = new HashMap<>();
40  
41      /** */
42      public DoubleMatrixSerializer()
43      {
44          super(FieldTypes.DOUBLE_64_UNIT_MATRIX, "Djunits_DoubleMatrix", 2);
45      }
46  
47      @Override
48      public int size(final M adm) throws SerializationException
49      {
50          try
51          {
52              return 4 + 4 + 2 + 8 * adm.rows() * adm.cols();
53          }
54          catch (ValueRuntimeException e)
55          {
56              throw new SerializationException(e);
57          }
58      }
59  
60      @Override
61      public void serialize(final M adm, final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
62              throws SerializationException
63      {
64          try
65          {
66              endianUtil.encodeInt(adm.rows(), buffer, pointer.getAndIncrement(4));
67              endianUtil.encodeInt(adm.cols(), buffer, pointer.getAndIncrement(4));
68              encodeUnit(adm.getDisplayUnit(), buffer, pointer, endianUtil);
69              for (int i = 0; i < adm.rows(); i++)
70              {
71                  for (int j = 0; j < adm.cols(); j++)
72                  {
73                      endianUtil.encodeDouble(adm.get(i, j).getSI(), buffer, pointer.getAndIncrement(8));
74                  }
75              }
76          }
77          catch (ValueRuntimeException e)
78          {
79              throw new SerializationException(e);
80          }
81      }
82  
83      @Override
84      public M deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil) throws SerializationException
85      {
86          try
87          {
88              int height = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
89              int width = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
90              Unit<? extends Unit<?>> unit = getUnit(buffer, pointer, endianUtil);
91              double[][] array = new double[height][width];
92              for (int i = 0; i < height; i++)
93              {
94                  for (int j = 0; j < width; j++)
95                  {
96                      array[i][j] = endianUtil.decodeDouble(buffer, pointer.getAndIncrement(8));
97                  }
98              }
99              DoubleMatrixData fvd = DoubleMatrixData.instantiate(array, IdentityScale.SCALE, StorageType.DENSE);
100             return instantiateAnonymous(fvd, unit);
101         }
102         catch (ValueRuntimeException exception)
103         {
104             throw new SerializationException(exception);
105         }
106     }
107 
108     /**
109      * Instantiate the DoubleMatrix based on its unit. Loose check for types on the compiler. This allows the unit to be
110      * specified as a Unit&lt;?&gt; type.<br>
111      * <b>Note</b> that it is possible to make mistakes with anonymous units.
112      * @param data DoubleMatrixData; the values
113      * @param unit Unit&lt;?&gt;; the unit in which the value is expressed
114      * @return M; an instantiated DoubleMatrix with the provided displayUunit
115      * @param <U> the unit type
116      * @param <S> the scalar type
117      * @param <V> the vector type
118      * @param <M> the matrix type
119      */
120     @SuppressWarnings("unchecked")
121     public static <U extends Unit<U>, S extends DoubleScalar<U, S>, V extends DoubleVector<U, S, V>,
122             M extends DoubleMatrix<U, S, V, M>> M instantiateAnonymous(final DoubleMatrixData data, final Unit<?> unit)
123     {
124         try
125         {
126             Constructor<? extends DoubleMatrix<?, ?, ?, ?>> matrixConstructor = CACHE.get(unit);
127             if (matrixConstructor == null)
128             {
129                 if (!unit.getClass().getSimpleName().endsWith("Unit"))
130                 {
131                     throw new ClassNotFoundException("Unit " + unit.getClass().getSimpleName()
132                             + " name does noet end with 'Unit'. Cannot find corresponding scalar");
133                 }
134                 Class<? extends DoubleMatrix<?, ?, ?, ?>> matrixClass;
135                 if (unit instanceof SIUnit)
136                 {
137                     matrixClass = SIMatrix.class;
138                 }
139                 else
140                 {
141                     matrixClass = (Class<DoubleMatrix<?, ?, ?, ?>>) Class.forName("org.djunits.value.vdouble.matrix."
142                             + unit.getClass().getSimpleName().replace("Unit", "") + "Matrix");
143                 }
144                 matrixConstructor = matrixClass.getDeclaredConstructor(DoubleMatrixData.class, unit.getClass());
145                 CACHE.put(unit, matrixConstructor);
146             }
147             return (M) matrixConstructor.newInstance(data, unit);
148         }
149         catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException
150                 | IllegalAccessException | IllegalArgumentException | InvocationTargetException exception)
151         {
152             throw new UnitRuntimeException(
153                     "Cannot instantiate DoubleMatrix of unit " + unit.toString() + ". Reason: " + exception.getMessage());
154         }
155     }
156 
157 }