libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ttypes.hpp
Go to the documentation of this file.
1 #ifndef LIBJMMCG_CORE_TTYPES_HPP
2 #define LIBJMMCG_CORE_TTYPES_HPP
3 
4 /******************************************************************************
5 ** Copyright © 2002 by J.M.McGuiness, coder@hussar.me.uk
6 **
7 ** This library is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU Lesser General Public
9 ** License as published by the Free Software Foundation; either
10 ** version 2.1 of the License, or (at your option) any later version.
11 **
12 ** This library is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ** Lesser General Public License for more details.
16 **
17 ** You should have received a copy of the GNU Lesser General Public
18 ** License along with this library; if not, write to the Free Software
19 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 
22 #include "config.h"
23 #include "debug_defines.hpp"
24 
25 #include <cassert>
26 #include <cinttypes>
27 #include <cmath>
28 
29 #ifdef _MSC_VER
30 
31 # include <tchar.h>
32 
33 #endif // _MSC_VER
34 
35 #include <algorithm>
36 #include <functional>
37 #include <istream>
38 #include <iterator>
39 #include <ostream>
40 #include <sstream>
41 #include <string>
42 
43 #ifndef _TCHAR_DEFINED
44 # define TCHAR jmmcg::LIBJMMCG_VER_NAMESPACE::tchar;
45 # define _TCHAR_DEFINED
46 # ifdef UNICODE
47 # define _JMMCG_WIDE_CHARS
48 # endif
49 #endif
50 
51 #undef _T
52 
53 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE {
54 
55 // Macros to make easy work of making your code wide-char compliant.
56 #ifdef _JMMCG_WIDE_CHARS
57  typedef std::wchar_t tchar;
58 # define _T(str) L##str
59 # define tsscanf swscanf
60 # define tstrlen wstrlen
61 #else
62  typedef char tchar;
63 # define _T(str) str
64 # define tsscanf sscanf
65 # define tstrlen strlen
66 #endif
67  // And to wrap some of the more used types to make them char-size independant.
74 
75 #if defined(_MSC_VER) && (_MSC_VER < 1300)
76 
77  /**
78  \todo Implement using the advice given in "Standard C++ IOStreams and Locales" by A.Langer & K.Kreft, page 170.
79  */
80  inline tostream & __fastcall
81  operator<<(tostream &o,const __int64 &i) {
82  tchar buff[34];
83  int radix=10;
84  if ((o.flags() & std::ios::basefield) == std::ios::oct) {
85  radix=8;
86  } else if ((o.flags() & std::ios::basefield) == std::ios::hex) {
87  radix=16;
88  }
89  ::_i64tot_s(i, buff, sizeof(buff), radix);
90  o << buff;
91  return o;
92  }
93 
94  /**
95  \todo Implement using the advice given in "Standard C++ IOStreams and Locales" by A.Langer & K.Kreft, page 170.
96  */
97  inline tistream & __fastcall
98  operator>>(tistream &o,__int64 &i) {
99  tstring buff;
100  o>>buff;
101  i=::_ttoi64(buff.c_str());
102  return o;
103  }
104 
105  /**
106  \todo Implement using the advice given in "Standard C++ IOStreams and Locales" by A.Langer & K.Kreft, page 170.
107  */
108  inline tostream & __fastcall
109  operator<<(tostream &o,const unsigned __int64 &i) {
110  tchar buff[34];
111  int radix=10;
112  if ((o.flags() & std::ios::basefield) == std::ios::oct) {
113  radix=8;
114  } else if ((o.flags() & std::ios::basefield) == std::ios::hex) {
115  radix=16;
116  }
117  ::_ui64tot_s(i, buff, sizeof(buff), radix);
118  o << buff;
119  return o;
120  }
121 
122  /**
123  \todo Implement using the advice given in "Standard C++ IOStreams and Locales" by A.Langer & K.Kreft, page 170.
124  */
125  inline tistream & __fastcall
126  operator>>(tistream &o,unsigned __int64 &i) {
127  tstring buff;
128  o>>buff;
129  i=::_ttoi64(buff.c_str());
130  return o;
131  }
132 
133 #endif // _MSC_VER
134 
135  /// Returns the number of digits in the base 10 representation of an uint64_t.
136  /**
137  Useful for preallocating buffers and such. It is also used internally, see below. Measurements suggest that defining a separate overload for 32-bit integers is not worthwhile.
138 
139  From <a href="https://github.com/facebook/folly">Folly</a>.
140  */
141  constexpr inline std::uint32_t
142  num_digits_in_base10(std::uint64_t v) noexcept(true) __attribute__((pure));
143  constexpr inline std::uint32_t
144  num_digits_in_base10(std::uint64_t v) noexcept(true) {
145 #ifdef __x86_64__
146  // For this arch we can get a little help from specialized CPU instructions which can count leading zeroes; 64 minus that is appx. log (base 2). Use that to approximate base-10 digits (log_10) and then adjust if needed.
147 
148  // 10^i, defined for i:[0, ..., 19). This is 20*8==160 bytes, which fits neatly into 5 cache lines (assuming a cache line size of 64).
149  ALIGN_TO_L1_CACHE constexpr const std::uint64_t powersOf10[]={
150  1ULL,
151  10ULL,
152  100ULL,
153  1000ULL,
154  10000ULL,
155  100000ULL,
156  1000000ULL,
157  10000000ULL,
158  100000000ULL,
159  1000000000ULL,
160  10000000000ULL,
161  100000000000ULL,
162  1000000000000ULL,
163  10000000000000ULL,
164  100000000000000ULL,
165  1000000000000000ULL,
166  10000000000000000ULL,
167  100000000000000000ULL,
168  1000000000000000000ULL,
169  10000000000000000000ULL,
170  };
171 
172  // "count leading zeroes" operation not valid; for 0; special case this.
173  if (UNLIKELY(!v)) {
174  return 1;
175  }
176  // Bits is in the ballpark of log_2(v).
177  const std::uint8_t leadingZeroes=__builtin_clzll(v);
178  const auto bits=sizeof(std::uint64_t)*8-1-leadingZeroes;
179 
180  // Approximate log_10(v) == log_10(2) * bits.
181  // Integer magic below: 77/256 is appx. 0.3010 (log_10(2)).
182  // The +1 is to make this the ceiling of the log_10 estimate.
183  const std::uint32_t minLength=1+((bits*77)>>8);
184 
185  // Return that log_10 lower bound, plus adjust if input >= 10^(that bound)
186  // in case there's a small error and we misjudged length.
187  return minLength+static_cast<std::uint32_t>(UNLIKELY(v>=powersOf10[minLength]));
188 #else
189  std::uint32_t result=1;
190  for (;;) {
191  if (LIKELY(v<10)) return result;
192  if (LIKELY(v<100)) return result + 1;
193  if (LIKELY(v<1000)) return result + 2;
194  if (LIKELY(v<10000)) return result + 3;
195  // Skip ahead by 4 orders of magnitude
196  v/=10000U;
197  result+=4;
198  }
199 #endif
200  }
201 
202  /// Copies the ASCII base 10 representation of v into the buffer and returns the number of bytes written.
203  /**
204  Assumes the buffer points to num_digits_in_base10(v) bytes of valid memory. Note that uint64 needs at most 20 bytes, uint32_t needs at most 10 bytes, uint16_t needs at most 5 bytes, and so on. Measurements suggest that defining a separate overload for 32-bit integers is not worthwhile.
205 
206  This primitive is unsafe because it makes the size assumption and does not write the terminal '\0'.
207 
208  From <a href="https://github.com/facebook/folly">Folly</a>.
209  */
210  inline std::uint32_t
211  uint64ToBufferUnsafe(std::uint64_t v, char * const buffer, [[maybe_unused]] std::uint32_t sz) noexcept(true) __attribute__((pure));
212  inline std::uint32_t
213  uint64ToBufferUnsafe(std::uint64_t v, char * const buffer, [[maybe_unused]] std::uint32_t sz) noexcept(true) {
214  assert(sz>0);
215  auto const digits_to_write=num_digits_in_base10(v);
216  assert(digits_to_write<=sz);
217  // WARNING: using size_t or pointer arithmetic for pos slows down the loop below 20x. This is because several 32-bit ops can be done in parallel, but only fewer 64-bit ones.
218  std::uint32_t pos=digits_to_write-1;
219  while (v>=10) {
220  // Keep these together so a peephole optimization "sees" them and computes them in one shot.
221  const auto q=v/10;
222  const auto r=static_cast<std::uint32_t>(v%10);
223  buffer[pos--]='0'+r;
224  v=q;
225  }
226  assert(pos==0);
227  // Last digit is trivial to handle.
228  buffer[pos]='0'+static_cast<char>(v);
229  return digits_to_write;
230  }
231 
232  /// Returns the ASCII base 10 representation in the buffer.
233  /**
234  \param buffer The ACSII base 10 representation of the natural number.
235  \param sz The length of the buffer.
236 
237  From <a href="https://github.com/facebook/folly">Folly</a>.
238  */
239  inline std::uint64_t
240  folly_ascii_to_int(char const *buffer, std::uint32_t sz) noexcept(true) __attribute__((pure));
241  inline std::uint64_t
242  folly_ascii_to_int(char const *buffer, std::uint32_t sz) noexcept(true) {
243  assert(buffer);
244  assert(sz>0);
245  ALIGN_TO_L1_CACHE static constexpr const std::uint64_t pow10[]={
246  10000000000000000000ULL,
247  1000000000000000000ULL,
248  100000000000000000ULL,
249  10000000000000000ULL,
250  1000000000000000ULL,
251  100000000000000ULL,
252  10000000000000ULL,
253  1000000000000ULL,
254  100000000000ULL,
255  10000000000ULL,
256  1000000000ULL,
257  100000000ULL,
258  10000000ULL,
259  1000000ULL,
260  100000ULL,
261  10000ULL,
262  1000ULL,
263  100ULL,
264  10ULL,
265  1ULL
266  };
267  char const * const e=buffer+sz;
268  std::uint64_t result=0;
269  auto i=sizeof(pow10)/sizeof(pow10[0])-sz;
270  for(; buffer!=e; ++buffer) {
271  assert(std::isdigit(*buffer));
272  const std::uint32_t digit=std::uint32_t(*buffer)-'0';
273  assert(digit<10U);
274  result+=digit*pow10[i++];
275  }
276  assert(std::strtoull(e-sz, nullptr, 10)==result);
277  return result;
278  }
279 
280  /// Returns the ASCII base 10 representation in the buffer.
281  /**
282  \param buffer The ACSII base 10 representation of the natural number.
283  \param sz The length of the buffer.
284  */
285  template<unsigned Base> inline std::uint64_t
286  ascii_to_int_baseline(char const * const buffer, std::size_t sz) noexcept(true) __attribute__((pure));
287  template<unsigned Base> inline std::uint64_t
288  ascii_to_int_baseline(char const * const buffer, std::size_t sz) noexcept(true) {
289  assert(buffer);
290  assert(sz>0);
291  char const *digit=buffer+sz;
292  std::uint64_t result=0;
293  std::uint64_t units=1;
294  while (--digit!=buffer) {
295  assert(std::isdigit(*digit));
296  const std::uint32_t d=std::uint32_t(*digit)-'0';
297  assert(d<10U);
298  result+=d*units;
299  units*=Base;
300  }
301  assert(std::isdigit(*digit));
302  result+=((*digit)-'0')*units;
303  assert(std::strtoull(buffer, nullptr, Base)==result);
304  return result;
305  }
306 
307  // Function to convert anything to a tstring, as long as "operator<<(...)" is defined for it.
308  template<typename T> inline tstring __fastcall
309  tostring(const T &val) {
310  tostringstream ss;
311  ss<<val;
312  return ss.str();
313  }
314  template<std::size_t N> inline tstring __fastcall
315  tostring(const std::array<tstring::value_type, N> &val) {
316  tostringstream ss;
317  if (std::find(val.begin(), val.end(), _T('\0'))!=val.end()) {
318  ss<<val.data();
319  } else {
320  std::copy(val.begin(), val.end(), std::ostream_iterator<tstring::value_type>(ss));
321  }
322  return ss.str();
323  }
324  template<> inline tstring __fastcall
325  tostring<tstring>(const tstring &val) {
326  return val;
327  }
328 
329  template<typename A,typename Fmt> inline tstring __fastcall
330  tostring(const A &a,const Fmt &format) {
331  tostringstream ss;
332  ss<<format<<a;
333  return ss.str();
334  }
335 
336  /// Convert the input value to a string stored in the supplied buffer.
337  /**
338  \param v The integer, decimal input value.
339  \param buff A buffer that must be large enough into which the value, represented as ASCII, decimal integers shall be converted.
340  \param Sz The size of the input buffer.
341  */
342  template<std::size_t Sz> constexpr inline std::size_t FORCE_INLINE
343  tostring(std::uint64_t v, char (&buff)[Sz]) noexcept(true) __attribute__((pure));
344  template<std::size_t Sz> constexpr inline std::size_t FORCE_INLINE
345  tostring(std::uint64_t v, char (&buff)[Sz]) noexcept(true) {
346  return uint64ToBufferUnsafe(v, buff, Sz);
347  }
348  /// Convert the input value to a string stored in the supplied buffer.
349  /**
350  \param v The integer, decimal input value.
351  \param buff A buffer that must be large enough into which the value, represented as ASCII, decimal integers shall be converted, zero-padded, right-justified.
352  \param Sz The size of the input buffer.
353  */
354  template<std::uint8_t Base, std::size_t Sz> constexpr inline std::size_t FORCE_INLINE
355  tostring_zero_pad_right_justify(std::uint32_t v, char (&buff)[Sz]) noexcept(true) __attribute__((pure));
356  template<std::uint8_t Base, std::size_t Sz> constexpr inline std::size_t FORCE_INLINE
357  tostring_zero_pad_right_justify(std::uint32_t v, char (&buff)[Sz]) noexcept(true) {
358  for (std::size_t i=Sz; i; --i) {
359  auto const q=v/Base;
360  auto const r=static_cast<char>(v%Base);
361  buff[i-1]=static_cast<char>(static_cast<std::uint8_t>('0')+r);
362  v=q;
363  }
364  return Sz;
365  }
366  /// Convert the input value to a string stored in the supplied buffer.
367  /**
368  \param v The integer, decimal input value.
369  \param buff A buffer that must be large enough into which the value, represented as ASCII, decimal integers shall be converted.
370  \param Sz The size of the input buffer.
371  */
372  template<std::size_t Sz> constexpr inline std::size_t FORCE_INLINE
373  tostring(std::int64_t v, char (&buff)[Sz]) noexcept(true) __attribute__((pure));
374  template<std::size_t Sz> constexpr inline std::size_t FORCE_INLINE
375  tostring(std::int64_t v, char (&buff)[Sz]) noexcept(true) {
376  if (v<0) {
377  buff[0]='-';
378  return uint64ToBufferUnsafe(-v, buff+1, Sz-1);
379  } else {
380  return uint64ToBufferUnsafe(v, buff, Sz);
381  }
382  }
383  template<class V> inline std::size_t
384  tostring(V v, char * const buff, std::size_t sz) noexcept(true)=delete;
385  /// Convert the input value to a string stored in the supplied buffer.
386  /**
387  \param v The integer, decimal input value.
388  \param buff A buffer that must be large enough into which the value, represented as ASCII, decimal integers shall be converted.
389  \param sz The size of the input buffer.
390  */
391  template<> inline std::size_t
392  tostring<int>(int v, char * const buff, std::size_t sz) noexcept(true) __attribute__((pure));
393  template<> inline std::size_t
394  tostring<int>(int v, char * const buff, std::size_t sz) noexcept(true) {
395  if (v<0) {
396  buff[0]='-';
397  return uint64ToBufferUnsafe(-v, buff+1, sz-1);
398  } else {
399  return uint64ToBufferUnsafe(v, buff, sz);
400  }
401  }
402  /// Convert the input value to a string stored in the supplied buffer.
403  /**
404  * \param v The integer, decimal input value.
405  * \param buff A buffer that must be large enough into which the value, represented as ASCII, decimal integers shall be converted.
406  * \param sz The size of the input buffer.
407  */
408  template<> inline std::size_t
409  tostring<unsigned int>(unsigned int v, char * const buff, std::size_t sz) noexcept(true) __attribute__((pure));
410  template<> inline std::size_t
411  tostring<unsigned int>(unsigned int v, char * const buff, std::size_t sz) noexcept(true) {
412  return uint64ToBufferUnsafe(v, buff, sz);
413  }
414  /// Convert the input value to a string stored in the supplied buffer.
415  /**
416  * \param v The integer, decimal input value.
417  * \param buff A buffer that must be large enough into which the value, represented as ASCII, decimal integers shall be converted.
418  * \param sz The size of the input buffer.
419  */
420  template<> inline std::size_t
421  tostring<long>(long v, char * const buff, std::size_t sz) noexcept(true) __attribute__((pure));
422  template<> inline std::size_t
423  tostring<long>(long v, char * const buff, std::size_t sz) noexcept(true) {
424  if (v<0) {
425  buff[0]='-';
426  return uint64ToBufferUnsafe(-v, buff+1, sz-1);
427  } else {
428  return uint64ToBufferUnsafe(v, buff, sz);
429  }
430  }
431  /// Convert the input value to a string stored in the supplied buffer.
432  /**
433  * \param v The integer, decimal input value.
434  * \param buff A buffer that must be large enough into which the value, represented as ASCII, decimal integers shall be converted.
435  * \param sz The size of the input buffer.
436  */
437  template<> inline std::size_t
438  tostring<unsigned long>(unsigned long v, char * const buff, std::size_t sz) noexcept(true) __attribute__((pure));
439  template<> inline std::size_t
440  tostring<unsigned long>(unsigned long v, char * const buff, std::size_t sz) noexcept(true) {
441  return uint64ToBufferUnsafe(v, buff, sz);
442  }
443  /// Convert the input value to a string stored in the supplied buffer.
444  /**
445  \param v The integer, decimal input value.
446  \param buff A buffer that must be large enough into which the value, represented as ASCII, decimal integers shall be converted.
447  \param sz The size of the input buffer.
448  */
449  inline std::size_t
450  tostring(std::uint32_t v, char * const buff, std::size_t sz) noexcept(true) __attribute__((pure));
451  inline std::size_t
452  tostring(std::uint32_t v, char * const buff, std::size_t sz) noexcept(true) {
453  return uint64ToBufferUnsafe(v, buff, sz);
454  }
455  /// Convert the input value to a string stored in the supplied buffer.
456  /**
457  \param v The integer, decimal input value.
458  \param buff A buffer that must be large enough into which the value, represented as ASCII, decimal integers shall be converted.
459  \param sz The size of the input buffer.
460  */
461  inline std::size_t
462  tostring(std::int64_t v, char * const buff, std::size_t sz) noexcept(true) __attribute__((pure));
463  inline std::size_t
464  tostring(std::int64_t v, char * const buff, std::size_t sz) noexcept(true) {
465  if (v<0) {
466  buff[0]='-';
467  return uint64ToBufferUnsafe(-v, buff+1, sz-1);
468  } else {
469  return uint64ToBufferUnsafe(v, buff, sz);
470  }
471  }
472  /// Convert the input value to a string stored in the supplied buffer.
473  /**
474  \param v The integer, decimal input value.
475  \param buff A buffer that must be large enough into which the value, represented as ASCII, decimal integers shall be converted.
476  \param sz The size of the input buffer.
477  */
478  inline std::size_t
479  tostring(std::uint64_t v, char * const buff, std::size_t sz) noexcept(true) __attribute__((pure));
480  inline std::size_t
481  tostring(std::uint64_t v, char * const buff, std::size_t sz) noexcept(true) {
482  return uint64ToBufferUnsafe(v, buff, sz);
483  }
484  /// Convert the input value to a string stored in the supplied buffer.
485  /**
486  \param v The floating-point, decimal input value.
487  \param buff A buffer that must be large enough into which the value, represented as ASCII, decimal, floating-point number shall be converted.
488  \param sz The size of the input buffer.
489 
490  \todo This is pretty slow. Write an optimised version for just decimal conversion.
491  */
492  inline std::size_t
493  tostring(double v, char * const buff, std::size_t sz) noexcept(true) {
494  return std::snprintf(buff, sz, "%f", v);
495  }
496 
497  // Function to convert anything from a tstring, as long as "operator>>(...)" is defined for it.
498  template<typename T> inline void __fastcall
499  fromstring(const tstring &str, T &val) {
500  tstringstream ss;
501  ss<<str;
502  ss>>val;
503  }
504  template<> inline void __fastcall
505  fromstring<tstring>(const tstring &str, tstring &val) {
506  val=str;
507  }
508  template<class V> typename std::enable_if<std::is_integral<V>::value || std::is_floating_point<V>::value, V>::type
509  fromstring(char const * const, std::uint32_t) noexcept(true) __attribute__((pure)) =delete;
510  /// Convert the decimal value contained in the input string into an integral value.
511  /**
512  * \param buff The input buffer that must contain the decimal value only.
513  * \return The scanned value.
514  */
515  template<> inline int
516  fromstring<int>(char const * const begin, std::uint32_t sz) noexcept(true) __attribute__((pure));
517  template<> inline int
518  fromstring<int>(char const * const begin, std::uint32_t sz) noexcept(true) {
519  return ascii_to_int_baseline<10u>(begin, sz);
520  }
521  /// Convert the decimal value contained in the input string into an integral value.
522  /**
523  * \param buff The input buffer that must contain the decimal value only.
524  * \return The scanned value.
525  */
526  template<> inline unsigned int
527  fromstring<unsigned int>(char const * const begin, std::uint32_t sz) noexcept(true) __attribute__((pure));
528  template<> inline unsigned int
529  fromstring<unsigned int>(char const * const begin, std::uint32_t sz) noexcept(true) {
530  return ascii_to_int_baseline<10u>(begin, sz);
531  }
532  /// Convert the decimal value contained in the input string into an integral value.
533  /**
534  * \param buff The input buffer that must contain the decimal value only.
535  * \return The scanned value.
536  */
537  template<> inline long
538  fromstring<long>(char const * const begin, std::uint32_t sz) noexcept(true) __attribute__((pure));
539  template<> inline long
540  fromstring<long>(char const * const begin, std::uint32_t sz) noexcept(true) {
541  return ascii_to_int_baseline<10u>(begin, sz);
542  }
543  /// Convert the decimal value contained in the input string into an integral value.
544  /**
545  \param buff The input buffer that must contain the decimal value only.
546  \return The scanned value.
547  */
548  template<> inline unsigned long
549  fromstring<unsigned long>(char const * const begin, std::uint32_t sz) noexcept(true) __attribute__((pure));
550  template<> inline unsigned long
551  fromstring<unsigned long>(char const * const begin, std::uint32_t sz) noexcept(true) {
552  return ascii_to_int_baseline<10u>(begin, sz);
553  }
554  /// Convert the decimal value contained in the input string into an integral value.
555  /**
556  \param buff The input buffer that must contain the decimal value only.
557  \return The scanned value.
558  */
559  template<> inline long long
560  fromstring<long long>(char const * const begin, std::uint32_t sz) noexcept(true) __attribute__((pure));
561  template<> inline long long
562  fromstring<long long>(char const * const begin, std::uint32_t sz) noexcept(true) {
563  return ascii_to_int_baseline<10u>(begin, sz);
564  }
565  /// Convert the decimal value contained in the input string into an integral value.
566  /**
567  \param buff The input buffer that must contain the decimal value only.
568  \return The scanned value.
569  */
570  template<> inline unsigned long long
571  fromstring<unsigned long long>(char const * const begin, std::uint32_t sz) noexcept(true) __attribute__((pure));
572  template<> inline unsigned long long
573  fromstring<unsigned long long>(char const * const begin, std::uint32_t sz) noexcept(true) {
574  return ascii_to_int_baseline<10u>(begin, sz);
575  }
576  /// Convert the decimal value contained in the input string into an integral value.
577  /**
578  \param buff The input buffer that must contain the decimal value only, including a decimal point.
579  \return The scanned value.
580  */
581  template<> inline double
582  fromstring<double>(char const * const begin, std::uint32_t) noexcept(true) __attribute__((pure));
583  template<> inline double
584  fromstring<double>(char const * const begin, std::uint32_t sz) noexcept(true) {
585  constexpr unsigned Base=10;
586  char const *decimal_point=begin;
587  using diff_t=decltype(std::distance(begin, decimal_point));
588  static_assert(std::numeric_limits<std::uint32_t>::max()<=std::numeric_limits<diff_t>::max());
589  while (std::distance(begin, decimal_point)<static_cast<diff_t>(sz) && *decimal_point!='.') {
590  ++decimal_point;
591  }
592  char const *whole=decimal_point;
593  double result=0;
594  std::uint64_t units;
595  if (std::distance(begin, decimal_point)<static_cast<diff_t>(sz)) {
596  const std::size_t num_frac_digits=sz-(decimal_point-begin);
597  char const *fraction=decimal_point+num_frac_digits;
598  units=num_frac_digits;
599  while (--fraction!=decimal_point) {
600  assert(std::isdigit(*fraction));
601  --units;
602  result+=((*fraction)-'0')/__builtin_powi(Base, units);
603  }
604  }
605  units=1;
606  while (--whole!=begin) {
607  assert(std::isdigit(*whole));
608  result+=((*whole)-'0')*units;
609  units*=Base;
610  }
611  assert(std::isdigit(*whole));
612  result+=((*whole)-'0')*units;
613  assert(std::abs(std::strtod(begin, nullptr)-result)<0.000001);
614  return result;
615  }
616 
617  template<typename T> inline void __fastcall
618  delete_ptr(T *ptr) {
619  // T should be a pointer type really....
620  delete ptr;
621  }
622 
623  /// A simple class to turn a character into upper case according to the current locale settings.
624  template<typename T>
625  class upperletter : public std::unary_function<T, T> {
626  public:
628  : ct(std::use_facet<std::ctype<T> >(std::locale())) {
629  }
630  T operator()(const T c) const {
631  return ct.toupper(c);
632  }
633 
634  private:
635  std::ctype<T> const &ct;
636  };
637 
638  /// A simple class to turn a character into lowercase according to the current locale settings.
639  template<typename T>
640  class lowerletter : public std::unary_function<T, T> {
641  public:
643  : ct(std::use_facet<std::ctype<T> >(std::locale())) {
644  }
645 
646  T operator()(const T c) const {
647  return ct.tolower(c);
648  }
649 
650  private:
651  std::ctype<T> const &ct;
652  };
653 
654  /// Turn the input string into an uppercase variant according to the current locale settings.
655  inline tstring
656  toupper(const tstring &l) {
657  tstring u;
658  std::transform(l.begin(),l.end(),std::back_inserter(u),upperletter<tstring::value_type>());
659  return u;
660  }
661 
662  /// Turn the input string into a lowercase variant according to the current locale settings.
663  inline tstring
664  tolower(const tstring &u) {
665  tstring l;
666  std::transform(u.begin(),u.end(),std::back_inserter<tstring>(l),lowerletter<tstring::value_type>());
667  return l;
668  }
669 
670  /// Turn the input range into an uppercase variant according to the current locale settings.
671  template<class Iter> inline Iter
672  toupper(const Iter b,const Iter e,Iter o) {
673  std::transform(b,e,o,upperletter<typename std::iterator_traits<Iter>::value_type>());
674  return o;
675  }
676 
677  /// Turn the input range into a lowercase variant according to the current locale settings.
678  template<class Iter> inline Iter
679  tolower(const Iter b,const Iter e,Iter o) {
680  std::transform(b,e,o,lowerletter<typename std::iterator_traits<Iter>::value_type>());
681  return o;
682  }
683 
684 } }
685 
686 namespace std {
687 
688  template<std::size_t Sz> inline jmmcg::LIBJMMCG_VER_NAMESPACE::tostream & __fastcall
689  operator<<(jmmcg::LIBJMMCG_VER_NAMESPACE::tostream &o, std::array<jmmcg::LIBJMMCG_VER_NAMESPACE::tstring::value_type, Sz> const &val) {
690  if (std::find(val.begin(), val.end(), _T('\0'))!=val.end()) {
691  o<<val.data();
692  } else {
693  o.write(val.data(), Sz);
694  }
695  return o;
696  }
697 
698  inline std::ostream & __fastcall
699  operator<<(std::ostream &o, std::exception_ptr ex) noexcept(false) {
700  try {
701  if (ex) {
702  std::rethrow_exception(ex);
703  }
704  } catch (std::exception const &e) {
705  o<<e.what();
706  }
707  return o;
708  }
709 
710 }
711 
712 #endif