|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r60225 - in trunk/boost/spirit/home: qi/nonterminal support
From: joel_at_[hidden]
Date: 2010-03-06 06:17:23
Author: djowel
Date: 2010-03-06 06:17:22 EST (Sat, 06 Mar 2010)
New Revision: 60225
URL: http://svn.boost.org/trac/boost/changeset/60225
Log:
correct casting of char with correct handling of signedness.
Text files modified:
trunk/boost/spirit/home/qi/nonterminal/rule.hpp | 2
trunk/boost/spirit/home/support/char_class.hpp | 61 ++++++++++++++++++++++++++++++++++-----
2 files changed, 53 insertions(+), 10 deletions(-)
Modified: trunk/boost/spirit/home/qi/nonterminal/rule.hpp
==============================================================================
--- trunk/boost/spirit/home/qi/nonterminal/rule.hpp (original)
+++ trunk/boost/spirit/home/qi/nonterminal/rule.hpp 2010-03-06 06:17:22 EST (Sat, 06 Mar 2010)
@@ -154,7 +154,7 @@
}
template <typename Expr>
- rule (Expr const& expr, std::string const& name_ = "unnamed-rule")
+ rule(Expr const& expr, std::string const& name_ = "unnamed-rule")
: base_type(terminal::make(reference_(*this)))
, name_(name_)
{
Modified: trunk/boost/spirit/home/support/char_class.hpp
==============================================================================
--- trunk/boost/spirit/home/support/char_class.hpp (original)
+++ trunk/boost/spirit/home/support/char_class.hpp 2010-03-06 06:17:22 EST (Sat, 06 Mar 2010)
@@ -18,12 +18,54 @@
#include <boost/config.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/spirit/home/support/unused.hpp>
+#include <boost/type_traits/is_signed.hpp>
+#include <boost/type_traits/make_unsigned.hpp>
+#include <boost/type_traits/make_signed.hpp>
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable: 4800) // 'int' : forcing value to bool 'true' or 'false' warning
#endif
+namespace boost { namespace spirit { namespace detail
+{
+ // Here's the thing... typical encodings except ASCII deals
+ // with unsigned integers > 127. ASCII uses only 127, but most
+ // char and wchar_t are signed. Thus, when you convert from, say,
+ // char with value > 127 it becomes negative (e.g. char 233 is
+ // -23). When you cast this to an unsigned int with 32 bits,
+ // you get 4294967273! The trick is to cast to an unsigned version
+ // of the source char first before casting to the target.
+ // {P.S. Don't worry about the code, the optimizer will
+ // optimize the if-else branches}
+
+ template <typename TargetChar, typename SourceChar>
+ TargetChar cast_char(SourceChar ch)
+ {
+ if (is_signed<TargetChar>::value != is_signed<SourceChar>::value)
+ {
+ typedef typename make_unsigned<SourceChar>::type USourceChar;
+ typedef typename make_signed<SourceChar>::type SSourceChar;
+
+ if (is_signed<SourceChar>::value)
+ {
+ // source is signed, target is unsigned
+ return TargetChar(USourceChar(ch));
+ }
+ else
+ {
+ // source is unsigned, target is signed
+ return TargetChar(SSourceChar(ch));
+ }
+ }
+ else
+ {
+ // source and target has same signedness
+ return TargetChar(ch); // just cast
+ }
+ }
+}}}
+
namespace boost { namespace spirit { namespace tag
{
struct char_ {};
@@ -250,7 +292,8 @@
is(tag::name, Char ch) \
{ \
return CharEncoding::isname \
- BOOST_PREVENT_MACRO_SUBSTITUTION (char_type(ch)); \
+ BOOST_PREVENT_MACRO_SUBSTITUTION \
+ (detail::cast_char<char_type>(ch)); \
} \
/***/
@@ -274,16 +317,16 @@
static bool
is(tag::lowernum, Char ch)
{
- return CharEncoding::islower(char_type(ch)) ||
- CharEncoding::isdigit(char_type(ch));
+ return CharEncoding::islower(detail::cast_char<char_type>(ch)) ||
+ CharEncoding::isdigit(detail::cast_char<char_type>(ch));
}
template <typename Char>
static bool
is(tag::uppernum, Char ch)
{
- return CharEncoding::isupper(char_type(ch)) ||
- CharEncoding::isdigit(char_type(ch));
+ return CharEncoding::isupper(detail::cast_char<char_type>(ch)) ||
+ CharEncoding::isdigit(detail::cast_char<char_type>(ch));
}
#if defined(BOOST_SPIRIT_UNICODE)
@@ -293,7 +336,7 @@
static bool \
is(tag::name, Char ch) \
{ \
- return CharEncoding::is_##name(char_type(ch)); \
+ return CharEncoding::is_##name(detail::cast_char<char_type>(ch)); \
} \
/***/
@@ -473,21 +516,21 @@
static Char
to(tag::lower, Char ch)
{
- return static_cast<Char>(CharEncoding::tolower(char_type(ch)));
+ return static_cast<Char>(CharEncoding::tolower(detail::cast_char<char_type>(ch)));
}
template <typename Char>
static Char
to(tag::upper, Char ch)
{
- return static_cast<Char>(CharEncoding::toupper(char_type(ch)));
+ return static_cast<Char>(CharEncoding::toupper(detail::cast_char<char_type>(ch)));
}
template <typename Char>
static Char
to(tag::ucs4, Char ch)
{
- return static_cast<Char>(CharEncoding::toucs4(char_type(ch)));
+ return static_cast<Char>(CharEncoding::toucs4(detail::cast_char<char_type>(ch)));
}
template <typename Char>
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk