Speed up safe_strtod and safe_strtof functions by using double-conversion library
Closes #12102. PiperOrigin-RevId: 193696537
This commit is contained in:
parent
49f3469d95
commit
570d90b9c7
@ -193,6 +193,7 @@ include(protobuf)
|
||||
include(re2)
|
||||
include(cub)
|
||||
include(sqlite)
|
||||
include(double_conversion)
|
||||
if (tensorflow_BUILD_CC_TESTS)
|
||||
include(googletest)
|
||||
endif()
|
||||
@ -213,6 +214,7 @@ set(tensorflow_EXTERNAL_LIBRARIES
|
||||
${protobuf_STATIC_LIBRARIES}
|
||||
${re2_STATIC_LIBRARIES}
|
||||
${sqlite_STATIC_LIBRARIES}
|
||||
${double_conversion_STATIC_LIBRARIES}
|
||||
)
|
||||
|
||||
if (systemlib_ZLIB)
|
||||
@ -240,6 +242,7 @@ set(tensorflow_EXTERNAL_DEPENDENCIES
|
||||
fft2d
|
||||
re2
|
||||
sqlite_copy_headers_to_destination
|
||||
double_conversion
|
||||
)
|
||||
|
||||
include_directories(
|
||||
@ -262,6 +265,7 @@ include_directories(
|
||||
${PROTOBUF_INCLUDE_DIRS}
|
||||
${re2_INCLUDE_DIR}
|
||||
${sqlite_INCLUDE_DIR}
|
||||
${double_conversion_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
if(tensorflow_ENABLE_SSL_SUPPORT)
|
||||
|
54
tensorflow/contrib/cmake/external/double_conversion.cmake
vendored
Normal file
54
tensorflow/contrib/cmake/external/double_conversion.cmake
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ==============================================================================
|
||||
include (ExternalProject)
|
||||
|
||||
set(double_conversion_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/double_conversion/src/double_conversion)
|
||||
set(double_conversion_URL https://github.com/google/double-conversion.git)
|
||||
set(double_conversion_TAG 5664746)
|
||||
set(double_conversion_BUILD ${double_conversion_INCLUDE_DIR})
|
||||
set(double_conversion_LIBRARIES ${double_conversion_BUILD}/double-conversion/libdouble-conversion.so)
|
||||
set(double_conversion_INCLUDES ${double_conversion_BUILD})
|
||||
|
||||
if(WIN32)
|
||||
set(double_conversion_STATIC_LIBRARIES ${double_conversion_BUILD}/double-conversion/$(Configuration)/double-conversion.lib)
|
||||
else()
|
||||
set(double_conversion_STATIC_LIBRARIES ${double_conversion_BUILD}/double-conversion/libdouble-conversion.a)
|
||||
endif()
|
||||
|
||||
set(double_conversion_HEADERS
|
||||
"${double_conversion_INCLUDE_DIR}/double-conversion/bignum-dtoa.h"
|
||||
"${double_conversion_INCLUDE_DIR}/double-conversion/cached-powers.h"
|
||||
"${double_conversion_INCLUDE_DIR}/double-conversion/double-conversion.h"
|
||||
"${double_conversion_INCLUDE_DIR}/double-conversion/fixed-dtoa.h"
|
||||
"${double_conversion_INCLUDE_DIR}/double-conversion/strtod.h"
|
||||
"${double_conversion_INCLUDE_DIR}/double-conversion/bignum.h"
|
||||
"${double_conversion_INCLUDE_DIR}/double-conversion/diy-fp.h"
|
||||
"${double_conversion_INCLUDE_DIR}/double-conversion/fast-dtoa.h"
|
||||
"${double_conversion_INCLUDE_DIR}/double-conversion/ieee.h"
|
||||
"${double_conversion_INCLUDE_DIR}/double-conversion/utils.h"
|
||||
)
|
||||
|
||||
ExternalProject_Add(double_conversion
|
||||
PREFIX double_conversion
|
||||
GIT_REPOSITORY ${double_conversion_URL}
|
||||
GIT_TAG ${double_conversion_TAG}
|
||||
DOWNLOAD_DIR "${DOWNLOAD_LOCATION}"
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND ""
|
||||
CMAKE_CACHE_ARGS
|
||||
-DCMAKE_BUILD_TYPE:STRING=Release
|
||||
-DCMAKE_VERBOSE_MAKEFILE:BOOL=OFF
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON
|
||||
)
|
@ -89,6 +89,7 @@ HOST_INCLUDES := \
|
||||
-I$(MAKEFILE_DIR)/downloads/gemmlowp \
|
||||
-I$(MAKEFILE_DIR)/downloads/nsync/public \
|
||||
-I$(MAKEFILE_DIR)/downloads/fft2d \
|
||||
-I$(MAKEFILE_DIR)/downloads/double_conversion \
|
||||
-I$(HOST_GENDIR)
|
||||
ifeq ($(HAS_GEN_HOST_PROTOC),true)
|
||||
HOST_INCLUDES += -I$(MAKEFILE_DIR)/gen/protobuf-host/include
|
||||
@ -125,7 +126,9 @@ PROTO_TEXT := $(HOST_BINDIR)proto_text
|
||||
# The list of dependencies is derived from the Bazel build file by running
|
||||
# the gen_file_lists.sh script on a system with a working Bazel setup.
|
||||
PROTO_TEXT_CC_FILES := $(shell cat $(MAKEFILE_DIR)/proto_text_cc_files.txt)
|
||||
PROTO_TEXT_PB_CC_LIST := $(shell cat $(MAKEFILE_DIR)/proto_text_pb_cc_files.txt)
|
||||
PROTO_TEXT_PB_CC_LIST := \
|
||||
$(shell cat $(MAKEFILE_DIR)/proto_text_pb_cc_files.txt) \
|
||||
$(wildcard tensorflow/contrib/makefile/downloads/double_conversion/double-conversion/*.cc)
|
||||
PROTO_TEXT_PB_H_LIST := $(shell cat $(MAKEFILE_DIR)/proto_text_pb_h_files.txt)
|
||||
|
||||
# Locations of the intermediate files proto_text generates.
|
||||
@ -171,6 +174,7 @@ INCLUDES := \
|
||||
-I$(MAKEFILE_DIR)/downloads/gemmlowp \
|
||||
-I$(MAKEFILE_DIR)/downloads/nsync/public \
|
||||
-I$(MAKEFILE_DIR)/downloads/fft2d \
|
||||
-I$(MAKEFILE_DIR)/downloads/double_conversion \
|
||||
-I$(PROTOGENDIR) \
|
||||
-I$(PBTGENDIR)
|
||||
ifeq ($(HAS_GEN_HOST_PROTOC),true)
|
||||
@ -326,6 +330,7 @@ $(MARCH_OPTION) \
|
||||
-I$(MAKEFILE_DIR)/downloads/gemmlowp \
|
||||
-I$(MAKEFILE_DIR)/downloads/nsync/public \
|
||||
-I$(MAKEFILE_DIR)/downloads/fft2d \
|
||||
-I$(MAKEFILE_DIR)/downloads/double_conversion \
|
||||
-I$(MAKEFILE_DIR)/gen/protobuf_android/$(ANDROID_ARCH)/include \
|
||||
-I$(PROTOGENDIR) \
|
||||
-I$(PBTGENDIR)
|
||||
@ -603,6 +608,7 @@ $(wildcard tensorflow/core/platform/*/*.cc) \
|
||||
$(wildcard tensorflow/core/platform/*/*/*.cc) \
|
||||
$(wildcard tensorflow/core/util/*.cc) \
|
||||
$(wildcard tensorflow/core/util/*/*.cc) \
|
||||
$(wildcard tensorflow/contrib/makefile/downloads/double_conversion/double-conversion/*.cc) \
|
||||
tensorflow/core/util/version_info.cc
|
||||
# Remove duplicates (for version_info.cc)
|
||||
CORE_CC_ALL_SRCS := $(sort $(CORE_CC_ALL_SRCS))
|
||||
|
@ -32,7 +32,8 @@ GOOGLETEST_URL="https://github.com/google/googletest/archive/release-1.8.0.tar.g
|
||||
NSYNC_URL="$(grep -o 'https://mirror.bazel.build/github.com/google/nsync/.*tar\.gz' "${BZL_FILE_PATH}" | head -n1)"
|
||||
PROTOBUF_URL="$(grep -o 'https://mirror.bazel.build/github.com/google/protobuf/.*tar\.gz' "${BZL_FILE_PATH}" | head -n1)"
|
||||
RE2_URL="$(grep -o 'https://mirror.bazel.build/github.com/google/re2/.*tar\.gz' "${BZL_FILE_PATH}" | head -n1)"
|
||||
FFT2D_URL="$(grep -o 'http.*fft\.tgz' "${BZL_FILE_PATH}" | grep -v mirror.bazel | head -n1)"
|
||||
FFT2D_URL="$(grep -o 'http.*fft\.tgz' "${BZL_FILE_PATH}" | grep -v bazel-mirror | head -n1)"
|
||||
DOUBLE_CONVERSION_URL="$(grep -o "https.*google/double-conversion.*\.zip" "${BZL_FILE_PATH}" | head -n1)"
|
||||
ABSL_URL="$(grep -o 'https://github.com/abseil/abseil-cpp/.*tar.gz' "${BZL_FILE_PATH}" | head -n1)"
|
||||
CUB_URL="$(grep -o 'https.*cub/archive.*zip' "${BZL_FILE_PATH}" | grep -v mirror.bazel | head -n1)"
|
||||
|
||||
@ -87,6 +88,7 @@ download_and_extract "${NSYNC_URL}" "${DOWNLOADS_DIR}/nsync"
|
||||
download_and_extract "${PROTOBUF_URL}" "${DOWNLOADS_DIR}/protobuf"
|
||||
download_and_extract "${RE2_URL}" "${DOWNLOADS_DIR}/re2"
|
||||
download_and_extract "${FFT2D_URL}" "${DOWNLOADS_DIR}/fft2d"
|
||||
download_and_extract "${DOUBLE_CONVERSION_URL}" "${DOWNLOADS_DIR}/double_conversion"
|
||||
download_and_extract "${ABSL_URL}" "${DOWNLOADS_DIR}/absl"
|
||||
download_and_extract "${CUB_URL}" "${DOWNLOADS_DIR}/cub/external/cub_archive"
|
||||
|
||||
|
@ -337,7 +337,9 @@ cc_library(
|
||||
"lib/bfloat16/bfloat16.h",
|
||||
] + tf_additional_proto_hdrs() + glob(tf_env_time_hdrs()),
|
||||
copts = tf_copts(),
|
||||
deps = tf_lib_proto_parsing_deps(),
|
||||
deps = tf_lib_proto_parsing_deps() + [
|
||||
"@double_conversion//:double-conversion",
|
||||
],
|
||||
)
|
||||
|
||||
# This build rule (along with :lib_internal, :framework, and
|
||||
@ -1231,6 +1233,7 @@ cc_library(
|
||||
deps = [
|
||||
":protos_all_cc_impl",
|
||||
"//third_party/eigen3",
|
||||
"@double_conversion//:double-conversion",
|
||||
"@nsync//:nsync_cpp",
|
||||
"@protobuf_archive//:protobuf",
|
||||
],
|
||||
@ -1270,6 +1273,7 @@ cc_library(
|
||||
deps = [
|
||||
":protos_all_cc_impl",
|
||||
"//third_party/eigen3",
|
||||
"@double_conversion//:double-conversion",
|
||||
"@nsync//:nsync_cpp",
|
||||
"@protobuf_archive//:protobuf",
|
||||
],
|
||||
@ -1333,6 +1337,7 @@ cc_library(
|
||||
deps = [
|
||||
":protos_all_cc_impl",
|
||||
"//third_party/eigen3",
|
||||
"@double_conversion//:double-conversion",
|
||||
"@nsync//:nsync_cpp",
|
||||
"@protobuf_archive//:protobuf",
|
||||
],
|
||||
@ -1355,6 +1360,7 @@ cc_library(
|
||||
deps = [
|
||||
":protos_all_cc_impl",
|
||||
"//third_party/eigen3",
|
||||
"@double_conversion//:double-conversion",
|
||||
"@nsync//:nsync_cpp",
|
||||
"@protobuf_archive//:protobuf",
|
||||
],
|
||||
@ -1751,6 +1757,7 @@ cc_library(
|
||||
"//tensorflow/core/platform/default/build_config:platformlib",
|
||||
"@snappy",
|
||||
"@zlib_archive//:zlib",
|
||||
"@double_conversion//:double-conversion",
|
||||
"@protobuf_archive//:protobuf",
|
||||
] + tf_protos_all_impl() + tf_protos_grappler_impl(),
|
||||
)
|
||||
|
@ -23,6 +23,8 @@ limitations under the License.
|
||||
#include <locale>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "double-conversion/double-conversion.h"
|
||||
|
||||
#include "tensorflow/core/lib/strings/str_util.h"
|
||||
#include "tensorflow/core/lib/strings/stringprintf.h"
|
||||
#include "tensorflow/core/platform/logging.h"
|
||||
@ -110,6 +112,17 @@ T locale_independent_strtonum(const char* str, const char** endptr) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline const double_conversion::StringToDoubleConverter&
|
||||
StringToFloatConverter() {
|
||||
static const double_conversion::StringToDoubleConverter converter(
|
||||
double_conversion::StringToDoubleConverter::ALLOW_LEADING_SPACES |
|
||||
double_conversion::StringToDoubleConverter::ALLOW_HEX |
|
||||
double_conversion::StringToDoubleConverter::ALLOW_TRAILING_SPACES |
|
||||
double_conversion::StringToDoubleConverter::ALLOW_CASE_INSENSIBILITY,
|
||||
0., 0., "inf", "nan");
|
||||
return converter;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace strings {
|
||||
@ -319,25 +332,31 @@ bool safe_strtou32(StringPiece str, uint32* value) {
|
||||
}
|
||||
|
||||
bool safe_strtof(const char* str, float* value) {
|
||||
const char* endptr;
|
||||
*value = locale_independent_strtonum<float>(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';
|
||||
int processed_characters_count = -1;
|
||||
auto len = str_util::Strnlen(str, kFastToBufferSize);
|
||||
|
||||
// If there is no zero-termination in str, fail.
|
||||
if (len == kFastToBufferSize) return false;
|
||||
// If string length exceeds int max, fail.
|
||||
if (len > std::numeric_limits<int>::max()) return false;
|
||||
|
||||
*value = StringToFloatConverter().StringToFloat(str, static_cast<int>(len),
|
||||
&processed_characters_count);
|
||||
return processed_characters_count > 0;
|
||||
}
|
||||
|
||||
bool safe_strtod(const char* str, double* value) {
|
||||
const char* endptr;
|
||||
*value = locale_independent_strtonum<double>(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';
|
||||
int processed_characters_count = -1;
|
||||
auto len = str_util::Strnlen(str, kFastToBufferSize);
|
||||
|
||||
// If there is no zero-termination in str, fail.
|
||||
if (len == kFastToBufferSize) return false;
|
||||
// If string length exceeds int max, fail.
|
||||
if (len > std::numeric_limits<int>::max()) return false;
|
||||
|
||||
*value = StringToFloatConverter().StringToDouble(str, static_cast<int>(len),
|
||||
&processed_characters_count);
|
||||
return processed_characters_count > 0;
|
||||
}
|
||||
|
||||
size_t FloatToBuffer(float value, char* buffer) {
|
||||
|
@ -114,11 +114,13 @@ 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.
|
||||
// Returns false on invalid input or if `strlen(value) >= kFastToBufferSize`.
|
||||
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.
|
||||
// Returns false on invalid input or if `strlen(value) >= kFastToBufferSize`.
|
||||
bool safe_strtod(const char* str, double* value);
|
||||
|
||||
inline bool ProtoParseNumeric(StringPiece s, int32* value) {
|
||||
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||
|
||||
#include "tensorflow/core/lib/strings/numbers.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include "tensorflow/core/platform/test.h"
|
||||
|
||||
@ -277,7 +278,49 @@ TEST(safe_strtof, Float) {
|
||||
EXPECT_TRUE(safe_strtof("-0x2A", &result));
|
||||
EXPECT_EQ(-42.0f, result);
|
||||
|
||||
EXPECT_TRUE(safe_strtof(" -0x2", &result));
|
||||
EXPECT_EQ(-2.0f, result);
|
||||
|
||||
EXPECT_TRUE(safe_strtof("8 \t", &result));
|
||||
EXPECT_EQ(8.0f, result);
|
||||
|
||||
EXPECT_TRUE(safe_strtof("\t20.0\t ", &result));
|
||||
EXPECT_EQ(20.0f, result);
|
||||
|
||||
EXPECT_FALSE(safe_strtof("-infinity is awesome", &result));
|
||||
|
||||
// Make sure we exit cleanly if the string is not terminated
|
||||
char test_str[2 * kFastToBufferSize];
|
||||
for (int i = 0; i < 2 * kFastToBufferSize; ++i) test_str[i] = 'a';
|
||||
EXPECT_FALSE(safe_strtof(test_str, &result));
|
||||
|
||||
// Make sure we exit cleanly if the string is too long
|
||||
test_str[kFastToBufferSize + 1] = '\0';
|
||||
EXPECT_FALSE(safe_strtof(test_str, &result));
|
||||
|
||||
EXPECT_TRUE(safe_strtof("-inf", &result));
|
||||
EXPECT_EQ(-std::numeric_limits<float>::infinity(), result);
|
||||
|
||||
EXPECT_TRUE(safe_strtof("+inf", &result));
|
||||
EXPECT_EQ(std::numeric_limits<float>::infinity(), result);
|
||||
|
||||
EXPECT_TRUE(safe_strtof("InF", &result));
|
||||
EXPECT_EQ(std::numeric_limits<float>::infinity(), result);
|
||||
|
||||
EXPECT_TRUE(safe_strtof("-INF", &result));
|
||||
EXPECT_EQ(-std::numeric_limits<float>::infinity(), result);
|
||||
|
||||
EXPECT_TRUE(safe_strtof("nan", &result));
|
||||
EXPECT_TRUE(std::isnan(result));
|
||||
|
||||
EXPECT_TRUE(safe_strtof("-nan", &result));
|
||||
EXPECT_TRUE(std::isnan(result));
|
||||
|
||||
EXPECT_TRUE(safe_strtof("-NaN", &result));
|
||||
EXPECT_TRUE(std::isnan(result));
|
||||
|
||||
EXPECT_TRUE(safe_strtof("+NAN", &result));
|
||||
EXPECT_TRUE(std::isnan(result));
|
||||
}
|
||||
|
||||
TEST(safe_strtod, Double) {
|
||||
@ -287,6 +330,15 @@ TEST(safe_strtod, Double) {
|
||||
EXPECT_EQ(0.1234567890123, result);
|
||||
EXPECT_FALSE(safe_strtod("0.1234567890123abc", &result));
|
||||
|
||||
// Make sure we exit cleanly if the string is not terminated
|
||||
char test_str[2 * kFastToBufferSize];
|
||||
for (int i = 0; i < 2 * kFastToBufferSize; ++i) test_str[i] = 'a';
|
||||
EXPECT_FALSE(safe_strtod(test_str, &result));
|
||||
|
||||
// Make sure we exit cleanly if the string is too long
|
||||
test_str[kFastToBufferSize + 1] = '\0';
|
||||
EXPECT_FALSE(safe_strtod(test_str, &result));
|
||||
|
||||
// Overflow to infinity, underflow to 0.
|
||||
EXPECT_TRUE(safe_strtod("1e310", &result));
|
||||
EXPECT_EQ(std::numeric_limits<double>::infinity(), result);
|
||||
@ -296,6 +348,41 @@ TEST(safe_strtod, Double) {
|
||||
|
||||
EXPECT_TRUE(safe_strtod("1e-325", &result));
|
||||
EXPECT_EQ(0, result);
|
||||
|
||||
EXPECT_TRUE(safe_strtod(" -0x1c", &result));
|
||||
EXPECT_EQ(-28.0, result);
|
||||
|
||||
EXPECT_TRUE(safe_strtod("50 \t", &result));
|
||||
EXPECT_EQ(50.0, result);
|
||||
|
||||
EXPECT_TRUE(safe_strtod("\t82.0\t ", &result));
|
||||
EXPECT_EQ(82.0, result);
|
||||
|
||||
EXPECT_FALSE(safe_strtod("infinity", &result));
|
||||
|
||||
EXPECT_TRUE(safe_strtod("-inf", &result));
|
||||
EXPECT_EQ(-std::numeric_limits<double>::infinity(), result);
|
||||
|
||||
EXPECT_TRUE(safe_strtod("+inf", &result));
|
||||
EXPECT_EQ(std::numeric_limits<double>::infinity(), result);
|
||||
|
||||
EXPECT_TRUE(safe_strtod("InF", &result));
|
||||
EXPECT_EQ(std::numeric_limits<double>::infinity(), result);
|
||||
|
||||
EXPECT_TRUE(safe_strtod("-INF", &result));
|
||||
EXPECT_EQ(-std::numeric_limits<double>::infinity(), result);
|
||||
|
||||
EXPECT_TRUE(safe_strtod("nan", &result));
|
||||
EXPECT_TRUE(std::isnan(result));
|
||||
|
||||
EXPECT_TRUE(safe_strtod("-nan", &result));
|
||||
EXPECT_TRUE(std::isnan(result));
|
||||
|
||||
EXPECT_TRUE(safe_strtod("-NaN", &result));
|
||||
EXPECT_TRUE(std::isnan(result));
|
||||
|
||||
EXPECT_TRUE(safe_strtod("+NAN", &result));
|
||||
EXPECT_TRUE(std::isnan(result));
|
||||
}
|
||||
|
||||
} // namespace strings
|
||||
|
@ -454,6 +454,14 @@ bool SplitAndParseAsFloats(StringPiece text, char delim,
|
||||
result);
|
||||
}
|
||||
|
||||
size_t Strnlen(const char* str, const size_t string_max_len) {
|
||||
size_t len = 0;
|
||||
while (len < string_max_len && str[len] != '\0') {
|
||||
++len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
bool StrContains(StringPiece haystack, StringPiece needle) {
|
||||
return std::search(haystack.begin(), haystack.end(), needle.begin(),
|
||||
needle.end()) != haystack.end();
|
||||
|
@ -223,6 +223,11 @@ std::vector<string> Split(StringPiece text, char delims, Predicate p) {
|
||||
return Split(text, StringPiece(&delims, 1), p);
|
||||
}
|
||||
|
||||
// Returns the length of the given null-terminated byte string 'str'.
|
||||
// Returns 'string_max_len' if the null character was not found in the first
|
||||
// 'string_max_len' bytes of 'str'.
|
||||
size_t Strnlen(const char* str, const size_t string_max_len);
|
||||
|
||||
} // namespace str_util
|
||||
} // namespace tensorflow
|
||||
|
||||
|
@ -430,56 +430,12 @@ TEST(StringReplace, EmptyStringReplaceAll) {
|
||||
EXPECT_EQ("", str_util::StringReplace("", "a", "X", /*replace_all=*/true));
|
||||
}
|
||||
|
||||
TEST(StartsWith, Basic) {
|
||||
const string s1(
|
||||
"123"
|
||||
"\0"
|
||||
"456",
|
||||
7);
|
||||
const StringPiece a("foobar");
|
||||
const StringPiece b(s1);
|
||||
const StringPiece e;
|
||||
EXPECT_TRUE(str_util::StartsWith(a, a));
|
||||
EXPECT_TRUE(str_util::StartsWith(a, "foo"));
|
||||
EXPECT_TRUE(str_util::StartsWith(a, e));
|
||||
EXPECT_TRUE(str_util::StartsWith(b, s1));
|
||||
EXPECT_TRUE(str_util::StartsWith(b, b));
|
||||
EXPECT_TRUE(str_util::StartsWith(b, e));
|
||||
EXPECT_TRUE(str_util::StartsWith(e, ""));
|
||||
EXPECT_FALSE(str_util::StartsWith(a, b));
|
||||
EXPECT_FALSE(str_util::StartsWith(b, a));
|
||||
EXPECT_FALSE(str_util::StartsWith(e, a));
|
||||
}
|
||||
|
||||
TEST(EndsWith, Basic) {
|
||||
const string s1(
|
||||
"123"
|
||||
"\0"
|
||||
"456",
|
||||
7);
|
||||
const StringPiece a("foobar");
|
||||
const StringPiece b(s1);
|
||||
const StringPiece e;
|
||||
EXPECT_TRUE(str_util::EndsWith(a, a));
|
||||
EXPECT_TRUE(str_util::EndsWith(a, "bar"));
|
||||
EXPECT_TRUE(str_util::EndsWith(a, e));
|
||||
EXPECT_TRUE(str_util::EndsWith(b, s1));
|
||||
EXPECT_TRUE(str_util::EndsWith(b, b));
|
||||
EXPECT_TRUE(str_util::EndsWith(b, e));
|
||||
EXPECT_TRUE(str_util::EndsWith(e, ""));
|
||||
EXPECT_FALSE(str_util::EndsWith(a, b));
|
||||
EXPECT_FALSE(str_util::EndsWith(b, a));
|
||||
EXPECT_FALSE(str_util::EndsWith(e, a));
|
||||
}
|
||||
|
||||
TEST(StrContains, Basic) {
|
||||
StringPiece a("abcdefg");
|
||||
StringPiece b("abcd");
|
||||
StringPiece c("efg");
|
||||
StringPiece d("gh");
|
||||
EXPECT_TRUE(str_util::StrContains(a, b));
|
||||
EXPECT_TRUE(str_util::StrContains(a, c));
|
||||
EXPECT_TRUE(!str_util::StrContains(a, d));
|
||||
TEST(Strnlen, Basic) {
|
||||
EXPECT_EQ(0, str_util::Strnlen("ab", 0));
|
||||
EXPECT_EQ(1, str_util::Strnlen("a", 1));
|
||||
EXPECT_EQ(2, str_util::Strnlen("abcd", 2));
|
||||
EXPECT_EQ(3, str_util::Strnlen("abc", 10));
|
||||
EXPECT_EQ(4, str_util::Strnlen("a \t\n", 10));
|
||||
}
|
||||
|
||||
} // namespace tensorflow
|
||||
|
@ -118,6 +118,7 @@ genrule(
|
||||
"@com_googlesource_code_re2//:LICENSE",
|
||||
"@cub_archive//:LICENSE.TXT",
|
||||
"@curl//:COPYING",
|
||||
"@double_conversion//:LICENSE",
|
||||
"@eigen_archive//:COPYING.MPL2",
|
||||
"@farmhash_archive//:COPYING",
|
||||
"@fft2d//:fft/readme.txt",
|
||||
@ -155,6 +156,7 @@ genrule(
|
||||
"@com_googlesource_code_re2//:LICENSE",
|
||||
"@cub_archive//:LICENSE.TXT",
|
||||
"@curl//:COPYING",
|
||||
"@double_conversion//:LICENSE",
|
||||
"@eigen_archive//:COPYING.MPL2",
|
||||
"@farmhash_archive//:COPYING",
|
||||
"@fft2d//:fft/readme.txt",
|
||||
|
@ -128,6 +128,7 @@ filegroup(
|
||||
"@com_googlesource_code_re2//:LICENSE",
|
||||
"@cub_archive//:LICENSE.TXT",
|
||||
"@curl//:COPYING",
|
||||
"@double_conversion//:LICENSE",
|
||||
"@eigen_archive//:COPYING.MPL2",
|
||||
"@farmhash_archive//:COPYING",
|
||||
"@fft2d//:fft/readme.txt",
|
||||
|
@ -693,6 +693,16 @@ def tf_workspace(path_prefix="", tf_repo_name=""):
|
||||
build_file = clean_dep("//third_party/flatbuffers:flatbuffers.BUILD"),
|
||||
)
|
||||
|
||||
native.new_http_archive(
|
||||
name = "double_conversion",
|
||||
urls = [
|
||||
"https://github.com/google/double-conversion/archive/3992066a95b823efc8ccc1baf82a1cfc73f6e9b8.zip",
|
||||
],
|
||||
sha256 = "2f7fbffac0d98d201ad0586f686034371a6d152ca67508ab611adc2386ad30de",
|
||||
strip_prefix = "double-conversion-3992066a95b823efc8ccc1baf82a1cfc73f6e9b8",
|
||||
build_file = clean_dep("//third_party:double_conversion.BUILD")
|
||||
)
|
||||
|
||||
tf_http_archive(
|
||||
name = "tflite_mobilenet",
|
||||
sha256 = "23f814d1c076bdf03715dfb6cab3713aa4fbdf040fd5448c43196bd2e97a4c1b",
|
||||
|
38
third_party/double_conversion.BUILD
vendored
Normal file
38
third_party/double_conversion.BUILD
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
# Bazel(http://bazel.io) BUILD file
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
exports_files(["LICENSE"])
|
||||
|
||||
cc_library(
|
||||
name = "double-conversion",
|
||||
srcs = [
|
||||
"double-conversion/bignum.cc",
|
||||
"double-conversion/bignum-dtoa.cc",
|
||||
"double-conversion/cached-powers.cc",
|
||||
"double-conversion/diy-fp.cc",
|
||||
"double-conversion/double-conversion.cc",
|
||||
"double-conversion/fast-dtoa.cc",
|
||||
"double-conversion/fixed-dtoa.cc",
|
||||
"double-conversion/strtod.cc",
|
||||
"double-conversion/utils.h",
|
||||
],
|
||||
hdrs = [
|
||||
"double-conversion/bignum.h",
|
||||
"double-conversion/bignum-dtoa.h",
|
||||
"double-conversion/cached-powers.h",
|
||||
"double-conversion/diy-fp.h",
|
||||
"double-conversion/double-conversion.h",
|
||||
"double-conversion/fast-dtoa.h",
|
||||
"double-conversion/fixed-dtoa.h",
|
||||
"double-conversion/ieee.h",
|
||||
"double-conversion/strtod.h",
|
||||
],
|
||||
includes = [
|
||||
".",
|
||||
],
|
||||
linkopts = [
|
||||
"-lm",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
Loading…
Reference in New Issue
Block a user