Commit a4798817 by Abseil Team Committed by Mark Barolak

Export of internal Abseil changes

--
197bd3e5e315f408bdc2f7111a0652be7f47609f by Jorg Brown <jorg@google.com>:

ConvertibleToStringView wastes a lot of cycles initializing a std::string
member that it never uses.  This CL restricts ConvertibleToStringView to just
the cases that don't nned a std::string member, and uses an additional StrSplit
overload to catch when users pass a temporary string.

This makes StrSplit() 0-30% faster depending on the use case.

PiperOrigin-RevId: 341378221
GitOrigin-RevId: 197bd3e5e315f408bdc2f7111a0652be7f47609f
Change-Id: Id863f2a3d298ed5a086ac912afab42dc30601be5
parent e96d4968
...@@ -51,9 +51,9 @@ ABSL_NAMESPACE_BEGIN ...@@ -51,9 +51,9 @@ ABSL_NAMESPACE_BEGIN
namespace strings_internal { namespace strings_internal {
// This class is implicitly constructible from everything that absl::string_view // This class is implicitly constructible from everything that absl::string_view
// is implicitly constructible from. If it's constructed from a temporary // is implicitly constructible from, except for rvalue strings. This means it
// string, the data is moved into a data member so its lifetime matches that of // can be used as a function parameter in places where passing a temporary
// the ConvertibleToStringView instance. // string might cause memory lifetime issues.
class ConvertibleToStringView { class ConvertibleToStringView {
public: public:
ConvertibleToStringView(const char* s) // NOLINT(runtime/explicit) ConvertibleToStringView(const char* s) // NOLINT(runtime/explicit)
...@@ -65,41 +65,12 @@ class ConvertibleToStringView { ...@@ -65,41 +65,12 @@ class ConvertibleToStringView {
: value_(s) {} : value_(s) {}
// Matches rvalue strings and moves their data to a member. // Matches rvalue strings and moves their data to a member.
ConvertibleToStringView(std::string&& s) // NOLINT(runtime/explicit) ConvertibleToStringView(std::string&& s) = delete;
: copy_(std::move(s)), value_(copy_) {} ConvertibleToStringView(const std::string&& s) = delete;
ConvertibleToStringView(const ConvertibleToStringView& other)
: copy_(other.copy_),
value_(other.IsSelfReferential() ? copy_ : other.value_) {}
ConvertibleToStringView(ConvertibleToStringView&& other) {
StealMembers(std::move(other));
}
ConvertibleToStringView& operator=(ConvertibleToStringView other) {
StealMembers(std::move(other));
return *this;
}
absl::string_view value() const { return value_; } absl::string_view value() const { return value_; }
private: private:
// Returns true if ctsp's value refers to its internal copy_ member.
bool IsSelfReferential() const { return value_.data() == copy_.data(); }
void StealMembers(ConvertibleToStringView&& other) {
if (other.IsSelfReferential()) {
copy_ = std::move(other.copy_);
value_ = copy_;
other.value_ = other.copy_;
} else {
value_ = other.value_;
}
}
// Holds the data moved from temporary std::string arguments. Declared first
// so that 'value' can refer to 'copy_'.
std::string copy_;
absl::string_view value_; absl::string_view value_;
}; };
...@@ -273,7 +244,11 @@ struct SplitterIsConvertibleTo ...@@ -273,7 +244,11 @@ struct SplitterIsConvertibleTo
// the split strings: only strings for which the predicate returns true will be // the split strings: only strings for which the predicate returns true will be
// kept. A Predicate object is any unary functor that takes an absl::string_view // kept. A Predicate object is any unary functor that takes an absl::string_view
// and returns bool. // and returns bool.
template <typename Delimiter, typename Predicate> //
// The StringType parameter can be either string_view or string, depending on
// whether the Splitter refers to a string stored elsewhere, or if the string
// resides inside the Splitter itself.
template <typename Delimiter, typename Predicate, typename StringType>
class Splitter { class Splitter {
public: public:
using DelimiterType = Delimiter; using DelimiterType = Delimiter;
...@@ -281,12 +256,12 @@ class Splitter { ...@@ -281,12 +256,12 @@ class Splitter {
using const_iterator = strings_internal::SplitIterator<Splitter>; using const_iterator = strings_internal::SplitIterator<Splitter>;
using value_type = typename std::iterator_traits<const_iterator>::value_type; using value_type = typename std::iterator_traits<const_iterator>::value_type;
Splitter(ConvertibleToStringView input_text, Delimiter d, Predicate p) Splitter(StringType input_text, Delimiter d, Predicate p)
: text_(std::move(input_text)), : text_(std::move(input_text)),
delimiter_(std::move(d)), delimiter_(std::move(d)),
predicate_(std::move(p)) {} predicate_(std::move(p)) {}
absl::string_view text() const { return text_.value(); } absl::string_view text() const { return text_; }
const Delimiter& delimiter() const { return delimiter_; } const Delimiter& delimiter() const { return delimiter_; }
const Predicate& predicate() const { return predicate_; } const Predicate& predicate() const { return predicate_; }
...@@ -443,7 +418,7 @@ class Splitter { ...@@ -443,7 +418,7 @@ class Splitter {
}; };
}; };
ConvertibleToStringView text_; StringType text_;
Delimiter delimiter_; Delimiter delimiter_;
Predicate predicate_; Predicate predicate_;
}; };
......
...@@ -369,6 +369,12 @@ struct SkipWhitespace { ...@@ -369,6 +369,12 @@ struct SkipWhitespace {
} }
}; };
template <typename T>
using EnableSplitIfString =
typename std::enable_if<std::is_same<T, std::string>::value ||
std::is_same<T, const std::string>::value,
int>::type;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// StrSplit() // StrSplit()
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
...@@ -489,22 +495,50 @@ struct SkipWhitespace { ...@@ -489,22 +495,50 @@ struct SkipWhitespace {
// Try not to depend on this distinction because the bug may one day be fixed. // Try not to depend on this distinction because the bug may one day be fixed.
template <typename Delimiter> template <typename Delimiter>
strings_internal::Splitter< strings_internal::Splitter<
typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty> typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty,
absl::string_view>
StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d) { StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d) {
using DelimiterType = using DelimiterType =
typename strings_internal::SelectDelimiter<Delimiter>::type; typename strings_internal::SelectDelimiter<Delimiter>::type;
return strings_internal::Splitter<DelimiterType, AllowEmpty>( return strings_internal::Splitter<DelimiterType, AllowEmpty,
absl::string_view>(
text.value(), DelimiterType(d), AllowEmpty());
}
template <typename Delimiter, typename StringType,
EnableSplitIfString<StringType> = 0>
strings_internal::Splitter<
typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty,
std::string>
StrSplit(StringType&& text, Delimiter d) {
using DelimiterType =
typename strings_internal::SelectDelimiter<Delimiter>::type;
return strings_internal::Splitter<DelimiterType, AllowEmpty, std::string>(
std::move(text), DelimiterType(d), AllowEmpty()); std::move(text), DelimiterType(d), AllowEmpty());
} }
template <typename Delimiter, typename Predicate> template <typename Delimiter, typename Predicate>
strings_internal::Splitter< strings_internal::Splitter<
typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate> typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate,
absl::string_view>
StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d, StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d,
Predicate p) { Predicate p) {
using DelimiterType = using DelimiterType =
typename strings_internal::SelectDelimiter<Delimiter>::type; typename strings_internal::SelectDelimiter<Delimiter>::type;
return strings_internal::Splitter<DelimiterType, Predicate>( return strings_internal::Splitter<DelimiterType, Predicate,
absl::string_view>(
text.value(), DelimiterType(d), std::move(p));
}
template <typename Delimiter, typename Predicate, typename StringType,
EnableSplitIfString<StringType> = 0>
strings_internal::Splitter<
typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate,
std::string>
StrSplit(StringType&& text, Delimiter d, Predicate p) {
using DelimiterType =
typename strings_internal::SelectDelimiter<Delimiter>::type;
return strings_internal::Splitter<DelimiterType, Predicate, std::string>(
std::move(text), DelimiterType(d), std::move(p)); std::move(text), DelimiterType(d), std::move(p));
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment