Export of internal Abseil changes

--
44ccc0320ffaa2106ba3c6393b5a40c3b4f7b901 by Abseil Team <absl-team@google.com>:

Clarify span iterator documentation.

PiperOrigin-RevId: 299110584

--
80d016d8026b8d6904aa0ff2d5e1c3ae27f129bb by Greg Falcon <gfalcon@google.com>:

Add Cord::TryFlat().

PiperOrigin-RevId: 298889772

--
da6900203f1e4131d5693cbca157b6dba099bbed by Greg Falcon <gfalcon@google.com>:

clang-format cord_test.cc.

PiperOrigin-RevId: 298851425
GitOrigin-RevId: 44ccc0320ffaa2106ba3c6393b5a40c3b4f7b901
Change-Id: Ia5394f6fbb473d206726fdd48a00eb07a6acad6a
This commit is contained in:
Abseil Team 2020-03-05 08:37:17 -08:00 committed by Derek Mauro
parent b19ba96766
commit cf3a1998e9
5 changed files with 101 additions and 25 deletions

View file

@ -285,6 +285,7 @@ cc_library(
"//absl/container:inlined_vector", "//absl/container:inlined_vector",
"//absl/functional:function_ref", "//absl/functional:function_ref",
"//absl/meta:type_traits", "//absl/meta:type_traits",
"//absl/types:optional",
], ],
) )

View file

@ -546,6 +546,7 @@ absl_cc_library(
absl::fixed_array absl::fixed_array
absl::function_ref absl::function_ref
absl::inlined_vector absl::inlined_vector
absl::optional
absl::raw_logging_internal absl::raw_logging_internal
absl::type_traits absl::type_traits
PUBLIC PUBLIC

View file

@ -53,6 +53,7 @@
#include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_internal.h"
#include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/types/optional.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
@ -512,6 +513,10 @@ class Cord {
// REQUIRES: 0 <= i < size() // REQUIRES: 0 <= i < size()
char operator[](size_t i) const; char operator[](size_t i) const;
// If this cord's representation is a single flat array, return a
// string_view referencing that array. Otherwise return nullopt.
absl::optional<absl::string_view> TryFlat() const;
// Flattens the cord into a single array and returns a view of the data. // Flattens the cord into a single array and returns a view of the data.
// //
// If the cord was already flat, the contents are not modified. // If the cord was already flat, the contents are not modified.
@ -630,7 +635,7 @@ class Cord {
// Helper for MemoryUsage() // Helper for MemoryUsage()
static size_t MemoryUsageAux(const absl::cord_internal::CordRep* rep); static size_t MemoryUsageAux(const absl::cord_internal::CordRep* rep);
// Helper for GetFlat() // Helper for GetFlat() and TryFlat()
static bool GetFlatAux(absl::cord_internal::CordRep* rep, static bool GetFlatAux(absl::cord_internal::CordRep* rep,
absl::string_view* fragment); absl::string_view* fragment);
@ -942,6 +947,18 @@ inline size_t Cord::EstimatedMemoryUsage() const {
return result; return result;
} }
inline absl::optional<absl::string_view> Cord::TryFlat() const {
absl::cord_internal::CordRep* rep = contents_.tree();
if (rep == nullptr) {
return absl::string_view(contents_.data(), contents_.size());
}
absl::string_view fragment;
if (GetFlatAux(rep, &fragment)) {
return fragment;
}
return absl::nullopt;
}
inline absl::string_view Cord::Flatten() { inline absl::string_view Cord::Flatten() {
absl::cord_internal::CordRep* rep = contents_.tree(); absl::cord_internal::CordRep* rep = contents_.tree();
if (rep == nullptr) { if (rep == nullptr) {

View file

@ -70,9 +70,8 @@ static std::string RandomLowercaseString(RandomEngine* rng) {
static std::string RandomLowercaseString(RandomEngine* rng, size_t length) { static std::string RandomLowercaseString(RandomEngine* rng, size_t length) {
std::string result(length, '\0'); std::string result(length, '\0');
std::uniform_int_distribution<int> chars('a', 'z'); std::uniform_int_distribution<int> chars('a', 'z');
std::generate(result.begin(), result.end(), [&]() { std::generate(result.begin(), result.end(),
return static_cast<char>(chars(*rng)); [&]() { return static_cast<char>(chars(*rng)); });
});
return result; return result;
} }
@ -424,6 +423,50 @@ TEST(Cord, CopyToString) {
"copying ", "to ", "a ", "string."})); "copying ", "to ", "a ", "string."}));
} }
TEST(TryFlat, Empty) {
absl::Cord c;
EXPECT_EQ(c.TryFlat(), "");
}
TEST(TryFlat, Flat) {
absl::Cord c("hello");
EXPECT_EQ(c.TryFlat(), "hello");
}
TEST(TryFlat, SubstrInlined) {
absl::Cord c("hello");
c.RemovePrefix(1);
EXPECT_EQ(c.TryFlat(), "ello");
}
TEST(TryFlat, SubstrFlat) {
absl::Cord c("longer than 15 bytes");
c.RemovePrefix(1);
EXPECT_EQ(c.TryFlat(), "onger than 15 bytes");
}
TEST(TryFlat, Concat) {
absl::Cord c = absl::MakeFragmentedCord({"hel", "lo"});
EXPECT_EQ(c.TryFlat(), absl::nullopt);
}
TEST(TryFlat, External) {
absl::Cord c = absl::MakeCordFromExternal("hell", [](absl::string_view) {});
EXPECT_EQ(c.TryFlat(), "hell");
}
TEST(TryFlat, SubstrExternal) {
absl::Cord c = absl::MakeCordFromExternal("hell", [](absl::string_view) {});
c.RemovePrefix(1);
EXPECT_EQ(c.TryFlat(), "ell");
}
TEST(TryFlat, SubstrConcat) {
absl::Cord c = absl::MakeFragmentedCord({"hello", " world"});
c.RemovePrefix(1);
EXPECT_EQ(c.TryFlat(), absl::nullopt);
}
static bool IsFlat(const absl::Cord& c) { static bool IsFlat(const absl::Cord& c) {
return c.chunk_begin() == c.chunk_end() || ++c.chunk_begin() == c.chunk_end(); return c.chunk_begin() == c.chunk_end() || ++c.chunk_begin() == c.chunk_end();
} }
@ -1089,7 +1132,7 @@ TEST(ConstructFromExternal, ReferenceQualifierOverloads) {
} }
TEST(ExternalMemory, BasicUsage) { TEST(ExternalMemory, BasicUsage) {
static const char* strings[] = { "", "hello", "there" }; static const char* strings[] = {"", "hello", "there"};
for (const char* str : strings) { for (const char* str : strings) {
absl::Cord dst("(prefix)"); absl::Cord dst("(prefix)");
AddExternalMemory(str, &dst); AddExternalMemory(str, &dst);

View file

@ -292,60 +292,74 @@ class Span {
// Span::front() // Span::front()
// //
// Returns a reference to the first element of this span. // Returns a reference to the first element of this span. The span must not
// be empty.
constexpr reference front() const noexcept { constexpr reference front() const noexcept {
return ABSL_ASSERT(size() > 0), *data(); return ABSL_ASSERT(size() > 0), *data();
} }
// Span::back() // Span::back()
// //
// Returns a reference to the last element of this span. // Returns a reference to the last element of this span. The span must not
// be empty.
constexpr reference back() const noexcept { constexpr reference back() const noexcept {
return ABSL_ASSERT(size() > 0), *(data() + size() - 1); return ABSL_ASSERT(size() > 0), *(data() + size() - 1);
} }
// Span::begin() // Span::begin()
// //
// Returns an iterator to the first element of this span. // Returns an iterator pointing to the first element of this span, or `end()`
// if the span is empty.
constexpr iterator begin() const noexcept { return data(); } constexpr iterator begin() const noexcept { return data(); }
// Span::cbegin() // Span::cbegin()
// //
// Returns a const iterator to the first element of this span. // Returns a const iterator pointing to the first element of this span, or
// `end()` if the span is empty.
constexpr const_iterator cbegin() const noexcept { return begin(); } constexpr const_iterator cbegin() const noexcept { return begin(); }
// Span::end() // Span::end()
// //
// Returns an iterator to the last element of this span. // Returns an iterator pointing just beyond the last element at the
// end of this span. This iterator acts as a placeholder; attempting to
// access it results in undefined behavior.
constexpr iterator end() const noexcept { return data() + size(); } constexpr iterator end() const noexcept { return data() + size(); }
// Span::cend() // Span::cend()
// //
// Returns a const iterator to the last element of this span. // Returns a const iterator pointing just beyond the last element at the
// end of this span. This iterator acts as a placeholder; attempting to
// access it results in undefined behavior.
constexpr const_iterator cend() const noexcept { return end(); } constexpr const_iterator cend() const noexcept { return end(); }
// Span::rbegin() // Span::rbegin()
// //
// Returns a reverse iterator starting at the last element of this span. // Returns a reverse iterator pointing to the last element at the end of this
// span, or `rend()` if the span is empty.
constexpr reverse_iterator rbegin() const noexcept { constexpr reverse_iterator rbegin() const noexcept {
return reverse_iterator(end()); return reverse_iterator(end());
} }
// Span::crbegin() // Span::crbegin()
// //
// Returns a reverse const iterator starting at the last element of this span. // Returns a const reverse iterator pointing to the last element at the end of
// this span, or `crend()` if the span is empty.
constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); } constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
// Span::rend() // Span::rend()
// //
// Returns a reverse iterator starting at the first element of this span. // Returns a reverse iterator pointing just before the first element
// at the beginning of this span. This pointer acts as a placeholder;
// attempting to access its element results in undefined behavior.
constexpr reverse_iterator rend() const noexcept { constexpr reverse_iterator rend() const noexcept {
return reverse_iterator(begin()); return reverse_iterator(begin());
} }
// Span::crend() // Span::crend()
// //
// Returns a reverse iterator starting at the first element of this span. // Returns a reverse const iterator pointing just before the first element
// at the beginning of this span. This pointer acts as a placeholder;
// attempting to access its element results in undefined behavior.
constexpr const_reverse_iterator crend() const noexcept { return rend(); } constexpr const_reverse_iterator crend() const noexcept { return rend(); }
// Span mutations // Span mutations