Blob Blame History Raw
# HG changeset patch
# User Rich Mattes <richmattes@gmail.com>
# Date 1451958768 18000
# Branch hex_float_fix
# Node ID 60b241197b435339efd4e60aa48d1127dd48fee0
# Parent  e720a29dc3df958af3101297f9fb72c27f4bd62e
Use stof functions to parse hex strings as floating point params

This commit changes the Param.cc parsing of floating point values to always
use the stof family of functions to parse parameters given as hex strings
(e.g. strings starting with 0x or 0X). It removes the special case handling
for hex strings in the parser, and processes all strings using the same logic.
The isHex check is now used to specify the correct numeric base for the integer
conversion functions.

This commit also removes the boost special case in the HexFloat/HexDouble
Param.cc unit tests. Comments around the special case indicated that
boost::lexical_cast is able to handle parsing floats from hex values in boost
versions 1.58.0 and higher.  This appears not to be the case based on
issue #108. The stof family does handle these hex strings properly, so the
revised tests always expect successful parsing. Tests were also added to parse
the hex value 0X2A with a capital X and an arbitrary numerical value.

Tested with gcc 5.3.1 and boost 1.58.0 on Fedora 23.

diff --git a/src/Param.cc b/src/Param.cc
--- a/src/Param.cc
+++ b/src/Param.cc
@@ -398,40 +398,28 @@
 
   try
   {
-    // If the string is hex, try to use stoi and stoul, and then
-    // lexical cast as a last resort.
+    // Try to use stoi and stoul for integers, and
+    // stof and stod for floating point values.
+    // Use boost lexical cast as a last resort.
+    int numericBase = 10;
     if (isHex)
+        numericBase = 16;
+
+    if (this->dataPtr->typeName == "int")
+      this->dataPtr->value = std::stoi(tmp, NULL, numericBase);
+    else if (this->dataPtr->typeName == "unsigned int")
     {
-      if (this->dataPtr->typeName == "int")
-        this->dataPtr->value = std::stoi(tmp, NULL, 16);
-      else if (this->dataPtr->typeName == "unsigned int")
-      {
-        this->dataPtr->value = static_cast<unsigned int>(
-            std::stoul(tmp, NULL, 16));
-      }
-      else
-      {
-        boost::apply_visitor(string_set(tmp), this->dataPtr->value);
-      }
+      this->dataPtr->value = static_cast<unsigned int>(
+          std::stoul(tmp, NULL, numericBase));
     }
-    // Otherwise use stod, stof, and lexical cast
+    else if (this->dataPtr->typeName == "double")
+      this->dataPtr->value = std::stod(tmp);
+    else if (this->dataPtr->typeName == "float")
+      this->dataPtr->value = std::stof(tmp);
     else
-    {
-      if (this->dataPtr->typeName == "int")
-        this->dataPtr->value = std::stoi(tmp, NULL, 10);
-      else if (this->dataPtr->typeName == "unsigned int")
-      {
-        this->dataPtr->value = static_cast<unsigned int>(
-            std::stoul(tmp, NULL, 10));
-      }
-      else if (this->dataPtr->typeName == "double")
-        this->dataPtr->value = std::stod(tmp);
-      else if (this->dataPtr->typeName == "float")
-        this->dataPtr->value = std::stof(tmp);
-      else
-        boost::apply_visitor(string_set(tmp), this->dataPtr->value);
-    }
+      boost::apply_visitor(string_set(tmp), this->dataPtr->value);
   }
+ 
   // Catch invalid argument exception from std::stoi/stoul/stod/stof
   catch(std::invalid_argument &)
   {
diff --git a/src/Param_TEST.cc b/src/Param_TEST.cc
--- a/src/Param_TEST.cc
+++ b/src/Param_TEST.cc
@@ -147,21 +147,13 @@
   EXPECT_TRUE(floatParam.Get<float>(value));
   EXPECT_FLOAT_EQ(value, 0.0f);
 
-  // Boost 1.58 and higher parses hex integers into floating point variables
-  // successfully, while older versions don't
-#if (BOOST_VERSION >= 105800)
-  {
-    EXPECT_TRUE(floatParam.SetFromString("0x01"));
-    EXPECT_TRUE(floatParam.Get<float>(value));
-    EXPECT_FLOAT_EQ(value, 1.0f);
-  }
-#else
-  {
-    EXPECT_FALSE(floatParam.SetFromString("0x01"));
-    EXPECT_TRUE(floatParam.Get<float>(value));
-    EXPECT_FLOAT_EQ(value, 0.0f);
-  }
-#endif
+  EXPECT_TRUE(floatParam.SetFromString("0x01"));
+  EXPECT_TRUE(floatParam.Get<float>(value));
+  EXPECT_FLOAT_EQ(value, 1.0f);
+ 
+  EXPECT_TRUE(floatParam.SetFromString("0X2A"));
+  EXPECT_TRUE(floatParam.Get<float>(value));
+  EXPECT_FLOAT_EQ(value, 42.0f);
 
   EXPECT_TRUE(floatParam.SetFromString("0.123"));
   EXPECT_TRUE(floatParam.Get<float>(value));
@@ -181,21 +173,13 @@
   EXPECT_TRUE(doubleParam.Get<double>(value));
   EXPECT_DOUBLE_EQ(value, 0.0);
 
-  // Boost 1.58 and higher parses hex integers into floating point variables
-  // successfully, while older versions don't
-#if (BOOST_VERSION >= 105800)
-  {
-    EXPECT_TRUE(doubleParam.SetFromString("0x01"));
-    EXPECT_TRUE(doubleParam.Get<double>(value));
-    EXPECT_DOUBLE_EQ(value, 1.0);
-  }
-#else
-  {
-    EXPECT_FALSE(doubleParam.SetFromString("0x01"));
-    EXPECT_TRUE(doubleParam.Get<double>(value));
-    EXPECT_DOUBLE_EQ(value, 0.0);
-  }
-#endif
+  EXPECT_TRUE(doubleParam.SetFromString("0x01"));
+  EXPECT_TRUE(doubleParam.Get<double>(value));
+  EXPECT_DOUBLE_EQ(value, 1.0);
+ 
+  EXPECT_TRUE(doubleParam.SetFromString("0X2A"));
+  EXPECT_TRUE(doubleParam.Get<double>(value));
+  EXPECT_DOUBLE_EQ(value, 42.0);
 
   EXPECT_TRUE(doubleParam.SetFromString("0.123"));
   EXPECT_TRUE(doubleParam.Get<double>(value));