ipfs-chromium
basic_algorithm.h
1 /* From: https://github.com/lockblox/multibase
2  * Copyright (c) 2018 markovchainy
3  * MIT License
4  */
5 #pragma once
6 
7 #include <multibase/algorithm.h>
8 #include <multibase/encoding.h>
9 
10 #include <algorithm>
11 #include <array>
12 #include <cmath>
13 #include <ratio>
14 #include <vector>
15 
16 namespace multibase {
17 
18 template <encoding T>
19 struct traits {
20  static const std::array<char, 0> charset;
21  static const char name[];
22  static const char padding = 0;
24 };
25 
28 template <encoding T, typename Traits = traits<T>>
30  public:
31  class encoder : public algorithm {
32  public:
33  size_t output_size() override;
34  size_t block_size() override;
35  std::string process(std::string_view input) override;
36 
37  private:
38  constexpr size_t input_size() { return ratio.den; }
39  };
40 
41  class decoder : public algorithm {
42  public:
43  size_t output_size() override;
44  size_t block_size() override;
45  std::string process(std::string_view input) override;
46 
47  private:
48  constexpr size_t input_size() { return ratio.num; }
49  };
50 
51  private:
52  constexpr static auto first = Traits::charset.cbegin();
53  constexpr static auto last = Traits::charset.cend();
54  using CharsetT = decltype(Traits::charset);
55  using value_type = typename CharsetT::value_type;
56  using iterator = typename CharsetT::const_iterator;
57 
59  constexpr static iterator find(iterator b, iterator e,
60  value_type const& v) noexcept {
61  return (b != e && *b != v) ? find(++b, e, v) : b;
62  }
63 
66  constexpr static unsigned char getval(unsigned char p) noexcept {
67  return find(first, last, p) == last
68  ? static_cast<unsigned char>(255)
69  : static_cast<unsigned char>(
70  std::distance(first, find(first, last, p)));
71  }
72 
74  constexpr static std::intmax_t log2(std::intmax_t n) noexcept {
75  return (n == 1) ? 0 : ((n < 2) ? 1 : 1 + log2(n / 2));
76  }
77 
79  constexpr static auto radix = sizeof(Traits::charset) / sizeof(value_type);
81  constexpr static auto ratio = std::ratio<log2(256), log2(radix)>{};
83  static const std::array<unsigned char, 256> valset;
84 
85  constexpr static auto base = T;
86 };
87 
88 template <encoding T, typename Traits>
89 const std::array<unsigned char, 256> basic_algorithm<T, Traits>::valset = {
90  getval(0), getval(1), getval(2), getval(3), getval(4),
91  getval(5), getval(6), getval(7), getval(8), getval(9),
92  getval(10), getval(11), getval(12), getval(13), getval(14),
93  getval(15), getval(16), getval(17), getval(18), getval(19),
94  getval(20), getval(21), getval(22), getval(23), getval(24),
95  getval(25), getval(26), getval(27), getval(28), getval(29),
96  getval(30), getval(31), getval(32), getval(33), getval(34),
97  getval(35), getval(36), getval(37), getval(38), getval(39),
98  getval(40), getval(41), getval(42), getval(43), getval(44),
99  getval(45), getval(46), getval(47), getval(48), getval(49),
100  getval(50), getval(51), getval(52), getval(53), getval(54),
101  getval(55), getval(56), getval(57), getval(58), getval(59),
102  getval(60), getval(61), getval(62), getval(63), getval(64),
103  getval(65), getval(66), getval(67), getval(68), getval(69),
104  getval(70), getval(71), getval(72), getval(73), getval(74),
105  getval(75), getval(76), getval(77), getval(78), getval(79),
106  getval(80), getval(81), getval(82), getval(83), getval(84),
107  getval(85), getval(86), getval(87), getval(88), getval(89),
108  getval(90), getval(91), getval(92), getval(93), getval(94),
109  getval(95), getval(96), getval(97), getval(98), getval(99),
110  getval(100), getval(101), getval(102), getval(103), getval(104),
111  getval(105), getval(106), getval(107), getval(108), getval(109),
112  getval(110), getval(111), getval(112), getval(113), getval(114),
113  getval(115), getval(116), getval(117), getval(118), getval(119),
114  getval(120), getval(121), getval(122), getval(123), getval(124),
115  getval(125), getval(126), getval(127), getval(128), getval(129),
116  getval(130), getval(131), getval(132), getval(133), getval(134),
117  getval(135), getval(136), getval(137), getval(138), getval(139),
118  getval(140), getval(141), getval(142), getval(143), getval(144),
119  getval(145), getval(146), getval(147), getval(148), getval(149),
120  getval(150), getval(151), getval(152), getval(153), getval(154),
121  getval(155), getval(156), getval(157), getval(158), getval(159),
122  getval(160), getval(161), getval(162), getval(163), getval(164),
123  getval(165), getval(166), getval(167), getval(168), getval(169),
124  getval(170), getval(171), getval(172), getval(173), getval(174),
125  getval(175), getval(176), getval(177), getval(178), getval(179),
126  getval(180), getval(181), getval(182), getval(183), getval(184),
127  getval(185), getval(186), getval(187), getval(188), getval(189),
128  getval(190), getval(191), getval(192), getval(193), getval(194),
129  getval(195), getval(196), getval(197), getval(198), getval(199),
130  getval(200), getval(201), getval(202), getval(203), getval(204),
131  getval(205), getval(206), getval(207), getval(208), getval(209),
132  getval(210), getval(211), getval(212), getval(213), getval(214),
133  getval(215), getval(216), getval(217), getval(218), getval(219),
134  getval(220), getval(221), getval(222), getval(223), getval(224),
135  getval(225), getval(226), getval(227), getval(228), getval(229),
136  getval(230), getval(231), getval(232), getval(233), getval(234),
137  getval(235), getval(236), getval(237), getval(238), getval(239),
138  getval(240), getval(241), getval(242), getval(243), getval(244),
139  getval(245), getval(246), getval(247), getval(248), getval(249),
140  getval(250), getval(251), getval(252), getval(253), getval(254),
141  getval(255)};
142 
143 template <encoding T, typename Traits>
145  std::string_view input) {
146  std::string output;
147  std::size_t isize = input.size();
148  auto partial_blocks = static_cast<float>(input.size()) / input_size();
149  auto num_blocks = static_cast<std::size_t>(partial_blocks);
150  auto osize = static_cast<size_t>(std::ceil(partial_blocks * output_size()));
151  if constexpr (std::is_same_v<typename Traits::execution_style, block_tag>) {
152  num_blocks = static_cast<size_t>(std::ceil(partial_blocks));
153  isize = input_size() * num_blocks;
154  }
155  output.resize(std::max(osize, (output_size() * num_blocks)));
156  auto input_it = std::begin(input);
157  int length = 0;
158  for (std::size_t i = 0; i < isize; ++i, ++input_it) {
159  int carry = i >= input.size() ? 0 : static_cast<unsigned char>(*input_it);
160  int j = 0;
161  for (auto oi = output.rbegin();
162  (oi != output.rend()) && (carry != 0 || j < length); ++oi, ++j) {
163  carry += 256 * (*oi);
164  auto byte = (unsigned char*)(&(*oi));
165  *byte = carry % radix;
166  carry /= radix;
167  }
168  length = j;
169  }
170  std::transform(output.rbegin(), output.rend(), output.rbegin(),
171  [](auto c) { return Traits::charset[c]; });
172  if constexpr (Traits::padding == 0) {
173  output.resize(osize);
174  } else {
175  auto pad_size = output.size() - osize;
176  output.replace(osize, pad_size, pad_size, Traits::padding);
177  }
178  if constexpr (std::is_same_v<typename Traits::execution_style, stream_tag>) {
179  output.erase(0, output.size() % output_size() ? output.size() - length : 0);
180  }
181  return output;
182 }
183 
184 template <encoding T, typename Traits>
186  return std::is_same_v<typename Traits::execution_style, block_tag>
187  ? input_size()
188  : 0;
189 }
190 
191 template <encoding T, typename Traits>
193  return ratio.num;
194 }
195 
196 template <encoding T, typename Traits>
198  return std::is_same_v<typename Traits::execution_style, block_tag>
199  ? input_size()
200  : 0;
201 }
202 
203 template <encoding T, typename Traits>
205  return ratio.den;
206 }
207 
208 template <encoding T, typename Traits>
210  std::string_view input) {
211  std::string output;
212  auto end = std::find(input.begin(), input.end(), Traits::padding);
213  size_t input_size = std::distance(input.begin(), end);
214  auto partial_blocks = static_cast<float>(input_size) / this->input_size();
215  auto output_size = static_cast<size_t>(this->output_size() * partial_blocks);
216  if constexpr (std::is_same_v<typename Traits::execution_style, block_tag>) {
217  std::size_t num_blocks = 0;
218  auto input_size_float = static_cast<float>(input.size());
219  num_blocks =
220  static_cast<size_t>(std::ceil(input_size_float / this->input_size()));
221  output.resize(this->output_size() * num_blocks);
222  input_size = this->input_size() * num_blocks;
223  } else {
224  output.resize(output_size);
225  }
226  auto input_it = input.begin();
227  for (size_t i = 0; i < input_size; ++i, ++input_it) {
228  int carry = i > input.size() || *input_it == Traits::padding
229  ? 0
230  : valset[(unsigned char)(*input_it)];
231  if (carry == 255) {
232  // throw std::invalid_argument(std::string{"Invalid input character
233  // "} + *input_it);
234  return {};
235  }
236  auto j = output.size();
237  while (carry != 0 || j > 0) {
238  auto index = j - 1;
239  carry += radix * static_cast<unsigned char>(output[index]);
240  output[index] = static_cast<unsigned char>(carry % 256);
241  carry /= 256;
242  if (carry > 0 && index == 0) {
243  output.insert(0, 1, 0);
244  } else {
245  j = index;
246  }
247  }
248  }
249  if constexpr (std::is_same_v<typename Traits::execution_style, block_tag>) {
250  output.erase(output_size, output.size());
251  }
252  return output;
253 }
254 
255 template <>
256 struct traits<encoding::base_16> {
257  constexpr static const std::array<char, 16> charset = {
258  '0', '1', '2', '3', '4', '5', '6', '7',
259  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
260  constexpr static const char name[] = "base_16";
262  constexpr static const char padding = 0;
263 };
265 
266 template <>
267 struct traits<encoding::base_36> {
268  constexpr static const std::array<char, 36> charset = {
269  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
270  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
271  'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
272  'u', 'v', 'w', 'x', 'y', 'z'};
273  constexpr static const char name[] = "base_36";
275  constexpr static const char padding = 0;
276 };
278 
279 
280 template <>
281 struct traits<encoding::base_58_btc> {
282  constexpr static const std::array<char, 58> charset = {
283  '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
284  'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
285  'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm',
286  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
287  constexpr static const char name[] = "base_58_btc";
289  constexpr static const char padding = 0;
290 };
292 
293 template <>
294 struct traits<encoding::base_64_pad> {
295  constexpr static const std::array<char, 64> charset = {
296  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
297  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
298  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
299  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
300  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
301  constexpr static const char name[] = "base_64_pad";
303  constexpr static const char padding = '=';
304 };
306 
307 template <>
308 struct traits<encoding::base_64> {
309  constexpr static const std::array<char, 64> charset = {
310  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
311  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
312  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
313  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
314  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
315  constexpr static const char name[] = "base_64";
318  constexpr static const char padding = 0;
319 };
321 
322 } // namespace multibase
Definition: algorithm.h:11
Definition: algorithm.h:14
Definition: algorithm.h:8
Definition: basic_algorithm.h:41
size_t block_size() override
Definition: basic_algorithm.h:197
std::string process(std::string_view input) override
Definition: basic_algorithm.h:209
size_t output_size() override
Definition: basic_algorithm.h:204
Definition: basic_algorithm.h:31
size_t output_size() override
Definition: basic_algorithm.h:192
size_t block_size() override
Definition: basic_algorithm.h:185
std::string process(std::string_view input) override
Definition: basic_algorithm.h:144
Definition: basic_algorithm.h:29
Definition: basic_algorithm.h:19