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.vfloat.matrix.FloatSIMatrix;
15  import org.djunits.value.vfloat.matrix.base.FloatMatrix;
16  import org.djunits.value.vfloat.matrix.data.FloatMatrixData;
17  import org.djunits.value.vfloat.scalar.base.FloatScalar;
18  import org.djunits.value.vfloat.vector.base.FloatVector;
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 FloatMatrix.
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 FloatMatrixSerializer<U extends Unit<U>, S extends FloatScalar<U, S>, V extends FloatVector<U, S, V>,
36          M extends FloatMatrix<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 FloatMatrix<?, ?, ?, ?>>> CACHE = new HashMap<>();
40  
41      /** */
42      public FloatMatrixSerializer()
43      {
44          super(FieldTypes.FLOAT_32_UNIT_MATRIX, "Djunits_FloatMatrix", 2);
45      }
46  
47      @Override
48      public int size(final M afm) throws SerializationException
49      {
50          try
51          {
52              return 4 + 4 + 2 + 4 * afm.rows() * afm.cols();
53          }
54          catch (ValueRuntimeException e)
55          {
56              throw new SerializationException(e);
57          }
58      }
59  
60      @Override
61      public void serialize(final M afm, final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
62              throws SerializationException
63      {
64          try
65          {
66              endianUtil.encodeInt(afm.rows(), buffer, pointer.getAndIncrement(4));
67              endianUtil.encodeInt(afm.cols(), buffer, pointer.getAndIncrement(4));
68              encodeUnit(afm.getDisplayUnit(), buffer, pointer, endianUtil);
69              for (int i = 0; i < afm.rows(); i++)
70              {
71                  for (int j = 0; j < afm.cols(); j++)
72                  {
73                      endianUtil.encodeFloat(afm.get(i, j).getSI(), buffer, pointer.getAndIncrement(4));
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          int height = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
87          int width = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
88          Unit<? extends Unit<?>> unit = getUnit(buffer, pointer, endianUtil);
89          float[][] array = new float[height][width];
90          for (int i = 0; i < height; i++)
91          {
92              for (int j = 0; j < width; j++)
93              {
94                  array[i][j] = endianUtil.decodeFloat(buffer, pointer.getAndIncrement(4));
95              }
96          }
97          try
98          {
99              FloatMatrixData fvd = FloatMatrixData.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 FloatMatrix 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 FloatMatrixData; the values
113      * @param unit Unit&lt;?&gt;; the unit in which the value is expressed
114      * @return M; an instantiated FloatMatrix 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 FloatScalar<U, S>, V extends FloatVector<U, S, V>,
122             M extends FloatMatrix<U, S, V, M>> M instantiateAnonymous(final FloatMatrixData data, final Unit<?> unit)
123     {
124         try
125         {
126             Constructor<? extends FloatMatrix<?, ?, ?, ?>> 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 FloatMatrix<?, ?, ?, ?>> matrixClass;
135                 if (unit instanceof SIUnit)
136                 {
137                     matrixClass = FloatSIMatrix.class;
138                 }
139                 else
140                 {
141                     matrixClass = (Class<FloatMatrix<?, ?, ?, ?>>) Class.forName("org.djunits.value.vfloat.matrix.Float"
142                             + unit.getClass().getSimpleName().replace("Unit", "") + "Matrix");
143                 }
144                 matrixConstructor = matrixClass.getDeclaredConstructor(FloatMatrixData.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 FloatMatrix of unit " + unit.toString() + ". Reason: " + exception.getMessage());
154         }
155     }
156 
157 }