Repository: thrift
Updated Branches:
  refs/heads/master 7f9fa8831 -> 12b06e4f8


THRIFT-2870 - C++: JSON protocol will read & write doubles using "C" locale

Client: C++
Patch: Simon Falsig


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/12b06e4f
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/12b06e4f
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/12b06e4f

Branch: refs/heads/master
Commit: 12b06e4f8ccf90de5e993eaf9ed7bec450c723e6
Parents: 7f9fa88
Author: Konrad Grochowski <[email protected]>
Authored: Sat Feb 21 13:48:56 2015 +0100
Committer: Konrad Grochowski <[email protected]>
Committed: Mon Feb 23 17:19:33 2015 +0100

----------------------------------------------------------------------
 lib/cpp/src/thrift/protocol/TJSONProtocol.cpp | 68 ++++++++++++++++------
 1 file changed, 49 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/12b06e4f/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
----------------------------------------------------------------------
diff --git a/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp 
b/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
index 72cd28b..5e1d42b 100644
--- a/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
+++ b/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
@@ -19,8 +19,14 @@
 
 #include <thrift/protocol/TJSONProtocol.h>
 
-#include <math.h>
+#include <limits>
+#include <locale>
+#include <sstream>
+#include <cmath>
+
+#include <boost/math/special_functions/fpclassify.hpp>
 #include <boost/lexical_cast.hpp>
+
 #include <thrift/protocol/TBase64Utils.h>
 #include <thrift/transport/TTransportException.h>
 
@@ -503,30 +509,40 @@ uint32_t TJSONProtocol::writeJSONInteger(NumberType num) {
   return result;
 }
 
+namespace
+{
+std::string doubleToString(double d)
+{
+  std::ostringstream str;
+  str.imbue(std::locale::classic());
+  str.precision(std::numeric_limits<double>::digits10 + 1);
+  str << d;
+  return str.str();
+}
+}
+
 // Convert the given double to a JSON string, which is either the number,
 // "NaN" or "Infinity" or "-Infinity".
 uint32_t TJSONProtocol::writeJSONDouble(double num) {
   uint32_t result = context_->write(*trans_);
-  std::string val(boost::lexical_cast<std::string>(num));
+  std::string val;
 
-  // Normalize output of boost::lexical_cast for NaNs and Infinities
   bool special = false;
-  switch (val[0]) {
-  case 'N':
-  case 'n':
-    val = kThriftNan;
+  switch (boost::math::fpclassify(num)) {
+  case FP_INFINITE:
+    if (boost::math::signbit(num)) {
+      val = kThriftNegativeInfinity;
+    } else {
+      val = kThriftInfinity;
+    }
     special = true;
     break;
-  case 'I':
-  case 'i':
-    val = kThriftInfinity;
+  case FP_NAN:
+    val = kThriftNan;
     special = true;
     break;
-  case '-':
-    if ((val[1] == 'I') || (val[1] == 'i')) {
-      val = kThriftNegativeInfinity;
-      special = true;
-    }
+  default:
+    val = doubleToString(num);
     break;
   }
 
@@ -801,6 +817,20 @@ uint32_t TJSONProtocol::readJSONInteger(NumberType& num) {
   return result;
 }
 
+namespace
+{
+double stringToDouble(const std::string& s)
+{
+  double d;
+  std::istringstream str(s);
+  str.imbue(std::locale::classic());
+  str >> d;
+  if (str.bad() || !str.eof())
+    throw std::runtime_error(s);
+  return d;
+}
+}
+
 // Reads a JSON number or string and interprets it as a double.
 uint32_t TJSONProtocol::readJSONDouble(double& num) {
   uint32_t result = context_->read(reader_);
@@ -821,8 +851,8 @@ uint32_t TJSONProtocol::readJSONDouble(double& num) {
                                      "Numeric data unexpectedly quoted");
       }
       try {
-        num = boost::lexical_cast<double>(str);
-      } catch (boost::bad_lexical_cast e) {
+        num = stringToDouble(str);
+      } catch (std::runtime_error e) {
         throw new TProtocolException(TProtocolException::INVALID_DATA,
                                      "Expected numeric value; got \"" + str + 
"\"");
       }
@@ -834,8 +864,8 @@ uint32_t TJSONProtocol::readJSONDouble(double& num) {
     }
     result += readJSONNumericChars(str);
     try {
-      num = boost::lexical_cast<double>(str);
-    } catch (boost::bad_lexical_cast e) {
+      num = stringToDouble(str);
+    } catch (std::runtime_error e) {
       throw new TProtocolException(TProtocolException::INVALID_DATA,
                                    "Expected numeric value; got \"" + str + 
"\"");
     }

Reply via email to