diff options
author | 2016-04-05 14:42:45 -0800 | |
---|---|---|
committer | 2016-04-05 15:51:36 -0700 | |
commit | 1d004f969867ee38c5398d68574e141ce8de86cb (patch) | |
tree | a10822e17b47992312f87043e508b967a7519569 /tensorflow | |
parent | a8f0dd875b86e0dcefbd978441f79c51f3cc241e (diff) |
Add safe_strtou32, safe_strtou64, and safe_strtod to numbers.h.
Change: 119099796
Diffstat (limited to 'tensorflow')
-rw-r--r-- | tensorflow/core/lib/strings/numbers.cc | 66 | ||||
-rw-r--r-- | tensorflow/core/lib/strings/numbers.h | 15 | ||||
-rw-r--r-- | tensorflow/core/lib/strings/numbers_test.cc | 96 |
3 files changed, 169 insertions, 8 deletions
diff --git a/tensorflow/core/lib/strings/numbers.cc b/tensorflow/core/lib/strings/numbers.cc index 9e3a6d5458..38a4b6698b 100644 --- a/tensorflow/core/lib/strings/numbers.cc +++ b/tensorflow/core/lib/strings/numbers.cc @@ -108,11 +108,13 @@ char SafeFirstChar(StringPiece str) { if (str.empty()) return '\0'; return str[0]; } +void SkipSpaces(StringPiece* str) { + while (isspace(SafeFirstChar(*str))) str->remove_prefix(1); +} } // namespace bool safe_strto64(StringPiece str, int64* value) { - // Skip leading space. - while (isspace(SafeFirstChar(str))) str.remove_prefix(1); + SkipSpaces(&str); int64 vlimit = kint64max; int sign = 1; @@ -145,9 +147,28 @@ bool safe_strto64(StringPiece str, int64* value) { } while (isdigit(SafeFirstChar(str))); } - // Skip trailing space. - while (isspace(SafeFirstChar(str))) str.remove_prefix(1); + SkipSpaces(&str); + if (!str.empty()) return false; + + *value = result; + return true; +} + +bool safe_strtou64(StringPiece str, uint64* value) { + SkipSpaces(&str); + if (!isdigit(SafeFirstChar(str))) return false; + + int64 result = 0; + do { + int digit = SafeFirstChar(str) - '0'; + if ((kuint64max - digit) / 10 < result) { + return false; + } + result = result * 10 + digit; + str.remove_prefix(1); + } while (isdigit(SafeFirstChar(str))); + SkipSpaces(&str); if (!str.empty()) return false; *value = result; @@ -155,8 +176,7 @@ bool safe_strto64(StringPiece str, int64* value) { } bool safe_strto32(StringPiece str, int32* value) { - // Skip leading space. - while (isspace(SafeFirstChar(str))) str.remove_prefix(1); + SkipSpaces(&str); int64 vmax = kint32max; int sign = 1; @@ -177,8 +197,7 @@ bool safe_strto32(StringPiece str, int32* value) { str.remove_prefix(1); } while (isdigit(SafeFirstChar(str))); - // Skip trailing space. - while (isspace(SafeFirstChar(str))) str.remove_prefix(1); + SkipSpaces(&str); if (!str.empty()) return false; @@ -186,6 +205,26 @@ bool safe_strto32(StringPiece str, int32* value) { return true; } +bool safe_strtou32(StringPiece str, uint32* value) { + SkipSpaces(&str); + if (!isdigit(SafeFirstChar(str))) return false; + + int64 result = 0; + do { + result = result * 10 + SafeFirstChar(str) - '0'; + if (result > kuint32max) { + return false; + } + str.remove_prefix(1); + } while (isdigit(SafeFirstChar(str))); + + SkipSpaces(&str); + if (!str.empty()) return false; + + *value = result; + return true; +} + bool safe_strtof(const char* str, float* value) { char* endptr; *value = strtof(str, &endptr); @@ -197,6 +236,17 @@ bool safe_strtof(const char* str, float* value) { return *str != '\0' && *endptr == '\0'; } +bool safe_strtod(const char* str, double* value) { + char* endptr; + *value = strtod(str, &endptr); + while (isspace(*endptr)) ++endptr; + // Ignore range errors from strtod/strtof. + // The values it returns on underflow and + // overflow are the right fallback in a + // robust setting. + return *str != '\0' && *endptr == '\0'; +} + char* FloatToBuffer(float value, char* buffer) { // FLT_DIG is 6 for IEEE-754 floats, which are used on almost all // platforms these days. Just in case some system exists where FLT_DIG diff --git a/tensorflow/core/lib/strings/numbers.h b/tensorflow/core/lib/strings/numbers.h index 68ddc68ebb..69a9a78fde 100644 --- a/tensorflow/core/lib/strings/numbers.h +++ b/tensorflow/core/lib/strings/numbers.h @@ -97,16 +97,31 @@ bool HexStringToUint64(const StringPiece& s, uint64* v); // Return false with overflow or invalid input. bool safe_strto32(StringPiece str, int32* value); +// Convert strings to unsigned 32bit integer values. +// Leading and trailing spaces are allowed. +// Return false with overflow or invalid input. +bool safe_strtou32(StringPiece str, uint32* value); + // Convert strings to 64bit integer values. // Leading and trailing spaces are allowed. // Return false with overflow or invalid input. bool safe_strto64(StringPiece str, int64* value); +// Convert strings to unsigned 64bit integer values. +// Leading and trailing spaces are allowed. +// Return false with overflow or invalid input. +bool safe_strtou64(StringPiece str, uint64* value); + // Convert strings to floating point values. // Leading and trailing spaces are allowed. // Values may be rounded on over- and underflow. bool safe_strtof(const char* str, float* value); +// Convert strings to double precision floating point values. +// Leading and trailing spaces are allowed. +// Values may be rounded on over- and underflow. +bool safe_strtod(const char* str, double* value); + // Converts from an int64 representing a number of bytes to a // human readable string representing the same number. // e.g. 12345678 -> "11.77MiB". diff --git a/tensorflow/core/lib/strings/numbers_test.cc b/tensorflow/core/lib/strings/numbers_test.cc index 88acd57852..52b77ac2f9 100644 --- a/tensorflow/core/lib/strings/numbers_test.cc +++ b/tensorflow/core/lib/strings/numbers_test.cc @@ -119,6 +119,39 @@ TEST(safe_strto32, Int32s) { EXPECT_EQ(false, safe_strto32(StringPiece(nullptr, 0), &result)); } +TEST(safe_strtou32, UInt32s) { + uint32 result; + + EXPECT_TRUE(safe_strtou32("0", &result)); + EXPECT_EQ(0, result); + EXPECT_TRUE(safe_strtou32("1", &result)); + EXPECT_EQ(1, result); + EXPECT_TRUE(safe_strtou32("123", &result)); + EXPECT_EQ(123, result); + EXPECT_TRUE(safe_strtou32("4294967295", &result)); + EXPECT_EQ(4294967295, result); + + // Invalid argument + EXPECT_FALSE(safe_strtou32(" 132as ", &result)); + EXPECT_FALSE(safe_strtou32(" 132.2 ", &result)); + EXPECT_FALSE(safe_strtou32(" -", &result)); + EXPECT_FALSE(safe_strtou32("", &result)); + EXPECT_FALSE(safe_strtou32(" ", &result)); + EXPECT_FALSE(safe_strtou32("123 a", &result)); + EXPECT_FALSE(safe_strtou32("123 456", &result)); + + // Overflow + EXPECT_FALSE(safe_strtou32("4294967296", &result)); + EXPECT_FALSE(safe_strtou32("-1", &result)); + + // Check that the StringPiece's length is respected. + EXPECT_TRUE(safe_strtou32(StringPiece("123", 1), &result)); + EXPECT_EQ(1, result); + EXPECT_TRUE(safe_strtou32(StringPiece(" 123", 3), &result)); + EXPECT_EQ(12, result); + EXPECT_FALSE(safe_strtou32(StringPiece(nullptr, 0), &result)); +} + TEST(safe_strto64, Int64s) { int64 result; @@ -155,5 +188,68 @@ TEST(safe_strto64, Int64s) { EXPECT_EQ(false, safe_strto64(StringPiece(nullptr, 0), &result)); } +TEST(safe_strtou64, UInt64s) { + uint64 result; + + EXPECT_TRUE(safe_strtou64("0", &result)); + EXPECT_EQ(0, result); + EXPECT_TRUE(safe_strtou64("1", &result)); + EXPECT_EQ(1, result); + EXPECT_TRUE(safe_strtou64("123", &result)); + EXPECT_EQ(123, result); + EXPECT_TRUE(safe_strtou64(" 345 ", &result)); + EXPECT_EQ(345, result); + EXPECT_TRUE(safe_strtou64("18446744073709551615", &result)); + EXPECT_EQ(18446744073709551615UL, result); + + // Invalid argument + EXPECT_FALSE(safe_strtou64(" 132.2 ", &result)); + EXPECT_FALSE(safe_strtou64(" 132.2 ", &result)); + EXPECT_FALSE(safe_strtou64(" -", &result)); + EXPECT_FALSE(safe_strtou64("", &result)); + EXPECT_FALSE(safe_strtou64(" ", &result)); + EXPECT_FALSE(safe_strtou64("123 a", &result)); + EXPECT_FALSE(safe_strtou64("123 456", &result)); + + // Overflow + EXPECT_FALSE(safe_strtou64("18446744073709551616", &result)); + EXPECT_FALSE(safe_strtou64("-1", &result)); + + // Check that the StringPiece's length is respected. + EXPECT_TRUE(safe_strtou64(StringPiece("123", 1), &result)); + EXPECT_EQ(1, result); + EXPECT_TRUE(safe_strtou64(StringPiece(" 123", 3), &result)); + EXPECT_EQ(12, result); + EXPECT_FALSE(safe_strtou64(StringPiece(nullptr, 0), &result)); +} + +TEST(safe_strtof, Float) { + float result = 0; + + EXPECT_TRUE(safe_strtof("0.123456", &result)); + EXPECT_EQ(0.123456f, result); + EXPECT_FALSE(safe_strtof("0.12345abc", &result)); + + // Overflow to infinity, underflow to 0. + EXPECT_TRUE(safe_strtof("1e39", &result)); + EXPECT_EQ(std::numeric_limits<float>::infinity(), result); + EXPECT_TRUE(safe_strtof("1e-50", &result)); + EXPECT_EQ(0, result); +} + +TEST(safe_strtod, Double) { + double result = 0; + + EXPECT_TRUE(safe_strtod("0.1234567890123", &result)); + EXPECT_EQ(0.1234567890123, result); + EXPECT_FALSE(safe_strtod("0.1234567890123abc", &result)); + + // Overflow to infinity, underflow to 0. + EXPECT_TRUE(safe_strtod("1e310", &result)); + EXPECT_EQ(std::numeric_limits<double>::infinity(), result); + EXPECT_TRUE(safe_strtod("1e-325", &result)); + EXPECT_EQ(0, result); +} + } // namespace strings } // namespace tensorflow |