stream/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_DETAIL_PACK_HPP
26 #define CRYPTO3_DETAIL_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  static bool const value = !(UnitBits % CHAR_BIT) && InputBits >= UnitBits && OutputBits >= UnitBits &&
52  sizeof(InT) * CHAR_BIT == InputBits && sizeof(OutT) * CHAR_BIT == OutputBits;
53  };
54 
55  template<typename Endianness, int InputBits, int OutputBits, typename InT, typename OutT>
56  struct can_memcpy {
57  static bool const value = InputBits == OutputBits && sizeof(InT) == sizeof(OutT);
58  };
59 
60  template<int UnitBits, int InputBits, int OutputBits, typename InT, typename OutT>
61  struct can_memcpy<stream_endian::host_unit<UnitBits>, InputBits, OutputBits, InT, OutT>
62  : host_can_memcpy<UnitBits, InputBits, OutputBits, InT, OutT> {};
63 
64 #ifdef BOOST_ENDIAN_LITTLE_BYTE_AVAILABLE
65  template<int UnitBits, int InputBits, int OutputBits, typename InT, typename OutT>
66  struct can_memcpy<stream_endian::little_unit_big_bit<UnitBits>, InputBits, OutputBits, InT, OutT>
67  : host_can_memcpy<UnitBits, InputBits, OutputBits, InT, OutT> {};
68  template<int UnitBits, int InputBits, int OutputBits, typename InT, typename OutT>
69  struct can_memcpy<stream_endian::little_unit_little_bit<UnitBits>, InputBits, OutputBits, InT, OutT>
70  : host_can_memcpy<UnitBits, InputBits, OutputBits, InT, OutT> {};
71 #endif
72 
73 #ifdef CRYPTO3_TARGET_CPU_IS_BIG_ENDIAN
74  template<int UnitBits, int InputBits, int OutputBits, typename InT, typename OutT>
75  struct can_memcpy<stream_endian::big_unit_big_bit<UnitBits>, InputBits, OutputBits, InT, OutT>
76  : host_can_memcpy<UnitBits, InputBits, OutputBits, InT, OutT> {};
77  template<int UnitBits, int InputBits, int OutputBits, typename InT, typename OutT>
78  struct can_memcpy<stream_endian::big_unit_little_bit<UnitBits>, InputBits, OutputBits, InT, OutT>
79  : host_can_memcpy<UnitBits, InputBits, OutputBits, InT, OutT> {};
80 #endif
81 
82 #endif
83 
84  template<typename Endianness, int InputBits, int OutputBits, bool Explode = (InputBits > OutputBits),
85  bool Implode = (InputBits < OutputBits)>
86  struct real_packer;
87 
88  template<typename Endianness, int Bits>
89  struct real_packer<Endianness, Bits, Bits, false, false> {
90 
91  template<typename InIter, typename OutIter>
92  static void pack_n(InIter in, size_t in_n, OutIter out) {
93  std::copy(in, in + in_n, out);
94  }
95 
96  template<typename InIter, typename OutIter>
97  static void pack(InIter in, InIter in_e, OutIter out) {
98  std::copy(in, in_e, out);
99  }
100  };
101 
102  template<typename Endianness, int InputBits, int OutputBits>
103  struct real_packer<Endianness, InputBits, OutputBits, true, false> {
104 
105  BOOST_STATIC_ASSERT(InputBits % OutputBits == 0);
106 
107  template<typename InIter, typename OutIter>
108  static void pack_n(InIter in, size_t in_n, OutIter out) {
109  while (in_n--) {
110  typedef typename std::iterator_traits<InIter>::value_type InValue;
111  InValue const value = *in++;
113  }
114  }
115 
116  template<typename InIter, typename OutIter>
117  static void pack(InIter in, InIter in_e, OutIter out) {
118  while (in != in_e) {
119  typedef typename std::iterator_traits<InIter>::value_type InValue;
120  InValue const value = *in++;
122  }
123  }
124  };
125 
126  template<typename Endianness, int InputBits, int OutputBits>
127  struct real_packer<Endianness, InputBits, OutputBits, false, true> {
128 
129  BOOST_STATIC_ASSERT(OutputBits % InputBits == 0);
130 
131  template<typename InIter, typename OutIter>
132  static void pack_n(InIter in, size_t in_n, OutIter out) {
133  size_t out_n = in_n / (OutputBits / InputBits);
134  while (out_n--) {
135  typedef typename detail::outvalue_helper<OutIter, OutputBits>::type OutValue;
136  OutValue value = OutValue();
138  *out++ = value;
139  }
140  }
141 
142  template<typename InIter, typename OutIter>
143  static void pack(InIter in, InIter in_e, OutIter out) {
144  while (in != in_e) {
145  typedef typename detail::outvalue_helper<OutIter, OutputBits>::type OutValue;
146  OutValue value = OutValue();
148  *out++ = value;
149  }
150  }
151  };
152 
153  template<typename Endianness, int InputBits, int OutputBits>
154  struct packer : real_packer<Endianness, InputBits, OutputBits> {
155 
156 #ifndef CRYPTO3_NO_OPTIMIZATION
157 
159 
160  template<typename InT, typename OutT>
161  static typename std::enable_if<can_memcpy<Endianness, InputBits, OutputBits, InT, OutT>::value>::type
162  pack_n(InT const *in, size_t n, OutT *out) {
163  std::memcpy(out, in, n * sizeof(InT));
164  }
165 
166  template<typename InT, typename OutT>
167  static typename std::enable_if<can_memcpy<Endianness, InputBits, OutputBits, InT, OutT>::value>::type
168  pack_n(InT *in, size_t n, OutT *out) {
169  std::memcpy(out, in, n * sizeof(InT));
170  }
171 
172 #endif
173  };
174 
175  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1,
176  typename InputIterator2>
177  void pack_n(InputIterator1 in, size_t in_n, InputIterator2 out) {
178  typedef packer<Endianness, InValueBits, OutValueBits> packer_type;
179  packer_type::pack_n(in, in_n, out);
180  }
181 
182  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1,
183  typename InputIterator2>
184  void pack_n(InputIterator1 in, size_t in_n, InputIterator2 out, size_t out_n) {
185  BOOST_ASSERT(in_n * InValueBits == out_n * OutValueBits);
186  pack_n<Endianness, InValueBits, OutValueBits>(in, in_n, out);
187  }
188 
189  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1,
190  typename InputIterator2>
191  void pack(InputIterator1 b1, InputIterator1 e1, std::random_access_iterator_tag, InputIterator2 b2) {
192  pack_n<Endianness, InValueBits, OutValueBits>(b1, e1 - b1, b2);
193  }
194 
195  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1, typename CatT1,
196  typename InputIterator2,
197  typename = typename std::enable_if<detail::is_iterator<InputIterator1>::value>::type,
198  typename = typename std::enable_if<detail::is_iterator<InputIterator2>::value>::type>
199  void pack(InputIterator1 b1, InputIterator1 e1, CatT1, InputIterator2 b2) {
200  typedef packer<Endianness, InValueBits, OutValueBits> packer_type;
201  packer_type::pack(b1, e1, b2);
202  }
203 
204  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1,
205  typename InputIterator2,
206  typename = typename std::enable_if<detail::is_iterator<InputIterator2>::value>::type>
207  void pack(InputIterator1 b1, InputIterator1 e1, InputIterator2 b2) {
208  typedef typename std::iterator_traits<InputIterator1>::iterator_category cat1;
209  pack<Endianness, InValueBits, OutValueBits>(b1, e1, cat1(), b2);
210  }
211 
212  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1,
213  typename InputIterator2>
214  void pack(InputIterator1 b1, InputIterator1 e1, std::random_access_iterator_tag, InputIterator2 b2,
215  InputIterator2 e2, std::random_access_iterator_tag) {
216  pack_n<Endianness, InValueBits, OutValueBits>(b1, e1 - b1, b2, e2 - b2);
217  }
218 
219  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1, typename CatT1,
220  typename InputIterator2, typename CatT2>
221  void pack(InputIterator1 b1, InputIterator1 e1, CatT1, InputIterator2 b2, InputIterator2, CatT2) {
222  pack<Endianness, InValueBits, OutValueBits>(b1, e1, b2);
223  }
224 
225  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator1,
226  typename InputIterator2>
227  void pack(InputIterator1 b1, InputIterator1 e1, InputIterator2 b2, InputIterator2 e2) {
228  typedef typename std::iterator_traits<InputIterator1>::iterator_category cat1;
229  typedef typename std::iterator_traits<InputIterator2>::iterator_category cat2;
230  pack<Endianness, InValueBits, OutValueBits>(b1, e1, cat1(), b2, e2, cat2());
231  }
232 
233  template<typename Endianness, int InValueBits, int OutValueBits, typename InputType, typename OutputType>
234  void pack(const InputType &in, OutputType &out) {
235  pack_n<Endianness, InValueBits, OutValueBits>(in.data(), in.size(), out.data(), out.size());
236  }
237 
238  template<typename Endianness, int InValueBits, int OutValueBits, typename InputIterator,
239  typename OutputType,
240  typename = typename std::enable_if<!std::is_arithmetic<OutputType>::value>::type>
241  inline void pack(InputIterator first, InputIterator last, OutputType &out) {
242  pack_n<Endianness, InValueBits, OutValueBits>(first, std::distance(first, last), out.begin(),
243  out.size());
244  }
245  } // namespace detail
246  } // namespace crypto3
247 } // namespace nil
248 
249 #endif // CRYPTO3_BLOCK_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
Definition: pair.hpp:31
can_memcpy trait is derived from host_can_memcpy trait and is invoked depending on data endianness....
Definition: block/include/nil/crypto3/detail/pack.hpp:90
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
The group of traits below is used to determine the possibility of fast data copy. By fast data copy w...
Definition: block/include/nil/crypto3/detail/pack.hpp:71
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
static std::enable_if< can_memcpy< Endianness, InputBits, OutputBits, InT, OutT >::value >::type pack_n(InT const *in, size_t n, OutT *out)
Definition: stream/include/nil/crypto3/detail/pack.hpp:162
static std::enable_if< can_memcpy< Endianness, InputBits, OutputBits, InT, OutT >::value >::type pack_n(InT *in, size_t n, OutT *out)
Definition: stream/include/nil/crypto3/detail/pack.hpp:168
static void pack_n(InIter in, size_t in_n, OutIter out)
Definition: stream/include/nil/crypto3/detail/pack.hpp:92
static void pack(InIter in, InIter in_e, OutIter out)
Definition: stream/include/nil/crypto3/detail/pack.hpp:97
static void pack_n(InIter in, size_t in_n, OutIter out)
Definition: stream/include/nil/crypto3/detail/pack.hpp:132
static void pack(InIter in, InIter in_e, OutIter out)
Definition: stream/include/nil/crypto3/detail/pack.hpp:143
static void pack(InIter in, InIter in_e, OutIter out)
Definition: stream/include/nil/crypto3/detail/pack.hpp:117
static void pack_n(InIter in, size_t in_n, OutIter out)
Definition: stream/include/nil/crypto3/detail/pack.hpp:108