Dendro  5.01
Dendro in Greek language means tree. The Dendro library is a large scale (262K cores on ORNL's Titan) distributed memory adaptive octree framework. The main goal of Dendro is to perform large scale multiphysics simulations efficeiently in mordern supercomputers. Dendro consists of efficient parallel data structures and algorithms to perform variational ( finite element) methods and finite difference mthods on 2:1 balanced arbitary adaptive octrees which enables the users to perform simulations raning from black holes (binary black hole mergers) to blood flow in human body, where applications ranging from relativity, astrophysics to biomedical engineering.
base.h
1 // Base64/85/91 en/decoders, still C-String, TSV, XML and JSON friendly.
2 // - rlyeh 2011..2016, zlib/libpng licensed.
3 
4 // Some notes {
5 // - [x] Base64: canonical implementation.
6 // - [x] Base85: 17% to 08% smaller than Base64, still C-String friendly. Custom Z85 variant.
7 // - [x] Base91: 19% to 10% smaller than Base64, still JSON, XML and TSV friendly. Custom basE91 variant.
8 // - [x] Encoded data can be "quoted", splitted with tabs, spaces, linefeeds and carriages.
9 // }
10 
11 // Extra licensing {
12 // - Base64 is based on code by RenĂ© Nyffenegger (zlib/libpng licensed)
13 // - Base91 is based on code by Joachim Henke {
14 // Copyright (c) 2000-2006 Joachim Henke
15 // http://base91.sourceforge.net/ (v0.6.0)
16 // Redistribution and use in source and binary forms, with or without
17 // modification, are permitted provided that the following conditions are met:
18 // - Redistributions of source code must retain the above copyright notice,
19 // this list of conditions and the following disclaimer.
20 // - Redistributions in binary form must reproduce the above copyright notice,
21 // this list of conditions and the following disclaimer in the documentation
22 // and/or other materials provided with the distribution.
23 // - Neither the name of Joachim Henke nor the names of his contributors may
24 // be used to endorse or promote products derived from this software without
25 // specific prior written permission.
26 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 // POSSIBILITY OF SUCH DAMAGE.
37 // } }
38 
39 #pragma once
40 #include <string>
41 
42 #define BASE_VERSION "1.0.2" /* (2016/04/20) Base85 support (custom Z85); In-place API; Project renamed
43 #define BASE_VERSION "1.0.1" // (2015/12/07) Update sample
44 #define BASE_VERSION "1.0.0" // (2014/04/26) Base64 support
45 #define BASE_VERSION "0.0.0" // (2013/04/12) Initial commit (custom basE91) */
46 
47 namespace {
48 
49  /* Public API */
50 
51  template<unsigned N> struct base {
52  static std::string encode( const std::string &binary ); // functional api
53  static std::string decode( const std::string &text ); // functional api
54  static bool encode( std::string &out, const std::string &binary ); // in-place api
55  static bool decode( std::string &out, const std::string &text ); // in-place api
56  };
57 
58  typedef base<64> base64;
59  typedef base<85> base85;
60  typedef base<91> base91;
61 
62  /* API details */
63 
64  template<>
65  bool base<91>::encode( std::string &out, const std::string &binary ) {
66 
67  const unsigned char enctab[91] = {
68  /* // Henke's original
69  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', //00..12
70  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', //13..25
71  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', //26..38
72  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', //39..51
73  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '#', '$', //52..64
74  '%', '&', '(', ')', '*', '+', ',', '.', '/', ':', ';', '<', '=', //65..77
75  '>', '?', '@', '[', ']', '^', '_', '`', '{', '|', '}', '~', '"' //78..90 */
76  // // rlyeh's modification
77  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', //00..12
78  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', //13..25
79  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', //26..38
80  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', //39..51
81  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '#', '$', //52..64
82  '%', '&', '(', ')', '*', '+', ',', '.', '/', ':', ';', '-', '=', //65..77
83  '\\','?', '@', '[', ']', '^', '_', '`', '{', '|', '}', '~', '\'' //78..90
84  };
85 
86  out.clear();
87  const unsigned char *ib = (unsigned char *) binary.c_str();
88 
89  unsigned long queue = 0;
90  unsigned int nbits = 0;
91 
92  for( size_t len = binary.size(); len--; ) {
93  queue |= *ib++ << nbits;
94  nbits += 8;
95  if (nbits > 13) { /* enough bits in queue */
96  unsigned int val = queue & 8191;
97 
98  if (val > 88) {
99  queue >>= 13;
100  nbits -= 13;
101  } else { /* we can take 14 bits */
102  val = queue & 16383;
103  queue >>= 14;
104  nbits -= 14;
105  }
106  out.push_back( enctab[val % 91] );
107  out.push_back( enctab[val / 91] );
108  }
109  }
110 
111  /* process remaining bits from bit queue; write up to 2 bytes */
112  if (nbits) {
113  out.push_back( enctab[queue % 91] );
114  if (nbits > 7 || queue > 90)
115  out.push_back( enctab[queue / 91] );
116  }
117 
118  return true;
119  }
120 
121 
122  template<>
123  bool base<91>::decode( std::string &out, const std::string &text ) {
124 
125  const unsigned char dectab[256] = {
126  /* // Henke's original
127  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //000..015
128  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //016..031
129  91, 62, 90, 63, 64, 65, 66, 91, 67, 68, 69, 70, 71, 91, 72, 73, //032..047
130  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 74, 75, 76, 77, 78, 79, //048..063
131  80, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //064..079
132  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 81, 91, 82, 83, 84, //080..095
133  85, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, //096..111
134  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 86, 87, 88, 89, 91, //112..127
135  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //128..143
136  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //144..159
137  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //160..175
138  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //176..191
139  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //192..207
140  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //208..223
141  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //224..239
142  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91 //240..255 */
143  // // rlyeh's modification
144  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //000..015
145  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //016..031
146  91, 62, 91, 63, 64, 65, 66, 90, 67, 68, 69, 70, 71, 76, 72, 73, //032..047 // @34: ", @39: ', @45: -
147  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 74, 75, 91, 77, 91, 79, //048..063 // @60: <, @62: >
148  80, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //064..079
149  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 81, 78, 82, 83, 84, //080..095 // @92: slash
150  85, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, //096..111
151  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 86, 87, 88, 89, 91, //112..127
152  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //128..143
153  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //144..159
154  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //160..175
155  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //176..191
156  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //192..207
157  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //208..223
158  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, //224..239
159  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91 //240..255
160  };
161 
162  out.clear();
163  const unsigned char *ib = (unsigned char *) text.c_str();
164 
165  unsigned long queue = 0;
166  unsigned int nbits = 0;
167  int val = -1;
168 
169  for( size_t len = text.size(); len--; ) {
170  unsigned int d = dectab[*ib++];
171  if (d == 91)
172  continue; /* ignore non-alphabet chars */
173  if (val == -1)
174  val = d; /* start next value */
175  else {
176  val += d * 91;
177  queue |= val << nbits;
178  nbits += (val & 8191) > 88 ? 13 : 14;
179  do {
180  out.push_back( char( queue ) );
181  queue >>= 8;
182  nbits -= 8;
183  } while (nbits > 7);
184  val = -1; /* mark value complete */
185  }
186  }
187 
188  /* process remaining bits; write at most 1 byte */
189  if (val != -1)
190  out.push_back( char( queue | val << nbits ) );
191 
192  return true;
193  }
194 
195  // base85 (z85): standard rfc size (multiples of 4/5)
196 
197  inline bool encode85( std::string &out, const unsigned char *raw, size_t rawlen ) {
198  if( rawlen % 4 ) {
199  return false; // error: raw string size must be multiple of 4
200  }
201  // encode
202  const char encoder[86] =
203  "0123456789" "abcdefghij" "klmnopqrst" "uvwxyzABCD" // 00..39
204  "EFGHIJKLMN" "OPQRSTUVWX" "YZ.-:+=^!/" "*?&<>()[]{" "}@%$#"; // 40..84 // free chars: , ; _ ` | ~ \'
205  out.resize( rawlen * 5 / 4 );
206  for( size_t o = 0; o < rawlen * 5 / 4; raw += 4 ) {
207  unsigned value = (raw[0] << 24) | (raw[1] << 16) | (raw[2] << 8) | raw[3];
208  out[o++] = encoder[ (value / 0x31C84B1) % 0x55 ];
209  out[o++] = encoder[ (value / 0x95EED) % 0x55 ];
210  out[o++] = encoder[ (value / 0x1C39) % 0x55 ];
211  out[o++] = encoder[ (value / 0x55) % 0x55 ];
212  out[o++] = encoder[ value % 0x55 ];
213  }
214  return true;
215  }
216 
217  inline bool decode85( std::string &out, const unsigned char *z85, size_t z85len ) {
218  if( z85len % 5 ) {
219  return false; // error: z85 string size must be multiple of 5
220  }
221  // decode
222  const unsigned char decoder[128] = {
223  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00..0x0F
224  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10..0x1F
225  0, 68, 0, 84, 83, 82, 72, 0, 75, 76, 70, 65, 0, 63, 62, 69, // 0x20..0x2F
226  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 64, 0, 73, 66, 74, 71, // 0x30..0x3F
227  81, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, // 0x40..0x4F
228  51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 0, 78, 67, 0, // 0x50..0x5F
229  0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x60..0x6F
230  25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 79, 0, 80, 0, 0, // 0x70..0x7F
231  };
232  out.resize( z85len * 4 / 5 );
233  for( size_t o = 0; o < z85len * 4 / 5; z85 += 5 ) {
234  unsigned value = decoder[z85[0]] * 0x31C84B1 + decoder[z85[1]] * 0x95EED +
235  decoder[z85[2]] * 0x1C39 + decoder[z85[3]] * 0x55 + decoder[z85[4]];
236  out[o++] = (value >> 24) & 0xFF;
237  out[o++] = (value >> 16) & 0xFF;
238  out[o++] = (value >> 8) & 0xFF;
239  out[o++] = (value >> 0) & 0xFF;
240  }
241  return true;
242  }
243 
244  // base85 (z85): arbitrary size (this may lead up to four additional bytes)
245 
246  template<>
247  bool base<85>::encode( std::string &out, const std::string &rawstr ) {
248  // create padding, if needed
249  std::string pad4 = std::string( (const char *)&rawstr[0], rawstr.size() ) + '\1' + std::string("\0\0\0\0", 4 - (rawstr.size() + 1) % 4);
250  return encode85( out, (const unsigned char *)pad4.c_str(), pad4.size() );
251  }
252 
253  template<>
254  bool base<85>::decode( std::string &out, const std::string &z85str ) {
255  if( !decode85( out, (const unsigned char *)&z85str[0], z85str.size() ) ) {
256  return false;
257  } else {
258  // remove padding, if needed
259  while( out.size() && *out.rbegin() == '\0' ) out.resize( out.size() - 1 );
260  if( out.size() && *out.rbegin() == '\1' ) out.resize( out.size() - 1 );
261  return true;
262  }
263  }
264 
265  // base64
266 
267  template<>
268  bool base<64>::encode( std::string &out, const std::string &text ) {
269 
270  const std::string chars =
271  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
272  "abcdefghijklmnopqrstuvwxyz"
273  "0123456789+/";
274 
275  unsigned char const* bytes_to_encode = (unsigned char const *)text.c_str();
276  unsigned int in_len = (unsigned int)text.size();
277  unsigned int i = 0;
278  unsigned int j = 0;
279  unsigned char char_array_3[3];
280  unsigned char char_array_4[4];
281  out.clear();
282 
283  while( in_len-- ) {
284  char_array_3[i++] = *(bytes_to_encode++);
285  if( i == 3 ) {
286  char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
287  char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
288  char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
289  char_array_4[3] = char_array_3[2] & 0x3f;
290 
291  for( i = 0; (i <4) ; i++ )
292  out += chars[char_array_4[i]];
293  i = 0;
294  }
295  }
296 
297  if( i ) {
298  for( j = i; j < 3; j++ )
299  char_array_3[j] = '\0';
300 
301  char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
302  char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
303  char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
304  char_array_4[3] = char_array_3[2] & 0x3f;
305 
306  for( j = 0; (j < i + 1); j++ )
307  out += chars[char_array_4[j]];
308 
309  while( (i++ < 3) )
310  out += '=';
311  }
312 
313  return true;
314  }
315 
316  template<>
317  bool base<64>::decode( std::string &out, const std::string &encoded ) {
318 
319  const std::string chars =
320  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
321  "abcdefghijklmnopqrstuvwxyz"
322  "0123456789+/";
323 
324  unsigned int in_len = (unsigned int)encoded.size();
325  unsigned int i = 0;
326  unsigned int j = 0;
327  unsigned int in_ = 0;
328  unsigned char char_array_4[4], char_array_3[3];
329  out.clear();
330 
331  while (in_len-- && ( encoded[in_] != '=') && //is_base64(encoded[in_])) {
332  (isalnum(encoded[in_]) || encoded[in_] == '+' || encoded[in_] == '/')) {
333  char_array_4[i++] = encoded[in_]; in_++;
334  if (i ==4) {
335  for (i = 0; i <4; i++)
336  char_array_4[i] = chars.find(char_array_4[i]);
337 
338  char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
339  char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
340  char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
341 
342  for (i = 0; (i < 3); i++)
343  out += char_array_3[i];
344  i = 0;
345  }
346  }
347 
348  if (i) {
349  for (j = i; j <4; j++)
350  char_array_4[j] = 0;
351 
352  for (j = 0; j <4; j++)
353  char_array_4[j] = chars.find(char_array_4[j]);
354 
355  char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
356  char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
357  char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
358 
359  for (j = 0; (j < i - 1); j++) out += char_array_3[j];
360  }
361 
362  return true;
363  }
364 
365 
366  // aliases
367  template<> std::string base<64>::encode( const std::string &binary ) {
368  std::string out;
369  return base<64>::encode( out, binary ) ? out : std::string();
370  }
371  template<> std::string base<64>::decode( const std::string &text ) {
372  std::string out;
373  return base<64>::decode( out, text ) ? out : std::string();
374  }
375 
376  template<> std::string base<85>::encode( const std::string &binary ) {
377  std::string out;
378  return base<85>::encode( out, binary ) ? out : std::string();
379  }
380  template<> std::string base<85>::decode( const std::string &text ) {
381  std::string out;
382  return base<85>::decode( out, text ) ? out : std::string();
383  }
384 
385  template<> std::string base<91>::encode( const std::string &binary ) {
386  std::string out;
387  return base<91>::encode( out, binary ) ? out : std::string();
388  }
389  template<> std::string base<91>::decode( const std::string &text ) {
390  std::string out;
391  return base<91>::decode( out, text ) ? out : std::string();
392  }
393 }
394 
395 
396 #ifdef BASE_BUILD_TESTS
397 
398 // tiny unittest suite. rlyeh, public domain {
399 #include <stdio.h>
400 #include <string.h>
401 #include <stdlib.h>
402 #define suite(...) if(printf("------ " __VA_ARGS__),puts(""),true)
403 #define test(...) (errno=0,++tst,err+=!(ok=!!(__VA_ARGS__))),printf("[%s] %d %s (%s)\n",ok?" OK ":"FAIL",__LINE__,#__VA_ARGS__,strerror(errno))
404 unsigned tst=0,err=0,ok=atexit([]{ suite("summary"){ printf("[%s] %d tests = %d passed + %d errors\n",err?"FAIL":" OK ",tst,tst-err,err); }});
405 // } /*usage:*/ int main() { /* orphan test */ test(1<2); suite("grouped tests") { test(1<2); test(1<2); } }
406 
407 #include <cassert>
408 #include <iostream>
409 
410 void unittest( const std::string &binary ) {
411  bool allows_preview = [&binary]{ for( const unsigned char &ch : binary ) if( ch > 127 ) return 0; return 1; }();
412  size_t base64len = 0, base85len = 0, base91len = 0, binarylen = binary.size();
413 
414  {
415  std::string enc64 = base64::encode(binary);
416  std::string dec64 = base64::decode(enc64);
417  base64len = enc64.size();
418 
419  // sanity check
420  test( dec64 == binary );
421  }
422 
423  {
424  std::string enc85 = base85::encode(binary);
425  std::string dec85 = base85::decode(enc85);
426  base85len = enc85.size();
427 
428  // sanity check
429  test( dec85 == binary );
430 
431  // C-string checks
432  test( enc85.find_first_of('"') == std::string::npos );
433  test( enc85.find_first_of('\\') == std::string::npos );
434  }
435 
436  {
437  std::string enc91 = base91::encode(binary);
438  std::string dec91 = base91::decode(enc91);
439  base91len = enc91.size();
440 
441  // sanity check
442  test( dec91 == binary );
443 
444  // XML, JSON checks
445  test( enc91.find_first_of('<') == std::string::npos );
446  test( enc91.find_first_of('>') == std::string::npos );
447  test( enc91.find_first_of('"') == std::string::npos );
448 
449  // extra whitespace check (base91 strings with extra whitespaces)
450  std::string white91 = " \r\n\f\t\v\n" + enc91 + " \r\n\f\t\v\n";
451  test( binary == base91::decode(white91));
452 
453  // break whitespace check (base91 strings with whitespaces in between)
454  std::string break91 = enc91;
455  break91.insert( break91.size() / 2, " \r\n\f\t\v\n" );
456  test( binary == base91::decode(break91));
457 
458  // split text check
459  std::string split91 = enc91.substr(0, enc91.size() / 2) + "\r\n\r\n\t\t " + enc91.substr(enc91.size() / 2);
460  test( binary == base91::decode(split91) );
461  }
462 
463  // more sanity checks
464  test( binarylen <= base91len );
465  test( base91len <= base85len );
466  test( base85len - 4 <= base64len ); // optional 4-bytes overhead
467 
468  auto overhead = [&binarylen]( size_t encoding_size ) -> size_t { return ((encoding_size*100/binarylen)-100); };
469  std::cout << "\nresults: " << ( allows_preview ? std::string() + '\"' + binary + '\"' : "(hidden text)" ) << '\n';
470  std::cout << "\tbinary: " << overhead(binarylen) << "% overhead (total: " << binarylen << " bytes)\n";
471  std::cout << "\tbase64: " << overhead(base64len) << "% overhead (total: " << base64len << " bytes)\n";
472  std::cout << "\tbase85: " << overhead(base85len) << "% overhead (total: " << base85len << " bytes)\n";
473  std::cout << "\tbase91: " << overhead(base91len) << "% overhead (total: " << base91len << " bytes)\n\n";
474 }
475 
476 void unittest_inplace( const std::string &binary ) {
477  {
478  std::string enc64, dec64;
479  test( base64::encode(enc64, binary) );
480  test( base64::decode(dec64, enc64) );
481  test( dec64 == binary );
482  }
483  {
484  std::string enc85, dec85;
485  test( base85::encode(enc85, binary) );
486  test( base85::decode(dec85, enc85) );
487  test( dec85 == binary );
488  }
489  {
490  std::string enc91, dec91;
491  test( base91::encode(enc91, binary) );
492  test( base91::decode(dec91, enc91) );
493  test( dec91 == binary );
494  }
495 }
496 
497 int main() {
498  // basic sample
499  std::string encoded_64 = base64::encode("Hello world from BASE64! \x1");
500  std::string decoded_64 = base64::decode(encoded_64);
501  std::cout<< decoded_64 << " <-> " << encoded_64 << std::endl;
502 
503  std::string encoded_85 = base85::encode("Hello world from BASE85! \x1");
504  std::string decoded_85 = base85::decode(encoded_85);
505  std::cout<< decoded_85 << " <-> " << encoded_85 << std::endl;
506 
507  std::string encoded_91 = base91::encode("Hello world from BASE91! \x1");
508  std::string decoded_91 = base91::decode(encoded_91);
509  std::cout<< decoded_91 << " <-> " << encoded_91 << std::endl << std::endl;
510 
511  // [ref] http://en.wikipedia.org/wiki/Base64
512  unittest( "Man is distinguished, not only by his reason, but by this singular passion from\n"
513  "other animals, which is a lust of the mind, that by a perseverance of delight in the continued\n"
514  "and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure." );
515 
516  // Binary test
517  unittest( "hello world \x1\x2");
518 
519  // Zero-ending
520  unittest( std::string("abc\x1\x2\0", 6 ) );
521 
522  // 16 mb dataset
523  std::string charset;
524  charset.reserve( 256 * 256 * 256 );
525  for( int i = 256 ; --i >= 0; ) {
526  for( int j = 256 ; --j >= 0; ) {
527  for( int k = 256 ; --k >= 0; ) {
528  charset += char(i) + char(j) + char(k);
529  }
530  }
531  }
532  unittest_inplace( charset );
533 
534  std::cout << "All ok." << std::endl;
535 }
536 #endif
537 
538 
539 #ifdef BASE_BUILD_DEMO
540 #include <fstream>
541 #include <iostream>
542 #include <sstream>
543 #include <string>
544 int main( int argc, const char **argv ) {
545  if( argc == 4 ) {
546  std::ifstream ifs( argv[3], std::ios::binary );
547  std::stringstream ss;
548  ss << ifs.rdbuf();
549  bool enc = argv[1][0] == 'e', dec = argv[1][0] == 'd';
550  bool b64 = argv[2][0] == '6', b85 = argv[2][0] == '8', b91 = argv[2][0] == '9';
551  if( b91 && enc ) return std::cout << base91::encode( ss.str() ), (ifs.good() ? 0 : 1);
552  else if( b91 && dec ) return std::cout << base91::decode( ss.str() ), (ifs.good() ? 0 : 1);
553  else if( b85 && enc ) return std::cout << base85::encode( ss.str() ), (ifs.good() ? 0 : 1);
554  else if( b85 && dec ) return std::cout << base85::decode( ss.str() ), (ifs.good() ? 0 : 1);
555  else if( b64 && enc ) return std::cout << base64::encode( ss.str() ), (ifs.good() ? 0 : 1);
556  else if( b64 && dec ) return std::cout << base64::decode( ss.str() ), (ifs.good() ? 0 : 1);
557  }
558  std::cout << argv[0] << " [e|d] [64|85|91] file" << std::endl;
559  return 1;
560 }
561 #endif
A collection of functions for debugging.