1 /*
2  * Copyright 2016 CodiLime
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 #pragma once
18 
19 #include "data/bindata.h"
20 #include "models.h"
21 
22 namespace veles {
23 namespace data {
24 
25 /** Represents data repacking format.  */
26 class Repacker : public RepackerModel {
27  public:
28   explicit Repacker(Endian endian = Endian::LITTLE, uint64_t from_width = 8,
29                     uint64_t to_width = 8, uint64_t high_pad = 0,
30                     uint64_t low_pad = 0)
RepackerModel(endian,from_width,to_width,high_pad,low_pad)31       : RepackerModel(endian, from_width, to_width, high_pad, low_pad) {}
32   using RepackerModel::RepackerModel;
33 
34   /** Element width, including padding.  */
paddedWidth()35   unsigned paddedWidth() const { return to_width + high_pad + low_pad; }
36 
37   /** Returns repacking unit for given format, ie. lowest common multiple
38       of source and padded destination widths in bits.  */
39   unsigned repackUnit() const;
40 
41   /** Returns the number of source elements that would be read to perform
42       the given repacking.  This is equal to
43       ceil(paddedWidth() * num_elements / from_width).  */
44   size_t repackSize(size_t num_elements) const;
45 
46   /** Returns the number of destination elements that can be retrieved
47       from the given source with the given repacking.  This is equal to
48       floor(from_width * src_size / paddedWidth()).  */
49   size_t repackableSize(size_t src_size) const;
50 
51   /** Repacks binary data to a different element width.  Repacking conceptually
52       works as follows:
53 
54       1. All source elements starting from the given index, are glued
55          together to form a big string of bits.  If LITTLE endian is selected,
56          lower-indexed elements are less significant in the resulting
57          string, otherwise they are more significant.
58       2. Starting from LSB (for LITTLE endian) or MSB (for BIG
59          endian) of the resulting string, num_elements * (format.width +
60          format.lowPad + format.highPad) bits are extracted and cut into
61          num_elements pieces (again ordered according to the selected
62          endian).
63       3. From each of the num_element pieces, high highPad and low lowPad bits
64          are cut off, and the rest is returned as the result.
65 
66       Of course, the actual repacking operation only reads as many source
67       elements as are actually necessary to determine the output.  This number
68       can be determined by the repackSize() function.  It is an error if fewer
69       elements than that are available in the source.  */
70   BinData repack(const BinData& src, size_t start, size_t num_elements) const;
71 };
72 
73 }  // namespace data
74 }  // namespace veles
75