Boost logo

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