Export of internal Abseil changes

--
87cdfd6aa40941e116cd79ef70f9a7a8271db163 by Abseil Team <absl-team@google.com>:

Fix a typo in random.h API documentation.

PiperOrigin-RevId: 305176308

--
8a38e1df49a18a954daca3ce617fd69045ff4c19 by Derek Mauro <dmauro@google.com>:

Import GitHub #647: Allow external add_subdirectory for using GoogleTest

PiperOrigin-RevId: 305156797

--
b1a2441536d4964fbe4e2329e74c322e6c41a4e6 by Gennadiy Rozental <rogeeff@google.com>:

temporary roll back.

PiperOrigin-RevId: 305149619

--
c78767577264348d2f881893f9407aadfe73ab75 by CJ Johnson <johnsoncj@google.com>:

Rollback update to linux_clang-latest container while investigating
a compiler bug.

PiperOrigin-RevId: 304897689

--
3c6fd38f53d2e982569fdba4043f75271c7b5de4 by Derek Mauro <dmauro@google.com>:

Update linux_clang-latest container to one based on Ubuntu 18.04,
which has libstdc++-8.

PiperOrigin-RevId: 304885120
GitOrigin-RevId: 87cdfd6aa40941e116cd79ef70f9a7a8271db163
Change-Id: Iefa6efee93907ec0eecb8add804c5cc2f052b64d
This commit is contained in:
Abseil Team 2020-04-06 20:53:47 -07:00 committed by Gennadiy Rozental
parent c01b9916e7
commit 73ea9a9572
5 changed files with 173 additions and 351 deletions

View file

@ -123,132 +123,12 @@ H HashFragmentedCord(H, const Cord&);
// Additionally, the API provides iterator utilities to iterate through Cord
// data via chunks or character bytes.
//
namespace cord_internal {
// It's expensive to keep a Cord's tree perfectly balanced, so instead we keep
// trees approximately balanced. A tree node N of depth D(N) that contains a
// string of L(N) characters is considered balanced if L >= Fibonacci(D + 2).
// The "+ 2" is used to ensure that every balanced leaf node contains at least
// one character. Here we presume that
// Fibonacci(0) = 0
// Fibonacci(1) = 1
// Fibonacci(2) = 1
// Fibonacci(3) = 2
// ...
// The algorithm is based on paper by Hans Boehm et al:
// https://www.cs.rit.edu/usr/local/pub/jeh/courses/QUARTERS/FP/Labs/CedarRope/rope-paper.pdf
// In this paper authors shows that rebalancing based on cord forest of already
// balanced subtrees can be proven to never produce tree of depth larger than
// largest Fibonacci number representable in the same integral type as cord size
// For 64 bit integers this is the 93rd Fibonacci number. For 32 bit integrals
// this is 47th Fibonacci number.
constexpr size_t MaxCordDepth() { return sizeof(size_t) == 8 ? 93 : 47; }
// This class models fixed max size stack of CordRep pointers.
// The elements are being pushed back and popped from the back.
template <typename CordRepPtr, size_t N>
class CordTreePath {
public:
CordTreePath() {}
explicit CordTreePath(CordRepPtr root) { push_back(root); }
bool empty() const { return size_ == 0; }
size_t size() const { return size_; }
void clear() { size_ = 0; }
CordRepPtr back() { return data_[size_ - 1]; }
void pop_back() {
--size_;
assert(size_ < N);
}
void push_back(CordRepPtr elem) { data_[size_++] = elem; }
private:
CordRepPtr data_[N];
size_t size_ = 0;
};
// Fixed length container for mutable "path" in cord tree, which can hold any
// possible valid path in cord tree.
using CordTreeMutablePath = CordTreePath<CordRep*, MaxCordDepth()>;
// Variable length container for mutable "path" in cord tree. It starts with
// capacity for 15 elements and grow if necessary.
using CordTreeDynamicPath =
absl::InlinedVector<absl::cord_internal::CordRep*, 15>;
} // namespace cord_internal
// A Cord is a sequence of characters.
class Cord {
private:
template <typename T>
using EnableIfString =
absl::enable_if_t<std::is_same<T, std::string>::value, int>;
//----------------------------------------------------------------------------
// Cord::GenericChunkIterator
//----------------------------------------------------------------------------
//
// A `Cord::GenericChunkIterator` provides an interface for the standard
// `Cord::ChunkIterator` as well as some private implementations.
template <typename StorageType>
class GenericChunkIterator {
public:
using iterator_category = std::input_iterator_tag;
using value_type = absl::string_view;
using difference_type = ptrdiff_t;
using pointer = const value_type*;
using reference = value_type;
GenericChunkIterator() = default;
GenericChunkIterator& operator++();
GenericChunkIterator operator++(int);
bool operator==(const GenericChunkIterator& other) const;
bool operator!=(const GenericChunkIterator& other) const;
reference operator*() const;
pointer operator->() const;
friend class Cord;
friend class CharIterator;
private:
// Constructs a `begin()` iterator from `cord`.
explicit GenericChunkIterator(const Cord* cord);
// Removes `n` bytes from `current_chunk_`. Expects `n` to be smaller than
// `current_chunk_.size()`.
void RemoveChunkPrefix(size_t n);
Cord AdvanceAndReadBytes(size_t n);
void AdvanceBytes(size_t n);
// Iterates `n` bytes, where `n` is expected to be greater than or equal to
// `current_chunk_.size()`.
void AdvanceBytesSlowPath(size_t n);
// A view into bytes of the current `CordRep`. It may only be a view to a
// suffix of bytes if this is being used by `CharIterator`.
absl::string_view current_chunk_;
// The current leaf, or `nullptr` if the iterator points to short data.
// If the current chunk is a substring node, current_leaf_ points to the
// underlying flat or external node.
cord_internal::CordRep* current_leaf_ = nullptr;
// The number of bytes left in the `Cord` over which we are iterating.
size_t bytes_remaining_ = 0;
StorageType stack_of_right_children_;
};
template <typename IteratorType>
class GenericChunkRange {
public:
explicit GenericChunkRange(const Cord* cord) : cord_(cord) {}
IteratorType begin() const { return IteratorType(cord_); }
IteratorType end() const { return IteratorType(); }
private:
const Cord* cord_;
};
public:
// Cord::Cord() Constructors
@ -464,8 +344,51 @@ class Cord {
// * The iterator keeps state that can grow for Cords that contain many
// nodes and are imbalanced due to sharing. Prefer to pass this type by
// const reference instead of by value.
using ChunkIterator =
GenericChunkIterator<cord_internal::CordTreeDynamicPath>;
class ChunkIterator {
public:
using iterator_category = std::input_iterator_tag;
using value_type = absl::string_view;
using difference_type = ptrdiff_t;
using pointer = const value_type*;
using reference = value_type;
ChunkIterator() = default;
ChunkIterator& operator++();
ChunkIterator operator++(int);
bool operator==(const ChunkIterator& other) const;
bool operator!=(const ChunkIterator& other) const;
reference operator*() const;
pointer operator->() const;
friend class Cord;
friend class CharIterator;
private:
// Constructs a `begin()` iterator from `cord`.
explicit ChunkIterator(const Cord* cord);
// Removes `n` bytes from `current_chunk_`. Expects `n` to be smaller than
// `current_chunk_.size()`.
void RemoveChunkPrefix(size_t n);
Cord AdvanceAndReadBytes(size_t n);
void AdvanceBytes(size_t n);
// Iterates `n` bytes, where `n` is expected to be greater than or equal to
// `current_chunk_.size()`.
void AdvanceBytesSlowPath(size_t n);
// A view into bytes of the current `CordRep`. It may only be a view to a
// suffix of bytes if this is being used by `CharIterator`.
absl::string_view current_chunk_;
// The current leaf, or `nullptr` if the iterator points to short data.
// If the current chunk is a substring node, current_leaf_ points to the
// underlying flat or external node.
absl::cord_internal::CordRep* current_leaf_ = nullptr;
// The number of bytes left in the `Cord` over which we are iterating.
size_t bytes_remaining_ = 0;
absl::InlinedVector<absl::cord_internal::CordRep*, 4>
stack_of_right_children_;
};
// Cord::ChunkIterator::chunk_begin()
//
@ -504,7 +427,16 @@ class Cord {
//
// Implementation note: `ChunkRange` is simply a convenience wrapper over
// `Cord::chunk_begin()` and `Cord::chunk_end()`.
using ChunkRange = GenericChunkRange<ChunkIterator>;
class ChunkRange {
public:
explicit ChunkRange(const Cord* cord) : cord_(cord) {}
ChunkIterator begin() const;
ChunkIterator end() const;
private:
const Cord* cord_;
};
// Cord::Chunks()
//
@ -800,14 +732,6 @@ class Cord {
static bool GetFlatAux(absl::cord_internal::CordRep* rep,
absl::string_view* fragment);
// Iterators for use inside Cord implementation
using InternalChunkIterator =
GenericChunkIterator<cord_internal::CordTreeMutablePath>;
using InternalChunkRange = GenericChunkRange<InternalChunkIterator>;
InternalChunkIterator internal_chunk_begin() const;
InternalChunkRange InternalChunks() const;
// Helper for ForEachChunk()
static void ForEachChunkAux(
absl::cord_internal::CordRep* rep,
@ -842,11 +766,6 @@ class Cord {
void AppendImpl(C&& src);
};
extern template class Cord::GenericChunkIterator<
cord_internal::CordTreeMutablePath>;
extern template class Cord::GenericChunkIterator<
cord_internal::CordTreeDynamicPath>;
ABSL_NAMESPACE_END
} // namespace absl
@ -1186,9 +1105,7 @@ inline bool Cord::StartsWith(absl::string_view rhs) const {
return EqualsImpl(rhs, rhs_size);
}
template <typename StorageType>
inline Cord::GenericChunkIterator<StorageType>::GenericChunkIterator(
const Cord* cord)
inline Cord::ChunkIterator::ChunkIterator(const Cord* cord)
: bytes_remaining_(cord->size()) {
if (cord->empty()) return;
if (cord->contents_.is_tree()) {
@ -1199,50 +1116,37 @@ inline Cord::GenericChunkIterator<StorageType>::GenericChunkIterator(
}
}
template <typename StorageType>
inline Cord::GenericChunkIterator<StorageType>
Cord::GenericChunkIterator<StorageType>::operator++(int) {
GenericChunkIterator tmp(*this);
inline Cord::ChunkIterator Cord::ChunkIterator::operator++(int) {
ChunkIterator tmp(*this);
operator++();
return tmp;
}
template <typename StorageType>
inline bool Cord::GenericChunkIterator<StorageType>::operator==(
const GenericChunkIterator<StorageType>& other) const {
inline bool Cord::ChunkIterator::operator==(const ChunkIterator& other) const {
return bytes_remaining_ == other.bytes_remaining_;
}
template <typename StorageType>
inline bool Cord::GenericChunkIterator<StorageType>::operator!=(
const GenericChunkIterator<StorageType>& other) const {
inline bool Cord::ChunkIterator::operator!=(const ChunkIterator& other) const {
return !(*this == other);
}
template <typename StorageType>
inline typename Cord::GenericChunkIterator<StorageType>::reference
Cord::GenericChunkIterator<StorageType>::operator*() const {
inline Cord::ChunkIterator::reference Cord::ChunkIterator::operator*() const {
ABSL_HARDENING_ASSERT(bytes_remaining_ != 0);
return current_chunk_;
}
template <typename StorageType>
inline typename Cord::GenericChunkIterator<StorageType>::pointer
Cord::GenericChunkIterator<StorageType>::operator->() const {
inline Cord::ChunkIterator::pointer Cord::ChunkIterator::operator->() const {
ABSL_HARDENING_ASSERT(bytes_remaining_ != 0);
return &current_chunk_;
}
template <typename StorageType>
inline void Cord::GenericChunkIterator<StorageType>::RemoveChunkPrefix(
size_t n) {
inline void Cord::ChunkIterator::RemoveChunkPrefix(size_t n) {
assert(n < current_chunk_.size());
current_chunk_.remove_prefix(n);
bytes_remaining_ -= n;
}
template <typename StorageType>
inline void Cord::GenericChunkIterator<StorageType>::AdvanceBytes(size_t n) {
inline void Cord::ChunkIterator::AdvanceBytes(size_t n) {
if (ABSL_PREDICT_TRUE(n < current_chunk_.size())) {
RemoveChunkPrefix(n);
} else if (n != 0) {
@ -1256,6 +1160,14 @@ inline Cord::ChunkIterator Cord::chunk_begin() const {
inline Cord::ChunkIterator Cord::chunk_end() const { return ChunkIterator(); }
inline Cord::ChunkIterator Cord::ChunkRange::begin() const {
return cord_->chunk_begin();
}
inline Cord::ChunkIterator Cord::ChunkRange::end() const {
return cord_->chunk_end();
}
inline Cord::ChunkRange Cord::Chunks() const { return ChunkRange(this); }
inline Cord::CharIterator& Cord::CharIterator::operator++() {