diff options
author | Abseil Team <absl-team@google.com> | 2023-06-02 13:49:30 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-06-02 13:50:21 -0700 |
commit | 77ba7ca9d2a523ef9f1837e53554fa65c232abc8 (patch) | |
tree | d2a48c86e20b4ed5117576acc8d5581656c7a5a6 /absl/strings/internal | |
parent | 55de7357c7f0e1af6bb7d61b924a9a9315cc1e81 (diff) |
Lifetime checks for `absl::StrSplit()`
PiperOrigin-RevId: 537400816
Change-Id: I06794a6b8b6a441e34121047024380190d42869a
Diffstat (limited to 'absl/strings/internal')
-rw-r--r-- | absl/strings/internal/str_split_internal.h | 62 |
1 files changed, 56 insertions, 6 deletions
diff --git a/absl/strings/internal/str_split_internal.h b/absl/strings/internal/str_split_internal.h index 35edf3aa..081ad85a 100644 --- a/absl/strings/internal/str_split_internal.h +++ b/absl/strings/internal/str_split_internal.h @@ -235,6 +235,24 @@ struct SplitterIsConvertibleTo HasMappedType<C>::value> { }; +template <typename StringType, typename Container, typename = void> +struct ShouldUseLifetimeBound : std::false_type {}; + +template <typename StringType, typename Container> +struct ShouldUseLifetimeBound< + StringType, Container, + std::enable_if_t< + std::is_same<StringType, std::string>::value && + std::is_same<typename Container::value_type, absl::string_view>::value>> + : std::true_type {}; + +template <typename StringType, typename First, typename Second> +using ShouldUseLifetimeBoundForPair = std::integral_constant< + bool, std::is_same<StringType, std::string>::value && + (std::is_same<First, absl::string_view>::value || + std::is_same<Second, absl::string_view>::value)>; + + // This class implements the range that is returned by absl::StrSplit(). This // class has templated conversion operators that allow it to be implicitly // converted to a variety of types that the caller may have specified on the @@ -281,10 +299,24 @@ class Splitter { // An implicit conversion operator that is restricted to only those containers // that the splitter is convertible to. - template <typename Container, - typename = typename std::enable_if< - SplitterIsConvertibleTo<Container>::value>::type> - operator Container() const { // NOLINT(runtime/explicit) + template < + typename Container, + std::enable_if_t<ShouldUseLifetimeBound<StringType, Container>::value && + SplitterIsConvertibleTo<Container>::value, + std::nullptr_t> = nullptr> + // NOLINTNEXTLINE(google-explicit-constructor) + operator Container() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + return ConvertToContainer<Container, typename Container::value_type, + HasMappedType<Container>::value>()(*this); + } + + template < + typename Container, + std::enable_if_t<!ShouldUseLifetimeBound<StringType, Container>::value && + SplitterIsConvertibleTo<Container>::value, + std::nullptr_t> = nullptr> + // NOLINTNEXTLINE(google-explicit-constructor) + operator Container() const { return ConvertToContainer<Container, typename Container::value_type, HasMappedType<Container>::value>()(*this); } @@ -293,8 +325,27 @@ class Splitter { // strings returned by the begin() iterator. Either/both of .first and .second // will be constructed with empty strings if the iterator doesn't have a // corresponding value. + template <typename First, typename Second, + std::enable_if_t< + ShouldUseLifetimeBoundForPair<StringType, First, Second>::value, + std::nullptr_t> = nullptr> + // NOLINTNEXTLINE(google-explicit-constructor) + operator std::pair<First, Second>() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + return ConvertToPair<First, Second>(); + } + + template <typename First, typename Second, + std::enable_if_t<!ShouldUseLifetimeBoundForPair<StringType, First, + Second>::value, + std::nullptr_t> = nullptr> + // NOLINTNEXTLINE(google-explicit-constructor) + operator std::pair<First, Second>() const { + return ConvertToPair<First, Second>(); + } + + private: template <typename First, typename Second> - operator std::pair<First, Second>() const { // NOLINT(runtime/explicit) + std::pair<First, Second> ConvertToPair() const { absl::string_view first, second; auto it = begin(); if (it != end()) { @@ -306,7 +357,6 @@ class Splitter { return {First(first), Second(second)}; } - private: // ConvertToContainer is a functor converting a Splitter to the requested // Container of ValueType. It is specialized below to optimize splitting to // certain combinations of Container and ValueType. |