lean cpp library
A lean C++ library providing efficient utility classes for high-performance C++ applications.
|
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