Remove the implementation of `absl::string_view`, which was only needed prior to C++17. `absl::string_view` is now an alias for `std::string_view`. It is recommended that clients simply use `std::string_view`. PiperOrigin-RevId: 845822478 Change-Id: I220530c84118e5b9ef110baa002c232ac8f2c5f2
diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index 9145d8b..cc9f792 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake
@@ -345,8 +345,6 @@ "strings/str_replace.h" "strings/str_split.cc" "strings/str_split.h" - "strings/string_view.cc" - "strings/string_view.h" "strings/strip.h" "strings/substitute.cc" "strings/substitute.h" @@ -446,6 +444,7 @@ "types/variant.h" "utility/utility.h" "debugging/leak_check.cc" + "strings/string_view.h" ) if(MSVC)
diff --git a/absl/base/config.h b/absl/base/config.h index e4518ca..39d60e3 100644 --- a/absl/base/config.h +++ b/absl/base/config.h
@@ -526,20 +526,11 @@ #define ABSL_USES_STD_ANY 1 #define ABSL_HAVE_STD_OPTIONAL 1 #define ABSL_USES_STD_OPTIONAL 1 +#define ABSL_HAVE_STD_STRING_VIEW 1 +#define ABSL_USES_STD_STRING_VIEW 1 #define ABSL_HAVE_STD_VARIANT 1 #define ABSL_USES_STD_VARIANT 1 -// ABSL_HAVE_STD_STRING_VIEW -// -// Deprecated: always defined to 1. -// std::string_view was added in C++17, which means all versions of C++ -// supported by Abseil have it. -#ifdef ABSL_HAVE_STD_STRING_VIEW -#error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set." -#else -#define ABSL_HAVE_STD_STRING_VIEW 1 -#endif - // ABSL_HAVE_STD_ORDERING // // Checks whether C++20 std::{partial,weak,strong}_ordering are available. @@ -556,20 +547,6 @@ #define ABSL_HAVE_STD_ORDERING 1 #endif -// ABSL_USES_STD_STRING_VIEW -// -// Indicates whether absl::string_view is an alias for std::string_view. -#if !defined(ABSL_OPTION_USE_STD_STRING_VIEW) -#error options.h is misconfigured. -#elif ABSL_OPTION_USE_STD_STRING_VIEW == 0 -#undef ABSL_USES_STD_STRING_VIEW -#elif ABSL_OPTION_USE_STD_STRING_VIEW == 1 || \ - ABSL_OPTION_USE_STD_STRING_VIEW == 2 -#define ABSL_USES_STD_STRING_VIEW 1 -#else -#error options.h is misconfigured. -#endif - // ABSL_USES_STD_ORDERING // // Indicates whether absl::{partial,weak,strong}_ordering are aliases for the
diff --git a/absl/base/options.h b/absl/base/options.h index 71bafb3..6f48e75 100644 --- a/absl/base/options.h +++ b/absl/base/options.h
@@ -73,32 +73,6 @@ // Type Compatibility Options // ----------------------------------------------------------------------------- -// ABSL_OPTION_USE_STD_STRING_VIEW -// -// This option controls whether absl::string_view is implemented as an alias to -// std::string_view, or as an independent implementation. -// -// A value of 0 means to use Abseil's implementation. This requires only C++11 -// support, and is expected to work on every toolchain we support. -// -// A value of 1 means to use an alias to std::string_view. This requires that -// all code using Abseil is built in C++17 mode or later. -// -// A value of 2 means to detect the C++ version being used to compile Abseil, -// and use an alias only if a working std::string_view is available. This -// option is useful when you are building your program from source. It should -// not be used otherwise -- for example, if you are distributing Abseil in a -// binary package manager -- since in mode 2, absl::string_view will name a -// different type, with a different mangled name and binary layout, depending on -// the compiler flags passed by the end user. For more info, see -// https://abseil.io/about/design/dropin-types. -// -// User code should not inspect this macro. To check in the preprocessor if -// absl::string_view is a typedef of std::string_view, use the feature macro -// ABSL_USES_STD_STRING_VIEW. - -#define ABSL_OPTION_USE_STD_STRING_VIEW 2 - // ABSL_OPTION_USE_STD_ORDERING // // This option controls whether absl::{partial,weak,strong}_ordering are
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 9dde5e5..49051bd 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel
@@ -36,16 +36,13 @@ cc_library( name = "string_view", - srcs = ["string_view.cc"], hdrs = ["string_view.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ - "//absl/base", "//absl/base:config", "//absl/base:core_headers", "//absl/base:nullability", - "//absl/base:throw_delegate", ], ) @@ -410,23 +407,6 @@ ], ) -cc_binary( - name = "string_view_benchmark", - testonly = True, - srcs = ["string_view_benchmark.cc"], - copts = ABSL_TEST_COPTS, - tags = ["benchmark"], - visibility = ["//visibility:private"], - deps = [ - ":string_view", - ":strings", - "//absl/base:core_headers", - "//absl/base:raw_logging_internal", - "//absl/random", - "@google_benchmark//:benchmark_main", - ], -) - cc_test( name = "string_view_test", size = "small",
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 2b97fb5..94e58ea 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt
@@ -19,16 +19,12 @@ string_view HDRS "string_view.h" - SRCS - "string_view.cc" COPTS ${ABSL_DEFAULT_COPTS} DEPS - absl::base absl::config absl::core_headers absl::nullability - absl::throw_delegate PUBLIC )
diff --git a/absl/strings/string_view.cc b/absl/strings/string_view.cc deleted file mode 100644 index 33bd1bb..0000000 --- a/absl/strings/string_view.cc +++ /dev/null
@@ -1,257 +0,0 @@ -// 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 -// -// https://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 "absl/strings/string_view.h" - -#ifndef ABSL_USES_STD_STRING_VIEW - -#include <algorithm> -#include <climits> -#include <cstring> -#include <ostream> - -#include "absl/base/nullability.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN - -namespace { - -// This is significantly faster for case-sensitive matches with very -// few possible matches. -const char* absl_nullable memmatch(const char* absl_nullable phaystack, - size_t haylen, - const char* absl_nullable pneedle, - size_t neelen) { - if (0 == neelen) { - return phaystack; // even if haylen is 0 - } - if (haylen < neelen) return nullptr; - - const char* match; - const char* hayend = phaystack + haylen - neelen + 1; - // A static cast is used here as memchr returns a const void *, and pointer - // arithmetic is not allowed on pointers to void. - while ( - (match = static_cast<const char*>(memchr( - phaystack, pneedle[0], static_cast<size_t>(hayend - phaystack))))) { - if (memcmp(match, pneedle, neelen) == 0) - return match; - else - phaystack = match + 1; - } - return nullptr; -} - -void WritePadding(std::ostream& o, size_t pad) { - char fill_buf[32]; - memset(fill_buf, o.fill(), sizeof(fill_buf)); - while (pad) { - size_t n = std::min(pad, sizeof(fill_buf)); - o.write(fill_buf, static_cast<std::streamsize>(n)); - pad -= n; - } -} - -class LookupTable { - public: - // For each character in wanted, sets the index corresponding - // to the ASCII code of that character. This is used by - // the find_.*_of methods below to tell whether or not a character is in - // the lookup table in constant time. - explicit LookupTable(string_view wanted) { - for (char c : wanted) { - table_[Index(c)] = true; - } - } - bool operator[](char c) const { return table_[Index(c)]; } - - private: - static unsigned char Index(char c) { return static_cast<unsigned char>(c); } - bool table_[UCHAR_MAX + 1] = {}; -}; - -} // namespace - -std::ostream& operator<<(std::ostream& o, string_view piece) { - std::ostream::sentry sentry(o); - if (sentry) { - size_t lpad = 0; - size_t rpad = 0; - if (static_cast<size_t>(o.width()) > piece.size()) { - size_t pad = static_cast<size_t>(o.width()) - piece.size(); - if ((o.flags() & o.adjustfield) == o.left) { - rpad = pad; - } else { - lpad = pad; - } - } - if (lpad) WritePadding(o, lpad); - o.write(piece.data(), static_cast<std::streamsize>(piece.size())); - if (rpad) WritePadding(o, rpad); - o.width(0); - } - return o; -} - -string_view::size_type string_view::find(string_view s, - size_type pos) const noexcept { - if (empty() || pos > length_) { - if (empty() && pos == 0 && s.empty()) return 0; - return npos; - } - const char* result = memmatch(ptr_ + pos, length_ - pos, s.ptr_, s.length_); - return result ? static_cast<size_type>(result - ptr_) : npos; -} - -string_view::size_type string_view::find(char c, size_type pos) const noexcept { - if (empty() || pos >= length_) { - return npos; - } - const char* result = - static_cast<const char*>(memchr(ptr_ + pos, c, length_ - pos)); - return result != nullptr ? static_cast<size_type>(result - ptr_) : npos; -} - -string_view::size_type string_view::rfind(string_view s, - size_type pos) const noexcept { - if (length_ < s.length_) return npos; - if (s.empty()) return std::min(length_, pos); - const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_; - const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_); - return result != last ? static_cast<size_type>(result - ptr_) : npos; -} - -// Search range is [0..pos] inclusive. If pos == npos, search everything. -string_view::size_type string_view::rfind(char c, - size_type pos) const noexcept { - // Note: memrchr() is not available on Windows. - if (empty()) return npos; - for (size_type i = std::min(pos, length_ - 1);; --i) { - if (ptr_[i] == c) { - return i; - } - if (i == 0) break; - } - return npos; -} - -string_view::size_type string_view::find_first_of( - string_view s, size_type pos) const noexcept { - if (empty() || s.empty()) { - return npos; - } - // Avoid the cost of LookupTable() for a single-character search. - if (s.length_ == 1) return find_first_of(s.ptr_[0], pos); - LookupTable tbl(s); - for (size_type i = pos; i < length_; ++i) { - if (tbl[ptr_[i]]) { - return i; - } - } - return npos; -} - -string_view::size_type string_view::find_first_not_of( - string_view s, size_type pos) const noexcept { - if (empty()) return npos; - // Avoid the cost of LookupTable() for a single-character search. - if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos); - LookupTable tbl(s); - for (size_type i = pos; i < length_; ++i) { - if (!tbl[ptr_[i]]) { - return i; - } - } - return npos; -} - -string_view::size_type string_view::find_first_not_of( - char c, size_type pos) const noexcept { - if (empty()) return npos; - for (; pos < length_; ++pos) { - if (ptr_[pos] != c) { - return pos; - } - } - return npos; -} - -string_view::size_type string_view::find_last_of(string_view s, - size_type pos) const noexcept { - if (empty() || s.empty()) return npos; - // Avoid the cost of LookupTable() for a single-character search. - if (s.length_ == 1) return find_last_of(s.ptr_[0], pos); - LookupTable tbl(s); - for (size_type i = std::min(pos, length_ - 1);; --i) { - if (tbl[ptr_[i]]) { - return i; - } - if (i == 0) break; - } - return npos; -} - -string_view::size_type string_view::find_last_not_of( - string_view s, size_type pos) const noexcept { - if (empty()) return npos; - size_type i = std::min(pos, length_ - 1); - if (s.empty()) return i; - // Avoid the cost of LookupTable() for a single-character search. - if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos); - LookupTable tbl(s); - for (;; --i) { - if (!tbl[ptr_[i]]) { - return i; - } - if (i == 0) break; - } - return npos; -} - -string_view::size_type string_view::find_last_not_of( - char c, size_type pos) const noexcept { - if (empty()) return npos; - size_type i = std::min(pos, length_ - 1); - for (;; --i) { - if (ptr_[i] != c) { - return i; - } - if (i == 0) break; - } - return npos; -} - -ABSL_NAMESPACE_END -} // namespace absl - -#else - -// https://github.com/abseil/abseil-cpp/issues/1465 -// CMake builds on Apple platforms error when libraries are empty. -// Our CMake configuration can avoid this error on header-only libraries, -// but since this library is conditionally empty, including a single -// variable is an easy workaround. -#ifdef __APPLE__ -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace strings_internal { -extern const char kAvoidEmptyStringViewLibraryWarning; -const char kAvoidEmptyStringViewLibraryWarning = 0; -} // namespace strings_internal -ABSL_NAMESPACE_END -} // namespace absl -#endif // __APPLE__ - -#endif // ABSL_USES_STD_STRING_VIEW
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h index 358570e..9daa149 100644 --- a/absl/strings/string_view.h +++ b/absl/strings/string_view.h
@@ -1,4 +1,3 @@ -// // Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,784 +16,24 @@ // File: string_view.h // ----------------------------------------------------------------------------- // -// This file contains the definition of the `absl::string_view` class. A -// `string_view` points to a contiguous span of characters, often part or all of -// another `std::string`, double-quoted string literal, character array, or even -// another `string_view`. -// -// This `absl::string_view` abstraction is designed to be a drop-in -// replacement for the C++17 `std::string_view` abstraction. +// Historical note: Abseil once provided an implementation of +// `absl::string_view` as a polyfill for `std::string_view` prior to C++17. Now +// that C++17 is required, `absl::string_view` is an alias for +// `std::string_view` + #ifndef ABSL_STRINGS_STRING_VIEW_H_ #define ABSL_STRINGS_STRING_VIEW_H_ -#include <algorithm> -#include <cassert> -#include <cstddef> -#include <cstring> -#include <iosfwd> -#include <iterator> -#include <limits> -#include <memory> -#include <string> -#include <type_traits> +#include <string_view> #include "absl/base/attributes.h" #include "absl/base/config.h" -#include "absl/base/internal/throw_delegate.h" -#include "absl/base/macros.h" #include "absl/base/nullability.h" -#include "absl/base/optimization.h" -#include "absl/base/port.h" - -#ifdef ABSL_USES_STD_STRING_VIEW - -#include <string_view> // IWYU pragma: export - -namespace absl { -ABSL_NAMESPACE_BEGIN -using string_view = std::string_view; -ABSL_NAMESPACE_END -} // namespace absl - -#else // ABSL_USES_STD_STRING_VIEW - -#if ABSL_HAVE_ATTRIBUTE(diagnose_if) -#define ABSL_INTERNAL_DIAGNOSE_IF_NULLPTR(x) \ - __attribute__((diagnose_if( \ - x == nullptr, \ - "null passed to a callee that requires a non-null argument", "error"))) -#else -#define ABSL_INTERNAL_DIAGNOSE_IF_NULLPTR(x) -#endif - -#if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \ - (defined(__GNUC__) && !defined(__clang__)) || \ - (defined(_MSC_VER) && _MSC_VER >= 1928) -#define ABSL_INTERNAL_STRING_VIEW_MEMCMP __builtin_memcmp -#else // ABSL_HAVE_BUILTIN(__builtin_memcmp) -#define ABSL_INTERNAL_STRING_VIEW_MEMCMP memcmp -#endif // ABSL_HAVE_BUILTIN(__builtin_memcmp) - -// If `std::ranges` is available, mark `string_view` as satisfying the -// `view` and `borrowed_range` concepts, just like `std::string_view`. -#ifdef __has_include -#if __has_include(<version>) -#include <version> -#endif -#endif - -#if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L -#include <ranges> // NOLINT(build/c++20) - -namespace absl { -ABSL_NAMESPACE_BEGIN -class string_view; -ABSL_NAMESPACE_END -} // namespace absl - -template <> -// NOLINTNEXTLINE(build/c++20) -inline constexpr bool std::ranges::enable_view<absl::string_view> = true; -template <> -// NOLINTNEXTLINE(build/c++20) -inline constexpr bool std::ranges::enable_borrowed_range<absl::string_view> = - true; -#endif namespace absl { ABSL_NAMESPACE_BEGIN -// absl::string_view -// -// A `string_view` provides a lightweight view into the string data provided by -// a `std::string`, double-quoted string literal, character array, or even -// another `string_view`. A `string_view` does *not* own the string to which it -// points, and that data cannot be modified through the view. -// -// You can use `string_view` as a function or method parameter anywhere a -// parameter can receive a double-quoted string literal, `const char*`, -// `std::string`, or another `absl::string_view` argument with no need to copy -// the string data. Systematic use of `string_view` within function arguments -// reduces data copies and `strlen()` calls. -// -// Because of its small size, prefer passing `string_view` by value: -// -// void MyFunction(absl::string_view arg); -// -// If circumstances require, you may also pass one by const reference: -// -// void MyFunction(const absl::string_view& arg); // not preferred -// -// Passing by value generates slightly smaller code for many architectures. -// -// In either case, the source data of the `string_view` must outlive the -// `string_view` itself. -// -// A `string_view` is also suitable for local variables if you know that the -// lifetime of the underlying object is longer than the lifetime of your -// `string_view` variable. However, beware of binding a `string_view` to a -// temporary value: -// -// // BAD use of string_view: lifetime problem -// absl::string_view sv = obj.ReturnAString(); -// -// // GOOD use of string_view: str outlives sv -// std::string str = obj.ReturnAString(); -// absl::string_view sv = str; -// -// Due to lifetime issues, a `string_view` is sometimes a poor choice for a -// return value and usually a poor choice for a data member. If you do use a -// `string_view` this way, it is your responsibility to ensure that the object -// pointed to by the `string_view` outlives the `string_view`. -// -// A `string_view` may represent a whole string or just part of a string. For -// example, when splitting a string, `std::vector<absl::string_view>` is a -// natural data type for the output. -// -// For another example, a Cord is a non-contiguous, potentially very -// long string-like object. The Cord class has an interface that iteratively -// provides string_view objects that point to the successive pieces of a Cord -// object. -// -// When constructed from a source which is NUL-terminated, the `string_view` -// itself will not include the NUL-terminator unless a specific size (including -// the NUL) is passed to the constructor. As a result, common idioms that work -// on NUL-terminated strings do not work on `string_view` objects. If you write -// code that scans a `string_view`, you must check its length rather than test -// for nul, for example. Note, however, that nuls may still be embedded within -// a `string_view` explicitly. -// -// You may create a null `string_view` in two ways: -// -// absl::string_view sv; -// absl::string_view sv(nullptr, 0); -// -// For the above, `sv.data() == nullptr`, `sv.length() == 0`, and -// `sv.empty() == true`. Also, if you create a `string_view` with a non-null -// pointer then `sv.data() != nullptr`. Thus, you can use `string_view()` to -// signal an undefined value that is different from other `string_view` values -// in a similar fashion to how `const char* p1 = nullptr;` is different from -// `const char* p2 = "";`. However, in practice, it is not recommended to rely -// on this behavior. -// -// Be careful not to confuse a null `string_view` with an empty one. A null -// `string_view` is an empty `string_view`, but some empty `string_view`s are -// not null. Prefer checking for emptiness over checking for null. -// -// There are many ways to create an empty string_view: -// -// const char* nullcp = nullptr; -// // string_view.size() will return 0 in all cases. -// absl::string_view(); -// absl::string_view(nullcp, 0); -// absl::string_view(""); -// absl::string_view("", 0); -// absl::string_view("abcdef", 0); -// absl::string_view("abcdef" + 6, 0); -// -// All empty `string_view` objects whether null or not, are equal: -// -// absl::string_view() == absl::string_view("", 0) -// absl::string_view(nullptr, 0) == absl::string_view("abcdef"+6, 0) -class ABSL_ATTRIBUTE_VIEW string_view { - public: - using traits_type = std::char_traits<char>; - using value_type = char; - using pointer = char* absl_nullable; - using const_pointer = const char* absl_nullable; - using reference = char&; - using const_reference = const char&; - using const_iterator = const char* absl_nullable; - using iterator = const_iterator; - using const_reverse_iterator = std::reverse_iterator<const_iterator>; - using reverse_iterator = const_reverse_iterator; - using size_type = size_t; - using difference_type = std::ptrdiff_t; - using absl_internal_is_view = std::true_type; - - static constexpr size_type npos = static_cast<size_type>(-1); - - // Null `string_view` constructor - constexpr string_view() noexcept : ptr_(nullptr), length_(0) {} - - // Implicit constructors - - template <typename Allocator> - string_view( // NOLINT(runtime/explicit) - const std::basic_string<char, std::char_traits<char>, Allocator>& str - ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept - // This is implemented in terms of `string_view(p, n)` so `str.size()` - // doesn't need to be reevaluated after `ptr_` is set. - // The length check is also skipped since it is unnecessary and causes - // code bloat. - : string_view(str.data(), str.size(), SkipCheckLengthTag{}) {} - - // Implicit constructor of a `string_view` from NUL-terminated `str`. When - // accepting possibly null strings, use `absl::NullSafeStringView(str)` - // instead (see below). - // The length check is skipped since it is unnecessary and causes code bloat. - constexpr string_view( // NOLINT(runtime/explicit) - const char* absl_nonnull str) ABSL_INTERNAL_DIAGNOSE_IF_NULLPTR(str) - : ptr_(str), length_(str ? StrlenInternal(str) : 0) { - ABSL_HARDENING_ASSERT(str != nullptr); - } - - // Constructor of a `string_view` from a `const char*` and length. - constexpr string_view(const char* absl_nullable data, size_type len) - : ptr_(data), length_(CheckLengthInternal(len)) { - ABSL_ASSERT(data != nullptr || len == 0); - } - -#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L - template <std::contiguous_iterator It, std::sized_sentinel_for<It> End> - requires(std::is_same_v<std::iter_value_t<It>, value_type> && - !std::is_convertible_v<End, size_type>) - constexpr string_view(It begin, End end) - : ptr_(std::to_address(begin)), length_(end - begin) { - ABSL_HARDENING_ASSERT(end >= begin); - } -#endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L - - // Deleted constructor from std::nullptr_t from C++23. - string_view(std::nullptr_t) = delete; - - constexpr string_view(const string_view&) noexcept = default; - string_view& operator=(const string_view&) noexcept = default; - - // Iterators - - // string_view::begin() - // - // Returns an iterator pointing to the first character at the beginning of the - // `string_view`, or `end()` if the `string_view` is empty. - constexpr const_iterator begin() const noexcept { return ptr_; } - - // string_view::end() - // - // Returns an iterator pointing just beyond the last character at the end of - // the `string_view`. This iterator acts as a placeholder; attempting to - // access it results in undefined behavior. - constexpr const_iterator end() const noexcept { return ptr_ + length_; } - - // string_view::cbegin() - // - // Returns a const iterator pointing to the first character at the beginning - // of the `string_view`, or `end()` if the `string_view` is empty. - constexpr const_iterator cbegin() const noexcept { return begin(); } - - // string_view::cend() - // - // Returns a const iterator pointing just beyond the last character at the end - // of the `string_view`. This pointer acts as a placeholder; attempting to - // access its element results in undefined behavior. - constexpr const_iterator cend() const noexcept { return end(); } - - // string_view::rbegin() - // - // Returns a reverse iterator pointing to the last character at the end of the - // `string_view`, or `rend()` if the `string_view` is empty. - const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); - } - - // string_view::rend() - // - // Returns a reverse iterator pointing just before the first character at the - // beginning of the `string_view`. This pointer acts as a placeholder; - // attempting to access its element results in undefined behavior. - const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); - } - - // string_view::crbegin() - // - // Returns a const reverse iterator pointing to the last character at the end - // of the `string_view`, or `crend()` if the `string_view` is empty. - const_reverse_iterator crbegin() const noexcept { return rbegin(); } - - // string_view::crend() - // - // Returns a const reverse iterator pointing just before the first character - // at the beginning of the `string_view`. This pointer acts as a placeholder; - // attempting to access its element results in undefined behavior. - const_reverse_iterator crend() const noexcept { return rend(); } - - // Capacity Utilities - - // string_view::size() - // - // Returns the number of characters in the `string_view`. - constexpr size_type size() const noexcept { return length_; } - - // string_view::length() - // - // Returns the number of characters in the `string_view`. Alias for `size()`. - constexpr size_type length() const noexcept { return size(); } - - // string_view::max_size() - // - // Returns the maximum number of characters the `string_view` can hold. - constexpr size_type max_size() const noexcept { return kMaxSize; } - - // string_view::empty() - // - // Checks if the `string_view` is empty (refers to no characters). - constexpr bool empty() const noexcept { return length_ == 0; } - - // string_view::operator[] - // - // Returns the ith element of the `string_view` using the array operator. - // Note that this operator does not perform any bounds checking. - constexpr const_reference operator[](size_type i) const { - ABSL_HARDENING_ASSERT(i < size()); - return ptr_[i]; - } - - // string_view::at() - // - // Returns the ith element of the `string_view`. Bounds checking is performed, - // and an exception of type `std::out_of_range` will be thrown on invalid - // access. - constexpr const_reference at(size_type i) const { - if (ABSL_PREDICT_FALSE(i >= size())) { - base_internal::ThrowStdOutOfRange("absl::string_view::at"); - } - return ptr_[i]; - } - - // string_view::front() - // - // Returns the first element of a `string_view`. - constexpr const_reference front() const { - ABSL_HARDENING_ASSERT(!empty()); - return ptr_[0]; - } - - // string_view::back() - // - // Returns the last element of a `string_view`. - constexpr const_reference back() const { - ABSL_HARDENING_ASSERT(!empty()); - return ptr_[size() - 1]; - } - - // string_view::data() - // - // Returns a pointer to the underlying character array (which is of course - // stored elsewhere). Note that `string_view::data()` may contain embedded nul - // characters, but the returned buffer may or may not be NUL-terminated; - // therefore, do not pass `data()` to a routine that expects a NUL-terminated - // string. - constexpr const_pointer data() const noexcept { return ptr_; } - - // Modifiers - - // string_view::remove_prefix() - // - // Removes the first `n` characters from the `string_view`. Note that the - // underlying string is not changed, only the view. - constexpr void remove_prefix(size_type n) { - ABSL_HARDENING_ASSERT(n <= length_); - ptr_ += n; - length_ -= n; - } - - // string_view::remove_suffix() - // - // Removes the last `n` characters from the `string_view`. Note that the - // underlying string is not changed, only the view. - constexpr void remove_suffix(size_type n) { - ABSL_HARDENING_ASSERT(n <= length_); - length_ -= n; - } - - // string_view::swap() - // - // Swaps this `string_view` with another `string_view`. - constexpr void swap(string_view& s) noexcept { - auto t = *this; - *this = s; - s = t; - } - - // Explicit conversion operators - - // Converts to `std::basic_string`. - template <typename A> - explicit operator std::basic_string<char, traits_type, A>() const { - if (!data()) return {}; - return std::basic_string<char, traits_type, A>(data(), size()); - } - - // string_view::copy() - // - // Copies the contents of the `string_view` at offset `pos` and length `n` - // into `buf`. - size_type copy(char* absl_nonnull buf, size_type n, size_type pos = 0) const { - if (ABSL_PREDICT_FALSE(pos > length_)) { - base_internal::ThrowStdOutOfRange("absl::string_view::copy"); - } - size_type rlen = (std::min)(length_ - pos, n); - if (rlen > 0) { - const char* start = ptr_ + pos; - traits_type::copy(buf, start, rlen); - } - return rlen; - } - - // string_view::substr() - // - // Returns a "substring" of the `string_view` (at offset `pos` and length - // `n`) as another string_view. This function throws `std::out_of_bounds` if - // `pos > size`. - // Use absl::ClippedSubstr if you need a truncating substr operation. - constexpr string_view substr(size_type pos = 0, size_type n = npos) const { - if (ABSL_PREDICT_FALSE(pos > length_)) { - base_internal::ThrowStdOutOfRange("absl::string_view::substr"); - } - return string_view(ptr_ + pos, (std::min)(n, length_ - pos)); - } - - // string_view::compare() - // - // Performs a lexicographical comparison between this `string_view` and - // another `string_view` `x`, returning a negative value if `*this` is less - // than `x`, 0 if `*this` is equal to `x`, and a positive value if `*this` - // is greater than `x`. - constexpr int compare(string_view x) const noexcept { - return CompareImpl(length_, x.length_, - (std::min)(length_, x.length_) == 0 - ? 0 - : ABSL_INTERNAL_STRING_VIEW_MEMCMP( - ptr_, x.ptr_, (std::min)(length_, x.length_))); - } - - // Overload of `string_view::compare()` for comparing a substring of the - // 'string_view` and another `absl::string_view`. - constexpr int compare(size_type pos1, size_type count1, string_view v) const { - return substr(pos1, count1).compare(v); - } - - // Overload of `string_view::compare()` for comparing a substring of the - // `string_view` and a substring of another `absl::string_view`. - constexpr int compare(size_type pos1, size_type count1, string_view v, - size_type pos2, size_type count2) const { - return substr(pos1, count1).compare(v.substr(pos2, count2)); - } - - // Overload of `string_view::compare()` for comparing a `string_view` and a - // a different C-style string `s`. - constexpr int compare(const char* absl_nonnull s) const { - return compare(string_view(s)); - } - - // Overload of `string_view::compare()` for comparing a substring of the - // `string_view` and a different string C-style string `s`. - constexpr int compare(size_type pos1, size_type count1, - const char* absl_nonnull s) const { - return substr(pos1, count1).compare(string_view(s)); - } - - // Overload of `string_view::compare()` for comparing a substring of the - // `string_view` and a substring of a different C-style string `s`. - constexpr int compare(size_type pos1, size_type count1, - const char* absl_nonnull s, size_type count2) const { - return substr(pos1, count1).compare(string_view(s, count2)); - } - - // Find Utilities - - // string_view::find() - // - // Finds the first occurrence of the substring `s` within the `string_view`, - // returning the position of the first character's match, or `npos` if no - // match was found. - size_type find(string_view s, size_type pos = 0) const noexcept; - - // Overload of `string_view::find()` for finding the given character `c` - // within the `string_view`. - size_type find(char c, size_type pos = 0) const noexcept; - - // Overload of `string_view::find()` for finding a substring of a different - // C-style string `s` within the `string_view`. - size_type find(const char* absl_nonnull s, size_type pos, - size_type count) const { - return find(string_view(s, count), pos); - } - - // Overload of `string_view::find()` for finding a different C-style string - // `s` within the `string_view`. - size_type find(const char* absl_nonnull s, size_type pos = 0) const { - return find(string_view(s), pos); - } - - // string_view::rfind() - // - // Finds the last occurrence of a substring `s` within the `string_view`, - // returning the position of the first character's match, or `npos` if no - // match was found. - size_type rfind(string_view s, size_type pos = npos) const noexcept; - - // Overload of `string_view::rfind()` for finding the last given character `c` - // within the `string_view`. - size_type rfind(char c, size_type pos = npos) const noexcept; - - // Overload of `string_view::rfind()` for finding a substring of a different - // C-style string `s` within the `string_view`. - size_type rfind(const char* absl_nonnull s, size_type pos, - size_type count) const { - return rfind(string_view(s, count), pos); - } - - // Overload of `string_view::rfind()` for finding a different C-style string - // `s` within the `string_view`. - size_type rfind(const char* absl_nonnull s, size_type pos = npos) const { - return rfind(string_view(s), pos); - } - - // string_view::find_first_of() - // - // Finds the first occurrence of any of the characters in `s` within the - // `string_view`, returning the start position of the match, or `npos` if no - // match was found. - size_type find_first_of(string_view s, size_type pos = 0) const noexcept; - - // Overload of `string_view::find_first_of()` for finding a character `c` - // within the `string_view`. - size_type find_first_of(char c, size_type pos = 0) const noexcept { - return find(c, pos); - } - - // Overload of `string_view::find_first_of()` for finding a substring of a - // different C-style string `s` within the `string_view`. - size_type find_first_of(const char* absl_nonnull s, size_type pos, - size_type count) const { - return find_first_of(string_view(s, count), pos); - } - - // Overload of `string_view::find_first_of()` for finding a different C-style - // string `s` within the `string_view`. - size_type find_first_of(const char* absl_nonnull s, size_type pos = 0) const { - return find_first_of(string_view(s), pos); - } - - // string_view::find_last_of() - // - // Finds the last occurrence of any of the characters in `s` within the - // `string_view`, returning the start position of the match, or `npos` if no - // match was found. - size_type find_last_of(string_view s, size_type pos = npos) const noexcept; - - // Overload of `string_view::find_last_of()` for finding a character `c` - // within the `string_view`. - size_type find_last_of(char c, size_type pos = npos) const noexcept { - return rfind(c, pos); - } - - // Overload of `string_view::find_last_of()` for finding a substring of a - // different C-style string `s` within the `string_view`. - size_type find_last_of(const char* absl_nonnull s, size_type pos, - size_type count) const { - return find_last_of(string_view(s, count), pos); - } - - // Overload of `string_view::find_last_of()` for finding a different C-style - // string `s` within the `string_view`. - size_type find_last_of(const char* absl_nonnull s, - size_type pos = npos) const { - return find_last_of(string_view(s), pos); - } - - // string_view::find_first_not_of() - // - // Finds the first occurrence of any of the characters not in `s` within the - // `string_view`, returning the start position of the first non-match, or - // `npos` if no non-match was found. - size_type find_first_not_of(string_view s, size_type pos = 0) const noexcept; - - // Overload of `string_view::find_first_not_of()` for finding a character - // that is not `c` within the `string_view`. - size_type find_first_not_of(char c, size_type pos = 0) const noexcept; - - // Overload of `string_view::find_first_not_of()` for finding a substring of a - // different C-style string `s` within the `string_view`. - size_type find_first_not_of(const char* absl_nonnull s, size_type pos, - size_type count) const { - return find_first_not_of(string_view(s, count), pos); - } - - // Overload of `string_view::find_first_not_of()` for finding a different - // C-style string `s` within the `string_view`. - size_type find_first_not_of(const char* absl_nonnull s, - size_type pos = 0) const { - return find_first_not_of(string_view(s), pos); - } - - // string_view::find_last_not_of() - // - // Finds the last occurrence of any of the characters not in `s` within the - // `string_view`, returning the start position of the last non-match, or - // `npos` if no non-match was found. - size_type find_last_not_of(string_view s, - size_type pos = npos) const noexcept; - - // Overload of `string_view::find_last_not_of()` for finding a character - // that is not `c` within the `string_view`. - size_type find_last_not_of(char c, size_type pos = npos) const noexcept; - - // Overload of `string_view::find_last_not_of()` for finding a substring of a - // different C-style string `s` within the `string_view`. - size_type find_last_not_of(const char* absl_nonnull s, size_type pos, - size_type count) const { - return find_last_not_of(string_view(s, count), pos); - } - - // Overload of `string_view::find_last_not_of()` for finding a different - // C-style string `s` within the `string_view`. - size_type find_last_not_of(const char* absl_nonnull s, - size_type pos = npos) const { - return find_last_not_of(string_view(s), pos); - } - -#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L - // string_view::starts_with() - // - // Returns true if the `string_view` starts with the prefix `s`. - // - // This method only exists when targeting at least C++20. - // If support for C++ prior to C++20 is required, use `absl::StartsWith()` - // from `//absl/strings/match.h` for compatibility. - constexpr bool starts_with(string_view s) const noexcept { - return s.empty() || - (size() >= s.size() && - ABSL_INTERNAL_STRING_VIEW_MEMCMP(data(), s.data(), s.size()) == 0); - } - - // Overload of `string_view::starts_with()` that returns true if `c` is the - // first character of the `string_view`. - constexpr bool starts_with(char c) const noexcept { - return !empty() && front() == c; - } - - // Overload of `string_view::starts_with()` that returns true if the - // `string_view` starts with the C-style prefix `s`. - constexpr bool starts_with(const char* absl_nonnull s) const { - return starts_with(string_view(s)); - } - - // string_view::ends_with() - // - // Returns true if the `string_view` ends with the suffix `s`. - // - // This method only exists when targeting at least C++20. - // If support for C++ prior to C++20 is required, use `absl::EndsWith()` - // from `//absl/strings/match.h` for compatibility. - constexpr bool ends_with(string_view s) const noexcept { - return s.empty() || (size() >= s.size() && ABSL_INTERNAL_STRING_VIEW_MEMCMP( - data() + (size() - s.size()), - s.data(), s.size()) == 0); - } - - // Overload of `string_view::ends_with()` that returns true if `c` is the - // last character of the `string_view`. - constexpr bool ends_with(char c) const noexcept { - return !empty() && back() == c; - } - - // Overload of `string_view::ends_with()` that returns true if the - // `string_view` ends with the C-style suffix `s`. - constexpr bool ends_with(const char* absl_nonnull s) const { - return ends_with(string_view(s)); - } -#endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L - - private: - // The constructor from std::string delegates to this constructor. - // See the comment on that constructor for the rationale. - struct SkipCheckLengthTag {}; - string_view(const char* absl_nullable data, size_type len, - SkipCheckLengthTag) noexcept - : ptr_(data), length_(len) {} - - static constexpr size_type kMaxSize = - (std::numeric_limits<difference_type>::max)(); - - static constexpr size_type CheckLengthInternal(size_type len) { - ABSL_HARDENING_ASSERT(len <= kMaxSize); - return len; - } - - static constexpr size_type StrlenInternal(const char* absl_nonnull str) { -#if defined(_MSC_VER) && !defined(__clang__) - // MSVC 2017+ can evaluate this at compile-time. - const char* begin = str; - while (*str != '\0') ++str; - return str - begin; -#elif ABSL_HAVE_BUILTIN(__builtin_strlen) || \ - (defined(__GNUC__) && !defined(__clang__)) - // GCC has __builtin_strlen according to - // https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Other-Builtins.html, but - // ABSL_HAVE_BUILTIN doesn't detect that, so we use the extra checks above. - // __builtin_strlen is constexpr. - return __builtin_strlen(str); -#else - return str ? strlen(str) : 0; -#endif - } - - static constexpr int CompareImpl(size_type length_a, size_type length_b, - int compare_result) { - return compare_result == 0 ? static_cast<int>(length_a > length_b) - - static_cast<int>(length_a < length_b) - : (compare_result < 0 ? -1 : 1); - } - - const char* absl_nullable ptr_; - size_type length_; -}; - -// This large function is defined inline so that in a fairly common case where -// one of the arguments is a literal, the compiler can elide a lot of the -// following comparisons. -constexpr bool operator==(string_view x, string_view y) noexcept { - return x.size() == y.size() && - (x.empty() || - ABSL_INTERNAL_STRING_VIEW_MEMCMP(x.data(), y.data(), x.size()) == 0); -} - -constexpr bool operator!=(string_view x, string_view y) noexcept { - return !(x == y); -} - -constexpr bool operator<(string_view x, string_view y) noexcept { - return x.compare(y) < 0; -} - -constexpr bool operator>(string_view x, string_view y) noexcept { - return y < x; -} - -constexpr bool operator<=(string_view x, string_view y) noexcept { - return !(y < x); -} - -constexpr bool operator>=(string_view x, string_view y) noexcept { - return !(x < y); -} - -// IO Insertion Operator -std::ostream& operator<<(std::ostream& o, string_view piece); - -ABSL_NAMESPACE_END -} // namespace absl - -#undef ABSL_INTERNAL_DIAGNOSE_IF_NULLPTR -#undef ABSL_INTERNAL_STRING_VIEW_MEMCMP - -#endif // ABSL_USES_STD_STRING_VIEW - -namespace absl { -ABSL_NAMESPACE_BEGIN +using std::string_view; // ClippedSubstr() //
diff --git a/absl/strings/string_view_benchmark.cc b/absl/strings/string_view_benchmark.cc deleted file mode 100644 index 546f6ed..0000000 --- a/absl/strings/string_view_benchmark.cc +++ /dev/null
@@ -1,380 +0,0 @@ -// Copyright 2018 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 -// -// https://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 <algorithm> -#include <cstddef> -#include <cstdint> -#include <map> -#include <random> -#include <string> -#include <unordered_set> -#include <vector> - -#include "absl/base/attributes.h" -#include "absl/base/internal/raw_logging.h" -#include "absl/base/macros.h" -#include "absl/random/random.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" -#include "benchmark/benchmark.h" - -namespace { - -void BM_StringViewFromString(benchmark::State& state) { - std::string s(state.range(0), 'x'); - std::string* ps = &s; - struct SV { - SV() = default; - explicit SV(const std::string& s) : sv(s) {} - absl::string_view sv; - } sv; - SV* psv = &sv; - benchmark::DoNotOptimize(ps); - benchmark::DoNotOptimize(psv); - for (auto _ : state) { - new (psv) SV(*ps); - benchmark::DoNotOptimize(sv); - } -} -BENCHMARK(BM_StringViewFromString)->Arg(12)->Arg(128); - -// Provide a forcibly out-of-line wrapper for operator== that can be used in -// benchmarks to measure the impact of inlining. -ABSL_ATTRIBUTE_NOINLINE -bool NonInlinedEq(absl::string_view a, absl::string_view b) { return a == b; } - -// We use functions that cannot be inlined to perform the comparison loops so -// that inlining of the operator== can't optimize away *everything*. -ABSL_ATTRIBUTE_NOINLINE -void DoEqualityComparisons(benchmark::State& state, absl::string_view a, - absl::string_view b) { - for (auto _ : state) { - benchmark::DoNotOptimize(a == b); - } -} - -void BM_EqualIdentical(benchmark::State& state) { - std::string x(state.range(0), 'a'); - DoEqualityComparisons(state, x, x); -} -BENCHMARK(BM_EqualIdentical)->DenseRange(0, 3)->Range(4, 1 << 10); - -void BM_EqualSame(benchmark::State& state) { - std::string x(state.range(0), 'a'); - std::string y = x; - DoEqualityComparisons(state, x, y); -} -BENCHMARK(BM_EqualSame) - ->DenseRange(0, 10) - ->Arg(20) - ->Arg(40) - ->Arg(70) - ->Arg(110) - ->Range(160, 4096); - -void BM_EqualDifferent(benchmark::State& state) { - const int len = state.range(0); - std::string x(len, 'a'); - std::string y = x; - if (len > 0) { - y[len - 1] = 'b'; - } - DoEqualityComparisons(state, x, y); -} -BENCHMARK(BM_EqualDifferent)->DenseRange(0, 3)->Range(4, 1 << 10); - -// This benchmark is intended to check that important simplifications can be -// made with absl::string_view comparisons against constant strings. The idea is -// that if constant strings cause redundant components of the comparison, the -// compiler should detect and eliminate them. Here we use 8 different strings, -// each with the same size. Provided our comparison makes the implementation -// inline-able by the compiler, it should fold all of these away into a single -// size check once per loop iteration. -ABSL_ATTRIBUTE_NOINLINE -void DoConstantSizeInlinedEqualityComparisons(benchmark::State& state, - absl::string_view a) { - for (auto _ : state) { - benchmark::DoNotOptimize(a == "aaa"); - benchmark::DoNotOptimize(a == "bbb"); - benchmark::DoNotOptimize(a == "ccc"); - benchmark::DoNotOptimize(a == "ddd"); - benchmark::DoNotOptimize(a == "eee"); - benchmark::DoNotOptimize(a == "fff"); - benchmark::DoNotOptimize(a == "ggg"); - benchmark::DoNotOptimize(a == "hhh"); - } -} -void BM_EqualConstantSizeInlined(benchmark::State& state) { - std::string x(state.range(0), 'a'); - DoConstantSizeInlinedEqualityComparisons(state, x); -} -// We only need to check for size of 3, and <> 3 as this benchmark only has to -// do with size differences. -BENCHMARK(BM_EqualConstantSizeInlined)->DenseRange(2, 4); - -// This benchmark exists purely to give context to the above timings: this is -// what they would look like if the compiler is completely unable to simplify -// between two comparisons when they are comparing against constant strings. -ABSL_ATTRIBUTE_NOINLINE -void DoConstantSizeNonInlinedEqualityComparisons(benchmark::State& state, - absl::string_view a) { - for (auto _ : state) { - // Force these out-of-line to compare with the above function. - benchmark::DoNotOptimize(NonInlinedEq(a, "aaa")); - benchmark::DoNotOptimize(NonInlinedEq(a, "bbb")); - benchmark::DoNotOptimize(NonInlinedEq(a, "ccc")); - benchmark::DoNotOptimize(NonInlinedEq(a, "ddd")); - benchmark::DoNotOptimize(NonInlinedEq(a, "eee")); - benchmark::DoNotOptimize(NonInlinedEq(a, "fff")); - benchmark::DoNotOptimize(NonInlinedEq(a, "ggg")); - benchmark::DoNotOptimize(NonInlinedEq(a, "hhh")); - } -} - -void BM_EqualConstantSizeNonInlined(benchmark::State& state) { - std::string x(state.range(0), 'a'); - DoConstantSizeNonInlinedEqualityComparisons(state, x); -} -// We only need to check for size of 3, and <> 3 as this benchmark only has to -// do with size differences. -BENCHMARK(BM_EqualConstantSizeNonInlined)->DenseRange(2, 4); - -void BM_CompareSame(benchmark::State& state) { - const int len = state.range(0); - std::string x; - for (int i = 0; i < len; i++) { - x += 'a'; - } - std::string y = x; - absl::string_view a = x; - absl::string_view b = y; - - for (auto _ : state) { - benchmark::DoNotOptimize(a); - benchmark::DoNotOptimize(b); - benchmark::DoNotOptimize(a.compare(b)); - } -} -BENCHMARK(BM_CompareSame)->DenseRange(0, 3)->Range(4, 1 << 10); - -void BM_CompareFirstOneLess(benchmark::State& state) { - const int len = state.range(0); - std::string x(len, 'a'); - std::string y = x; - y.back() = 'b'; - absl::string_view a = x; - absl::string_view b = y; - - for (auto _ : state) { - benchmark::DoNotOptimize(a); - benchmark::DoNotOptimize(b); - benchmark::DoNotOptimize(a.compare(b)); - } -} -BENCHMARK(BM_CompareFirstOneLess)->DenseRange(1, 3)->Range(4, 1 << 10); - -void BM_CompareSecondOneLess(benchmark::State& state) { - const int len = state.range(0); - std::string x(len, 'a'); - std::string y = x; - x.back() = 'b'; - absl::string_view a = x; - absl::string_view b = y; - - for (auto _ : state) { - benchmark::DoNotOptimize(a); - benchmark::DoNotOptimize(b); - benchmark::DoNotOptimize(a.compare(b)); - } -} -BENCHMARK(BM_CompareSecondOneLess)->DenseRange(1, 3)->Range(4, 1 << 10); - -void BM_find_string_view_len_one(benchmark::State& state) { - std::string haystack(state.range(0), '0'); - absl::string_view s(haystack); - for (auto _ : state) { - benchmark::DoNotOptimize(s.find("x")); // not present; length 1 - } -} -BENCHMARK(BM_find_string_view_len_one)->Range(1, 1 << 20); - -void BM_find_string_view_len_two(benchmark::State& state) { - std::string haystack(state.range(0), '0'); - absl::string_view s(haystack); - for (auto _ : state) { - benchmark::DoNotOptimize(s.find("xx")); // not present; length 2 - } -} -BENCHMARK(BM_find_string_view_len_two)->Range(1, 1 << 20); - -void BM_find_one_char(benchmark::State& state) { - std::string haystack(state.range(0), '0'); - absl::string_view s(haystack); - for (auto _ : state) { - benchmark::DoNotOptimize(s.find('x')); // not present - } -} -BENCHMARK(BM_find_one_char)->Range(1, 1 << 20); - -void BM_rfind_one_char(benchmark::State& state) { - std::string haystack(state.range(0), '0'); - absl::string_view s(haystack); - for (auto _ : state) { - benchmark::DoNotOptimize(s.rfind('x')); // not present - } -} -BENCHMARK(BM_rfind_one_char)->Range(1, 1 << 20); - -void BM_worst_case_find_first_of(benchmark::State& state, int haystack_len) { - const int needle_len = state.range(0); - std::string needle; - for (int i = 0; i < needle_len; ++i) { - needle += 'a' + i; - } - std::string haystack(haystack_len, '0'); // 1000 zeros. - - absl::string_view s(haystack); - for (auto _ : state) { - benchmark::DoNotOptimize(s.find_first_of(needle)); - } -} - -void BM_find_first_of_short(benchmark::State& state) { - BM_worst_case_find_first_of(state, 10); -} - -void BM_find_first_of_medium(benchmark::State& state) { - BM_worst_case_find_first_of(state, 100); -} - -void BM_find_first_of_long(benchmark::State& state) { - BM_worst_case_find_first_of(state, 1000); -} - -BENCHMARK(BM_find_first_of_short)->DenseRange(0, 4)->Arg(8)->Arg(16)->Arg(32); -BENCHMARK(BM_find_first_of_medium)->DenseRange(0, 4)->Arg(8)->Arg(16)->Arg(32); -BENCHMARK(BM_find_first_of_long)->DenseRange(0, 4)->Arg(8)->Arg(16)->Arg(32); - -struct EasyMap : public std::map<absl::string_view, uint64_t> { - explicit EasyMap(size_t) {} -}; - -// This templated benchmark helper function is intended to stress operator== or -// operator< in a realistic test. It surely isn't entirely realistic, but it's -// a start. The test creates a map of type Map, a template arg, and populates -// it with table_size key/value pairs. Each key has WordsPerKey words. After -// creating the map, a number of lookups are done in random order. Some keys -// are used much more frequently than others in this phase of the test. -template <typename Map, int WordsPerKey> -void StringViewMapBenchmark(benchmark::State& state) { - const int table_size = state.range(0); - const double kFractionOfKeysThatAreHot = 0.2; - const int kNumLookupsOfHotKeys = 20; - const int kNumLookupsOfColdKeys = 1; - const char* words[] = {"the", "quick", "brown", "fox", "jumped", - "over", "the", "lazy", "dog", "and", - "found", "a", "large", "mushroom", "and", - "a", "couple", "crickets", "eating", "pie"}; - // Create some keys that consist of words in random order. - absl::InsecureBitGen rng; - std::vector<std::string> keys(table_size); - std::vector<int> all_indices; - const int kBlockSize = 1 << 12; - std::unordered_set<std::string> t(kBlockSize); - std::uniform_int_distribution<int> uniform(0, ABSL_ARRAYSIZE(words) - 1); - for (int i = 0; i < table_size; i++) { - all_indices.push_back(i); - do { - keys[i].clear(); - for (int j = 0; j < WordsPerKey; j++) { - absl::StrAppend(&keys[i], j > 0 ? " " : "", words[uniform(rng)]); - } - } while (!t.insert(keys[i]).second); - } - - // Create a list of strings to lookup: a permutation of the array of - // keys we just created, with repeats. "Hot" keys get repeated more. - std::shuffle(all_indices.begin(), all_indices.end(), rng); - const int num_hot = table_size * kFractionOfKeysThatAreHot; - const int num_cold = table_size - num_hot; - std::vector<int> hot_indices(all_indices.begin(), - all_indices.begin() + num_hot); - std::vector<int> indices; - for (int i = 0; i < kNumLookupsOfColdKeys; i++) { - indices.insert(indices.end(), all_indices.begin(), all_indices.end()); - } - for (int i = 0; i < kNumLookupsOfHotKeys - kNumLookupsOfColdKeys; i++) { - indices.insert(indices.end(), hot_indices.begin(), hot_indices.end()); - } - std::shuffle(indices.begin(), indices.end(), rng); - ABSL_RAW_CHECK( - num_cold * kNumLookupsOfColdKeys + num_hot * kNumLookupsOfHotKeys == - indices.size(), - ""); - // After constructing the array we probe it with absl::string_views built from - // test_strings. This means operator== won't see equal pointers, so - // it'll have to check for equal lengths and equal characters. - std::vector<std::string> test_strings(indices.size()); - for (int i = 0; i < indices.size(); i++) { - test_strings[i] = keys[indices[i]]; - } - - // Run the benchmark. It includes map construction but is mostly - // map lookups. - for (auto _ : state) { - Map h(table_size); - for (int i = 0; i < table_size; i++) { - h[keys[i]] = i * 2; - } - ABSL_RAW_CHECK(h.size() == table_size, ""); - uint64_t sum = 0; - for (int i = 0; i < indices.size(); i++) { - sum += h[test_strings[i]]; - } - benchmark::DoNotOptimize(sum); - } -} - -void BM_StdMap_4(benchmark::State& state) { - StringViewMapBenchmark<EasyMap, 4>(state); -} -BENCHMARK(BM_StdMap_4)->Range(1 << 10, 1 << 16); - -void BM_StdMap_8(benchmark::State& state) { - StringViewMapBenchmark<EasyMap, 8>(state); -} -BENCHMARK(BM_StdMap_8)->Range(1 << 10, 1 << 16); - -void BM_CopyToStringNative(benchmark::State& state) { - std::string src(state.range(0), 'x'); - absl::string_view sv(src); - std::string dst; - for (auto _ : state) { - dst.assign(sv.begin(), sv.end()); - } -} -BENCHMARK(BM_CopyToStringNative)->Range(1 << 3, 1 << 12); - -void BM_AppendToStringNative(benchmark::State& state) { - std::string src(state.range(0), 'x'); - absl::string_view sv(src); - std::string dst; - for (auto _ : state) { - dst.clear(); - dst.insert(dst.end(), sv.begin(), sv.end()); - } -} -BENCHMARK(BM_AppendToStringNative)->Range(1 << 3, 1 << 12); - -} // namespace
diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc index 390173f..d6cec6f 100644 --- a/absl/strings/string_view_test.cc +++ b/absl/strings/string_view_test.cc
@@ -14,8 +14,6 @@ #include "absl/strings/string_view.h" -#include <stdlib.h> - #include <array> #include <cstddef> #include <cstdlib> @@ -35,740 +33,8 @@ #include "absl/base/config.h" #include "absl/meta/type_traits.h" -#ifdef __has_include -#if __has_include(<version>) -#include <version> // NOLINT(misc-include-cleaner) -#endif -#endif - -#if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L -#include <ranges> // NOLINT(build/c++20) -#endif - -#if defined(ABSL_USES_STD_STRING_VIEW) || defined(__ANDROID__) -// We don't control the death messaging when using std::string_view. -// Android assert messages only go to system log, so death tests cannot inspect -// the message for matching. -#define ABSL_EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ - EXPECT_DEATH_IF_SUPPORTED(statement, ".*") -#else -#define ABSL_EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ - EXPECT_DEATH_IF_SUPPORTED(statement, regex) -#endif - namespace { -static_assert(!absl::type_traits_internal::IsOwner<absl::string_view>::value && - absl::type_traits_internal::IsView<absl::string_view>::value, - "string_view is a view, not an owner"); - -static_assert(absl::type_traits_internal::IsLifetimeBoundAssignment< - absl::string_view, std::string>::value, - "lifetimebound assignment not detected"); - -#if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L -// NOLINTNEXTLINE(build/c++20) -static_assert(std::ranges::enable_view<absl::string_view>, - "std::ranges::view not enabled"); -// NOLINTNEXTLINE(build/c++20) -static_assert(std::ranges::enable_borrowed_range<absl::string_view>, - "std::ranges::borrowed_range not enabled"); -#endif - -// A minimal allocator that uses malloc(). -template <typename T> -struct Mallocator { - typedef T value_type; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - - size_type max_size() const { - return size_t(std::numeric_limits<size_type>::max()) / sizeof(value_type); - } - template <typename U> - struct rebind { - typedef Mallocator<U> other; - }; - Mallocator() = default; - template <class U> - Mallocator(const Mallocator<U>&) {} // NOLINT(runtime/explicit) - - T* allocate(size_t n) { return static_cast<T*>(std::malloc(n * sizeof(T))); } - void deallocate(T* p, size_t) { std::free(p); } -}; -template <typename T, typename U> -bool operator==(const Mallocator<T>&, const Mallocator<U>&) { - return true; -} -template <typename T, typename U> -bool operator!=(const Mallocator<T>&, const Mallocator<U>&) { - return false; -} - -TEST(StringViewTest, Ctor) { - { - // Null. - absl::string_view s10; - EXPECT_TRUE(s10.data() == nullptr); - EXPECT_EQ(0u, s10.length()); - } - - { - // const char* without length. - const char* hello = "hello"; - absl::string_view s20(hello); - EXPECT_TRUE(s20.data() == hello); - EXPECT_EQ(5u, s20.length()); - - // const char* with length. - absl::string_view s21(hello, 4); - EXPECT_TRUE(s21.data() == hello); - EXPECT_EQ(4u, s21.length()); - - // Not recommended, but valid C++ - absl::string_view s22(hello, 6); - EXPECT_TRUE(s22.data() == hello); - EXPECT_EQ(6u, s22.length()); - } - - { - // std::string. - std::string hola = "hola"; - absl::string_view s30(hola); - EXPECT_TRUE(s30.data() == hola.data()); - EXPECT_EQ(4u, s30.length()); - - // std::string with embedded '\0'. - hola.push_back('\0'); - hola.append("h2"); - hola.push_back('\0'); - absl::string_view s31(hola); - EXPECT_TRUE(s31.data() == hola.data()); - EXPECT_EQ(8u, s31.length()); - } - -#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L - { - // Iterator constructor - std::string str = "hello"; - absl::string_view s1(str.begin(), str.end()); - EXPECT_EQ(s1, "hello"); - - std::array<char, 3> arr = { '1', '2', '3' }; - absl::string_view s2(arr.begin(), arr.end()); - EXPECT_EQ(s2, "123"); - - const char carr[] = "carr"; - absl::string_view s3(carr, carr + strlen(carr)); - EXPECT_EQ(s3, "carr"); - } -#endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L - - { - using mstring = - std::basic_string<char, std::char_traits<char>, Mallocator<char>>; - mstring str1("BUNGIE-JUMPING!"); - const mstring str2("SLEEPING!"); - - absl::string_view s1(str1); - s1.remove_prefix(strlen("BUNGIE-JUM")); - - absl::string_view s2(str2); - s2.remove_prefix(strlen("SLEE")); - - EXPECT_EQ(s1, s2); - EXPECT_EQ(s1, "PING!"); - } - - // TODO(mec): absl::string_view(const absl::string_view&); -} - -TEST(StringViewTest, Swap) { - absl::string_view a("a"); - absl::string_view b("bbb"); - EXPECT_TRUE(noexcept(a.swap(b))); - a.swap(b); - EXPECT_EQ(a, "bbb"); - EXPECT_EQ(b, "a"); - a.swap(b); - EXPECT_EQ(a, "a"); - EXPECT_EQ(b, "bbb"); -} - -TEST(StringViewTest, STLComparator) { - std::string s1("foo"); - std::string s2("bar"); - std::string s3("baz"); - - absl::string_view p1(s1); - absl::string_view p2(s2); - absl::string_view p3(s3); - - typedef std::map<absl::string_view, int> TestMap; - TestMap map; - - map.insert(std::make_pair(p1, 0)); - map.insert(std::make_pair(p2, 1)); - map.insert(std::make_pair(p3, 2)); - EXPECT_EQ(map.size(), 3u); - - TestMap::const_iterator iter = map.begin(); - EXPECT_EQ(iter->second, 1); - ++iter; - EXPECT_EQ(iter->second, 2); - ++iter; - EXPECT_EQ(iter->second, 0); - ++iter; - EXPECT_TRUE(iter == map.end()); - - TestMap::iterator new_iter = map.find("zot"); - EXPECT_TRUE(new_iter == map.end()); - - new_iter = map.find("bar"); - EXPECT_TRUE(new_iter != map.end()); - - map.erase(new_iter); - EXPECT_EQ(map.size(), 2u); - - iter = map.begin(); - EXPECT_EQ(iter->second, 2); - ++iter; - EXPECT_EQ(iter->second, 0); - ++iter; - EXPECT_TRUE(iter == map.end()); -} - -#define COMPARE(result, op, x, y) \ - EXPECT_EQ(result, absl::string_view((x)) op absl::string_view((y))); \ - EXPECT_EQ(result, absl::string_view((x)).compare(absl::string_view((y))) op 0) - -TEST(StringViewTest, ComparisonOperators) { - COMPARE(true, ==, "", ""); - COMPARE(true, ==, "", absl::string_view()); - COMPARE(true, ==, absl::string_view(), ""); - COMPARE(true, ==, "a", "a"); - COMPARE(true, ==, "aa", "aa"); - COMPARE(false, ==, "a", ""); - COMPARE(false, ==, "", "a"); - COMPARE(false, ==, "a", "b"); - COMPARE(false, ==, "a", "aa"); - COMPARE(false, ==, "aa", "a"); - - COMPARE(false, !=, "", ""); - COMPARE(false, !=, "a", "a"); - COMPARE(false, !=, "aa", "aa"); - COMPARE(true, !=, "a", ""); - COMPARE(true, !=, "", "a"); - COMPARE(true, !=, "a", "b"); - COMPARE(true, !=, "a", "aa"); - COMPARE(true, !=, "aa", "a"); - - COMPARE(true, <, "a", "b"); - COMPARE(true, <, "a", "aa"); - COMPARE(true, <, "aa", "b"); - COMPARE(true, <, "aa", "bb"); - COMPARE(false, <, "a", "a"); - COMPARE(false, <, "b", "a"); - COMPARE(false, <, "aa", "a"); - COMPARE(false, <, "b", "aa"); - COMPARE(false, <, "bb", "aa"); - - COMPARE(true, <=, "a", "a"); - COMPARE(true, <=, "a", "b"); - COMPARE(true, <=, "a", "aa"); - COMPARE(true, <=, "aa", "b"); - COMPARE(true, <=, "aa", "bb"); - COMPARE(false, <=, "b", "a"); - COMPARE(false, <=, "aa", "a"); - COMPARE(false, <=, "b", "aa"); - COMPARE(false, <=, "bb", "aa"); - - COMPARE(false, >=, "a", "b"); - COMPARE(false, >=, "a", "aa"); - COMPARE(false, >=, "aa", "b"); - COMPARE(false, >=, "aa", "bb"); - COMPARE(true, >=, "a", "a"); - COMPARE(true, >=, "b", "a"); - COMPARE(true, >=, "aa", "a"); - COMPARE(true, >=, "b", "aa"); - COMPARE(true, >=, "bb", "aa"); - - COMPARE(false, >, "a", "a"); - COMPARE(false, >, "a", "b"); - COMPARE(false, >, "a", "aa"); - COMPARE(false, >, "aa", "b"); - COMPARE(false, >, "aa", "bb"); - COMPARE(true, >, "b", "a"); - COMPARE(true, >, "aa", "a"); - COMPARE(true, >, "b", "aa"); - COMPARE(true, >, "bb", "aa"); -} - -TEST(StringViewTest, ComparisonOperatorsByCharacterPosition) { - std::string x; - for (size_t i = 0; i < 256; i++) { - x += 'a'; - std::string y = x; - COMPARE(true, ==, x, y); - for (size_t j = 0; j < i; j++) { - std::string z = x; - z[j] = 'b'; // Differs in position 'j' - COMPARE(false, ==, x, z); - COMPARE(true, <, x, z); - COMPARE(true, >, z, x); - if (j + 1 < i) { - z[j + 1] = 'A'; // Differs in position 'j+1' as well - COMPARE(false, ==, x, z); - COMPARE(true, <, x, z); - COMPARE(true, >, z, x); - z[j + 1] = 'z'; // Differs in position 'j+1' as well - COMPARE(false, ==, x, z); - COMPARE(true, <, x, z); - COMPARE(true, >, z, x); - } - } - } -} -#undef COMPARE - -// Sadly, our users often confuse std::string::npos with -// absl::string_view::npos; So much so that we test here that they are the same. -// They need to both be unsigned, and both be the maximum-valued integer of -// their type. - -template <typename T> -struct is_type { - template <typename U> - static bool same(U) { - return false; - } - static bool same(T) { return true; } -}; - -TEST(StringViewTest, NposMatchesStdStringView) { - EXPECT_EQ(absl::string_view::npos, std::string::npos); - - EXPECT_TRUE(is_type<size_t>::same(absl::string_view::npos)); - EXPECT_FALSE(is_type<size_t>::same("")); - - // Make sure absl::string_view::npos continues to be a header constant. - char test[absl::string_view::npos & 1] = {0}; - EXPECT_EQ(0, test[0]); -} - -TEST(StringViewTest, STL1) { - const absl::string_view a("abcdefghijklmnopqrstuvwxyz"); - const absl::string_view b("abc"); - const absl::string_view c("xyz"); - const absl::string_view d("foobar"); - const absl::string_view e; - std::string temp("123"); - temp += '\0'; - temp += "456"; - const absl::string_view f(temp); - - EXPECT_EQ(a[6], 'g'); - EXPECT_EQ(b[0], 'a'); - EXPECT_EQ(c[2], 'z'); - EXPECT_EQ(f[3], '\0'); - EXPECT_EQ(f[5], '5'); - - EXPECT_EQ(*d.data(), 'f'); - EXPECT_EQ(d.data()[5], 'r'); - EXPECT_TRUE(e.data() == nullptr); - - EXPECT_EQ(*a.begin(), 'a'); - EXPECT_EQ(*(b.begin() + 2), 'c'); - EXPECT_EQ(*(c.end() - 1), 'z'); - - EXPECT_EQ(*a.rbegin(), 'z'); - EXPECT_EQ(*(b.rbegin() + 2), 'a'); - EXPECT_EQ(*(c.rend() - 1), 'x'); - EXPECT_TRUE(a.rbegin() + 26 == a.rend()); - - EXPECT_EQ(a.size(), 26u); - EXPECT_EQ(b.size(), 3u); - EXPECT_EQ(c.size(), 3u); - EXPECT_EQ(d.size(), 6u); - EXPECT_EQ(e.size(), 0u); - EXPECT_EQ(f.size(), 7u); - - EXPECT_TRUE(!d.empty()); - EXPECT_TRUE(d.begin() != d.end()); - EXPECT_TRUE(d.begin() + 6 == d.end()); - - EXPECT_TRUE(e.empty()); - EXPECT_TRUE(e.begin() == e.end()); - - char buf[4] = { '%', '%', '%', '%' }; - EXPECT_EQ(a.copy(buf, 4), 4u); - EXPECT_EQ(buf[0], a[0]); - EXPECT_EQ(buf[1], a[1]); - EXPECT_EQ(buf[2], a[2]); - EXPECT_EQ(buf[3], a[3]); - EXPECT_EQ(a.copy(buf, 3, 7), 3u); - EXPECT_EQ(buf[0], a[7]); - EXPECT_EQ(buf[1], a[8]); - EXPECT_EQ(buf[2], a[9]); - EXPECT_EQ(buf[3], a[3]); - EXPECT_EQ(c.copy(buf, 99), 3u); - EXPECT_EQ(buf[0], c[0]); - EXPECT_EQ(buf[1], c[1]); - EXPECT_EQ(buf[2], c[2]); - EXPECT_EQ(buf[3], a[3]); -#ifdef ABSL_HAVE_EXCEPTIONS - EXPECT_THROW(a.copy(buf, 1, 27), std::out_of_range); -#else - ABSL_EXPECT_DEATH_IF_SUPPORTED(a.copy(buf, 1, 27), "absl::string_view::copy"); -#endif -} - -// Separated from STL1() because some compilers produce an overly -// large stack frame for the combined function. -TEST(StringViewTest, STL2) { - const absl::string_view a("abcdefghijklmnopqrstuvwxyz"); - const absl::string_view b("abc"); - const absl::string_view c("xyz"); - absl::string_view d("foobar"); - const absl::string_view e; - const absl::string_view f( - "123" - "\0" - "456", - 7); - - d = absl::string_view(); - EXPECT_EQ(d.size(), 0u); - EXPECT_TRUE(d.empty()); - EXPECT_TRUE(d.data() == nullptr); - EXPECT_TRUE(d.begin() == d.end()); - - EXPECT_EQ(a.find(b), 0u); - EXPECT_EQ(a.find(b, 1), absl::string_view::npos); - EXPECT_EQ(a.find(c), 23u); - EXPECT_EQ(a.find(c, 9), 23u); - EXPECT_EQ(a.find(c, absl::string_view::npos), absl::string_view::npos); - EXPECT_EQ(b.find(c), absl::string_view::npos); - EXPECT_EQ(b.find(c, absl::string_view::npos), absl::string_view::npos); - EXPECT_EQ(a.find(d), 0u); - EXPECT_EQ(a.find(e), 0u); - EXPECT_EQ(a.find(d, 12), 12u); - EXPECT_EQ(a.find(e, 17), 17u); - absl::string_view g("xx not found bb"); - EXPECT_EQ(a.find(g), absl::string_view::npos); - // empty string nonsense - EXPECT_EQ(d.find(b), absl::string_view::npos); - EXPECT_EQ(e.find(b), absl::string_view::npos); - EXPECT_EQ(d.find(b, 4), absl::string_view::npos); - EXPECT_EQ(e.find(b, 7), absl::string_view::npos); - - size_t empty_search_pos = std::string().find(std::string()); - EXPECT_EQ(d.find(d), empty_search_pos); - EXPECT_EQ(d.find(e), empty_search_pos); - EXPECT_EQ(e.find(d), empty_search_pos); - EXPECT_EQ(e.find(e), empty_search_pos); - EXPECT_EQ(d.find(d, 4), std::string().find(std::string(), 4)); - EXPECT_EQ(d.find(e, 4), std::string().find(std::string(), 4)); - EXPECT_EQ(e.find(d, 4), std::string().find(std::string(), 4)); - EXPECT_EQ(e.find(e, 4), std::string().find(std::string(), 4)); - - EXPECT_EQ(a.find('a'), 0u); - EXPECT_EQ(a.find('c'), 2u); - EXPECT_EQ(a.find('z'), 25u); - EXPECT_EQ(a.find('$'), absl::string_view::npos); - EXPECT_EQ(a.find('\0'), absl::string_view::npos); - EXPECT_EQ(f.find('\0'), 3u); - EXPECT_EQ(f.find('3'), 2u); - EXPECT_EQ(f.find('5'), 5u); - EXPECT_EQ(g.find('o'), 4u); - EXPECT_EQ(g.find('o', 4), 4u); - EXPECT_EQ(g.find('o', 5), 8u); - EXPECT_EQ(a.find('b', 5), absl::string_view::npos); - // empty string nonsense - EXPECT_EQ(d.find('\0'), absl::string_view::npos); - EXPECT_EQ(e.find('\0'), absl::string_view::npos); - EXPECT_EQ(d.find('\0', 4), absl::string_view::npos); - EXPECT_EQ(e.find('\0', 7), absl::string_view::npos); - EXPECT_EQ(d.find('x'), absl::string_view::npos); - EXPECT_EQ(e.find('x'), absl::string_view::npos); - EXPECT_EQ(d.find('x', 4), absl::string_view::npos); - EXPECT_EQ(e.find('x', 7), absl::string_view::npos); - - EXPECT_EQ(a.find(b.data(), 1, 0), 1u); - EXPECT_EQ(a.find(c.data(), 9, 0), 9u); - EXPECT_EQ(a.find(c.data(), absl::string_view::npos, 0), - absl::string_view::npos); - EXPECT_EQ(b.find(c.data(), absl::string_view::npos, 0), - absl::string_view::npos); - // empty string nonsense - EXPECT_EQ(d.find(b.data(), 4, 0), absl::string_view::npos); - EXPECT_EQ(e.find(b.data(), 7, 0), absl::string_view::npos); - - EXPECT_EQ(a.find(b.data(), 1), absl::string_view::npos); - EXPECT_EQ(a.find(c.data(), 9), 23u); - EXPECT_EQ(a.find(c.data(), absl::string_view::npos), absl::string_view::npos); - EXPECT_EQ(b.find(c.data(), absl::string_view::npos), absl::string_view::npos); - // empty string nonsense - EXPECT_EQ(d.find(b.data(), 4), absl::string_view::npos); - EXPECT_EQ(e.find(b.data(), 7), absl::string_view::npos); - - EXPECT_EQ(a.rfind(b), 0u); - EXPECT_EQ(a.rfind(b, 1), 0u); - EXPECT_EQ(a.rfind(c), 23u); - EXPECT_EQ(a.rfind(c, 22), absl::string_view::npos); - EXPECT_EQ(a.rfind(c, 1), absl::string_view::npos); - EXPECT_EQ(a.rfind(c, 0), absl::string_view::npos); - EXPECT_EQ(b.rfind(c), absl::string_view::npos); - EXPECT_EQ(b.rfind(c, 0), absl::string_view::npos); - EXPECT_EQ(a.rfind(d), std::string(a).rfind(std::string())); - EXPECT_EQ(a.rfind(e), std::string(a).rfind(std::string())); - EXPECT_EQ(a.rfind(d, 12), 12u); - EXPECT_EQ(a.rfind(e, 17), 17u); - EXPECT_EQ(a.rfind(g), absl::string_view::npos); - EXPECT_EQ(d.rfind(b), absl::string_view::npos); - EXPECT_EQ(e.rfind(b), absl::string_view::npos); - EXPECT_EQ(d.rfind(b, 4), absl::string_view::npos); - EXPECT_EQ(e.rfind(b, 7), absl::string_view::npos); - // empty string nonsense - EXPECT_EQ(d.rfind(d, 4), std::string().rfind(std::string())); - EXPECT_EQ(e.rfind(d, 7), std::string().rfind(std::string())); - EXPECT_EQ(d.rfind(e, 4), std::string().rfind(std::string())); - EXPECT_EQ(e.rfind(e, 7), std::string().rfind(std::string())); - EXPECT_EQ(d.rfind(d), std::string().rfind(std::string())); - EXPECT_EQ(e.rfind(d), std::string().rfind(std::string())); - EXPECT_EQ(d.rfind(e), std::string().rfind(std::string())); - EXPECT_EQ(e.rfind(e), std::string().rfind(std::string())); - - EXPECT_EQ(g.rfind('o'), 8u); - EXPECT_EQ(g.rfind('q'), absl::string_view::npos); - EXPECT_EQ(g.rfind('o', 8), 8u); - EXPECT_EQ(g.rfind('o', 7), 4u); - EXPECT_EQ(g.rfind('o', 3), absl::string_view::npos); - EXPECT_EQ(f.rfind('\0'), 3u); - EXPECT_EQ(f.rfind('\0', 12), 3u); - EXPECT_EQ(f.rfind('3'), 2u); - EXPECT_EQ(f.rfind('5'), 5u); - // empty string nonsense - EXPECT_EQ(d.rfind('o'), absl::string_view::npos); - EXPECT_EQ(e.rfind('o'), absl::string_view::npos); - EXPECT_EQ(d.rfind('o', 4), absl::string_view::npos); - EXPECT_EQ(e.rfind('o', 7), absl::string_view::npos); - - EXPECT_EQ(a.rfind(b.data(), 1, 0), 1u); - EXPECT_EQ(a.rfind(c.data(), 22, 0), 22u); - EXPECT_EQ(a.rfind(c.data(), 1, 0), 1u); - EXPECT_EQ(a.rfind(c.data(), 0, 0), 0u); - EXPECT_EQ(b.rfind(c.data(), 0, 0), 0u); - EXPECT_EQ(d.rfind(b.data(), 4, 0), 0u); - EXPECT_EQ(e.rfind(b.data(), 7, 0), 0u); -} - -// Continued from STL2 -TEST(StringViewTest, STL2FindFirst) { - const absl::string_view a("abcdefghijklmnopqrstuvwxyz"); - const absl::string_view b("abc"); - const absl::string_view c("xyz"); - absl::string_view d("foobar"); - const absl::string_view e; - const absl::string_view f( - "123" - "\0" - "456", - 7); - absl::string_view g("xx not found bb"); - - d = absl::string_view(); - EXPECT_EQ(a.find_first_of(b), 0u); - EXPECT_EQ(a.find_first_of(b, 0), 0u); - EXPECT_EQ(a.find_first_of(b, 1), 1u); - EXPECT_EQ(a.find_first_of(b, 2), 2u); - EXPECT_EQ(a.find_first_of(b, 3), absl::string_view::npos); - EXPECT_EQ(a.find_first_of(c), 23u); - EXPECT_EQ(a.find_first_of(c, 23), 23u); - EXPECT_EQ(a.find_first_of(c, 24), 24u); - EXPECT_EQ(a.find_first_of(c, 25), 25u); - EXPECT_EQ(a.find_first_of(c, 26), absl::string_view::npos); - EXPECT_EQ(g.find_first_of(b), 13u); - EXPECT_EQ(g.find_first_of(c), 0u); - EXPECT_EQ(a.find_first_of(f), absl::string_view::npos); - EXPECT_EQ(f.find_first_of(a), absl::string_view::npos); - // empty string nonsense - EXPECT_EQ(a.find_first_of(d), absl::string_view::npos); - EXPECT_EQ(a.find_first_of(e), absl::string_view::npos); - EXPECT_EQ(d.find_first_of(b), absl::string_view::npos); - EXPECT_EQ(e.find_first_of(b), absl::string_view::npos); - EXPECT_EQ(d.find_first_of(d), absl::string_view::npos); - EXPECT_EQ(e.find_first_of(d), absl::string_view::npos); - EXPECT_EQ(d.find_first_of(e), absl::string_view::npos); - EXPECT_EQ(e.find_first_of(e), absl::string_view::npos); - - EXPECT_EQ(a.find_first_not_of(b), 3u); - EXPECT_EQ(a.find_first_not_of(c), 0u); - EXPECT_EQ(b.find_first_not_of(a), absl::string_view::npos); - EXPECT_EQ(c.find_first_not_of(a), absl::string_view::npos); - EXPECT_EQ(f.find_first_not_of(a), 0u); - EXPECT_EQ(a.find_first_not_of(f), 0u); - EXPECT_EQ(a.find_first_not_of(d), 0u); - EXPECT_EQ(a.find_first_not_of(e), 0u); - // empty string nonsense - EXPECT_EQ(a.find_first_not_of(d), 0u); - EXPECT_EQ(a.find_first_not_of(e), 0u); - EXPECT_EQ(a.find_first_not_of(d, 1), 1u); - EXPECT_EQ(a.find_first_not_of(e, 1), 1u); - EXPECT_EQ(a.find_first_not_of(d, a.size() - 1), a.size() - 1); - EXPECT_EQ(a.find_first_not_of(e, a.size() - 1), a.size() - 1); - EXPECT_EQ(a.find_first_not_of(d, a.size()), absl::string_view::npos); - EXPECT_EQ(a.find_first_not_of(e, a.size()), absl::string_view::npos); - EXPECT_EQ(a.find_first_not_of(d, absl::string_view::npos), - absl::string_view::npos); - EXPECT_EQ(a.find_first_not_of(e, absl::string_view::npos), - absl::string_view::npos); - EXPECT_EQ(d.find_first_not_of(a), absl::string_view::npos); - EXPECT_EQ(e.find_first_not_of(a), absl::string_view::npos); - EXPECT_EQ(d.find_first_not_of(d), absl::string_view::npos); - EXPECT_EQ(e.find_first_not_of(d), absl::string_view::npos); - EXPECT_EQ(d.find_first_not_of(e), absl::string_view::npos); - EXPECT_EQ(e.find_first_not_of(e), absl::string_view::npos); - - absl::string_view h("===="); - EXPECT_EQ(h.find_first_not_of('='), absl::string_view::npos); - EXPECT_EQ(h.find_first_not_of('=', 3), absl::string_view::npos); - EXPECT_EQ(h.find_first_not_of('\0'), 0u); - EXPECT_EQ(g.find_first_not_of('x'), 2u); - EXPECT_EQ(f.find_first_not_of('\0'), 0u); - EXPECT_EQ(f.find_first_not_of('\0', 3), 4u); - EXPECT_EQ(f.find_first_not_of('\0', 2), 2u); - // empty string nonsense - EXPECT_EQ(d.find_first_not_of('x'), absl::string_view::npos); - EXPECT_EQ(e.find_first_not_of('x'), absl::string_view::npos); - EXPECT_EQ(d.find_first_not_of('\0'), absl::string_view::npos); - EXPECT_EQ(e.find_first_not_of('\0'), absl::string_view::npos); -} - -// Continued from STL2 -TEST(StringViewTest, STL2FindLast) { - const absl::string_view a("abcdefghijklmnopqrstuvwxyz"); - const absl::string_view b("abc"); - const absl::string_view c("xyz"); - absl::string_view d("foobar"); - const absl::string_view e; - const absl::string_view f( - "123" - "\0" - "456", - 7); - absl::string_view g("xx not found bb"); - absl::string_view h("===="); - absl::string_view i("56"); - - d = absl::string_view(); - EXPECT_EQ(h.find_last_of(a), absl::string_view::npos); - EXPECT_EQ(g.find_last_of(a), g.size() - 1); - EXPECT_EQ(a.find_last_of(b), 2u); - EXPECT_EQ(a.find_last_of(c), a.size() - 1); - EXPECT_EQ(f.find_last_of(i), 6u); - EXPECT_EQ(a.find_last_of('a'), 0u); - EXPECT_EQ(a.find_last_of('b'), 1u); - EXPECT_EQ(a.find_last_of('z'), 25u); - EXPECT_EQ(a.find_last_of('a', 5), 0u); - EXPECT_EQ(a.find_last_of('b', 5), 1u); - EXPECT_EQ(a.find_last_of('b', 0), absl::string_view::npos); - EXPECT_EQ(a.find_last_of('z', 25), 25u); - EXPECT_EQ(a.find_last_of('z', 24), absl::string_view::npos); - EXPECT_EQ(f.find_last_of(i, 5), 5u); - EXPECT_EQ(f.find_last_of(i, 6), 6u); - EXPECT_EQ(f.find_last_of(a, 4), absl::string_view::npos); - // empty string nonsense - EXPECT_EQ(f.find_last_of(d), absl::string_view::npos); - EXPECT_EQ(f.find_last_of(e), absl::string_view::npos); - EXPECT_EQ(f.find_last_of(d, 4), absl::string_view::npos); - EXPECT_EQ(f.find_last_of(e, 4), absl::string_view::npos); - EXPECT_EQ(d.find_last_of(d), absl::string_view::npos); - EXPECT_EQ(d.find_last_of(e), absl::string_view::npos); - EXPECT_EQ(e.find_last_of(d), absl::string_view::npos); - EXPECT_EQ(e.find_last_of(e), absl::string_view::npos); - EXPECT_EQ(d.find_last_of(f), absl::string_view::npos); - EXPECT_EQ(e.find_last_of(f), absl::string_view::npos); - EXPECT_EQ(d.find_last_of(d, 4), absl::string_view::npos); - EXPECT_EQ(d.find_last_of(e, 4), absl::string_view::npos); - EXPECT_EQ(e.find_last_of(d, 4), absl::string_view::npos); - EXPECT_EQ(e.find_last_of(e, 4), absl::string_view::npos); - EXPECT_EQ(d.find_last_of(f, 4), absl::string_view::npos); - EXPECT_EQ(e.find_last_of(f, 4), absl::string_view::npos); - - EXPECT_EQ(a.find_last_not_of(b), a.size() - 1); - EXPECT_EQ(a.find_last_not_of(c), 22u); - EXPECT_EQ(b.find_last_not_of(a), absl::string_view::npos); - EXPECT_EQ(b.find_last_not_of(b), absl::string_view::npos); - EXPECT_EQ(f.find_last_not_of(i), 4u); - EXPECT_EQ(a.find_last_not_of(c, 24), 22u); - EXPECT_EQ(a.find_last_not_of(b, 3), 3u); - EXPECT_EQ(a.find_last_not_of(b, 2), absl::string_view::npos); - // empty string nonsense - EXPECT_EQ(f.find_last_not_of(d), f.size() - 1); - EXPECT_EQ(f.find_last_not_of(e), f.size() - 1); - EXPECT_EQ(f.find_last_not_of(d, 4), 4u); - EXPECT_EQ(f.find_last_not_of(e, 4), 4u); - EXPECT_EQ(d.find_last_not_of(d), absl::string_view::npos); - EXPECT_EQ(d.find_last_not_of(e), absl::string_view::npos); - EXPECT_EQ(e.find_last_not_of(d), absl::string_view::npos); - EXPECT_EQ(e.find_last_not_of(e), absl::string_view::npos); - EXPECT_EQ(d.find_last_not_of(f), absl::string_view::npos); - EXPECT_EQ(e.find_last_not_of(f), absl::string_view::npos); - EXPECT_EQ(d.find_last_not_of(d, 4), absl::string_view::npos); - EXPECT_EQ(d.find_last_not_of(e, 4), absl::string_view::npos); - EXPECT_EQ(e.find_last_not_of(d, 4), absl::string_view::npos); - EXPECT_EQ(e.find_last_not_of(e, 4), absl::string_view::npos); - EXPECT_EQ(d.find_last_not_of(f, 4), absl::string_view::npos); - EXPECT_EQ(e.find_last_not_of(f, 4), absl::string_view::npos); - - EXPECT_EQ(h.find_last_not_of('x'), h.size() - 1); - EXPECT_EQ(h.find_last_not_of('='), absl::string_view::npos); - EXPECT_EQ(b.find_last_not_of('c'), 1u); - EXPECT_EQ(h.find_last_not_of('x', 2), 2u); - EXPECT_EQ(h.find_last_not_of('=', 2), absl::string_view::npos); - EXPECT_EQ(b.find_last_not_of('b', 1), 0u); - // empty string nonsense - EXPECT_EQ(d.find_last_not_of('x'), absl::string_view::npos); - EXPECT_EQ(e.find_last_not_of('x'), absl::string_view::npos); - EXPECT_EQ(d.find_last_not_of('\0'), absl::string_view::npos); - EXPECT_EQ(e.find_last_not_of('\0'), absl::string_view::npos); -} - -// Continued from STL2 -TEST(StringViewTest, STL2Substr) { - const absl::string_view a("abcdefghijklmnopqrstuvwxyz"); - const absl::string_view b("abc"); - const absl::string_view c("xyz"); - absl::string_view d("foobar"); - const absl::string_view e; - - d = absl::string_view(); - EXPECT_EQ(a.substr(0, 3), b); - EXPECT_EQ(a.substr(23), c); - EXPECT_EQ(a.substr(23, 3), c); - EXPECT_EQ(a.substr(23, 99), c); - EXPECT_EQ(a.substr(0), a); - EXPECT_EQ(a.substr(), a); - EXPECT_EQ(a.substr(3, 2), "de"); - // empty string nonsense - EXPECT_EQ(d.substr(0, 99), e); - // use of npos - EXPECT_EQ(a.substr(0, absl::string_view::npos), a); - EXPECT_EQ(a.substr(23, absl::string_view::npos), c); - // throw exception -#ifdef ABSL_HAVE_EXCEPTIONS - EXPECT_THROW((void)a.substr(99, 2), std::out_of_range); -#else - ABSL_EXPECT_DEATH_IF_SUPPORTED((void)a.substr(99, 2), - "absl::string_view::substr"); -#endif -} - TEST(StringViewTest, TruncSubstr) { const absl::string_view hi("hi"); EXPECT_EQ("", absl::ClippedSubstr(hi, 0, 0)); @@ -780,272 +46,6 @@ EXPECT_EQ("", absl::ClippedSubstr(hi, 3, 2)); // truncation } -TEST(StringViewTest, UTF8) { - std::string utf8 = "\u00E1"; - std::string utf8_twice = utf8 + " " + utf8; - size_t utf8_len = strlen(utf8.data()); - EXPECT_EQ(utf8_len, absl::string_view(utf8_twice).find_first_of(" ")); - EXPECT_EQ(utf8_len, absl::string_view(utf8_twice).find_first_of(" \t")); -} - -TEST(StringViewTest, FindConformance) { - struct { - std::string haystack; - std::string needle; - } specs[] = { - {"", ""}, - {"", "a"}, - {"a", ""}, - {"a", "a"}, - {"a", "b"}, - {"aa", ""}, - {"aa", "a"}, - {"aa", "b"}, - {"ab", "a"}, - {"ab", "b"}, - {"abcd", ""}, - {"abcd", "a"}, - {"abcd", "d"}, - {"abcd", "ab"}, - {"abcd", "bc"}, - {"abcd", "cd"}, - {"abcd", "abcd"}, - }; - for (const auto& s : specs) { - SCOPED_TRACE(s.haystack); - SCOPED_TRACE(s.needle); - std::string st = s.haystack; - absl::string_view sp = s.haystack; - for (size_t i = 0; i <= sp.size(); ++i) { - size_t pos = (i == sp.size()) ? absl::string_view::npos : i; - SCOPED_TRACE(pos); - EXPECT_EQ(sp.find(s.needle, pos), - st.find(s.needle, pos)); - EXPECT_EQ(sp.rfind(s.needle, pos), - st.rfind(s.needle, pos)); - EXPECT_EQ(sp.find_first_of(s.needle, pos), - st.find_first_of(s.needle, pos)); - EXPECT_EQ(sp.find_first_not_of(s.needle, pos), - st.find_first_not_of(s.needle, pos)); - EXPECT_EQ(sp.find_last_of(s.needle, pos), - st.find_last_of(s.needle, pos)); - EXPECT_EQ(sp.find_last_not_of(s.needle, pos), - st.find_last_not_of(s.needle, pos)); - } - } -} - -TEST(StringViewTest, Remove) { - absl::string_view a("foobar"); - std::string s1("123"); - s1 += '\0'; - s1 += "456"; - absl::string_view e; - std::string s2; - - // remove_prefix - absl::string_view c(a); - c.remove_prefix(3); - EXPECT_EQ(c, "bar"); - c = a; - c.remove_prefix(0); - EXPECT_EQ(c, a); - c.remove_prefix(c.size()); - EXPECT_EQ(c, e); - - // remove_suffix - c = a; - c.remove_suffix(3); - EXPECT_EQ(c, "foo"); - c = a; - c.remove_suffix(0); - EXPECT_EQ(c, a); - c.remove_suffix(c.size()); - EXPECT_EQ(c, e); -} - -TEST(StringViewTest, Set) { - absl::string_view a("foobar"); - absl::string_view empty; - absl::string_view b; - - // set - b = absl::string_view("foobar", 6); - EXPECT_EQ(b, a); - b = absl::string_view("foobar", 0); - EXPECT_EQ(b, empty); - b = absl::string_view("foobar", 7); - EXPECT_NE(b, a); - - b = absl::string_view("foobar"); - EXPECT_EQ(b, a); -} - -TEST(StringViewTest, FrontBack) { - static const char arr[] = "abcd"; - const absl::string_view csp(arr, 4); - EXPECT_EQ(&arr[0], &csp.front()); - EXPECT_EQ(&arr[3], &csp.back()); -} - -TEST(StringViewTest, FrontBackSingleChar) { - static const char c = 'a'; - const absl::string_view csp(&c, 1); - EXPECT_EQ(&c, &csp.front()); - EXPECT_EQ(&c, &csp.back()); -} - -TEST(StringViewTest, FrontBackEmpty) { -#ifndef ABSL_USES_STD_STRING_VIEW -#if !defined(NDEBUG) || ABSL_OPTION_HARDENED - // Abseil's string_view implementation has debug assertions that check that - // front() and back() are not called on an empty string_view. - absl::string_view sv; - ABSL_EXPECT_DEATH_IF_SUPPORTED(sv.front(), ""); - ABSL_EXPECT_DEATH_IF_SUPPORTED(sv.back(), ""); -#endif -#endif -} - -TEST(StringViewTest, DefaultConstructor) { - absl::string_view s; - EXPECT_EQ(s.data(), nullptr); - EXPECT_EQ(s.size(), 0u); -} - -TEST(StringViewTest, Comparisons2) { - // The `compare` member has 6 overloads (v: string_view, s: const char*): - // (1) compare(v) - // (2) compare(pos1, count1, v) - // (3) compare(pos1, count1, v, pos2, count2) - // (4) compare(s) - // (5) compare(pos1, count1, s) - // (6) compare(pos1, count1, s, count2) - - absl::string_view abc("abcdefghijklmnopqrstuvwxyz"); - - // check comparison operations on strings longer than 4 bytes. - EXPECT_EQ(abc, absl::string_view("abcdefghijklmnopqrstuvwxyz")); - EXPECT_EQ(abc.compare(absl::string_view("abcdefghijklmnopqrstuvwxyz")), 0); - - EXPECT_LT(abc, absl::string_view("abcdefghijklmnopqrstuvwxzz")); - EXPECT_LT(abc.compare(absl::string_view("abcdefghijklmnopqrstuvwxzz")), 0); - - EXPECT_GT(abc, absl::string_view("abcdefghijklmnopqrstuvwxyy")); - EXPECT_GT(abc.compare(absl::string_view("abcdefghijklmnopqrstuvwxyy")), 0); - - // The "substr" variants of `compare`. - absl::string_view digits("0123456789"); - auto npos = absl::string_view::npos; - - // Taking string_view - EXPECT_EQ(digits.compare(3, npos, absl::string_view("3456789")), 0); // 2 - EXPECT_EQ(digits.compare(3, 4, absl::string_view("3456")), 0); // 2 - EXPECT_EQ(digits.compare(10, 0, absl::string_view()), 0); // 2 - EXPECT_EQ(digits.compare(3, 4, absl::string_view("0123456789"), 3, 4), - 0); // 3 - EXPECT_LT(digits.compare(3, 4, absl::string_view("0123456789"), 3, 5), - 0); // 3 - EXPECT_LT(digits.compare(0, npos, absl::string_view("0123456789"), 3, 5), - 0); // 3 - // Taking const char* - EXPECT_EQ(digits.compare(3, 4, "3456"), 0); // 5 - EXPECT_EQ(digits.compare(3, npos, "3456789"), 0); // 5 - EXPECT_EQ(digits.compare(10, 0, ""), 0); // 5 - EXPECT_EQ(digits.compare(3, 4, "0123456789", 3, 4), 0); // 6 - EXPECT_LT(digits.compare(3, 4, "0123456789", 3, 5), 0); // 6 - EXPECT_LT(digits.compare(0, npos, "0123456789", 3, 5), 0); // 6 -} - -TEST(StringViewTest, At) { - absl::string_view abc = "abc"; - EXPECT_EQ(abc.at(0), 'a'); - EXPECT_EQ(abc.at(1), 'b'); - EXPECT_EQ(abc.at(2), 'c'); -#ifdef ABSL_HAVE_EXCEPTIONS - EXPECT_THROW((void)abc.at(3), std::out_of_range); -#else - ABSL_EXPECT_DEATH_IF_SUPPORTED((void)abc.at(3), "absl::string_view::at"); -#endif -} - -#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L -TEST(StringViewTest, StartsWith) { - const absl::string_view a("foobar"); - const absl::string_view b("123\0abc", 7); - const absl::string_view e; - EXPECT_TRUE(a.starts_with(a)); - EXPECT_TRUE(a.starts_with("foo")); - EXPECT_TRUE(a.starts_with('f')); - EXPECT_TRUE(a.starts_with(e)); - EXPECT_TRUE(b.starts_with(b)); - EXPECT_TRUE(b.starts_with('1')); - EXPECT_TRUE(b.starts_with(e)); - EXPECT_TRUE(e.starts_with("")); - EXPECT_FALSE(a.starts_with(b)); - EXPECT_FALSE(b.starts_with(a)); - EXPECT_FALSE(e.starts_with(a)); - EXPECT_FALSE(a.starts_with('r')); - EXPECT_FALSE(a.starts_with('\0')); - EXPECT_FALSE(e.starts_with('r')); - EXPECT_FALSE(e.starts_with('\0')); - - // Test that constexpr compiles. - constexpr absl::string_view kFooBar("foobar"); - constexpr absl::string_view kFoo("foo"); - constexpr absl::string_view kBar("bar"); - constexpr bool k1 = kFooBar.starts_with(kFoo); - EXPECT_TRUE(k1); - constexpr bool k2 = kFooBar.starts_with(kBar); - EXPECT_FALSE(k2); - constexpr bool k3 = kFooBar.starts_with('f'); - EXPECT_TRUE(k3); - constexpr bool k4 = kFooBar.starts_with("fo"); - EXPECT_TRUE(k4); -} - -TEST(StringViewTest, EndsWith) { - const absl::string_view a("foobar"); - const absl::string_view b("123\0abc", 7); - const absl::string_view e; - EXPECT_TRUE(a.ends_with(a)); - EXPECT_TRUE(a.ends_with('r')); - EXPECT_TRUE(a.ends_with("bar")); - EXPECT_TRUE(a.ends_with(e)); - EXPECT_TRUE(b.ends_with(b)); - EXPECT_TRUE(b.ends_with('c')); - EXPECT_TRUE(b.ends_with(e)); - EXPECT_TRUE(e.ends_with("")); - EXPECT_FALSE(a.ends_with(b)); - EXPECT_FALSE(b.ends_with(a)); - EXPECT_FALSE(e.ends_with(a)); - EXPECT_FALSE(a.ends_with('f')); - EXPECT_FALSE(a.ends_with('\0')); - EXPECT_FALSE(e.ends_with('r')); - EXPECT_FALSE(e.ends_with('\0')); - - // Test that constexpr compiles. - constexpr absl::string_view kFooBar("foobar"); - constexpr absl::string_view kFoo("foo"); - constexpr absl::string_view kBar("bar"); - constexpr bool k1 = kFooBar.ends_with(kFoo); - EXPECT_FALSE(k1); - constexpr bool k2 = kFooBar.ends_with(kBar); - EXPECT_TRUE(k2); - constexpr bool k3 = kFooBar.ends_with('r'); - EXPECT_TRUE(k3); - constexpr bool k4 = kFooBar.ends_with("ar"); - EXPECT_TRUE(k4); -} -#endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L - -struct MyCharAlloc : std::allocator<char> {}; - -TEST(StringViewTest, ExplicitConversionOperator) { - absl::string_view sp = "hi"; - EXPECT_EQ(sp, std::string(sp)); -} - TEST(StringViewTest, NullSafeStringView) { { absl::string_view s = absl::NullSafeStringView(nullptr); @@ -1083,317 +83,4 @@ } } -TEST(StringViewTest, ConstexprCompiles) { - constexpr absl::string_view sp; - // With `-Wnonnull` turned on, there is no way to test the defensive null - // check in the `string_view(const char*)` constructor in a constexpr context, - // as the argument needs to be constexpr. The compiler will therefore always - // know at compile time that the argument is nullptr and complain because the - // parameter is annotated nonnull. We hence turn the warning off for this - // test. - constexpr absl::string_view cstr_len("cstr", 4); - -#if defined(ABSL_USES_STD_STRING_VIEW) - // In libstdc++ (as of 7.2), `std::string_view::string_view(const char*)` - // calls `std::char_traits<char>::length(const char*)` to get the string - // length, but it is not marked constexpr yet. See GCC bug: - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78156 - // Also, there is a LWG issue that adds constexpr to length() which was just - // resolved 2017-06-02. See - // http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2232 - // TODO(zhangxy): Update the condition when libstdc++ adopts the constexpr - // length(). -#if !defined(__GLIBCXX__) -#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1 -#endif // !__GLIBCXX__ - -#else // ABSL_USES_STD_STRING_VIEW - -// This duplicates the check for __builtin_strlen in the header. -#if ABSL_HAVE_BUILTIN(__builtin_strlen) || \ - (defined(__GNUC__) && !defined(__clang__)) -#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1 -#elif defined(__GNUC__) // GCC or clang -#error GCC/clang should have constexpr string_view. -#endif - -// MSVC 2017+ should be able to construct a constexpr string_view from a cstr. -#if defined(_MSC_VER) -#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1 -#endif - -#endif // ABSL_USES_STD_STRING_VIEW - -#ifdef ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR - constexpr absl::string_view cstr_strlen("foo"); - EXPECT_EQ(cstr_strlen.length(), 3u); - constexpr absl::string_view cstr_strlen2 = "bar"; - EXPECT_EQ(cstr_strlen2, "bar"); - -#if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \ - (defined(__GNUC__) && !defined(__clang__)) -#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_COMPARISON 1 -#endif -#ifdef ABSL_HAVE_CONSTEXPR_STRING_VIEW_COMPARISON - constexpr absl::string_view foo = "foo"; - constexpr absl::string_view bar = "bar"; - constexpr bool foo_eq_bar = foo == bar; - constexpr bool foo_ne_bar = foo != bar; - constexpr bool foo_lt_bar = foo < bar; - constexpr bool foo_le_bar = foo <= bar; - constexpr bool foo_gt_bar = foo > bar; - constexpr bool foo_ge_bar = foo >= bar; - constexpr int foo_compare_bar = foo.compare(bar); - EXPECT_FALSE(foo_eq_bar); - EXPECT_TRUE(foo_ne_bar); - EXPECT_FALSE(foo_lt_bar); - EXPECT_FALSE(foo_le_bar); - EXPECT_TRUE(foo_gt_bar); - EXPECT_TRUE(foo_ge_bar); - EXPECT_GT(foo_compare_bar, 0); -#endif -#endif - - constexpr absl::string_view::iterator const_begin_empty = sp.begin(); - constexpr absl::string_view::iterator const_end_empty = sp.end(); - EXPECT_EQ(const_begin_empty, const_end_empty); - - constexpr absl::string_view::iterator const_begin = cstr_len.begin(); - constexpr absl::string_view::iterator const_end = cstr_len.end(); - constexpr absl::string_view::size_type const_size = cstr_len.size(); - constexpr absl::string_view::size_type const_length = cstr_len.length(); - static_assert(const_begin + const_size == const_end, - "pointer arithmetic check"); - static_assert(const_begin + const_length == const_end, - "pointer arithmetic check"); -#ifndef _MSC_VER - // MSVC has bugs doing constexpr pointer arithmetic. - // https://developercommunity.visualstudio.com/content/problem/482192/bad-pointer-arithmetic-in-constepxr-2019-rc1-svc1.html - EXPECT_EQ(const_begin + const_size, const_end); - EXPECT_EQ(const_begin + const_length, const_end); -#endif - - constexpr bool isempty = sp.empty(); - EXPECT_TRUE(isempty); - - constexpr const char c = cstr_len[2]; - EXPECT_EQ(c, 't'); - - constexpr const char cfront = cstr_len.front(); - constexpr const char cback = cstr_len.back(); - EXPECT_EQ(cfront, 'c'); - EXPECT_EQ(cback, 'r'); - - constexpr const char* np = sp.data(); - constexpr const char* cstr_ptr = cstr_len.data(); - EXPECT_EQ(np, nullptr); - EXPECT_NE(cstr_ptr, nullptr); - - constexpr size_t sp_npos = sp.npos; - EXPECT_EQ(sp_npos, static_cast<size_t>(-1)); - -#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L - { - static constexpr std::array<char, 3> arr = { '1', '2', '3' }; - constexpr absl::string_view s2(arr.begin(), arr.end()); - EXPECT_EQ(s2, "123"); - - static constexpr char carr[] = "carr"; - constexpr absl::string_view s3(carr, carr + 4); - EXPECT_EQ(s3, "carr"); - } -#endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L -} - -constexpr char ConstexprMethodsHelper() { -#if defined(__cplusplus) && __cplusplus >= 201402L - absl::string_view str("123", 3); - str.remove_prefix(1); - str.remove_suffix(1); - absl::string_view bar; - str.swap(bar); - return bar.front(); -#else - return '2'; -#endif -} - -TEST(StringViewTest, ConstexprMethods) { - // remove_prefix, remove_suffix, swap - static_assert(ConstexprMethodsHelper() == '2', ""); - - // substr - constexpr absl::string_view foobar("foobar", 6); - constexpr absl::string_view foo = foobar.substr(0, 3); - constexpr absl::string_view bar = foobar.substr(3); - EXPECT_EQ(foo, "foo"); - EXPECT_EQ(bar, "bar"); -} - -TEST(StringViewTest, Noexcept) { - EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view, - const std::string&>::value)); - EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view, - const std::string&>::value)); - EXPECT_TRUE(std::is_nothrow_constructible<absl::string_view>::value); - constexpr absl::string_view sp; - EXPECT_TRUE(noexcept(sp.begin())); - EXPECT_TRUE(noexcept(sp.end())); - EXPECT_TRUE(noexcept(sp.cbegin())); - EXPECT_TRUE(noexcept(sp.cend())); - EXPECT_TRUE(noexcept(sp.rbegin())); - EXPECT_TRUE(noexcept(sp.rend())); - EXPECT_TRUE(noexcept(sp.crbegin())); - EXPECT_TRUE(noexcept(sp.crend())); - EXPECT_TRUE(noexcept(sp.size())); - EXPECT_TRUE(noexcept(sp.length())); - EXPECT_TRUE(noexcept(sp.empty())); - EXPECT_TRUE(noexcept(sp.data())); - EXPECT_TRUE(noexcept(sp.compare(sp))); - EXPECT_TRUE(noexcept(sp.find(sp))); - EXPECT_TRUE(noexcept(sp.find('f'))); - EXPECT_TRUE(noexcept(sp.rfind(sp))); - EXPECT_TRUE(noexcept(sp.rfind('f'))); - EXPECT_TRUE(noexcept(sp.find_first_of(sp))); - EXPECT_TRUE(noexcept(sp.find_first_of('f'))); - EXPECT_TRUE(noexcept(sp.find_last_of(sp))); - EXPECT_TRUE(noexcept(sp.find_last_of('f'))); - EXPECT_TRUE(noexcept(sp.find_first_not_of(sp))); - EXPECT_TRUE(noexcept(sp.find_first_not_of('f'))); - EXPECT_TRUE(noexcept(sp.find_last_not_of(sp))); - EXPECT_TRUE(noexcept(sp.find_last_not_of('f'))); -} - -TEST(StringViewTest, BoundsCheck) { -#ifndef ABSL_USES_STD_STRING_VIEW -#if !defined(NDEBUG) || ABSL_OPTION_HARDENED - // Abseil's string_view implementation has bounds-checking in debug mode. - absl::string_view h = "hello"; - ABSL_EXPECT_DEATH_IF_SUPPORTED(h[5], ""); - ABSL_EXPECT_DEATH_IF_SUPPORTED(h[static_cast<size_t>(-1)], ""); -#endif -#endif -} - -TEST(ComparisonOpsTest, StringCompareNotAmbiguous) { - EXPECT_EQ("hello", std::string("hello")); - EXPECT_LT("hello", std::string("world")); -} - -TEST(ComparisonOpsTest, HeterogeneousStringViewEquals) { - EXPECT_EQ(absl::string_view("hello"), std::string("hello")); - EXPECT_EQ("hello", absl::string_view("hello")); -} - -TEST(FindOneCharTest, EdgeCases) { - absl::string_view a("xxyyyxx"); - - // Set a = "xyyyx". - a.remove_prefix(1); - a.remove_suffix(1); - - EXPECT_EQ(0u, a.find('x')); - EXPECT_EQ(0u, a.find('x', 0)); - EXPECT_EQ(4u, a.find('x', 1)); - EXPECT_EQ(4u, a.find('x', 4)); - EXPECT_EQ(absl::string_view::npos, a.find('x', 5)); - - EXPECT_EQ(4u, a.rfind('x')); - EXPECT_EQ(4u, a.rfind('x', 5)); - EXPECT_EQ(4u, a.rfind('x', 4)); - EXPECT_EQ(0u, a.rfind('x', 3)); - EXPECT_EQ(0u, a.rfind('x', 0)); - - // Set a = "yyy". - a.remove_prefix(1); - a.remove_suffix(1); - - EXPECT_EQ(absl::string_view::npos, a.find('x')); - EXPECT_EQ(absl::string_view::npos, a.rfind('x')); -} - -#ifndef ABSL_HAVE_THREAD_SANITIZER // Allocates too much memory for tsan. -TEST(HugeStringView, TwoPointTwoGB) { - if (sizeof(size_t) <= 4) - return; - // Try a huge string piece. - const size_t size = size_t{2200} * 1000 * 1000; - std::string s(size, 'a'); - absl::string_view sp(s); - EXPECT_EQ(size, sp.length()); - sp.remove_prefix(1); - EXPECT_EQ(size - 1, sp.length()); - sp.remove_suffix(2); - EXPECT_EQ(size - 1 - 2, sp.length()); -} -#endif // ABSL_HAVE_THREAD_SANITIZER - -#if !defined(NDEBUG) && !defined(ABSL_USES_STD_STRING_VIEW) -TEST(NonNegativeLenTest, NonNegativeLen) { - ABSL_EXPECT_DEATH_IF_SUPPORTED( - absl::string_view("xyz", static_cast<size_t>(-1)), "len <= kMaxSize"); -} - -TEST(LenExceedsMaxSizeTest, LenExceedsMaxSize) { - auto max_size = absl::string_view().max_size(); - - // This should construct ok (although the view itself is obviously invalid). - absl::string_view ok_view("", max_size); - - // Adding one to the max should trigger an assertion. - ABSL_EXPECT_DEATH_IF_SUPPORTED(absl::string_view("", max_size + 1), - "len <= kMaxSize"); -} -#endif // !defined(NDEBUG) && !defined(ABSL_USES_STD_STRING_VIEW) - -class StringViewStreamTest : public ::testing::Test { - public: - // Set negative 'width' for right justification. - template <typename T> - std::string Pad(const T& s, int width, char fill = 0) { - std::ostringstream oss; - if (fill != 0) { - oss << std::setfill(fill); - } - if (width < 0) { - width = -width; - oss << std::right; - } - oss << std::setw(width) << s; - return oss.str(); - } -}; - -TEST_F(StringViewStreamTest, Padding) { - std::string s("hello"); - absl::string_view sp(s); - for (int w = -64; w < 64; ++w) { - SCOPED_TRACE(w); - EXPECT_EQ(Pad(s, w), Pad(sp, w)); - } - for (int w = -64; w < 64; ++w) { - SCOPED_TRACE(w); - EXPECT_EQ(Pad(s, w, '#'), Pad(sp, w, '#')); - } -} - -TEST_F(StringViewStreamTest, ResetsWidth) { - // Width should reset after one formatted write. - // If we weren't resetting width after formatting the string_view, - // we'd have width=5 carrying over to the printing of the "]", - // creating "[###hi####]". - std::string s = "hi"; - absl::string_view sp = s; - { - std::ostringstream oss; - oss << "[" << std::setfill('#') << std::setw(5) << s << "]"; - ASSERT_EQ("[###hi]", oss.str()); - } - { - std::ostringstream oss; - oss << "[" << std::setfill('#') << std::setw(5) << sp << "]"; - EXPECT_EQ("[###hi]", oss.str()); - } -} - } // namespace
diff --git a/ci/absl_alternate_options.h b/ci/absl_alternate_options.h index 20bf010..d5567f3 100644 --- a/ci/absl_alternate_options.h +++ b/ci/absl_alternate_options.h
@@ -20,7 +20,6 @@ #ifndef ABSL_CI_ABSL_ALTERNATE_OPTIONS_H_ #define ABSL_CI_ABSL_ALTERNATE_OPTIONS_H_ -#define ABSL_OPTION_USE_STD_STRING_VIEW 0 #define ABSL_OPTION_USE_STD_ORDERING 0 #define ABSL_OPTION_USE_INLINE_NAMESPACE 1 #define ABSL_OPTION_INLINE_NAMESPACE_NAME ns