-/* $Id$
-
-This file is part of libmspstrings
-Copyright © 2006-2008 Mikko Rasa
-Distributed under the LGPL
-*/
-
#include <cmath>
#include <limits>
+#include <msp/core/inttypes.h>
+#include "format.h"
#include "lexicalcast.h"
using namespace std;
struct IsSigned
{ enum { result = !(static_cast<T>(-1)>0) }; };
-template<typename T, bool f = (sizeof(T)>sizeof(unsigned long))>
-struct Temporary
-{ typedef unsigned long Type; };
-
-template<typename T>
-struct Temporary<T, true>
-{
-#ifdef WIN32
- typedef __int64 Type;
-#else
- typedef unsigned long long Type;
-#endif
-};
-
/* Helper to avoid warnings about an unsigned type never being < 0 */
template<typename T, bool f = IsSigned<T>::result>
struct IsNegative
const char *digits = (f.get_uppercase() ? udigits : ldigits);
if(v)
{
- typename Temporary<T>::Type w = Absolute<T>::eval(v);
+ typename MatchingInt<T>::UnsignedType w = Absolute<T>::eval(v);
while(w)
{
*--ptr = digits[w%base];
T str_to_int(const std::string &s, const Fmt &f)
{
if(s.empty())
- throw LexicalError("Empty input in integer conversion");
+ throw lexical_error("conversion of '' to integer");
std::string::const_iterator i = s.begin();
if(*i=='-')
{
if(!IsSigned<T>::result)
- throw LexicalError("Negative sign in unsigned integer conversion");
+ throw lexical_error(format("conversion of '%s' to unsigned integer", s));
neg = true;
++i;
}
// Must have some digits to convert
if(i==s.end())
- throw LexicalError("Missing digits in integer conversion");
+ throw lexical_error(format("conversion of '%s' to integer", s));
T base = f.get_base();
if(!base && i!=s.end())
else if(*i>='a' && *i<='f')
digit = *i-'a'+10;
if(digit>=base)
- throw LexicalError("Invalid digit in integer conversion");
+ throw lexical_error(format("conversion of '%s' to integer (base-%d)", s, base));
T next = result*base+digit;
if(next/base!=result)
- throw LexicalError("Overflow in integer conversion");
+ throw lexical_error(format("conversion of '%s' to %d-bit integer", s, sizeof(T)*8));
result = next;
}
bool str_to_bool(const string &s)
{
if(s.empty())
- throw LexicalError("Empty input in boolean conversion");
+ throw lexical_error("conversion of '' to boolean");
if(s=="1" || s=="true" || s=="yes" || s=="on")
return true;
else if(s=="0" || s=="false" || s=="no" || s=="off")
return false;
- throw LexicalError("Invalid input in boolean conversion");
+ throw lexical_error(format("conversion of '%s' to boolean", s));
}
string flt_to_str(T v, const Fmt &f)
{
if(f.get_type()==Fmt::CHAR)
- throw LexicalError("Character format in floating-point conversion");
+ throw format_mismatch("floating-point conversion with character format");
Fmt::FloatMode mode = f.get_floatmode();
long double w = abs(v);
if(w>=10)
{
long double div = 1;
- while(div*10<w)
+ while(div*10<=w)
{
++exp;
div *= 10;
// Decide how to format the number
unsigned digits;
+ unsigned leading_zeroes = 0;
unsigned point = 1;
bool showexp = false;
if(mode==Fmt::FIXED)
}
else
{
- point = max(exp, 0)+1;
if(exp<0)
- digits += -exp;
+ leading_zeroes = -exp;
+ else
+ point = exp+1;
}
}
// Apply rounding
w += 5.0l/pow(10.0l, static_cast<long double>(digits));
- if(w>10)
+ if(w>=10)
{
// Rounding bumped us to the next exponent, deal with it
w /= 10;
}
if(!showexp)
{
- ++digits;
- ++point;
+ if(mode==Fmt::FIXED)
+ ++digits;
+ if(leading_zeroes)
+ --leading_zeroes;
+ else
+ ++point;
}
else
++exp;
}
+ digits += leading_zeroes;
+
// Create a buffer and start from the end
unsigned size = max(f.get_width(), digits+8);
char *buf = new char[size];
{
if(i==point)
*mptr++ = '.';
- if(showexp || static_cast<int>(i)>=-exp)
+ if(!leading_zeroes)
{
int digit = static_cast<int>(w);
*mptr++ = '0'+digit;
w = (w-digit)*10;
}
else
+ {
*mptr++ = '0';
+ --leading_zeroes;
+ }
}
if(f.get_showpoint())
T str_to_flt(const string &s, const Fmt &)
{
if(s.empty())
- throw LexicalError("Empty input in floating-point conversion");
+ throw lexical_error("conversion of '' to floating-point");
std::string::const_iterator i = s.begin();
// Must have some digits to convert
if(i==s.end())
- throw LexicalError("Missing digits in floating-point conversion");
+ throw lexical_error(format("conversion of '%s' to floating-point", s));
long double v = 0;
int exp = 0;
if(*i=='.')
{
if(point_seen)
- throw LexicalError("Extra point in floating-point conversion");
+ throw lexical_error(format("conversion of '%s' to floating-point", s));
point_seen = true;
}
else if(*i>='0' && *i<='9')
break;
}
else
- throw LexicalError("Invalid digit in floating-point conversion");
+ throw lexical_error(format("conversion of '%s' to floating-point", s));
}
// Scale and negate the result as needed
string str_to_str(const string &s, const Fmt &f)
{
if(f.get_type()==Fmt::NUM)
- throw LexicalError("Numeric format in string conversion");
+ throw format_mismatch("string conversion with numeric format");
return s;
}
void LexicalConverter::result(const string &s)
{
+ filled = true;
if(s.size()<fmt.get_width())
{
if(fmt.get_align()==Fmt::RIGHT)
buf = s;
}
+const string &LexicalConverter::get() const
+{
+ if(!filled)
+ throw lexical_error("conversion not performed");
+ return buf;
+}
+
/*** operator<< ***/
{ c.result(str_to_str(s, c.get_fmt())); }
void operator<<(LexicalConverter &c, const void *p)
-{ c.result(int_to_str(reinterpret_cast<unsigned long>(p), c.get_fmt())); }
+{ c.result(int_to_str(reinterpret_cast<IntPtr>(p), c.get_fmt())); }
/*** operator>> ***/
{
const std::string &s = c.get();
if(s.empty())
- throw LexicalError("Empty input in character conversion");
+ throw lexical_error("conversion of '' to character");
if(s.size()>1)
- throw LexicalError("Extra input in character conversion");
+ throw lexical_error(format("conversion of '%s' to character", s));
v = s[0];
}
}