Move strcat library to core/platform
PiperOrigin-RevId: 266030368
This commit is contained in:
parent
778059ae71
commit
524f81e516
@ -32,7 +32,6 @@ tensorflow/core/lib/random/simple_philox.cc
|
||||
tensorflow/core/lib/random/weighted_picker.cc
|
||||
tensorflow/core/lib/strings/ordered_code.cc
|
||||
tensorflow/core/lib/strings/proto_text_util.cc
|
||||
tensorflow/core/lib/strings/strcat.cc
|
||||
tensorflow/core/lib/wav/wav_io.cc
|
||||
tensorflow/core/platform/cpu_info.cc
|
||||
tensorflow/core/platform/default/logging.cc
|
||||
@ -53,6 +52,7 @@ tensorflow/core/platform/protobuf.cc
|
||||
tensorflow/core/platform/protobuf_util.cc
|
||||
tensorflow/core/platform/scanner.cc
|
||||
tensorflow/core/platform/setround.cc
|
||||
tensorflow/core/platform/strcat.cc
|
||||
tensorflow/core/platform/stringprintf.cc
|
||||
tensorflow/core/platform/str_util.cc
|
||||
tensorflow/core/platform/tensor_coding.cc
|
||||
|
@ -2491,6 +2491,7 @@ cc_library(
|
||||
"//tensorflow/core/platform:numbers",
|
||||
"//tensorflow/core/platform:platform_strings",
|
||||
"//tensorflow/core/platform:scanner",
|
||||
"//tensorflow/core/platform:strcat",
|
||||
"//tensorflow/core/platform:stringprintf",
|
||||
"//tensorflow/core/platform:str_util",
|
||||
"//tensorflow/core/platform/default/build_config:platformlib",
|
||||
@ -3735,6 +3736,7 @@ tf_cc_tests(
|
||||
"//tensorflow/core/platform:scanner_test.cc",
|
||||
"//tensorflow/core/platform:stacktrace_handler_test.cc",
|
||||
"//tensorflow/core/platform:str_util_test.cc",
|
||||
"//tensorflow/core/platform:strcat_test.cc",
|
||||
"//tensorflow/core/platform:stringpiece_test.cc",
|
||||
"//tensorflow/core/platform:stringprintf_test.cc",
|
||||
"//tensorflow/core/platform:subprocess_test.cc",
|
||||
@ -3750,6 +3752,7 @@ tf_cc_tests(
|
||||
":test_main",
|
||||
"//tensorflow/core/platform:scanner",
|
||||
"//tensorflow/core/platform:str_util",
|
||||
"//tensorflow/core/platform:strcat",
|
||||
"//tensorflow/core/platform:stringpiece",
|
||||
"//tensorflow/core/platform:stringprintf",
|
||||
"//third_party/eigen3",
|
||||
|
@ -28,6 +28,7 @@ limitations under the License.
|
||||
#include "tensorflow/core/common_runtime/shared_counter.h"
|
||||
#include "tensorflow/core/framework/allocator.h"
|
||||
#include "tensorflow/core/lib/gtl/stl_util.h"
|
||||
#include "tensorflow/core/lib/strings/numbers.h"
|
||||
#include "tensorflow/core/lib/strings/strcat.h"
|
||||
#include "tensorflow/core/platform/macros.h"
|
||||
#include "tensorflow/core/platform/mutex.h"
|
||||
|
@ -29,25 +29,15 @@ cc_library(
|
||||
|
||||
cc_library(
|
||||
name = "string_utils",
|
||||
srcs = [
|
||||
"strcat.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"numbers.h",
|
||||
"str_util.h",
|
||||
"strcat.h",
|
||||
],
|
||||
deps = [
|
||||
"//tensorflow/core/lib/gtl:stl_util",
|
||||
"//tensorflow/core/platform:logging",
|
||||
"//tensorflow/core/platform:macros",
|
||||
"//tensorflow/core/platform:numbers",
|
||||
"//tensorflow/core/platform:str_util",
|
||||
"//tensorflow/core/platform:stringpiece",
|
||||
"//tensorflow/core/platform:stringprintf",
|
||||
"//tensorflow/core/platform:types",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/strings",
|
||||
"//tensorflow/core/platform:strcat",
|
||||
],
|
||||
)
|
||||
|
||||
@ -80,7 +70,6 @@ filegroup(
|
||||
"ordered_code.cc",
|
||||
"proto_serialization.cc",
|
||||
"proto_text_util.cc",
|
||||
"strcat.cc",
|
||||
],
|
||||
visibility = ["//tensorflow/core:__pkg__"],
|
||||
)
|
||||
@ -91,7 +80,6 @@ filegroup(
|
||||
"base64_test.cc",
|
||||
"ordered_code_test.cc",
|
||||
"proto_serialization_test.cc",
|
||||
"strcat_test.cc",
|
||||
],
|
||||
visibility = ["//tensorflow/core:__pkg__"],
|
||||
)
|
||||
@ -142,7 +130,6 @@ filegroup(
|
||||
name = "legacy_low_level_library_tests",
|
||||
srcs = [
|
||||
"base64_test.cc",
|
||||
"strcat_test.cc",
|
||||
],
|
||||
visibility = ["//tensorflow/core:__pkg__"],
|
||||
)
|
||||
|
@ -20,226 +20,6 @@ limitations under the License.
|
||||
#ifndef TENSORFLOW_CORE_LIB_STRINGS_STRCAT_H_
|
||||
#define TENSORFLOW_CORE_LIB_STRINGS_STRCAT_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "tensorflow/core/lib/strings/numbers.h"
|
||||
#include "tensorflow/core/platform/macros.h"
|
||||
#include "tensorflow/core/platform/stringpiece.h"
|
||||
#include "tensorflow/core/platform/types.h"
|
||||
|
||||
// The AlphaNum type was designed to be used as the parameter type for StrCat().
|
||||
// Any routine accepting either a string or a number may accept it.
|
||||
// The basic idea is that by accepting a "const AlphaNum &" as an argument
|
||||
// to your function, your callers will automatically convert bools, integers,
|
||||
// and floating point values to strings for you.
|
||||
//
|
||||
// NOTE: Use of AlphaNum outside of the //strings package is unsupported except
|
||||
// for the specific case of function parameters of type "AlphaNum" or "const
|
||||
// AlphaNum &". In particular, instantiating AlphaNum directly as a stack
|
||||
// variable is not supported.
|
||||
//
|
||||
// Conversion from 8-bit values is not accepted because if it were, then an
|
||||
// attempt to pass ':' instead of ":" might result in a 58 ending up in your
|
||||
// result.
|
||||
//
|
||||
// Bools convert to "0" or "1".
|
||||
//
|
||||
// Floating point values are converted to a string which, if passed to strtod(),
|
||||
// would produce the exact same original double (except in case of NaN; all NaNs
|
||||
// are considered the same value). We try to keep the string short but it's not
|
||||
// guaranteed to be as short as possible.
|
||||
//
|
||||
// You can convert to Hexadecimal output rather than Decimal output using Hex.
|
||||
// To do this, pass strings::Hex(my_int) as a parameter to StrCat. You may
|
||||
// specify a minimum field width using a separate parameter, so the equivalent
|
||||
// of Printf("%04x", my_int) is StrCat(Hex(my_int, strings::kZeroPad4))
|
||||
//
|
||||
// This class has implicit constructors.
|
||||
namespace tensorflow {
|
||||
namespace strings {
|
||||
|
||||
enum PadSpec {
|
||||
kNoPad = 1,
|
||||
kZeroPad2,
|
||||
kZeroPad3,
|
||||
kZeroPad4,
|
||||
kZeroPad5,
|
||||
kZeroPad6,
|
||||
kZeroPad7,
|
||||
kZeroPad8,
|
||||
kZeroPad9,
|
||||
kZeroPad10,
|
||||
kZeroPad11,
|
||||
kZeroPad12,
|
||||
kZeroPad13,
|
||||
kZeroPad14,
|
||||
kZeroPad15,
|
||||
kZeroPad16
|
||||
};
|
||||
|
||||
struct Hex {
|
||||
uint64 value;
|
||||
enum PadSpec spec;
|
||||
template <class Int>
|
||||
explicit Hex(Int v, PadSpec s = kNoPad) : spec(s) {
|
||||
// Prevent sign-extension by casting integers to
|
||||
// their unsigned counterparts.
|
||||
static_assert(
|
||||
sizeof(v) == 1 || sizeof(v) == 2 || sizeof(v) == 4 || sizeof(v) == 8,
|
||||
"Unknown integer type");
|
||||
value = sizeof(v) == 1
|
||||
? static_cast<uint8>(v)
|
||||
: sizeof(v) == 2 ? static_cast<uint16>(v)
|
||||
: sizeof(v) == 4 ? static_cast<uint32>(v)
|
||||
: static_cast<uint64>(v);
|
||||
}
|
||||
};
|
||||
|
||||
class AlphaNum {
|
||||
public:
|
||||
// No bool ctor -- bools convert to an integral type.
|
||||
// A bool ctor would also convert incoming pointers (bletch).
|
||||
|
||||
AlphaNum(int i32) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, FastInt32ToBufferLeft(i32, digits_)) {}
|
||||
AlphaNum(unsigned int u32) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, FastUInt32ToBufferLeft(u32, digits_)) {}
|
||||
AlphaNum(long x) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, FastInt64ToBufferLeft(x, digits_)) {}
|
||||
AlphaNum(unsigned long x) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, FastUInt64ToBufferLeft(x, digits_)) {}
|
||||
AlphaNum(long long int i64) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, FastInt64ToBufferLeft(i64, digits_)) {}
|
||||
AlphaNum(unsigned long long int u64) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, FastUInt64ToBufferLeft(u64, digits_)) {}
|
||||
|
||||
AlphaNum(float f) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, FloatToBuffer(f, digits_)) {}
|
||||
AlphaNum(double f) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, DoubleToBuffer(f, digits_)) {}
|
||||
|
||||
AlphaNum(Hex hex); // NOLINT(runtime/explicit)
|
||||
|
||||
AlphaNum(const char *c_str) : piece_(c_str) {} // NOLINT(runtime/explicit)
|
||||
AlphaNum(const StringPiece &pc) : piece_(pc) {} // NOLINT(runtime/explicit)
|
||||
AlphaNum(const tensorflow::string &str) // NOLINT(runtime/explicit)
|
||||
: piece_(str) {}
|
||||
#ifdef USE_TSTRING
|
||||
// TODO(dero): Temp guard to prevent duplicate declaration during tstring
|
||||
// migration.
|
||||
AlphaNum(const tensorflow::tstring &str) // NOLINT(runtime/explicit)
|
||||
: piece_(str) {}
|
||||
#endif
|
||||
template <typename A>
|
||||
AlphaNum(const std::basic_string<char, std::char_traits<char>, A> &str)
|
||||
: piece_(str) {} // NOLINT(runtime/explicit)
|
||||
|
||||
StringPiece::size_type size() const { return piece_.size(); }
|
||||
const char *data() const { return piece_.data(); }
|
||||
StringPiece Piece() const { return piece_; }
|
||||
|
||||
private:
|
||||
StringPiece piece_;
|
||||
char digits_[kFastToBufferSize];
|
||||
|
||||
// Use ":" not ':'
|
||||
AlphaNum(char c); // NOLINT(runtime/explicit)
|
||||
|
||||
TF_DISALLOW_COPY_AND_ASSIGN(AlphaNum);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// StrCat()
|
||||
// This merges the given strings or numbers, with no delimiter. This
|
||||
// is designed to be the fastest possible way to construct a string out
|
||||
// of a mix of raw C strings, StringPieces, strings, bool values,
|
||||
// and numeric values.
|
||||
//
|
||||
// Don't use this for user-visible strings. The localization process
|
||||
// works poorly on strings built up out of fragments.
|
||||
//
|
||||
// For clarity and performance, don't use StrCat when appending to a
|
||||
// string. In particular, avoid using any of these (anti-)patterns:
|
||||
// str.append(StrCat(...))
|
||||
// str += StrCat(...)
|
||||
// str = StrCat(str, ...)
|
||||
// where the last is the worse, with the potential to change a loop
|
||||
// from a linear time operation with O(1) dynamic allocations into a
|
||||
// quadratic time operation with O(n) dynamic allocations. StrAppend
|
||||
// is a better choice than any of the above, subject to the restriction
|
||||
// of StrAppend(&str, a, b, c, ...) that none of the a, b, c, ... may
|
||||
// be a reference into str.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
// For performance reasons, we have specializations for <= 4 args.
|
||||
string StrCat(const AlphaNum &a) TF_MUST_USE_RESULT;
|
||||
string StrCat(const AlphaNum &a, const AlphaNum &b) TF_MUST_USE_RESULT;
|
||||
string StrCat(const AlphaNum &a, const AlphaNum &b,
|
||||
const AlphaNum &c) TF_MUST_USE_RESULT;
|
||||
string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
|
||||
const AlphaNum &d) TF_MUST_USE_RESULT;
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Do not call directly - this is not part of the public API.
|
||||
string CatPieces(std::initializer_list<StringPiece> pieces);
|
||||
void AppendPieces(string *dest, std::initializer_list<StringPiece> pieces);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Support 5 or more arguments
|
||||
template <typename... AV>
|
||||
string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
|
||||
const AlphaNum &d, const AlphaNum &e,
|
||||
const AV &... args) TF_MUST_USE_RESULT;
|
||||
|
||||
template <typename... AV>
|
||||
string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
|
||||
const AlphaNum &d, const AlphaNum &e, const AV &... args) {
|
||||
return internal::CatPieces({a.Piece(), b.Piece(), c.Piece(), d.Piece(),
|
||||
e.Piece(),
|
||||
static_cast<const AlphaNum &>(args).Piece()...});
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// StrAppend()
|
||||
// Same as above, but adds the output to the given string.
|
||||
// WARNING: For speed, StrAppend does not try to check each of its input
|
||||
// arguments to be sure that they are not a subset of the string being
|
||||
// appended to. That is, while this will work:
|
||||
//
|
||||
// string s = "foo";
|
||||
// s += s;
|
||||
//
|
||||
// This will not (necessarily) work:
|
||||
//
|
||||
// string s = "foo";
|
||||
// StrAppend(&s, s);
|
||||
//
|
||||
// Note: while StrCat supports appending up to 26 arguments, StrAppend
|
||||
// is currently limited to 9. That's rarely an issue except when
|
||||
// automatically transforming StrCat to StrAppend, and can easily be
|
||||
// worked around as consecutive calls to StrAppend are quite efficient.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void StrAppend(string *dest, const AlphaNum &a);
|
||||
void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b);
|
||||
void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b,
|
||||
const AlphaNum &c);
|
||||
void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b,
|
||||
const AlphaNum &c, const AlphaNum &d);
|
||||
|
||||
// Support 5 or more arguments
|
||||
template <typename... AV>
|
||||
inline void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b,
|
||||
const AlphaNum &c, const AlphaNum &d, const AlphaNum &e,
|
||||
const AV &... args) {
|
||||
internal::AppendPieces(dest,
|
||||
{a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
|
||||
static_cast<const AlphaNum &>(args).Piece()...});
|
||||
}
|
||||
|
||||
} // namespace strings
|
||||
} // namespace tensorflow
|
||||
#include "tensorflow/core/platform/strcat.h"
|
||||
|
||||
#endif // TENSORFLOW_CORE_LIB_STRINGS_STRCAT_H_
|
||||
|
@ -258,6 +258,20 @@ cc_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "strcat",
|
||||
srcs = ["strcat.cc"],
|
||||
hdrs = ["strcat.h"],
|
||||
deps = [
|
||||
":logging",
|
||||
":macros",
|
||||
":numbers",
|
||||
":stringpiece",
|
||||
":types",
|
||||
"@com_google_absl//absl/meta:type_traits",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "stringpiece",
|
||||
hdrs = ["stringpiece.h"],
|
||||
@ -336,6 +350,7 @@ filegroup(
|
||||
"platform_strings.cc",
|
||||
"protobuf.cc",
|
||||
"scanner.cc",
|
||||
"strcat.cc",
|
||||
"stringprintf.cc",
|
||||
],
|
||||
),
|
||||
@ -434,6 +449,7 @@ filegroup(
|
||||
"platform_strings.cc",
|
||||
"protobuf.cc",
|
||||
"scanner.cc",
|
||||
"strcat.cc",
|
||||
"stringprintf.cc",
|
||||
"str_util.cc",
|
||||
],
|
||||
|
@ -13,14 +13,14 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
#include "tensorflow/core/lib/strings/strcat.h"
|
||||
#include "tensorflow/core/platform/strcat.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tensorflow/core/lib/gtl/stl_util.h"
|
||||
#include "absl/meta/type_traits.h"
|
||||
#include "tensorflow/core/platform/logging.h"
|
||||
|
||||
namespace tensorflow {
|
||||
@ -85,8 +85,7 @@ static char *Append4(char *out, const AlphaNum &x1, const AlphaNum &x2,
|
||||
string StrCat(const AlphaNum &a) { return string(a.data(), a.size()); }
|
||||
|
||||
string StrCat(const AlphaNum &a, const AlphaNum &b) {
|
||||
string result;
|
||||
gtl::STLStringResizeUninitialized(&result, a.size() + b.size());
|
||||
string result(a.size() + b.size(), '\0');
|
||||
char *const begin = &*result.begin();
|
||||
char *out = Append2(begin, a, b);
|
||||
DCHECK_EQ(out, begin + result.size());
|
||||
@ -94,8 +93,7 @@ string StrCat(const AlphaNum &a, const AlphaNum &b) {
|
||||
}
|
||||
|
||||
string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) {
|
||||
string result;
|
||||
gtl::STLStringResizeUninitialized(&result, a.size() + b.size() + c.size());
|
||||
string result(a.size() + b.size() + c.size(), '\0');
|
||||
char *const begin = &*result.begin();
|
||||
char *out = Append2(begin, a, b);
|
||||
out = Append1(out, c);
|
||||
@ -105,23 +103,47 @@ string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) {
|
||||
|
||||
string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
|
||||
const AlphaNum &d) {
|
||||
string result;
|
||||
gtl::STLStringResizeUninitialized(&result,
|
||||
a.size() + b.size() + c.size() + d.size());
|
||||
string result(a.size() + b.size() + c.size() + d.size(), '\0');
|
||||
char *const begin = &*result.begin();
|
||||
char *out = Append4(begin, a, b, c, d);
|
||||
DCHECK_EQ(out, begin + result.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace {
|
||||
// HasMember is true_type or false_type, depending on whether or not
|
||||
// T has a __resize_default_init member. Resize will call the
|
||||
// __resize_default_init member if it exists, and will call the resize
|
||||
// member otherwise.
|
||||
template <typename string_type, typename = void>
|
||||
struct ResizeUninitializedTraits {
|
||||
using HasMember = std::false_type;
|
||||
static void Resize(string_type* s, size_t new_size) { s->resize(new_size); }
|
||||
};
|
||||
|
||||
// __resize_default_init is provided by libc++ >= 8.0.
|
||||
template <typename string_type>
|
||||
struct ResizeUninitializedTraits<
|
||||
string_type, absl::void_t<decltype(std::declval<string_type&>()
|
||||
.__resize_default_init(237))> > {
|
||||
using HasMember = std::true_type;
|
||||
static void Resize(string_type* s, size_t new_size) {
|
||||
s->__resize_default_init(new_size);
|
||||
}
|
||||
};
|
||||
|
||||
static inline void STLStringResizeUninitialized(string* s, size_t new_size) {
|
||||
ResizeUninitializedTraits<string>::Resize(s, new_size);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
namespace internal {
|
||||
|
||||
// Do not call directly - these are not part of the public API.
|
||||
string CatPieces(std::initializer_list<StringPiece> pieces) {
|
||||
string result;
|
||||
size_t total_size = 0;
|
||||
for (const StringPiece piece : pieces) total_size += piece.size();
|
||||
gtl::STLStringResizeUninitialized(&result, total_size);
|
||||
string result(total_size, '\0');
|
||||
|
||||
char *const begin = &*result.begin();
|
||||
char *out = begin;
|
||||
@ -148,7 +170,7 @@ void AppendPieces(string *result, std::initializer_list<StringPiece> pieces) {
|
||||
DCHECK_NO_OVERLAP(*result, piece);
|
||||
total_size += piece.size();
|
||||
}
|
||||
gtl::STLStringResizeUninitialized(result, total_size);
|
||||
STLStringResizeUninitialized(result, total_size);
|
||||
|
||||
char *const begin = &*result->begin();
|
||||
char *out = begin + old_size;
|
||||
@ -171,7 +193,7 @@ void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b) {
|
||||
DCHECK_NO_OVERLAP(*result, a);
|
||||
DCHECK_NO_OVERLAP(*result, b);
|
||||
string::size_type old_size = result->size();
|
||||
gtl::STLStringResizeUninitialized(result, old_size + a.size() + b.size());
|
||||
STLStringResizeUninitialized(result, old_size + a.size() + b.size());
|
||||
char *const begin = &*result->begin();
|
||||
char *out = Append2(begin + old_size, a, b);
|
||||
DCHECK_EQ(out, begin + result->size());
|
||||
@ -183,8 +205,8 @@ void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b,
|
||||
DCHECK_NO_OVERLAP(*result, b);
|
||||
DCHECK_NO_OVERLAP(*result, c);
|
||||
string::size_type old_size = result->size();
|
||||
gtl::STLStringResizeUninitialized(result,
|
||||
old_size + a.size() + b.size() + c.size());
|
||||
STLStringResizeUninitialized(result,
|
||||
old_size + a.size() + b.size() + c.size());
|
||||
char *const begin = &*result->begin();
|
||||
char *out = Append2(begin + old_size, a, b);
|
||||
out = Append1(out, c);
|
||||
@ -198,7 +220,7 @@ void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b,
|
||||
DCHECK_NO_OVERLAP(*result, c);
|
||||
DCHECK_NO_OVERLAP(*result, d);
|
||||
string::size_type old_size = result->size();
|
||||
gtl::STLStringResizeUninitialized(
|
||||
STLStringResizeUninitialized(
|
||||
result, old_size + a.size() + b.size() + c.size() + d.size());
|
||||
char *const begin = &*result->begin();
|
||||
char *out = Append4(begin + old_size, a, b, c, d);
|
245
tensorflow/core/platform/strcat.h
Normal file
245
tensorflow/core/platform/strcat.h
Normal file
@ -0,0 +1,245 @@
|
||||
/* Copyright 2015 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.
|
||||
==============================================================================*/
|
||||
|
||||
// #status: RECOMMENDED
|
||||
// #category: operations on strings
|
||||
// #summary: Merges strings or numbers with no delimiter.
|
||||
//
|
||||
#ifndef TENSORFLOW_CORE_PLATFORM_STRCAT_H_
|
||||
#define TENSORFLOW_CORE_PLATFORM_STRCAT_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "tensorflow/core/platform/macros.h"
|
||||
#include "tensorflow/core/platform/numbers.h"
|
||||
#include "tensorflow/core/platform/stringpiece.h"
|
||||
#include "tensorflow/core/platform/types.h"
|
||||
|
||||
// The AlphaNum type was designed to be used as the parameter type for StrCat().
|
||||
// Any routine accepting either a string or a number may accept it.
|
||||
// The basic idea is that by accepting a "const AlphaNum &" as an argument
|
||||
// to your function, your callers will automatically convert bools, integers,
|
||||
// and floating point values to strings for you.
|
||||
//
|
||||
// NOTE: Use of AlphaNum outside of the //strings package is unsupported except
|
||||
// for the specific case of function parameters of type "AlphaNum" or "const
|
||||
// AlphaNum &". In particular, instantiating AlphaNum directly as a stack
|
||||
// variable is not supported.
|
||||
//
|
||||
// Conversion from 8-bit values is not accepted because if it were, then an
|
||||
// attempt to pass ':' instead of ":" might result in a 58 ending up in your
|
||||
// result.
|
||||
//
|
||||
// Bools convert to "0" or "1".
|
||||
//
|
||||
// Floating point values are converted to a string which, if passed to strtod(),
|
||||
// would produce the exact same original double (except in case of NaN; all NaNs
|
||||
// are considered the same value). We try to keep the string short but it's not
|
||||
// guaranteed to be as short as possible.
|
||||
//
|
||||
// You can convert to Hexadecimal output rather than Decimal output using Hex.
|
||||
// To do this, pass strings::Hex(my_int) as a parameter to StrCat. You may
|
||||
// specify a minimum field width using a separate parameter, so the equivalent
|
||||
// of Printf("%04x", my_int) is StrCat(Hex(my_int, strings::kZeroPad4))
|
||||
//
|
||||
// This class has implicit constructors.
|
||||
namespace tensorflow {
|
||||
namespace strings {
|
||||
|
||||
enum PadSpec {
|
||||
kNoPad = 1,
|
||||
kZeroPad2,
|
||||
kZeroPad3,
|
||||
kZeroPad4,
|
||||
kZeroPad5,
|
||||
kZeroPad6,
|
||||
kZeroPad7,
|
||||
kZeroPad8,
|
||||
kZeroPad9,
|
||||
kZeroPad10,
|
||||
kZeroPad11,
|
||||
kZeroPad12,
|
||||
kZeroPad13,
|
||||
kZeroPad14,
|
||||
kZeroPad15,
|
||||
kZeroPad16
|
||||
};
|
||||
|
||||
struct Hex {
|
||||
uint64 value;
|
||||
enum PadSpec spec;
|
||||
template <class Int>
|
||||
explicit Hex(Int v, PadSpec s = kNoPad) : spec(s) {
|
||||
// Prevent sign-extension by casting integers to
|
||||
// their unsigned counterparts.
|
||||
static_assert(
|
||||
sizeof(v) == 1 || sizeof(v) == 2 || sizeof(v) == 4 || sizeof(v) == 8,
|
||||
"Unknown integer type");
|
||||
value = sizeof(v) == 1
|
||||
? static_cast<uint8>(v)
|
||||
: sizeof(v) == 2 ? static_cast<uint16>(v)
|
||||
: sizeof(v) == 4 ? static_cast<uint32>(v)
|
||||
: static_cast<uint64>(v);
|
||||
}
|
||||
};
|
||||
|
||||
class AlphaNum {
|
||||
public:
|
||||
// No bool ctor -- bools convert to an integral type.
|
||||
// A bool ctor would also convert incoming pointers (bletch).
|
||||
|
||||
AlphaNum(int i32) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, FastInt32ToBufferLeft(i32, digits_)) {}
|
||||
AlphaNum(unsigned int u32) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, FastUInt32ToBufferLeft(u32, digits_)) {}
|
||||
AlphaNum(long x) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, FastInt64ToBufferLeft(x, digits_)) {}
|
||||
AlphaNum(unsigned long x) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, FastUInt64ToBufferLeft(x, digits_)) {}
|
||||
AlphaNum(long long int i64) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, FastInt64ToBufferLeft(i64, digits_)) {}
|
||||
AlphaNum(unsigned long long int u64) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, FastUInt64ToBufferLeft(u64, digits_)) {}
|
||||
|
||||
AlphaNum(float f) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, FloatToBuffer(f, digits_)) {}
|
||||
AlphaNum(double f) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, DoubleToBuffer(f, digits_)) {}
|
||||
|
||||
AlphaNum(Hex hex); // NOLINT(runtime/explicit)
|
||||
|
||||
AlphaNum(const char *c_str) : piece_(c_str) {} // NOLINT(runtime/explicit)
|
||||
AlphaNum(const StringPiece &pc) : piece_(pc) {} // NOLINT(runtime/explicit)
|
||||
AlphaNum(const tensorflow::string &str) // NOLINT(runtime/explicit)
|
||||
: piece_(str) {}
|
||||
#ifdef USE_TSTRING
|
||||
// TODO(dero): Temp guard to prevent duplicate declaration during tstring
|
||||
// migration.
|
||||
AlphaNum(const tensorflow::tstring &str) // NOLINT(runtime/explicit)
|
||||
: piece_(str) {}
|
||||
#endif
|
||||
template <typename A>
|
||||
AlphaNum(const std::basic_string<char, std::char_traits<char>, A> &str)
|
||||
: piece_(str) {} // NOLINT(runtime/explicit)
|
||||
|
||||
StringPiece::size_type size() const { return piece_.size(); }
|
||||
const char *data() const { return piece_.data(); }
|
||||
StringPiece Piece() const { return piece_; }
|
||||
|
||||
private:
|
||||
StringPiece piece_;
|
||||
char digits_[kFastToBufferSize];
|
||||
|
||||
// Use ":" not ':'
|
||||
AlphaNum(char c); // NOLINT(runtime/explicit)
|
||||
|
||||
TF_DISALLOW_COPY_AND_ASSIGN(AlphaNum);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// StrCat()
|
||||
// This merges the given strings or numbers, with no delimiter. This
|
||||
// is designed to be the fastest possible way to construct a string out
|
||||
// of a mix of raw C strings, StringPieces, strings, bool values,
|
||||
// and numeric values.
|
||||
//
|
||||
// Don't use this for user-visible strings. The localization process
|
||||
// works poorly on strings built up out of fragments.
|
||||
//
|
||||
// For clarity and performance, don't use StrCat when appending to a
|
||||
// string. In particular, avoid using any of these (anti-)patterns:
|
||||
// str.append(StrCat(...))
|
||||
// str += StrCat(...)
|
||||
// str = StrCat(str, ...)
|
||||
// where the last is the worse, with the potential to change a loop
|
||||
// from a linear time operation with O(1) dynamic allocations into a
|
||||
// quadratic time operation with O(n) dynamic allocations. StrAppend
|
||||
// is a better choice than any of the above, subject to the restriction
|
||||
// of StrAppend(&str, a, b, c, ...) that none of the a, b, c, ... may
|
||||
// be a reference into str.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
// For performance reasons, we have specializations for <= 4 args.
|
||||
string StrCat(const AlphaNum &a) TF_MUST_USE_RESULT;
|
||||
string StrCat(const AlphaNum &a, const AlphaNum &b) TF_MUST_USE_RESULT;
|
||||
string StrCat(const AlphaNum &a, const AlphaNum &b,
|
||||
const AlphaNum &c) TF_MUST_USE_RESULT;
|
||||
string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
|
||||
const AlphaNum &d) TF_MUST_USE_RESULT;
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Do not call directly - this is not part of the public API.
|
||||
string CatPieces(std::initializer_list<StringPiece> pieces);
|
||||
void AppendPieces(string *dest, std::initializer_list<StringPiece> pieces);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Support 5 or more arguments
|
||||
template <typename... AV>
|
||||
string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
|
||||
const AlphaNum &d, const AlphaNum &e,
|
||||
const AV &... args) TF_MUST_USE_RESULT;
|
||||
|
||||
template <typename... AV>
|
||||
string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
|
||||
const AlphaNum &d, const AlphaNum &e, const AV &... args) {
|
||||
return internal::CatPieces({a.Piece(), b.Piece(), c.Piece(), d.Piece(),
|
||||
e.Piece(),
|
||||
static_cast<const AlphaNum &>(args).Piece()...});
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// StrAppend()
|
||||
// Same as above, but adds the output to the given string.
|
||||
// WARNING: For speed, StrAppend does not try to check each of its input
|
||||
// arguments to be sure that they are not a subset of the string being
|
||||
// appended to. That is, while this will work:
|
||||
//
|
||||
// string s = "foo";
|
||||
// s += s;
|
||||
//
|
||||
// This will not (necessarily) work:
|
||||
//
|
||||
// string s = "foo";
|
||||
// StrAppend(&s, s);
|
||||
//
|
||||
// Note: while StrCat supports appending up to 26 arguments, StrAppend
|
||||
// is currently limited to 9. That's rarely an issue except when
|
||||
// automatically transforming StrCat to StrAppend, and can easily be
|
||||
// worked around as consecutive calls to StrAppend are quite efficient.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void StrAppend(string *dest, const AlphaNum &a);
|
||||
void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b);
|
||||
void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b,
|
||||
const AlphaNum &c);
|
||||
void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b,
|
||||
const AlphaNum &c, const AlphaNum &d);
|
||||
|
||||
// Support 5 or more arguments
|
||||
template <typename... AV>
|
||||
inline void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b,
|
||||
const AlphaNum &c, const AlphaNum &d, const AlphaNum &e,
|
||||
const AV &... args) {
|
||||
internal::AppendPieces(dest,
|
||||
{a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
|
||||
static_cast<const AlphaNum &>(args).Piece()...});
|
||||
}
|
||||
|
||||
} // namespace strings
|
||||
} // namespace tensorflow
|
||||
|
||||
#endif // TENSORFLOW_CORE_PLATFORM_STRCAT_H_
|
@ -13,11 +13,11 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
#include "tensorflow/core/lib/strings/strcat.h"
|
||||
#include "tensorflow/core/platform/strcat.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "tensorflow/core/lib/strings/stringprintf.h"
|
||||
#include "tensorflow/core/platform/stringprintf.h"
|
||||
#include "tensorflow/core/platform/test.h"
|
||||
#include "tensorflow/core/platform/types.h"
|
||||
|
||||
@ -357,10 +357,10 @@ static void TestFastPrints() {
|
||||
CheckHex32(0x12345678);
|
||||
|
||||
int8 minus_one_8bit = -1;
|
||||
EXPECT_EQ("ff", StrCat(Hex(minus_one_8bit)));
|
||||
EXPECT_EQ("ff", tensorflow::strings::StrCat(Hex(minus_one_8bit)));
|
||||
|
||||
int16 minus_one_16bit = -1;
|
||||
EXPECT_EQ("ffff", StrCat(Hex(minus_one_16bit)));
|
||||
EXPECT_EQ("ffff", tensorflow::strings::StrCat(Hex(minus_one_16bit)));
|
||||
}
|
||||
|
||||
TEST(Numbers, TestFunctionsMovedOverFromNumbersMain) { TestFastPrints(); }
|
Loading…
Reference in New Issue
Block a user