File: Shaper.java

package info (click to toggle)
jcdf 1.2.5%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 572 kB
  • sloc: java: 5,315; makefile: 198; sh: 98
file content (373 lines) | stat: -rw-r--r-- 12,575 bytes parent folder | download | duplicates (4)
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
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
package uk.ac.bristol.star.cdf;

import java.lang.reflect.Array;
import java.util.Arrays;

/**
 * Takes care of turning raw variable record values into shaped
 * record values.  The raw values are those stored in the CDF data stream,
 * and the shaped ones are those notionally corresponding to record values.
 *
 * @author   Mark Taylor
 * @since    20 Jun 2013
 */
public abstract class Shaper {

    private final int[] dimSizes_;
    private final boolean[] dimVarys_;

    /**
     * Constructor.
     *
     * @param   dimSizes  dimensionality of shaped array
     * @param   dimVarys  for each dimension, true for varying, false for fixed
     */
    protected Shaper( int[] dimSizes, boolean[] dimVarys ) {
        dimSizes_ = dimSizes;
        dimVarys_ = dimVarys;
    }

    /**
     * Returns the number of array elements in the raw value array.
     *
     * @return  raw value array size
     */
    public abstract int getRawItemCount();

    /**
     * Returns the number of array elements in the shaped value array.
     *
     * @return  shaped value array size
     */
    public abstract int getShapedItemCount();

    /** 
     * Returns the dimensions of the notional array.
     *
     * @return   dimension sizes array
     */
    public int[] getDimSizes() {
        return dimSizes_;
    }

    /**
     * Returns the dimension variances of the array.
     *
     * @return   for each dimension, true if the data varies, false if fixed
     */
    public boolean[] getDimVarys() {
        return dimVarys_;
    }

    /**
     * Returns the data type of the result of the {@link #shape shape} method.
     *
     * @return  shaped value class
     */
    public abstract Class<?> getShapeClass();

    /**
     * Takes a raw value array and turns it into an object of
     * the notional shape for this shaper.
     * The returned object is new; it is not rawValue.
     *
     * @param   rawValue  input raw value array
     * @return  rowMajor  required majority for result;
     *                    true for row major, false for column major
     */
    public abstract Object shape( Object rawValue, boolean rowMajor );

    /**
     * Returns the index into the raw value array at which the value for
     * the given element of the notional array can be found.
     *
     * @param   coords  coordinate array, same length as dimensionality
     * @return  index into raw value array
     */
    public abstract int getArrayIndex( int[] coords );

    /**
     * Returns an appropriate shaper instance.
     *
     * @param   dataType  data type
     * @param   dimSizes  dimensions of notional shaped array
     * @param   dimVarys  variances of shaped array
     * @param   rowMajor  majority of raw data array;
     *                    true for row major, false for column major
     */
    public static Shaper createShaper( DataType dataType,
                                       int[] dimSizes, boolean[] dimVarys,
                                       boolean rowMajor ) {
        int rawItemCount = 1;
        int shapedItemCount = 1;
        int nDimVary = 0;
        int ndim = dimSizes.length;
        for ( int idim = 0; idim < dimSizes.length; idim++ ) {
            int dimSize = dimSizes[ idim ];
            shapedItemCount *= dimSize;
            if ( dimVarys[ idim ] ) {
                nDimVary++;
                rawItemCount *= dimSize;
            }
        }
        if ( shapedItemCount == 1 ) {
            return new ScalarShaper( dataType );
        }
        else if ( ndim == 1  && nDimVary == 1 ) {
            assert Arrays.equals( dimVarys, new boolean[] { true } ); 
            assert Arrays.equals( dimSizes, new int[] { rawItemCount } );
            return new VectorShaper( dataType, rawItemCount );
        }
        else if ( nDimVary == ndim ) {
            return new SimpleArrayShaper( dataType, dimSizes, rowMajor );
        }
        else {
            return new GeneralShaper( dataType, dimSizes, dimVarys, rowMajor );
        }
    }

    /**
     * Shaper implementation for scalar values.  Easy.
     */
    private static class ScalarShaper extends Shaper {
        private final DataType dataType_;

        /**
         * Constructor.
         *
         * @param  dataType  data type
         */
        ScalarShaper( DataType dataType ) {
            super( new int[ 0 ], new boolean[ 0 ] );
            dataType_ = dataType;
        }
        public int getRawItemCount() {
            return 1;
        }
        public int getShapedItemCount() {
            return 1;
        }
        public Class<?> getShapeClass() {
            return dataType_.getScalarClass();
        }
        public Object shape( Object rawValue, boolean rowMajor ) {
            return dataType_.getScalar( rawValue, 0 );
        }
        public int getArrayIndex( int[] coords ) {
            for ( int i = 0; i < coords.length; i++ ) {
                if ( coords[ i ] != 0 ) {
                    throw new IllegalArgumentException( "Out of bounds" );
                }
            }
            return 0;
        }
    }

    /**
     * Shaper implementation for 1-dimensional arrays with true dimension
     * variance along the single dimension.
     * No need to worry about majority, since the question doesn't arise
     * in one dimension.
     */
    private static class VectorShaper extends Shaper {
        private final DataType dataType_;
        private final int itemCount_;
        private final int step_;
        private final Class<?> shapeClass_;

        /**
         * Constructor.
         *
         * @param  dataType  data type
         * @param  itemCount   number of elements in raw and shaped arrays
         */
        VectorShaper( DataType dataType, int itemCount ) {
            super( new int[] { itemCount }, new boolean[] { true } );
            dataType_ = dataType;
            itemCount_ = itemCount;
            step_ = dataType.getGroupSize();
            shapeClass_ = getArrayClass( dataType.getArrayElementClass() );
        }
        public int getRawItemCount() {
            return itemCount_;
        }
        public int getShapedItemCount() {
            return itemCount_;
        }
        public Class<?> getShapeClass() {
            return shapeClass_;
        }
        public Object shape( Object rawValue, boolean rowMajor ) {
            Object out = Array.newInstance( dataType_.getArrayElementClass(),
                                            itemCount_ );

            // Contract requires that we return a new object.
            System.arraycopy( rawValue, 0, out, 0, itemCount_ );
            return out;
        }
        public int getArrayIndex( int[] coords ) {
            return coords[ 0 ] * step_;
        }
    }

    /**
     * Shaper implementation that can deal with multiple dimensions,
     * majority switching, and dimension variances,
     */
    private static class GeneralShaper extends Shaper {

        private final DataType dataType_;
        private final int[] dimSizes_;
        private final boolean rowMajor_;
        private final int ndim_;
        private final int rawItemCount_;
        private final int shapedItemCount_;
        private final int[] strides_;
        private final int itemSize_;
        private final Class<?> shapeClass_;
        
        /**
         * Constructor.
         *
         * @param   dataType  data type
         * @param   dimSizes  dimensionality of shaped array
         * @param   dimVarys  variances of shaped array
         * @param   rowMajor  majority of raw data array;
         *                    true for row major, false for column major
         */
        GeneralShaper( DataType dataType, int[] dimSizes, boolean[] dimVarys,
                       boolean rowMajor ) {
            super( dimSizes, dimVarys );
            dataType_ = dataType;
            dimSizes_ = dimSizes;
            rowMajor_ = rowMajor;
            ndim_ = dimSizes.length;

            int rawItemCount = 1;
            int shapedItemCount = 1;
            int nDimVary = 0;
            int ndim = dimSizes.length;
            strides_ = new int[ ndim_ ];
            for ( int idim = 0; idim < ndim_; idim++ ) {
                int jdim = rowMajor ? ndim_ - idim - 1 : idim;
                int dimSize = dimSizes[ jdim ];
                shapedItemCount *= dimSize;
                if ( dimVarys[ jdim ] ) {
                    nDimVary++;
                    strides_[ jdim ] = rawItemCount;
                    rawItemCount *= dimSize;
                }
            }
            rawItemCount_ = rawItemCount;
            shapedItemCount_ = shapedItemCount;
            itemSize_ = dataType_.getGroupSize();
            shapeClass_ = getArrayClass( dataType.getArrayElementClass() );
        }

        public int getRawItemCount() {
            return rawItemCount_;
        }

        public int getShapedItemCount() {
            return shapedItemCount_;
        }

        public int getArrayIndex( int[] coords ) {
            int index = 0;
            for ( int idim = 0; idim < ndim_; idim++ ) {
                index += coords[ idim ] * strides_[ idim ];
            }
            return index * itemSize_;
        }

        public Class<?> getShapeClass() {
            return shapeClass_;
        }

        public Object shape( Object rawValue, boolean rowMajor ) {
            Object out = Array.newInstance( dataType_.getArrayElementClass(),
                                            shapedItemCount_ * itemSize_ );
            int[] coords = new int[ ndim_ ];
            Arrays.fill( coords, -1 );
            for ( int ix = 0; ix < shapedItemCount_; ix++ ) {
                for ( int idim = 0; idim < ndim_; idim++ ) {
                    int jdim = rowMajor ? ndim_ - idim - 1 : idim;
                    coords[ jdim ] = ( coords[ jdim ] + 1 ) % dimSizes_[ jdim ];
                    if ( coords[ jdim ] != 0 ) {
                        break;
                    }
                }
                System.arraycopy( rawValue, getArrayIndex( coords ),
                                  out, ix * itemSize_, itemSize_ );
            }
            return out;
        }
    }

    /**
     * Shaper implementation that can deal with multiple dimensions and
     * majority switching, but not false dimension variances.
     */
    private static class SimpleArrayShaper extends GeneralShaper {

        private final DataType dataType_;
        private final boolean rowMajor_;

        /**
         * Constructor.
         *
         * @param   dataType  data type
         * @param   dimSizes  dimensionality of shaped array
         * @param   rowMajor  majority of raw data array;
         *                    true for row major, false for column major
         */
        public SimpleArrayShaper( DataType dataType, int[] dimSizes,
                                  boolean rowMajor ) {
            super( dataType, dimSizes, trueArray( dimSizes.length ),
                   rowMajor );
            dataType_ = dataType;
            rowMajor_ = rowMajor;
        }

        public Object shape( Object rawValue, boolean rowMajor ) {
            if ( rowMajor == rowMajor_ ) {
                int count = Array.getLength( rawValue );
                Object out =
                    Array.newInstance( dataType_.getArrayElementClass(),
                                       count );
                System.arraycopy( rawValue, 0, out, 0, count );
                return out;
            }
            else {
                // Probably there's a more efficient way to do this -
                // it's an n-dimensional generalisation of transposing
                // a matrix (though don't forget to keep units of
                // groupSize intact).
                return super.shape( rawValue, rowMajor );
            }
        }

        /**
         * Utility method that returns a boolean array of a given size
         * populated with true values.
         *
         * @param  n  size
         * @return   n-element array filled with true
         */
        private static boolean[] trueArray( int n ) {
            boolean[] a = new boolean[ n ];
            Arrays.fill( a, true );
            return a;
        }
    }

    /**
     * Returns the array class corresponding to a given scalar class.
     *
     * @param  elementClass  scalar class
     * @return   array class
     */
    private static Class<?> getArrayClass( Class elementClass ) {
        return Array.newInstance( elementClass, 0 ).getClass();
    }
}