From: Pavel Labath Date: Fri, 23 Jun 2017 12:55:02 +0000 (+0000) Subject: [ADT] Add llvm::to_float X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=44499d7a41877ab2e2b825e262bce55750973c94;p=llvm [ADT] Add llvm::to_float 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 --- diff --git a/include/llvm/ADT/StringExtras.h b/include/llvm/ADT/StringExtras.h index ffcf998a3d3..0425e5ec136 100644 --- a/include/llvm/ADT/StringExtras.h +++ b/include/llvm/ADT/StringExtras.h @@ -15,10 +15,12 @@ #define LLVM_ADT_STRINGEXTRAS_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include #include #include +#include #include #include #include @@ -129,6 +131,32 @@ template bool to_integer(StringRef S, N &Num, unsigned Base = 0) { return !S.getAsInteger(Base, Num); } +namespace detail { +template +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); diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index de0ca940b40..0345a5e3d2a 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -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::parse(Option &O, StringRef ArgName, // parser/parser 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::parse(Option &O, StringRef ArgName, StringRef Arg, diff --git a/lib/Support/YAMLTraits.cpp b/lib/Support/YAMLTraits.cpp index 8684cd950d8..601084f9eae 100644 --- a/lib/Support/YAMLTraits.cpp +++ b/lib/Support/YAMLTraits.cpp @@ -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::output(const double &Val, void *, raw_ostream &Out) { } StringRef ScalarTraits::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::output(const float &Val, void *, raw_ostream &Out) { @@ -925,12 +923,9 @@ void ScalarTraits::output(const float &Val, void *, raw_ostream &Out) { } StringRef ScalarTraits::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::output(const Hex8 &Val, void *, raw_ostream &Out) { diff --git a/unittests/ADT/StringExtrasTest.cpp b/unittests/ADT/StringExtrasTest.cpp index 2cc9cad32b0..8f06f1e6e38 100644 --- a/unittests/ADT/StringExtrasTest.cpp +++ b/unittests/ADT/StringExtrasTest.cpp @@ -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 +}