passhash/include/nil/crypto3/detail/pack.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2018-2020 Mikhail Komarov <nemo@nil.foundation>
3 //
4 // MIT License
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in all
14 // copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 // SOFTWARE.
23 //---------------------------------------------------------------------------//
24 
25 #ifndef CRYPTO3_PACK_HPP
26 #define CRYPTO3_PACK_HPP
27 
28 #include <nil/crypto3/detail/type_traits.hpp>
29 #include <nil/crypto3/detail/stream_endian.hpp>
30 #include <nil/crypto3/detail/exploder.hpp>
31 #include <nil/crypto3/detail/imploder.hpp>
32 #include <nil/crypto3/detail/predef.hpp>
33 
34 #include <boost/assert.hpp>
35 #include <boost/static_assert.hpp>
36 
37 #ifndef CRYPTO3_NO_OPTIMIZATION
38 
39 #include <boost/endian.hpp>
40 #include <boost/utility/enable_if.hpp>
41 
42 #endif
43 
44 namespace nil {
45  namespace crypto3 {
46  namespace detail {
47 #ifndef CRYPTO3_NO_OPTIMIZATION
48 
49  template<int UnitBits, int InputBits, int OutputBits, typename InT, typename OutT>
50  struct host_can_memcpy {
51  constexpr static const bool value = !(UnitBits % CHAR_BIT) && InputBits >= UnitBits &&
52  OutputBits >= UnitBits && sizeof(InT) * CHAR_BIT == InputBits &&
53  sizeof(OutT) * CHAR_BIT == OutputBits;
54  };
55 
56  template<typename Endianness, int InputBits, int OutputBits, typename InT, typename OutT>
57  struct can_memcpy {
58  constexpr static const bool value = InputBits == OutputBits && sizeof(InT) == sizeof(OutT);
59  };
60 
61  template<int UnitBits, int InputBits, int OutputBits, typename InT, typename OutT>
62  struct can_memcpy<stream_endian::host_unit<UnitBits>, InputBits, OutputBits, InT, OutT>
63  : host_can_memcpy<UnitBits, InputBits, OutputBits, InT, OutT> {};
64 
65 #ifdef BOOST_ENDIAN_LITTLE_BYTE_AVAILABLE
66  template<int UnitBits, int InputBits, int OutputBits, typename InT, typename OutT>
67  struct can_memcpy<stream_endian::little_unit_big_bit<UnitBits>, InputBits, OutputBits, InT, OutT>
68  : host_can_memcpy<UnitBits, InputBits, OutputBits, InT, OutT> {};
69  template<int UnitBits, int InputBits, int OutputBits, typename InT, typename OutT>
70  struct can_memcpy<stream_endian::little_unit_little_bit<UnitBits>, InputBits, OutputBits, InT, OutT>
71  : host_can_memcpy<UnitBits, InputBits, OutputBits, InT, OutT> {};
72 #endif
73 
74 #ifdef CRYPTO3_TARGET_CPU_IS_BIG_ENDIAN
75  template<int UnitBits, int InputBits, int OutputBits, typename InT, typename OutT>
76  struct can_memcpy<stream_endian::big_unit_big_bit<UnitBits>, InputBits, OutputBits, InT, OutT>
77  : host_can_memcpy<UnitBits, InputBits, OutputBits, InT, OutT> {};
78  template<int UnitBits, int InputBits, int OutputBits, typename InT, typename OutT>
79  struct can_memcpy<stream_endian::big_unit_little_bit<UnitBits>, InputBits, OutputBits, InT, OutT>
80  : host_can_memcpy<UnitBits, InputBits, OutputBits, InT, OutT> {};
81 #endif
82 
83 #endif
84 
85  template<typename Endianness, int InputBits, int OutputBits, bool Explode = (InputBits > OutputBits),
86  bool Implode = (InputBits < OutputBits)>
87  struct real_packer;
88 
89  template<typename Endianness, int Bits>
90  struct real_packer<Endianness, Bits, Bits, false, false> {
91 
92  template<typename InIter, typename OutIter>
93  inline static void pack_n(InIter in, size_t in_n, OutIter out) {
94  std::copy(in, in + in_n, out);
95  }
96 
97  template<typename InIter, typename OutIter>
98  inline static void pack(InIter in, InIter in_e, OutIter out) {
99  std::copy(in, in_e, out);
100  }
101  };
102 
103  template<typename Endianness, int InputBits, int OutputBits>
104  struct real_packer<Endianness, InputBits, OutputBits, true, false> {
105 
106  BOOST_STATIC_ASSERT(InputBits % OutputBits == 0);
107 
108  template<typename InIter, typename OutIter>
109  inline static void pack_n(InIter in, size_t in_n, OutIter out) {
110  while (in_n--) {
111  typedef typename std::iterator_traits<InIter>::value_type InValue;
112  InValue const value = *in++;
114  }
115  }
116 
117  template<typename InIter, typename OutIter>
118  inline static void pack(InIter in, InIter in_e, OutIter out) {
119  while (in != in_e) {
120  typedef typename std::iterator_traits<InIter>::value_type InValue;
121  InValue const value = *in++;
123  }
124  }
125  };
126 
127  template<typename Endianness, int InputBits, int OutputBits>
128  struct real_packer<Endianness, InputBits, OutputBits, false, true> {
129 
130  BOOST_STATIC_ASSERT(OutputBits % InputBits == 0);
131 
132  template<typename InIter, typename OutIter>
133  inline static void pack_n(InIter in, size_t in_n, OutIter out) {
134  size_t out_n = in_n / (OutputBits / InputBits);
135  while (out_n--) {
136  typedef typename detail::outvalue_helper<OutIter, OutputBits>::type OutValue;
137  OutValue value = OutValue();
139  *out++ = value;
140  }
141  }
142 
143  template<typename InIter, typename OutIter>
144  inline static void pack(InIter in, InIter in_e, OutIter out) {
145  while (in != in_e) {
146  typedef typename detail::outvalue_helper<OutIter, OutputBits>::type OutValue;
147  OutValue value = OutValue();
149  *out++ = value;
150  }
151  }
152  };
153 
154  template<typename Endianness, int InputBits, int OutputBits>
155  struct packer : real_packer<Endianness, InputBits, OutputBits> {
156 
157 #ifndef CRYPTO3_NO_OPTIMIZATION
158 
160 
161  template<typename InT, typename OutT>
162  inline static
163  typename std::enable_if<can_memcpy<Endianness, InputBits, OutputBits, InT, OutT>::value>::type
164  pack_n(InT const *in, size_t n, OutT *out) {
165  std::memcpy(out, in, n * sizeof(InT));
166  }
167 
168  template<typename InT, typename OutT>
169  inline static
170  typename std::enable_if<can_memcpy<Endianness, InputBits, OutputBits, InT, OutT>::value>::type
171  pack_n(InT *in, size_t n, OutT *out) {
172  std::memcpy(out, in, n * sizeof(InT));
173  }
174 
175 #endif
176  };
177 
178  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1,
179  typename InputIterator2>
180  inline void pack_n(InputIterator1 in, size_t in_n, InputIterator2 out) {
182  packer_type::pack_n(in, in_n, out);
183  }
184 
185  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1,
186  typename InputIterator2>
187  inline void pack_n(InputIterator1 in, size_t in_n, InputIterator2 out, size_t out_n) {
188  BOOST_ASSERT(in_n * InValueBits == out_n * OutValueBits);
189  pack_n<Endianness, InValueBits, OutValueBits>(in, in_n, out);
190  }
191 
192  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1,
193  typename InputIterator2>
194  inline void pack(InputIterator1 b1, InputIterator1 e1, std::random_access_iterator_tag, InputIterator2 b2) {
195  pack_n<Endianness, InValueBits, OutValueBits>(b1, e1 - b1, b2);
196  }
197 
198  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1, typename CatT1,
199  typename InputIterator2,
200  typename = typename std::enable_if<detail::is_iterator<InputIterator1>::value>::type,
201  typename = typename std::enable_if<detail::is_iterator<InputIterator2>::value>::type>
202  inline void pack(InputIterator1 b1, InputIterator1 e1, CatT1, InputIterator2 b2) {
204  packer_type::pack(b1, e1, b2);
205  }
206 
207  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1,
208  typename InputIterator2,
209  typename = typename std::enable_if<detail::is_iterator<InputIterator2>::value>::type>
210  inline void pack(InputIterator1 b1, InputIterator1 e1, InputIterator2 b2) {
211  typedef typename std::iterator_traits<InputIterator1>::iterator_category cat1;
212 
213  pack<Endianness, InValueBits, OutValueBits>(b1, e1, cat1(), b2);
214  }
215 
216  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1,
217  typename InputIterator2>
218  inline void pack(InputIterator1 b1, InputIterator1 e1, std::random_access_iterator_tag, InputIterator2 b2,
219  InputIterator2 e2, std::random_access_iterator_tag) {
220  pack_n<Endianness, InValueBits, OutValueBits>(b1, e1 - b1, b2, e2 - b2);
221  }
222 
223  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1, typename CatT1,
224  typename InputIterator2, typename CatT2>
225  inline void pack(InputIterator1 b1, InputIterator1 e1, CatT1, InputIterator2 b2, InputIterator2, CatT2) {
226  pack<Endianness, InValueBits, OutValueBits>(b1, e1, b2);
227  }
228 
229  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1,
230  typename InputIterator2>
231  inline void pack(InputIterator1 b1, InputIterator1 e1, InputIterator2 b2, InputIterator2 e2) {
232  typedef typename std::iterator_traits<InputIterator1>::iterator_category cat1;
233  typedef typename std::iterator_traits<InputIterator2>::iterator_category cat2;
234  pack<Endianness, InValueBits, OutValueBits>(b1, e1, cat1(), b2, e2, cat2());
235  }
236 
237  template<typename Endianness, int InValueBits, int OutValueBits, typename InputType, typename OutputType>
238  inline void pack(const InputType &in, OutputType &out) {
239  pack_n<Endianness, InValueBits, OutValueBits>(in.begin(), in.size(), out.begin(), out.size());
240  }
241 
242  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator,
243  typename OutputType,
244  typename = typename std::enable_if<!std::is_arithmetic<OutputType>::value>::type>
245  inline void pack(InputIterator first, InputIterator last, OutputType &out) {
246  pack_n<Endianness, InValueBits, OutValueBits>(first, std::distance(first, last), out.begin(),
247  out.size());
248  }
249  } // namespace detail
250  } // namespace crypto3
251 } // namespace nil
252 
253 #endif // CRYPTO3_CODEC_PACK_HPP
void pack_n(InputIterator in, std::size_t in_n, OutputIterator out)
Packs in_n input elements starting from in into output elements beginning from out.
Definition: block/include/nil/crypto3/detail/pack.hpp:776
void pack(InputIterator first, InputIterator last, std::random_access_iterator_tag, OutputIterator out)
Packs elements from the range [first, last) into elements starting from out. Works for input containe...
Definition: block/include/nil/crypto3/detail/pack.hpp:835
void pack_n(InputIterator1 in, size_t in_n, InputIterator2 out, size_t out_n)
Definition: passhash/include/nil/crypto3/detail/pack.hpp:187
void pack(InputIterator first, InputIterator last, OutputType &out)
Definition: passhash/include/nil/crypto3/detail/pack.hpp:245
Definition: pair.hpp:31
constexpr static const bool value
Definition: block/include/nil/crypto3/detail/pack.hpp:91
exploder forms a sequence of output values represented in OutputEndianness endianness from an input v...
Definition: block/include/nil/crypto3/detail/exploder.hpp:148
constexpr static const bool value
Definition: block/include/nil/crypto3/detail/pack.hpp:72
imploder processes a sequence of input values represented in InputEndianness endianness into an outpu...
Definition: block/include/nil/crypto3/detail/imploder.hpp:122
T type
Definition: block/include/nil/crypto3/detail/exploder.hpp:64
This packer deals with arbitrary input and output (but not bool) data elements.
Definition: block/include/nil/crypto3/detail/pack.hpp:444
static std::enable_if< can_memcpy< Endianness, InputBits, OutputBits, InT, OutT >::value >::type pack_n(InT const *in, size_t n, OutT *out)
Definition: passhash/include/nil/crypto3/detail/pack.hpp:164
static std::enable_if< can_memcpy< Endianness, InputBits, OutputBits, InT, OutT >::value >::type pack_n(InT *in, size_t n, OutT *out)
Definition: passhash/include/nil/crypto3/detail/pack.hpp:171
static void pack_n(InIter in, size_t in_n, OutIter out)
Definition: passhash/include/nil/crypto3/detail/pack.hpp:93
static void pack(InIter in, InIter in_e, OutIter out)
Definition: passhash/include/nil/crypto3/detail/pack.hpp:98
static void pack_n(InIter in, size_t in_n, OutIter out)
Definition: passhash/include/nil/crypto3/detail/pack.hpp:133
static void pack(InIter in, InIter in_e, OutIter out)
Definition: passhash/include/nil/crypto3/detail/pack.hpp:144
static void pack(InIter in, InIter in_e, OutIter out)
Definition: passhash/include/nil/crypto3/detail/pack.hpp:118
static void pack_n(InIter in, size_t in_n, OutIter out)
Definition: passhash/include/nil/crypto3/detail/pack.hpp:109
Real_packer is used to transform input data divided into chunks of the bit size InputValueBits repres...
Definition: block/include/nil/crypto3/detail/pack.hpp:144