Bug 1573648 - Introduce ToDoubleAllowTrailingChars and ToFloatAllowTrailingChars. r=njn a=RyanVM
authorHiroyuki Ikezoe <hikezoe.birchill@mozilla.com>
Fri, 16 Aug 2019 22:38:01 +0000
changeset 545208 40120557f1e2e80a7e4022b8ecc0b740ce1841b5
parent 545207 894ca270cd7e5b15d5ed7a0a1baa87b0c11e4b74
child 545209 750a7788ab0382d51c8fe04b9203a078720511aa
push id2131
push userffxbld-merge
push dateMon, 26 Aug 2019 18:30:20 +0000
treeherdermozilla-release@b19ffb3ca153 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnjn, RyanVM
bugs1573648
milestone69.0
Bug 1573648 - Introduce ToDoubleAllowTrailingChars and ToFloatAllowTrailingChars. r=njn a=RyanVM Differential Revision: https://phabricator.services.mozilla.com/D42239
xpcom/string/nsStringObsolete.cpp
xpcom/string/nsTString.h
xpcom/tests/gtest/TestStrings.cpp
--- a/xpcom/string/nsStringObsolete.cpp
+++ b/xpcom/string/nsStringObsolete.cpp
@@ -913,40 +913,68 @@ bool nsTString<T>::EqualsIgnoreCase(cons
   return result == 0;
 }
 
 /**
  * nsTString::ToDouble
  */
 
 template <>
-double nsTString<char>::ToDouble(nsresult* aErrorCode) const {
+double nsTString<char>::ToDouble(TrailingCharsPolicy aTrailingCharsPolicy,
+                                 nsresult* aErrorCode) const {
   double res = 0.0;
   if (this->mLength > 0) {
     char* conv_stopped;
     const char* str = this->mData;
     // Use PR_strtod, not strtod, since we don't want locale involved.
     res = PR_strtod(str, &conv_stopped);
-    if (conv_stopped == str + this->mLength)
+    if (aTrailingCharsPolicy == TrailingCharsPolicy::Allow &&
+        conv_stopped != str) {
       *aErrorCode = NS_OK;
-    else  // Not all the string was scanned
+    } else if (aTrailingCharsPolicy == TrailingCharsPolicy::Disallow &&
+               conv_stopped == str + this->mLength) {
+      *aErrorCode = NS_OK;
+    } else {
       *aErrorCode = NS_ERROR_ILLEGAL_VALUE;
+    }
   } else {
     // The string was too short (0 characters)
     *aErrorCode = NS_ERROR_ILLEGAL_VALUE;
   }
   return res;
 }
 
 template <>
+double nsTString<char>::ToDouble(nsresult* aErrorCode) const {
+  return ToDouble(TrailingCharsPolicy::Disallow, aErrorCode);
+}
+
+template <>
 double nsTString<char16_t>::ToDouble(nsresult* aErrorCode) const {
   return NS_LossyConvertUTF16toASCII(*this).ToDouble(aErrorCode);
 }
 
 template <typename T>
 float nsTString<T>::ToFloat(nsresult* aErrorCode) const {
   return (float)ToDouble(aErrorCode);
 }
 
+template <>
+double nsTString<char>::ToDoubleAllowTrailingChars(nsresult* aErrorCode) const {
+  return ToDouble(TrailingCharsPolicy::Allow, aErrorCode);
+}
+
+template <>
+double nsTString<char16_t>::ToDoubleAllowTrailingChars(
+    nsresult* aErrorCode) const {
+  return NS_LossyConvertUTF16toASCII(*this).ToDoubleAllowTrailingChars(
+      aErrorCode);
+}
+
+template <typename T>
+float nsTString<T>::ToFloatAllowTrailingChars(nsresult* aErrorCode) const {
+  return (float)ToDoubleAllowTrailingChars(aErrorCode);
+}
+
 template class nsTString<char>;
 template class nsTString<char16_t>;
 
 #endif  // !MOZ_STRING_WITH_OBSOLETE_API
--- a/xpcom/string/nsTString.h
+++ b/xpcom/string/nsTString.h
@@ -319,16 +319,23 @@ class nsTString : public nsTSubstring<T>
    * Perform string to single-precision float conversion.
    *
    * @param   aErrorCode will contain error if one occurs
    * @return  single-precision float rep of string value
    */
   float ToFloat(nsresult* aErrorCode) const;
 
   /**
+   * Similar to above ToDouble and ToFloat but allows trailing characters that
+   * are not converted.
+   */
+  double ToDoubleAllowTrailingChars(nsresult* aErrorCode) const;
+  float ToFloatAllowTrailingChars(nsresult* aErrorCode) const;
+
+  /**
    * |Left|, |Mid|, and |Right| are annoying signatures that seem better almost
    * any _other_ way than they are now.  Consider these alternatives
    *
    * // ...a member function that returns a |Substring|
    * aWritable = aReadable.Left(17);
    * // ...a global function that returns a |Substring|
    * aWritable = Left(aReadable, 17);
    * // ...a global function that does the assignment
@@ -468,16 +475,24 @@ class nsTString : public nsTSubstring<T>
   friend const nsTString<char16_t>& VoidString();
 
   // Used by Null[C]String.
   explicit nsTString(DataFlags aDataFlags)
       : substring_type(char_traits::sEmptyBuffer, 0,
                        aDataFlags | DataFlags::TERMINATED,
                        ClassFlags::NULL_TERMINATED) {}
 
+  enum class TrailingCharsPolicy {
+    Disallow,
+    Allow,
+  };
+  // Utility function for ToDouble and ToDoubleAllowTrailingChars.
+  double ToDouble(TrailingCharsPolicy aTrailingCharsPolicy,
+                  nsresult* aErrorCode) const;
+
   struct Segment {
     uint32_t mBegin, mLength;
     Segment(uint32_t aBegin, uint32_t aLength)
         : mBegin(aBegin), mLength(aLength) {}
   };
 };
 
 // TODO(erahm): Do something with ToDouble so that we can extern the
--- a/xpcom/tests/gtest/TestStrings.cpp
+++ b/xpcom/tests/gtest/TestStrings.cpp
@@ -1546,16 +1546,43 @@ TEST_F(Strings, tofloat) {
   test_tofloat_helper(NS_LITERAL_STRING("1.23456789"), 1.23456789f, true);
   test_tofloat_helper(NS_LITERAL_STRING("1.98765432123456"), 1.98765432123456f,
                       true);
   test_tofloat_helper(NS_LITERAL_STRING("0"), 0.f, true);
   test_tofloat_helper(NS_LITERAL_STRING("1.e5"), 100000, true);
   test_tofloat_helper(NS_LITERAL_STRING(""), 0.f, false);
   test_tofloat_helper(NS_LITERAL_STRING("42foo"), 42.f, false);
   test_tofloat_helper(NS_LITERAL_STRING("foo"), 0.f, false);
+  test_tofloat_helper(NS_LITERAL_STRING("1.5e-"), 1.5f, false);
+}
+
+static void test_tofloat_allow_trailing_chars_helper(const nsString& aStr,
+                                                     float aExpected,
+                                                     bool aSuccess) {
+  nsresult result;
+  EXPECT_EQ(aStr.ToFloatAllowTrailingChars(&result), aExpected);
+  if (aSuccess) {
+    EXPECT_EQ(result, NS_OK);
+  } else {
+    EXPECT_NE(result, NS_OK);
+  }
+}
+
+TEST_F(Strings, ToFloatAllowTrailingChars) {
+  test_tofloat_allow_trailing_chars_helper(NS_LITERAL_STRING(""), 0.f, false);
+  test_tofloat_allow_trailing_chars_helper(NS_LITERAL_STRING("foo"), 0.f,
+                                           false);
+  test_tofloat_allow_trailing_chars_helper(NS_LITERAL_STRING("42foo"), 42.f,
+                                           true);
+  test_tofloat_allow_trailing_chars_helper(NS_LITERAL_STRING("42-5"), 42.f,
+                                           true);
+  test_tofloat_allow_trailing_chars_helper(NS_LITERAL_STRING("13.37.8"), 13.37f,
+                                           true);
+  test_tofloat_allow_trailing_chars_helper(NS_LITERAL_STRING("1.5e-"), 1.5f,
+                                           true);
 }
 
 static void test_todouble_helper(const nsString& aStr, double aExpected,
                                  bool aSuccess) {
   nsresult result;
   EXPECT_EQ(aStr.ToDouble(&result), aExpected);
   if (aSuccess) {
     EXPECT_EQ(result, NS_OK);
@@ -1575,16 +1602,42 @@ TEST_F(Strings, todouble) {
                        true);
   test_todouble_helper(NS_LITERAL_STRING("123456789.98765432123456"),
                        123456789.98765432123456, true);
   test_todouble_helper(NS_LITERAL_STRING("0"), 0, true);
   test_todouble_helper(NS_LITERAL_STRING("1.e5"), 100000, true);
   test_todouble_helper(NS_LITERAL_STRING(""), 0, false);
   test_todouble_helper(NS_LITERAL_STRING("42foo"), 42, false);
   test_todouble_helper(NS_LITERAL_STRING("foo"), 0, false);
+  test_todouble_helper(NS_LITERAL_STRING("1.5e-"), 1.5, false);
+}
+
+static void test_todouble_allow_trailing_chars_helper(const nsString& aStr,
+                                                      double aExpected,
+                                                      bool aSuccess) {
+  nsresult result;
+  EXPECT_EQ(aStr.ToDoubleAllowTrailingChars(&result), aExpected);
+  if (aSuccess) {
+    EXPECT_EQ(result, NS_OK);
+  } else {
+    EXPECT_NE(result, NS_OK);
+  }
+}
+
+TEST_F(Strings, ToDoubleAllowTrailingChars) {
+  test_todouble_allow_trailing_chars_helper(NS_LITERAL_STRING(""), 0, false);
+  test_todouble_allow_trailing_chars_helper(NS_LITERAL_STRING("foo"), 0, false);
+  test_todouble_allow_trailing_chars_helper(NS_LITERAL_STRING("42foo"), 42,
+                                            true);
+  test_todouble_allow_trailing_chars_helper(NS_LITERAL_STRING("42-5"), 42,
+                                            true);
+  test_todouble_allow_trailing_chars_helper(NS_LITERAL_STRING("13.37.8"), 13.37,
+                                            true);
+  test_todouble_allow_trailing_chars_helper(NS_LITERAL_STRING("1.5e-"), 1.5,
+                                            true);
 }
 
 TEST_F(Strings, Split) {
   nsCString one("one"), two("one;two"), three("one--three"), empty(""),
       delimStart("-two"), delimEnd("one-");
 
   nsString wide(u"hello world");