Changes imported from Abseil "staging" branch:
- 6e88015f26885b66ce9b11696eb9c8d96ef7c0f6 Add ABSL_MUST_USE_RESULT to absl::StripPrefix and absl::S... by Mark Barolak <mbar@google.com> - 47d8de97748da346ad2a962f27389e0380a7a716 Fix missing header include when compiling with _GLIBCXX_D... by Alex Strelnikov <strel@google.com> GitOrigin-RevId: 6e88015f26885b66ce9b11696eb9c8d96ef7c0f6 Change-Id: I8698c77d9eab81455b209a6bef4bb2d5b32ebd65
This commit is contained in:
parent
6365d1744b
commit
0271cd3557
6 changed files with 241 additions and 18 deletions
|
@ -39,6 +39,7 @@ cc_library(
|
|||
"escaping.cc",
|
||||
"internal/memutil.cc",
|
||||
"internal/memutil.h",
|
||||
"internal/stl_type_traits.h",
|
||||
"internal/str_join_internal.h",
|
||||
"internal/str_split_internal.h",
|
||||
"match.cc",
|
||||
|
|
|
@ -35,6 +35,7 @@ list(APPEND STRINGS_INTERNAL_HEADERS
|
|||
"internal/memutil.h"
|
||||
"internal/ostringstream.h"
|
||||
"internal/resize_uninitialized.h"
|
||||
"internal/stl_type_traits.h"
|
||||
"internal/str_join_internal.h"
|
||||
"internal/str_split_internal.h"
|
||||
"internal/utf8.h"
|
||||
|
|
213
absl/strings/internal/stl_type_traits.h
Normal file
213
absl/strings/internal/stl_type_traits.h
Normal file
|
@ -0,0 +1,213 @@
|
|||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
// Thie file provides the IsStrictlyBaseOfAndConvertibleToSTLContainer type
|
||||
// trait metafunction to assist in working with the _GLIBCXX_DEBUG debug
|
||||
// wrappers of STL containers.
|
||||
//
|
||||
// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including
|
||||
// absl/strings/str_split.h.
|
||||
//
|
||||
// IWYU pragma: private, include "absl/strings/str_split.h"
|
||||
|
||||
#ifndef ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_
|
||||
#define ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_
|
||||
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <deque>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/meta/type_traits.h"
|
||||
|
||||
namespace absl {
|
||||
namespace strings_internal {
|
||||
|
||||
template <typename C, template <typename...> class T>
|
||||
struct IsSpecializationImpl : std::false_type {};
|
||||
template <template <typename...> class T, typename... Args>
|
||||
struct IsSpecializationImpl<T<Args...>, T> : std::true_type {};
|
||||
template <typename C, template <typename...> class T>
|
||||
using IsSpecialization = IsSpecializationImpl<absl::decay_t<C>, T>;
|
||||
|
||||
template <typename C>
|
||||
struct IsArrayImpl : std::false_type {};
|
||||
template <template <typename, size_t> class A, typename T, size_t N>
|
||||
struct IsArrayImpl<A<T, N>> : std::is_same<A<T, N>, std::array<T, N>> {};
|
||||
template <typename C>
|
||||
using IsArray = IsArrayImpl<absl::decay_t<C>>;
|
||||
|
||||
template <typename C>
|
||||
struct IsBitsetImpl : std::false_type {};
|
||||
template <template <size_t> class B, size_t N>
|
||||
struct IsBitsetImpl<B<N>> : std::is_same<B<N>, std::bitset<N>> {};
|
||||
template <typename C>
|
||||
using IsBitset = IsBitsetImpl<absl::decay_t<C>>;
|
||||
|
||||
template <typename C>
|
||||
struct IsSTLContainer
|
||||
: absl::disjunction<
|
||||
IsArray<C>, IsBitset<C>, IsSpecialization<C, std::deque>,
|
||||
IsSpecialization<C, std::forward_list>,
|
||||
IsSpecialization<C, std::list>, IsSpecialization<C, std::map>,
|
||||
IsSpecialization<C, std::multimap>, IsSpecialization<C, std::set>,
|
||||
IsSpecialization<C, std::multiset>,
|
||||
IsSpecialization<C, std::unordered_map>,
|
||||
IsSpecialization<C, std::unordered_multimap>,
|
||||
IsSpecialization<C, std::unordered_set>,
|
||||
IsSpecialization<C, std::unordered_multiset>,
|
||||
IsSpecialization<C, std::vector>> {};
|
||||
|
||||
template <typename C, template <typename...> class T, typename = void>
|
||||
struct IsBaseOfSpecializationImpl : std::false_type {};
|
||||
// IsBaseOfSpecializationImpl must have three partial specializations,
|
||||
// because we must only compare templates that take the same number of
|
||||
// arguments. Otherwise, for example, std::vector can be compared with std::map,
|
||||
// and fail to compile because of too few or too many template arguments.
|
||||
//
|
||||
// We must also SFINAE on the existence of an allocator_type. Otherwise, we may
|
||||
// try to compare, for example, a std::pair<std::string, std::string> with a
|
||||
// std::vector<std::string, std:std::string>. This would fail to compile, because
|
||||
// of expected properties of the type passed in as the allocator.
|
||||
template <template <typename, typename> class U,
|
||||
template <typename, typename> class T, typename... Args>
|
||||
struct IsBaseOfSpecializationImpl<
|
||||
U<Args...>, T, absl::void_t<typename U<Args...>::allocator_type>>
|
||||
: std::is_base_of<U<Args...>, T<Args...>> {};
|
||||
template <template <typename, typename, typename> class U,
|
||||
template <typename, typename, typename> class T, typename... Args>
|
||||
struct IsBaseOfSpecializationImpl<
|
||||
U<Args...>, T, absl::void_t<typename U<Args...>::allocator_type>>
|
||||
: std::is_base_of<U<Args...>, T<Args...>> {};
|
||||
template <template <typename, typename, typename, typename> class U,
|
||||
template <typename, typename, typename, typename> class T,
|
||||
typename... Args>
|
||||
struct IsBaseOfSpecializationImpl<
|
||||
U<Args...>, T, absl::void_t<typename U<Args...>::allocator_type>>
|
||||
: std::is_base_of<U<Args...>, T<Args...>> {};
|
||||
template <typename C, template <typename...> class T>
|
||||
using IsBaseOfSpecialization = IsBaseOfSpecializationImpl<absl::decay_t<C>, T>;
|
||||
|
||||
template <typename C>
|
||||
struct IsBaseOfArrayImpl : std::false_type {};
|
||||
template <template <typename, size_t> class A, typename T, size_t N>
|
||||
struct IsBaseOfArrayImpl<A<T, N>> : std::is_base_of<A<T, N>, std::array<T, N>> {
|
||||
};
|
||||
template <typename C>
|
||||
using IsBaseOfArray = IsBaseOfArrayImpl<absl::decay_t<C>>;
|
||||
|
||||
template <typename C>
|
||||
struct IsBaseOfBitsetImpl : std::false_type {};
|
||||
template <template <size_t> class B, size_t N>
|
||||
struct IsBaseOfBitsetImpl<B<N>> : std::is_base_of<B<N>, std::bitset<N>> {};
|
||||
template <typename C>
|
||||
using IsBaseOfBitset = IsBaseOfBitsetImpl<absl::decay_t<C>>;
|
||||
|
||||
template <typename C>
|
||||
struct IsBaseOfSTLContainer
|
||||
: absl::disjunction<IsBaseOfArray<C>, IsBaseOfBitset<C>,
|
||||
IsBaseOfSpecialization<C, std::deque>,
|
||||
IsBaseOfSpecialization<C, std::forward_list>,
|
||||
IsBaseOfSpecialization<C, std::list>,
|
||||
IsBaseOfSpecialization<C, std::map>,
|
||||
IsBaseOfSpecialization<C, std::multimap>,
|
||||
IsBaseOfSpecialization<C, std::set>,
|
||||
IsBaseOfSpecialization<C, std::multiset>,
|
||||
IsBaseOfSpecialization<C, std::unordered_map>,
|
||||
IsBaseOfSpecialization<C, std::unordered_multimap>,
|
||||
IsBaseOfSpecialization<C, std::unordered_set>,
|
||||
IsBaseOfSpecialization<C, std::unordered_multiset>,
|
||||
IsBaseOfSpecialization<C, std::vector>> {};
|
||||
|
||||
template <typename C, template <typename...> class T, typename = void>
|
||||
struct IsConvertibleToSpecializationImpl : std::false_type {};
|
||||
// IsConvertibleToSpecializationImpl must have three partial specializations,
|
||||
// because we must only compare templates that take the same number of
|
||||
// arguments. Otherwise, for example, std::vector can be compared with std::map,
|
||||
// and fail to compile because of too few or too many template arguments.
|
||||
//
|
||||
// We must also SFINAE on the existence of an allocator_type. Otherwise, we may
|
||||
// try to compare, for example, a std::pair<std::string, std::string> with a
|
||||
// std::vector<std::string, std:std::string>. This would fail to compile, because
|
||||
// of expected properties of the type passed in as the allocator.
|
||||
template <template <typename, typename> class U,
|
||||
template <typename, typename> class T, typename... Args>
|
||||
struct IsConvertibleToSpecializationImpl<
|
||||
U<Args...>, T, absl::void_t<typename U<Args...>::allocator_type>>
|
||||
: std::is_convertible<U<Args...>, T<Args...>> {};
|
||||
template <template <typename, typename, typename> class U,
|
||||
template <typename, typename, typename> class T, typename... Args>
|
||||
struct IsConvertibleToSpecializationImpl<
|
||||
U<Args...>, T, absl::void_t<typename U<Args...>::allocator_type>>
|
||||
: std::is_convertible<U<Args...>, T<Args...>> {};
|
||||
template <template <typename, typename, typename, typename> class U,
|
||||
template <typename, typename, typename, typename> class T,
|
||||
typename... Args>
|
||||
struct IsConvertibleToSpecializationImpl<
|
||||
U<Args...>, T, absl::void_t<typename U<Args...>::allocator_type>>
|
||||
: std::is_convertible<U<Args...>, T<Args...>> {};
|
||||
template <typename C, template <typename...> class T>
|
||||
using IsConvertibleToSpecialization =
|
||||
IsConvertibleToSpecializationImpl<absl::decay_t<C>, T>;
|
||||
|
||||
template <typename C>
|
||||
struct IsConvertibleToArrayImpl : std::false_type {};
|
||||
template <template <typename, size_t> class A, typename T, size_t N>
|
||||
struct IsConvertibleToArrayImpl<A<T, N>>
|
||||
: std::is_convertible<A<T, N>, std::array<T, N>> {};
|
||||
template <typename C>
|
||||
using IsConvertibleToArray = IsConvertibleToArrayImpl<absl::decay_t<C>>;
|
||||
|
||||
template <typename C>
|
||||
struct IsConvertibleToBitsetImpl : std::false_type {};
|
||||
template <template <size_t> class B, size_t N>
|
||||
struct IsConvertibleToBitsetImpl<B<N>>
|
||||
: std::is_convertible<B<N>, std::bitset<N>> {};
|
||||
template <typename C>
|
||||
using IsConvertibleToBitset = IsConvertibleToBitsetImpl<absl::decay_t<C>>;
|
||||
|
||||
template <typename C>
|
||||
struct IsConvertibleToSTLContainer
|
||||
: absl::disjunction<
|
||||
IsConvertibleToArray<C>, IsConvertibleToBitset<C>,
|
||||
IsConvertibleToSpecialization<C, std::deque>,
|
||||
IsConvertibleToSpecialization<C, std::forward_list>,
|
||||
IsConvertibleToSpecialization<C, std::list>,
|
||||
IsConvertibleToSpecialization<C, std::map>,
|
||||
IsConvertibleToSpecialization<C, std::multimap>,
|
||||
IsConvertibleToSpecialization<C, std::set>,
|
||||
IsConvertibleToSpecialization<C, std::multiset>,
|
||||
IsConvertibleToSpecialization<C, std::unordered_map>,
|
||||
IsConvertibleToSpecialization<C, std::unordered_multimap>,
|
||||
IsConvertibleToSpecialization<C, std::unordered_set>,
|
||||
IsConvertibleToSpecialization<C, std::unordered_multiset>,
|
||||
IsConvertibleToSpecialization<C, std::vector>> {};
|
||||
|
||||
template <typename C>
|
||||
struct IsStrictlyBaseOfAndConvertibleToSTLContainer
|
||||
: absl::conjunction<absl::negation<IsSTLContainer<C>>,
|
||||
IsBaseOfSTLContainer<C>,
|
||||
IsConvertibleToSTLContainer<C>> {};
|
||||
|
||||
} // namespace strings_internal
|
||||
} // namespace absl
|
||||
#endif // ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_
|
|
@ -29,10 +29,6 @@
|
|||
#ifndef ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_
|
||||
#define ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_
|
||||
|
||||
#ifdef _GLIBCXX_DEBUG
|
||||
#include <glibcxx_debug_traits.h>
|
||||
#endif // _GLIBCXX_DEBUG
|
||||
|
||||
#include <array>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
|
@ -46,15 +42,13 @@
|
|||
#include "absl/meta/type_traits.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
#ifdef _GLIBCXX_DEBUG
|
||||
#include "absl/strings/internal/stl_type_traits.h"
|
||||
#endif // _GLIBCXX_DEBUG
|
||||
|
||||
namespace absl {
|
||||
namespace strings_internal {
|
||||
|
||||
#ifdef _GLIBCXX_DEBUG
|
||||
using ::glibcxx_debug_traits::IsStrictlyDebugWrapperBase;
|
||||
#else // _GLIBCXX_DEBUG
|
||||
template <typename T> struct IsStrictlyDebugWrapperBase : std::false_type {};
|
||||
#endif // _GLIBCXX_DEBUG
|
||||
|
||||
// This class is implicitly constructible from everything that absl::string_view
|
||||
// is implicitly constructible from. If it's constructed from a temporary
|
||||
// std::string, the data is moved into a data member so its lifetime matches that of
|
||||
|
@ -237,10 +231,12 @@ struct IsInitializerList
|
|||
template <typename C>
|
||||
struct SplitterIsConvertibleTo
|
||||
: std::enable_if<
|
||||
!IsStrictlyDebugWrapperBase<C>::value &&
|
||||
!IsInitializerList<C>::value &&
|
||||
HasValueType<C>::value &&
|
||||
HasConstIterator<C>::value> {};
|
||||
#ifdef _GLIBCXX_DEBUG
|
||||
!IsStrictlyBaseOfAndConvertibleToSTLContainer<C>::value &&
|
||||
#endif // _GLIBCXX_DEBUG
|
||||
!IsInitializerList<C>::value && HasValueType<C>::value &&
|
||||
HasConstIterator<C>::value> {
|
||||
};
|
||||
|
||||
// This class implements the range that is returned by absl::StrSplit(). This
|
||||
// class has templated conversion operators that allow it to be implicitly
|
||||
|
|
|
@ -165,6 +165,18 @@ TEST(Split, APIExamples) {
|
|||
EXPECT_THAT(v, ElementsAre("abc", "def", "g"));
|
||||
}
|
||||
|
||||
{
|
||||
// Different forms of initialization / conversion.
|
||||
std::vector<std::string> v1 = absl::StrSplit("a,b,c", ',');
|
||||
EXPECT_THAT(v1, ElementsAre("a", "b", "c"));
|
||||
std::vector<std::string> v2(absl::StrSplit("a,b,c", ','));
|
||||
EXPECT_THAT(v2, ElementsAre("a", "b", "c"));
|
||||
auto v3 = std::vector<std::string>(absl::StrSplit("a,b,c", ','));
|
||||
EXPECT_THAT(v3, ElementsAre("a", "b", "c"));
|
||||
v3 = absl::StrSplit("a,b,c", ',');
|
||||
EXPECT_THAT(v3, ElementsAre("a", "b", "c"));
|
||||
}
|
||||
|
||||
{
|
||||
// Results stored in a std::map.
|
||||
std::map<std::string, std::string> m = absl::StrSplit("a,1,b,2,a,3", ',');
|
||||
|
|
|
@ -67,8 +67,8 @@ inline bool ConsumeSuffix(absl::string_view* str, absl::string_view expected) {
|
|||
// Returns a view into the input std::string 'str' with the given 'prefix' removed,
|
||||
// but leaving the original std::string intact. If the prefix does not match at the
|
||||
// start of the std::string, returns the original std::string instead.
|
||||
inline absl::string_view StripPrefix(absl::string_view str,
|
||||
absl::string_view prefix) {
|
||||
ABSL_MUST_USE_RESULT inline absl::string_view StripPrefix(
|
||||
absl::string_view str, absl::string_view prefix) {
|
||||
if (absl::StartsWith(str, prefix)) str.remove_prefix(prefix.size());
|
||||
return str;
|
||||
}
|
||||
|
@ -78,8 +78,8 @@ inline absl::string_view StripPrefix(absl::string_view str,
|
|||
// Returns a view into the input std::string 'str' with the given 'suffix' removed,
|
||||
// but leaving the original std::string intact. If the suffix does not match at the
|
||||
// end of the std::string, returns the original std::string instead.
|
||||
inline absl::string_view StripSuffix(absl::string_view str,
|
||||
absl::string_view suffix) {
|
||||
ABSL_MUST_USE_RESULT inline absl::string_view StripSuffix(
|
||||
absl::string_view str, absl::string_view suffix) {
|
||||
if (absl::EndsWith(str, suffix)) str.remove_suffix(suffix.size());
|
||||
return str;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue