lean cpp library
A lean C++ library providing efficient utility classes for high-performance C++ applications.
numeric.h
00001 /*****************************************************/
00002 /* lean IO                      (c) Tobias Zirr 2011 */
00003 /*****************************************************/
00004 
00005 #ifndef LEAN_IO_NUMERIC
00006 #define LEAN_IO_NUMERIC
00007 
00008 #include "../lean.h"
00009 #include "../meta/strip.h"
00010 #include <clocale>
00011 #include <cstdio>
00012 #include "../strings/types.h"
00013 
00014 namespace lean
00015 {
00016 namespace io
00017 {
00018 
00021 template <class CharIter, class Integer>
00022 inline CharIter int_to_char(CharIter buffer, Integer num)
00023 {
00024     typedef typename lean::strip_modifiers<typename lean::strip_reference<Integer>::type>::type int_type;
00025     typedef typename lean::int_type<lean::sign_class::sign, sizeof(int_type)>::type sint_type;
00026     typedef typename lean::int_type<lean::sign_class::no_sign, sizeof(int_type)>::type uint_type;
00027 
00028     uint_type unum = static_cast<uint_type>(num);
00029 
00030     // Check, if signed
00031     if (static_cast<int_type>(-1) < static_cast<int_type>(0))
00032     {
00033         // Check sign
00034         if (num < static_cast<int_type>(0))
00035         {
00036             unum = static_cast<uint_type>(-static_cast<sint_type>(num));
00037             *(buffer++) = '-';
00038         }
00039     }
00040 
00041     CharIter first = buffer;
00042 
00043     // Convert backwards
00044     do
00045     {
00046         *(buffer++) = '0' + static_cast<char>(unum % 10U);
00047         unum = unum / 10U;
00048     }
00049     while (unum > 0);
00050 
00051     CharIter last = buffer;
00052 
00053     // Swap character order
00054     do
00055     {
00056         char tmp = *(--last);
00057         *last = *first;
00058         *(first++) = tmp;
00059     }
00060     while (first < last);
00061 
00062     // Return end
00063     return buffer;
00064 }
00065 
00067 template <class Integer>
00068 struct max_int_string_length
00069 {
00071     static const int value = (size_info<Integer>::bits + 2) / 3 + 3;
00072 };
00073 
00075 template <class Integer>
00076 inline utf8_string int_to_string(Integer num)
00077 {
00078     // Estimate decimal length
00079     char buffer[max_int_string_length<Integer>::value];
00080     // Assign to string
00081     return utf8_string(buffer, int_to_char(buffer, num));
00082 }
00083 
00086 template <class CharIter, class Integer>
00087 inline CharIter char_to_int(CharIter begin, CharIter end, Integer &num)
00088 {
00089     typedef typename lean::strip_modifiers<Integer>::type int_type;
00090     typedef typename lean::int_type<lean::sign_class::sign, sizeof(int_type)>::type sint_type;
00091     typedef typename lean::int_type<lean::sign_class::no_sign, sizeof(int_type)>::type uint_type;
00092 
00093     bool flip = false;
00094 
00095     // Check, if signed
00096     if (static_cast<int_type>(-1) < static_cast<int_type>(0))
00097     {
00098         // Check sign
00099         if (*begin == '-')
00100         {
00101             flip = true;
00102             ++begin;
00103         }
00104         else if(*begin == '+')
00105             ++begin;
00106     }
00107 
00108     uint_type unum = 0U;
00109 
00110     CharIter first = begin;
00111 
00112     // Convert front-to-back (Horner)
00113     while (begin != end)
00114     {
00115         unsigned int digit = static_cast<unsigned int>(*begin - '0');
00116 
00117         // Stop on non-digit character
00118         if (digit > 9)
00119             break;
00120 
00121         unum = unum * 10U + static_cast<uint_type>(digit);
00122         ++begin;
00123     }
00124 
00125     // Immediately return iterator to invalid character on error
00126     if (begin != first)
00127     {
00128         num = static_cast<int_type>(unum);
00129 
00130         // Check, if signed
00131         if (static_cast<int_type>(-1) < static_cast<int_type>(0))
00132         {
00133             // Flip number, if negative
00134             if (flip)
00135                 num = static_cast<int_type>(-static_cast<sint_type>(unum));
00136         }
00137     }
00138 
00139     // Return end position
00140     return begin;
00141 }
00142 
00144 template <class Integer>
00145 inline bool string_to_int(const utf8_ntri &string, Integer &num)
00146 {
00147     utf8_ntri::const_iterator end = string.end();
00148     return (char_to_int(string.begin(), end, num) == end);
00149 }
00150 
00152 template <class Float>
00153 struct max_float_string_length
00154 {
00156     static const int value = ((size_info<Float>::bits + 2) / 3) * 3 + 8;
00157 };
00158 
00161 template <class CharIter, class Float>
00162 inline CharIter float_to_char(CharIter buffer, Float num)
00163 {
00164     static const int precision = static_cast<int>(
00165         (ieee_float_desc<Float>::mantissa_bits + 5) / 3 );
00166 
00167 #ifdef _MSC_VER
00168     // Use MS extension
00169     static const _locale_t invariantLocale = _create_locale(LC_ALL, "C");
00170     return buffer + _sprintf_l(&(*buffer), "%.*g", invariantLocale, precision, num);
00171 #else
00172     // TODO: Do what the standard library does?
00173     return buffer + sprintf(&(*buffer), "%.*g", precision, num);
00174 #endif
00175 }
00176 
00178 template <class Float>
00179 inline utf8_string float_to_string(Float num)
00180 {
00181     // Estimate decimal length
00182     char buffer[max_float_string_length<Float>::value];
00183     // Assign to string
00184     return utf8_string(buffer, float_to_char(buffer, num));
00185 }
00186 
00190 template <class CharIter, class Float>
00191 inline CharIter char_to_float(CharIter begin, CharIter end, Float &num)
00192 {
00193     double value;
00194     const char *pBegin = &(*begin);
00195     const char *pEnd;
00196 
00197 #ifdef _MSC_VER
00198     // Use MS extension
00199     static const _locale_t invariantLocale = _create_locale(LC_ALL, "C");
00200     value = _strtod_l(pBegin, const_cast<char**>(&pEnd), invariantLocale);
00201 #else
00202     // TODO: Do what the standard library does?
00203     value = strtod(pBegin, const_cast<char**>(&pEnd));
00204 #endif
00205 
00206     CharIter stop = begin + (pEnd - pBegin);
00207 
00208     // First check for errors, the
00209     if (stop == end)
00210         num = static_cast<Float>(value);
00211 
00212     return stop;
00213 }
00214 
00216 template <class Float>
00217 inline bool string_to_float(const utf8_ntri &string, Float &num)
00218 {
00219     utf8_ntri::const_iterator end = string.end();
00220     return (char_to_float(string.begin(), end, num) == end);
00221 }
00222 
00223 } // namespace
00224 
00225 using io::int_to_char;
00226 using io::int_to_string;
00227 using io::max_int_string_length;
00228 using io::char_to_int;
00229 using io::string_to_int;
00230 
00231 using io::float_to_char;
00232 using io::float_to_string;
00233 using io::max_float_string_length;
00234 using io::char_to_float;
00235 using io::string_to_float;
00236 
00237 } // namespace
00238 
00239 #endif