$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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>