From a94bd828dcf53e4fd29436664cbeb66191caee2e Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Tue, 14 Feb 2017 19:06:37 +0000 Subject: [PATCH] [Support] Add StringRef::getAsDouble. Differential Revision: https://reviews.llvm.org/D29918 llvm-svn: 295089 --- include/llvm/ADT/StringRef.h | 8 ++++++++ lib/Support/StringRef.cpp | 13 +++++++++++++ unittests/ADT/StringRefTest.cpp | 21 +++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/include/llvm/ADT/StringRef.h b/include/llvm/ADT/StringRef.h index 0fc0b4becf1..ce48f6d3bad 100644 --- a/include/llvm/ADT/StringRef.h +++ b/include/llvm/ADT/StringRef.h @@ -557,6 +557,14 @@ namespace llvm { /// string is well-formed in the given radix. bool getAsInteger(unsigned Radix, APInt &Result) const; + /// Parse the current string as an IEEE double-precision floating + /// point value. The string must be a well-formed double. + /// + /// If \p AllowInexact is false, the function will fail if the string + /// cannot be represented exactly. Otherwise, the function only fails + /// in case of an overflow or underflow. + bool getAsDouble(double &Result, bool AllowInexact = true) const; + /// @} /// @name String Operations /// @{ diff --git a/lib/Support/StringRef.cpp b/lib/Support/StringRef.cpp index d81250e48dd..9b7cc1c1d18 100644 --- a/lib/Support/StringRef.cpp +++ b/lib/Support/StringRef.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/edit_distance.h" @@ -595,6 +596,18 @@ bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const { return false; } +bool StringRef::getAsDouble(double &Result, bool AllowInexact) const { + APFloat F(0.0); + APFloat::opStatus Status = + F.convertFromString(*this, APFloat::rmNearestTiesToEven); + if (Status != APFloat::opOK) { + if (!AllowInexact || Status != APFloat::opInexact) + return true; + } + + Result = F.convertToDouble(); + return false; +} // Implementation of StringRef hashing. hash_code llvm::hash_value(StringRef S) { diff --git a/unittests/ADT/StringRefTest.cpp b/unittests/ADT/StringRefTest.cpp index 5b6822ed757..614ec5d59e6 100644 --- a/unittests/ADT/StringRefTest.cpp +++ b/unittests/ADT/StringRefTest.cpp @@ -852,6 +852,27 @@ TEST(StringRefTest, consumeIntegerSigned) { } } +struct GetDoubleStrings { + const char *Str; + bool AllowInexact; + bool ShouldFail; + double D; +} DoubleStrings[] = {{"0", false, false, 0.0}, + {"0.0", false, false, 0.0}, + {"-0.0", false, false, -0.0}, + {"123.45", false, true, 123.45}, + {"123.45", true, false, 123.45}}; + +TEST(StringRefTest, getAsDouble) { + for (const auto &Entry : DoubleStrings) { + double Result; + StringRef S(Entry.Str); + EXPECT_EQ(Entry.ShouldFail, S.getAsDouble(Result, Entry.AllowInexact)); + if (!Entry.ShouldFail) + EXPECT_EQ(Result, Entry.D); + } +} + static const char *join_input[] = { "a", "b", "c" }; static const char join_result1[] = "a"; static const char join_result2[] = "a:b:c";