OSDN Git Service

[ADT] Add llvm::to_float
authorPavel Labath <labath@google.com>
Fri, 23 Jun 2017 12:55:02 +0000 (12:55 +0000)
committerPavel Labath <labath@google.com>
Fri, 23 Jun 2017 12:55:02 +0000 (12:55 +0000)
Summary:
The function matches the interface of llvm::to_integer, but as we are
calling out to a C library function, I let it take a Twine argument, so
we can avoid a string copy at least in some cases.

I add a test and replace a couple of existing uses of strtod with this
function.

Reviewers: zturner

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D34518

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306096 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/ADT/StringExtras.h
lib/Support/CommandLine.cpp
lib/Support/YAMLTraits.cpp
unittests/ADT/StringExtrasTest.cpp

index ffcf998..0425e5e 100644 (file)
 #define LLVM_ADT_STRINGEXTRAS_H
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
 #include <cassert>
 #include <cstddef>
 #include <cstdint>
+#include <cstdlib>
 #include <cstring>
 #include <iterator>
 #include <string>
@@ -129,6 +131,32 @@ template <typename N> bool to_integer(StringRef S, N &Num, unsigned Base = 0) {
   return !S.getAsInteger(Base, Num);
 }
 
+namespace detail {
+template <typename N>
+inline bool to_float(const Twine &T, N &Num, N (*StrTo)(const char *, char **)) {
+  SmallString<32> Storage;
+  StringRef S = T.toNullTerminatedStringRef(Storage);
+  char *End;
+  N Temp = StrTo(S.data(), &End);
+  if (*End != '\0')
+    return false;
+  Num = Temp;
+  return true;
+}
+}
+
+inline bool to_float(const Twine &T, float &Num) {
+  return detail::to_float(T, Num, std::strtof);
+}
+
+inline bool to_float(const Twine &T, double &Num) {
+  return detail::to_float(T, Num, std::strtod);
+}
+
+inline bool to_float(const Twine &T, long double &Num) {
+  return detail::to_float(T, Num, std::strtold);
+}
+
 static inline std::string utostr(uint64_t X, bool isNeg = false) {
   char Buffer[21];
   char *BufPtr = std::end(Buffer);
index de0ca94..0345a5e 100644 (file)
@@ -24,6 +24,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Config/config.h"
@@ -1522,13 +1523,9 @@ bool parser<unsigned long long>::parse(Option &O, StringRef ArgName,
 // parser<double>/parser<float> implementation
 //
 static bool parseDouble(Option &O, StringRef Arg, double &Value) {
-  SmallString<32> TmpStr(Arg.begin(), Arg.end());
-  const char *ArgStart = TmpStr.c_str();
-  char *End;
-  Value = strtod(ArgStart, &End);
-  if (*End != 0)
-    return O.error("'" + Arg + "' value invalid for floating point argument!");
-  return false;
+  if (to_float(Arg, Value))
+    return false;
+  return O.error("'" + Arg + "' value invalid for floating point argument!");
 }
 
 bool parser<double>::parse(Option &O, StringRef ArgName, StringRef Arg,
index 8684cd9..601084f 100644 (file)
@@ -10,6 +10,7 @@
 #include "llvm/Support/YAMLTraits.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Support/Casting.h"
@@ -912,12 +913,9 @@ void ScalarTraits<double>::output(const double &Val, void *, raw_ostream &Out) {
 }
 
 StringRef ScalarTraits<double>::input(StringRef Scalar, void *, double &Val) {
-  SmallString<32> buff(Scalar.begin(), Scalar.end());
-  char *end;
-  Val = strtod(buff.c_str(), &end);
-  if (*end != '\0')
-    return "invalid floating point number";
-  return StringRef();
+  if (to_float(Scalar, Val))
+    return StringRef();
+  return "invalid floating point number";
 }
 
 void ScalarTraits<float>::output(const float &Val, void *, raw_ostream &Out) {
@@ -925,12 +923,9 @@ void ScalarTraits<float>::output(const float &Val, void *, raw_ostream &Out) {
 }
 
 StringRef ScalarTraits<float>::input(StringRef Scalar, void *, float &Val) {
-  SmallString<32> buff(Scalar.begin(), Scalar.end());
-  char *end;
-  Val = strtod(buff.c_str(), &end);
-  if (*end != '\0')
-    return "invalid floating point number";
-  return StringRef();
+  if (to_float(Scalar, Val))
+    return StringRef();
+  return "invalid floating point number";
 }
 
 void ScalarTraits<Hex8>::output(const Hex8 &Val, void *, raw_ostream &Out) {
index 2cc9cad..8f06f1e 100644 (file)
@@ -65,4 +65,22 @@ TEST(StringExtrasTest, ToAndFromHex) {
                      EvenBytes.size());
   EXPECT_EQ(EvenStr, toHex(EvenData));
   EXPECT_EQ(EvenData, fromHex(EvenStr));
-}
\ No newline at end of file
+}
+
+TEST(StringExtrasTest, to_float) {
+  float F;
+  EXPECT_TRUE(to_float("4.7", F));
+  EXPECT_FLOAT_EQ(4.7, F);
+
+  double D;
+  EXPECT_TRUE(to_float("4.7", D));
+  EXPECT_DOUBLE_EQ(4.7, D);
+
+  long double LD;
+  EXPECT_TRUE(to_float("4.7", LD));
+  EXPECT_DOUBLE_EQ(4.7, LD);
+
+  EXPECT_FALSE(to_float("foo", F));
+  EXPECT_FALSE(to_float("7.4 foo", F));
+  EXPECT_FLOAT_EQ(4.7, F); // F should be unchanged
+}