forked from HebiRobotics/MFL
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Mat5.java
266 lines (216 loc) · 8.26 KB
/
Mat5.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
/*-
* #%L
* Mat-File IO
* %%
* Copyright (C) 2018 HEBI Robotics
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package us.hebi.matlab.mat.format;
import us.hebi.matlab.mat.util.Unsafe9R;
import us.hebi.matlab.mat.types.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
import static us.hebi.matlab.mat.types.AbstractArray.*;
/**
* Utility methods for creating Matlab classes that are compatible with
* the Mat 5 file format.
*
* @author Florian Enner
* @since 29 Aug 2018
*/
public class Mat5 {
// ------------------------- User-facing Factory API
public static Mat5File newMatFile() {
return new Mat5File();
}
public static Mat5Reader newReader(Source source) {
return new Mat5Reader(source);
}
public static Mat5Writer newWriter(Sink sink) {
return new Mat5Writer(sink);
}
public static int[] index(int rows, int cols) {
return new int[]{rows, cols};
}
public static int[] index(int rows, int cols, int... other) {
int[] dims = new int[other.length + 2];
dims[0] = rows;
dims[1] = cols;
System.arraycopy(other, 0, dims, 2, other.length);
return dims;
}
public static int[] dims(int rows, int cols) {
return index(rows, cols);
}
public static int[] dims(int rows, int cols, int... other) {
return index(rows, cols, other);
}
public static Cell newCell(int rows, int cols) {
return newCell(dims(rows, cols));
}
public static Cell newCell(int[] dims) {
return new MatCell(dims, false);
}
public static Struct newStruct() {
return newStruct(1, 1);
}
public static Struct newStruct(int rows, int cols) {
return newStruct(dims(rows, cols));
}
public static Struct newStruct(int[] dims) {
return new MatStruct(dims, false);
}
public static Char newChar(int rows, int cols) {
return newChar(dims(rows, cols));
}
public static Char newChar(int rows, int cols, CharEncoding encoding) {
return new MatChar(dims(rows, cols), encoding);
}
public static Char newChar(int[] dims) {
return newChar(dims, CharEncoding.Utf8);
}
public static Char newChar(int[] dims, CharEncoding encoding) {
return new MatChar(dims, encoding);
}
/**
* Creates a column character vector identical to the
* single quoted 'string' representation in MATLAB
*
* @param value input
* @return Char array
*/
public static Char newString(String value) {
return newString(value, CharEncoding.Utf8);
}
public static Char newString(String value, CharEncoding encoding) {
return new MatChar(new int[]{1, value.length()}, false, encoding, CharBuffer.wrap(value));
}
public static Matrix newLogicalScalar(boolean value) {
Matrix logical = newLogical(1, 1);
logical.setBoolean(0, value);
return logical;
}
public static Matrix newScalar(double value) {
Matrix matrix = newMatrix(1, 1);
matrix.setDouble(0, 0, value);
return matrix;
}
public static Matrix newComplexScalar(double real, double imaginary) {
Matrix complex = newComplex(1, 1);
complex.setDouble(0, real);
complex.setImaginaryDouble(0, imaginary);
return complex;
}
public static Matrix newLogical(int rows, int cols) {
return newLogical(dims(rows, cols));
}
public static Matrix newLogical(int[] dims) {
return newNumerical(dims, MatlabType.Int8, true, false);
}
public static Matrix newMatrix(int rows, int cols) {
return newMatrix(dims(rows, cols));
}
public static Matrix newMatrix(int[] dims) {
return newMatrix(dims, MatlabType.Double);
}
public static Matrix newMatrix(int rows, int cols, MatlabType type) {
return newMatrix(dims(rows, cols), type);
}
public static Matrix newMatrix(int[] dims, MatlabType type) {
return newNumerical(dims, type, false, false);
}
public static Matrix newComplex(int rows, int cols) {
return newComplex(dims(rows, cols));
}
public static Matrix newComplex(int rows, int cols, MatlabType type) {
return newComplex(dims(rows, cols), type);
}
public static Matrix newComplex(int[] dims) {
return newComplex(dims, MatlabType.Double);
}
public static Matrix newComplex(int[] dims, MatlabType type) {
return newNumerical(dims, type, false, true);
}
public static int getSerializedSize(String name, Array array) {
if (array instanceof Mat5Serializable) {
return ((Mat5Serializable) array).getMat5Size(name);
}
throw new IllegalArgumentException("Array does not support the MAT5 format");
}
private static Matrix newNumerical(int[] dims, MatlabType type, boolean logical, boolean complex) {
return newNumerical(dims, type, logical, complex, getDefaultBufferAllocator());
}
public static Matrix newNumerical(int[] dims, MatlabType type, boolean logical, boolean complex, BufferAllocator allocator) {
return new MatMatrix(dims, false, type, logical,
createStore(type, dims, allocator), complex ? createStore(type, dims, allocator) : null);
}
private static NumberStore createStore(MatlabType type, int[] dims, BufferAllocator bufferAllocator) {
Mat5Type tagType = Mat5Type.fromNumericalType(type);
int numBytes = getNumElements(dims) * tagType.bytes();
ByteBuffer buffer = bufferAllocator.allocate(numBytes);
return new UniversalNumberStore(tagType, buffer, bufferAllocator);
}
static BufferAllocator getDefaultBufferAllocator() {
return DEFAULT_BUFFER_ALLOCATOR;
}
/**
* Buffer allocator that gets used for all arrays, readers, and writers created
* in this class. If we find a valid use case for changing this, this may become
* settable in the future.
*/
private final static BufferAllocator DEFAULT_BUFFER_ALLOCATOR = new BufferAllocator() {
@Override
public ByteBuffer allocate(int numBytes) {
ByteBuffer buffer = numBytes <= 4096 ? // (arbitrary) threshold for staying on-heap
ByteBuffer.allocate(numBytes) : ByteBuffer.allocateDirect(numBytes);
buffer.order(DEFAULT_ORDER);
return buffer;
}
@Override
public void release(ByteBuffer buffer) {
if (buffer.isDirect()) {
Unsafe9R.invokeCleaner(buffer);
}
}
};
/**
* Currently just used internally for matrices that contain
* binary data that needs to be parsed (e.g. subsystem or
* Java serialization)
* <p>
* The buffer may be a direct buffer that may be closed by
* the holding Matrix, so the buffer should not be held on to
* or go into user managed space!
*
* @param matrix matrix
* @return internal matrix buffer
*/
static ByteBuffer exportBytes(Matrix matrix) {
if (matrix instanceof MatMatrix) {
MatMatrix matMatrix = (MatMatrix) matrix;
if (matMatrix.getRealStore() instanceof UniversalNumberStore)
return ((UniversalNumberStore) matMatrix.getRealStore()).getByteBuffer();
}
throw new IllegalStateException("Not implemented for input type");
}
public static final Array EMPTY_MATRIX = newMatrix(0, 0);
public static final ByteOrder DEFAULT_ORDER = ByteOrder.nativeOrder();
private Mat5() {
}
public static final int MATRIX_TAG_SIZE = 8; // no padding as all sub-fields are already padded
public static final int FILE_HEADER_SIZE = 116 + 8 + 2 + 2;
public static final int REDUCED_FILE_HEADER_SIZE = 2 + 2 + 4 /* padding */;
}