Commit c2ef7033 by Abseil Team Committed by vslashg

Export of internal Abseil changes

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

Remove division from the profile guided optimization

PiperOrigin-RevId: 428444108

--
fc27059f1b0c0b4cb8ddd9a7a88220af52c0c755 by Evan Brown <ezb@google.com>:

Rename btree_node::leaf to is_leaf and also add is_internal for readability improvements.

PiperOrigin-RevId: 428076422

--
6a90d18477cc3a6de84282b6e38d6f294aa72748 by Evan Brown <ezb@google.com>:

In sanitizer mode, add generation integers to b-tree nodes and iterators and validate that iterators have not been invalidated already when they're used.

Even though generation integers are stored in all nodes, we only use the one stored in the root node for validation. The reason we keep one in all the nodes is that nodes can become a root node after they are allocated.

Also change the order of args in init_leaf to not violate the style guide.

PiperOrigin-RevId: 428054226

--
ede4a0f676f43e7003fd2599c263d55222e760ba by Martijn Vels <mvels@google.com>:

Physically remove CordRepConcat

This CL removes all uses of CordRepConcat. This change is executed by removing all the dead 'btree_enabled()' and 'IsConcat' branches, and all subsequent dead code. This change explicitly does not optimize any of the remaining code other than the most trivial ones such as removing 'stack' loop vars and loops.

PiperOrigin-RevId: 428002308

--
7cc83d96118149cf1aa1258a066b8fd4517df5f6 by Evan Brown <ezb@google.com>:

Change btree_iterator from a struct to a class.

Motivation: btree_iterator has private members and invariants so it should be a class.

Also merge two private sections.

PiperOrigin-RevId: 427768836

--
524d478b0af422e1a867a8823d9fbad149030360 by Martijn Vels <mvels@google.com>:

Physically block the creation of new CordRepConcat nodes.

This change removes CordRepConcat creation, issuing a FATAL errors on the (practically impossible) call path on broken invariants. This change is deliberately limited in impact, subsequent changes will be more voluminous ripping out the (now dead) CordRepConcat code.

PiperOrigin-RevId: 427741022

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

Update the implementation of ABSL_DEPRECATED to work with GCC, and
recommend using the standard attribute [[deprecated]] for C++14 and newer

GCC users that are experiencing new warnings can silence them with
-Wno-deprecated-declatations.

GCC users that want to see the warnings but not error on them can use
-Wno-error=deprecated-declarations.
PiperOrigin-RevId: 427228952

--
0ab4ee5660f3a072054dc4ab5056925c26977c7a by Laramie Leavitt <lar@google.com>:

Change comment to avoid overflow.

PiperOrigin-RevId: 427090218
GitOrigin-RevId: ceee18732f9499d3a53d46d5974f12ea0774b900
Change-Id: Ida00477b6a3d02a8b7bb467be7621b618385d1e9
parent 73316fc3
...@@ -212,7 +212,6 @@ set(ABSL_INTERNAL_DLL_FILES ...@@ -212,7 +212,6 @@ set(ABSL_INTERNAL_DLL_FILES
"strings/internal/cord_rep_btree_navigator.h" "strings/internal/cord_rep_btree_navigator.h"
"strings/internal/cord_rep_btree_reader.cc" "strings/internal/cord_rep_btree_reader.cc"
"strings/internal/cord_rep_btree_reader.h" "strings/internal/cord_rep_btree_reader.h"
"strings/internal/cord_rep_concat.cc"
"strings/internal/cord_rep_crc.cc" "strings/internal/cord_rep_crc.cc"
"strings/internal/cord_rep_crc.h" "strings/internal/cord_rep_crc.h"
"strings/internal/cord_rep_consume.h" "strings/internal/cord_rep_consume.h"
......
...@@ -646,6 +646,9 @@ ...@@ -646,6 +646,9 @@
// declarations. The macro argument is used as a custom diagnostic message (e.g. // declarations. The macro argument is used as a custom diagnostic message (e.g.
// suggestion of a better alternative). // suggestion of a better alternative).
// //
// For code or headers that are assured to only build with C++14 and up, prefer
// just using the standard `[[deprecated("message")]]` directly over this macro.
//
// Examples: // Examples:
// //
// class ABSL_DEPRECATED("Use Bar instead") Foo {...}; // class ABSL_DEPRECATED("Use Bar instead") Foo {...};
...@@ -661,13 +664,12 @@ ...@@ -661,13 +664,12 @@
// }; // };
// //
// Every usage of a deprecated entity will trigger a warning when compiled with // Every usage of a deprecated entity will trigger a warning when compiled with
// clang's `-Wdeprecated-declarations` option. This option is turned off by // GCC/Clang's `-Wdeprecated-declarations` option. Google's production toolchain
// default, but the warnings will be reported by clang-tidy. // turns this warning off by default, instead relying on clang-tidy to report
#if defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L // new uses of deprecated code.
#if ABSL_HAVE_ATTRIBUTE(deprecated)
#define ABSL_DEPRECATED(message) __attribute__((deprecated(message))) #define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
#endif #else
#ifndef ABSL_DEPRECATED
#define ABSL_DEPRECATED(message) #define ABSL_DEPRECATED(message)
#endif #endif
......
...@@ -914,6 +914,7 @@ cc_library( ...@@ -914,6 +914,7 @@ cc_library(
":container_memory", ":container_memory",
":layout", ":layout",
"//absl/base:core_headers", "//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/base:throw_delegate", "//absl/base:throw_delegate",
"//absl/memory", "//absl/memory",
"//absl/meta:type_traits", "//absl/meta:type_traits",
......
...@@ -35,6 +35,7 @@ absl_cc_library( ...@@ -35,6 +35,7 @@ absl_cc_library(
absl::core_headers absl::core_headers
absl::layout absl::layout
absl::memory absl::memory
absl::raw_logging_internal
absl::strings absl::strings
absl::throw_delegate absl::throw_delegate
absl::type_traits absl::type_traits
......
...@@ -1213,6 +1213,11 @@ class BtreeNodePeer { ...@@ -1213,6 +1213,11 @@ class BtreeNodePeer {
constexpr static bool UsesLinearNodeSearch() { constexpr static bool UsesLinearNodeSearch() {
return btree_node<typename Btree::params_type>::use_linear_search::value; return btree_node<typename Btree::params_type>::use_linear_search::value;
} }
template <typename Btree>
constexpr static bool UsesGenerations() {
return Btree::params_type::kEnableGenerations;
}
}; };
namespace { namespace {
...@@ -1478,8 +1483,10 @@ TEST(Btree, MovesComparisonsCopiesSwapsTracking) { ...@@ -1478,8 +1483,10 @@ TEST(Btree, MovesComparisonsCopiesSwapsTracking) {
EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>(), 61); EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>(), 61);
EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set100)>(), 100); EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set100)>(), 100);
if (sizeof(void *) == 8) { if (sizeof(void *) == 8) {
EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<absl::btree_set<int32_t>>(), EXPECT_EQ(
BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>()); BtreeNodePeer::GetNumSlotsPerNode<absl::btree_set<int32_t>>(),
// When we have generations, there is one fewer slot.
BtreeNodePeer::UsesGenerations<absl::btree_set<int32_t>>() ? 60 : 61);
} }
// Test key insertion/deletion in random order. // Test key insertion/deletion in random order.
...@@ -1533,8 +1540,10 @@ TEST(Btree, MovesComparisonsCopiesSwapsTrackingThreeWayCompare) { ...@@ -1533,8 +1540,10 @@ TEST(Btree, MovesComparisonsCopiesSwapsTrackingThreeWayCompare) {
EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>(), 61); EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>(), 61);
EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set100)>(), 100); EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set100)>(), 100);
if (sizeof(void *) == 8) { if (sizeof(void *) == 8) {
EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<absl::btree_set<int32_t>>(), EXPECT_EQ(
BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>()); BtreeNodePeer::GetNumSlotsPerNode<absl::btree_set<int32_t>>(),
// When we have generations, there is one fewer slot.
BtreeNodePeer::UsesGenerations<absl::btree_set<int32_t>>() ? 60 : 61);
} }
// Test key insertion/deletion in random order. // Test key insertion/deletion in random order.
...@@ -3020,8 +3029,38 @@ TEST(Btree, InvalidComparatorsCaught) { ...@@ -3020,8 +3029,38 @@ TEST(Btree, InvalidComparatorsCaught) {
} }
}; };
absl::btree_set<int, ThreeWaySumGreaterZeroCmp> set; absl::btree_set<int, ThreeWaySumGreaterZeroCmp> set;
EXPECT_DEATH(set.insert({0, 1, 2}), EXPECT_DEATH(set.insert({0, 1, 2}), "lhs_comp_rhs < 0 -> rhs_comp_lhs > 0");
R"regex(lhs_comp_rhs < 0 -> rhs_comp_lhs > 0)regex"); }
}
#endif
#ifndef _MSC_VER
// This test crashes on MSVC.
TEST(Btree, InvalidIteratorUse) {
if (!BtreeNodePeer::UsesGenerations<absl::btree_set<int>>())
GTEST_SKIP() << "Generation validation for iterators is disabled.";
{
absl::btree_set<int> set;
for (int i = 0; i < 10; ++i) set.insert(i);
auto it = set.begin();
set.erase(it++);
EXPECT_DEATH(set.erase(it++), "invalidated iterator");
}
{
absl::btree_set<int> set;
for (int i = 0; i < 10; ++i) set.insert(i);
auto it = set.insert(20).first;
set.insert(30);
EXPECT_DEATH(*it, "invalidated iterator");
}
{
absl::btree_set<int> set;
for (int i = 0; i < 10000; ++i) set.insert(i);
auto it = set.find(5000);
ASSERT_NE(it, set.end());
set.erase(1);
EXPECT_DEATH(*it, "invalidated iterator");
} }
} }
#endif #endif
......
...@@ -537,6 +537,7 @@ class btree_multiset_container : public btree_container<Tree> { ...@@ -537,6 +537,7 @@ class btree_multiset_container : public btree_container<Tree> {
using params_type = typename Tree::params_type; using params_type = typename Tree::params_type;
using init_type = typename params_type::init_type; using init_type = typename params_type::init_type;
using is_key_compare_to = typename params_type::is_key_compare_to; using is_key_compare_to = typename params_type::is_key_compare_to;
friend class BtreeNodePeer;
template <class K> template <class K>
using key_arg = typename super_type::template key_arg<K>; using key_arg = typename super_type::template key_arg<K>;
...@@ -668,6 +669,7 @@ template <typename Tree> ...@@ -668,6 +669,7 @@ template <typename Tree>
class btree_multimap_container : public btree_multiset_container<Tree> { class btree_multimap_container : public btree_multiset_container<Tree> {
using super_type = btree_multiset_container<Tree>; using super_type = btree_multiset_container<Tree>;
using params_type = typename Tree::params_type; using params_type = typename Tree::params_type;
friend class BtreeNodePeer;
public: public:
using mapped_type = typename params_type::mapped_type; using mapped_type = typename params_type::mapped_type;
......
...@@ -87,7 +87,7 @@ class BitGenRef; ...@@ -87,7 +87,7 @@ class BitGenRef;
// //
// ON_CALL(absl::MockUniform<int>(), Call(bitgen, testing::_, testing::_)) // ON_CALL(absl::MockUniform<int>(), Call(bitgen, testing::_, testing::_))
// .WillByDefault([] (int low, int high) { // .WillByDefault([] (int low, int high) {
// return (low + high) / 2; // return low + (high - low) / 2;
// }); // });
// //
// EXPECT_EQ(absl::Uniform<int>(gen, 0, 10), 5); // EXPECT_EQ(absl::Uniform<int>(gen, 0, 10), 5);
......
...@@ -271,7 +271,6 @@ cc_library( ...@@ -271,7 +271,6 @@ cc_library(
"internal/cord_rep_btree.cc", "internal/cord_rep_btree.cc",
"internal/cord_rep_btree_navigator.cc", "internal/cord_rep_btree_navigator.cc",
"internal/cord_rep_btree_reader.cc", "internal/cord_rep_btree_reader.cc",
"internal/cord_rep_concat.cc",
"internal/cord_rep_consume.cc", "internal/cord_rep_consume.cc",
"internal/cord_rep_crc.cc", "internal/cord_rep_crc.cc",
"internal/cord_rep_ring.cc", "internal/cord_rep_ring.cc",
......
...@@ -568,7 +568,6 @@ absl_cc_library( ...@@ -568,7 +568,6 @@ absl_cc_library(
"internal/cord_rep_btree.cc" "internal/cord_rep_btree.cc"
"internal/cord_rep_btree_navigator.cc" "internal/cord_rep_btree_navigator.cc"
"internal/cord_rep_btree_reader.cc" "internal/cord_rep_btree_reader.cc"
"internal/cord_rep_concat.cc"
"internal/cord_rep_crc.cc" "internal/cord_rep_crc.cc"
"internal/cord_rep_consume.cc" "internal/cord_rep_consume.cc"
"internal/cord_rep_ring.cc" "internal/cord_rep_ring.cc"
......
...@@ -1553,7 +1553,6 @@ class CordTestAccess { ...@@ -1553,7 +1553,6 @@ class CordTestAccess {
public: public:
static size_t FlatOverhead(); static size_t FlatOverhead();
static size_t MaxFlatLength(); static size_t MaxFlatLength();
static size_t SizeofCordRepConcat();
static size_t SizeofCordRepExternal(); static size_t SizeofCordRepExternal();
static size_t SizeofCordRepSubstring(); static size_t SizeofCordRepSubstring();
static size_t FlatTagToLength(uint8_t tag); static size_t FlatTagToLength(uint8_t tag);
......
...@@ -128,45 +128,6 @@ void AnalyzeDataEdge(CordRepRef<mode> rep, RawUsage<mode>& raw_usage) { ...@@ -128,45 +128,6 @@ void AnalyzeDataEdge(CordRepRef<mode> rep, RawUsage<mode>& raw_usage) {
raw_usage.Add(size, rep); raw_usage.Add(size, rep);
} }
// Computes the memory size of the provided Concat tree.
template <Mode mode>
void AnalyzeConcat(CordRepRef<mode> rep, RawUsage<mode>& raw_usage) {
absl::InlinedVector<CordRepRef<mode>, 47> pending;
while (rep.rep != nullptr) {
const CordRepConcat* concat = rep.rep->concat();
CordRepRef<mode> left = rep.Child(concat->left);
CordRepRef<mode> right = rep.Child(concat->right);
raw_usage.Add(sizeof(CordRepConcat), rep);
switch ((IsDataEdge(left.rep) ? 1 : 0) | (IsDataEdge(right.rep) ? 2 : 0)) {
case 0: // neither left or right are data edges
rep = left;
pending.push_back(right);
break;
case 1: // only left is a data edge
AnalyzeDataEdge(left, raw_usage);
rep = right;
break;
case 2: // only right is a data edge
AnalyzeDataEdge(right, raw_usage);
rep = left;
break;
case 3: // left and right are data edges
AnalyzeDataEdge(right, raw_usage);
AnalyzeDataEdge(left, raw_usage);
if (!pending.empty()) {
rep = pending.back();
pending.pop_back();
} else {
rep.rep = nullptr;
}
break;
}
}
}
// Computes the memory size of the provided Ring tree. // Computes the memory size of the provided Ring tree.
template <Mode mode> template <Mode mode>
void AnalyzeRing(CordRepRef<mode> rep, RawUsage<mode>& raw_usage) { void AnalyzeRing(CordRepRef<mode> rep, RawUsage<mode>& raw_usage) {
...@@ -211,8 +172,6 @@ size_t GetEstimatedUsage(const CordRep* rep) { ...@@ -211,8 +172,6 @@ size_t GetEstimatedUsage(const CordRep* rep) {
AnalyzeDataEdge(repref, raw_usage); AnalyzeDataEdge(repref, raw_usage);
} else if (repref.rep->tag == BTREE) { } else if (repref.rep->tag == BTREE) {
AnalyzeBtree(repref, raw_usage); AnalyzeBtree(repref, raw_usage);
} else if (repref.rep->IsConcat()) {
AnalyzeConcat(repref, raw_usage);
} else if (repref.rep->tag == RING) { } else if (repref.rep->tag == RING) {
AnalyzeRing(repref, raw_usage); AnalyzeRing(repref, raw_usage);
} else { } else {
......
...@@ -36,53 +36,31 @@ ABSL_CONST_INIT std::atomic<bool> cord_btree_exhaustive_validation(false); ...@@ -36,53 +36,31 @@ ABSL_CONST_INIT std::atomic<bool> cord_btree_exhaustive_validation(false);
void CordRep::Destroy(CordRep* rep) { void CordRep::Destroy(CordRep* rep) {
assert(rep != nullptr); assert(rep != nullptr);
absl::InlinedVector<CordRep*, Constants::kInlinedVectorSize> pending;
while (true) { while (true) {
assert(!rep->refcount.IsImmortal()); assert(!rep->refcount.IsImmortal());
if (rep->IsConcat()) { if (rep->tag == BTREE) {
CordRepConcat* rep_concat = rep->concat();
CordRep* right = rep_concat->right;
if (!right->refcount.Decrement()) {
pending.push_back(right);
}
CordRep* left = rep_concat->left;
delete rep_concat;
rep = nullptr;
if (!left->refcount.Decrement()) {
rep = left;
continue;
}
} else if (rep->tag == BTREE) {
CordRepBtree::Destroy(rep->btree()); CordRepBtree::Destroy(rep->btree());
rep = nullptr; return;
} else if (rep->tag == RING) { } else if (rep->tag == RING) {
CordRepRing::Destroy(rep->ring()); CordRepRing::Destroy(rep->ring());
rep = nullptr; return;
} else if (rep->tag == EXTERNAL) { } else if (rep->tag == EXTERNAL) {
CordRepExternal::Delete(rep); CordRepExternal::Delete(rep);
rep = nullptr; return;
} else if (rep->tag == SUBSTRING) { } else if (rep->tag == SUBSTRING) {
CordRepSubstring* rep_substring = rep->substring(); CordRepSubstring* rep_substring = rep->substring();
CordRep* child = rep_substring->child; rep = rep_substring->child;
delete rep_substring; delete rep_substring;
rep = nullptr; if (rep->refcount.Decrement()) {
if (!child->refcount.Decrement()) { return;
rep = child;
continue;
} }
} else if (rep->tag == CRC) { } else if (rep->tag == CRC) {
CordRepCrc::Destroy(rep->crc()); CordRepCrc::Destroy(rep->crc());
rep = nullptr; return;
} else { } else {
assert(rep->IsFlat());
CordRepFlat::Delete(rep); CordRepFlat::Delete(rep);
rep = nullptr; return;
}
if (!pending.empty()) {
rep = pending.back();
pending.pop_back();
} else {
break;
} }
} }
} }
......
...@@ -171,7 +171,7 @@ class CordRepBtree; ...@@ -171,7 +171,7 @@ class CordRepBtree;
// Various representations that we allow // Various representations that we allow
enum CordRepKind { enum CordRepKind {
CONCAT = 0, UNUSED_0 = 0,
SUBSTRING = 1, SUBSTRING = 1,
CRC = 2, CRC = 2,
BTREE = 3, BTREE = 3,
...@@ -239,7 +239,6 @@ struct CordRep { ...@@ -239,7 +239,6 @@ struct CordRep {
// Returns true if this instance's tag matches the requested type. // Returns true if this instance's tag matches the requested type.
constexpr bool IsRing() const { return tag == RING; } constexpr bool IsRing() const { return tag == RING; }
constexpr bool IsConcat() const { return tag == CONCAT; }
constexpr bool IsSubstring() const { return tag == SUBSTRING; } constexpr bool IsSubstring() const { return tag == SUBSTRING; }
constexpr bool IsCrc() const { return tag == CRC; } constexpr bool IsCrc() const { return tag == CRC; }
constexpr bool IsExternal() const { return tag == EXTERNAL; } constexpr bool IsExternal() const { return tag == EXTERNAL; }
...@@ -248,8 +247,6 @@ struct CordRep { ...@@ -248,8 +247,6 @@ struct CordRep {
inline CordRepRing* ring(); inline CordRepRing* ring();
inline const CordRepRing* ring() const; inline const CordRepRing* ring() const;
inline CordRepConcat* concat();
inline const CordRepConcat* concat() const;
inline CordRepSubstring* substring(); inline CordRepSubstring* substring();
inline const CordRepSubstring* substring() const; inline const CordRepSubstring* substring() const;
inline CordRepCrc* crc(); inline CordRepCrc* crc();
...@@ -276,21 +273,6 @@ struct CordRep { ...@@ -276,21 +273,6 @@ struct CordRep {
static inline void Unref(CordRep* rep); static inline void Unref(CordRep* rep);
}; };
struct CordRepConcat : public CordRep {
CordRep* left;
CordRep* right;
uint8_t depth() const { return storage[0]; }
void set_depth(uint8_t depth) { storage[0] = depth; }
// Extracts the right-most flat in the provided concat tree if the entire path
// to that flat is not shared, and the flat has the requested extra capacity.
// Returns the (potentially new) top level tree node and the extracted flat,
// or {tree, nullptr} if no flat was extracted.
static ExtractResult ExtractAppendBuffer(CordRepConcat* tree,
size_t extra_capacity);
};
struct CordRepSubstring : public CordRep { struct CordRepSubstring : public CordRep {
size_t start; // Starting offset of substring in child size_t start; // Starting offset of substring in child
CordRep* child; CordRep* child;
...@@ -569,16 +551,6 @@ class InlineData { ...@@ -569,16 +551,6 @@ class InlineData {
static_assert(sizeof(InlineData) == kMaxInline + 1, ""); static_assert(sizeof(InlineData) == kMaxInline + 1, "");
inline CordRepConcat* CordRep::concat() {
assert(IsConcat());
return static_cast<CordRepConcat*>(this);
}
inline const CordRepConcat* CordRep::concat() const {
assert(IsConcat());
return static_cast<const CordRepConcat*>(this);
}
inline CordRepSubstring* CordRep::substring() { inline CordRepSubstring* CordRep::substring() {
assert(IsSubstring()); assert(IsSubstring());
return static_cast<CordRepSubstring*>(this); return static_cast<CordRepSubstring*>(this);
......
// Copyright 2021 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 <cstdint>
#include "absl/base/config.h"
#include "absl/container/inlined_vector.h"
#include "absl/strings/internal/cord_internal.h"
#include "absl/strings/internal/cord_rep_flat.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace cord_internal {
CordRepConcat::ExtractResult CordRepConcat::ExtractAppendBuffer(
CordRepConcat* tree, size_t extra_capacity) {
absl::InlinedVector<CordRepConcat*, kInlinedVectorSize> stack;
CordRepConcat* concat = tree;
CordRep* rep = concat->right;
// Dive down the tree, making sure no edges are shared
while (concat->refcount.IsOne() && rep->IsConcat()) {
stack.push_back(concat);
concat = rep->concat();
rep = concat->right;
}
// Validate we ended on a non shared flat.
if (concat->refcount.IsOne() && rep->IsFlat() &&
rep->refcount.IsOne()) {
// Verify it has at least the requested extra capacity
CordRepFlat* flat = rep->flat();
size_t remaining = flat->Capacity() - flat->length;
if (extra_capacity > remaining) return {tree, nullptr};
// Check if we have a parent to adjust, or if we must return the left node.
rep = concat->left;
if (!stack.empty()) {
stack.back()->right = rep;
for (CordRepConcat* parent : stack) {
parent->length -= flat->length;
}
rep = tree;
}
delete concat;
return {rep, flat};
}
return {tree, nullptr};
}
} // namespace cord_internal
ABSL_NAMESPACE_END
} // namespace absl
...@@ -40,88 +40,21 @@ CordRep* ClipSubstring(CordRepSubstring* substring) { ...@@ -40,88 +40,21 @@ CordRep* ClipSubstring(CordRepSubstring* substring) {
return child; return child;
} }
// Unrefs the provided `concat`, and returns `{concat->left, concat->right}` } // namespace
// Adds or assumes a reference on `concat->left` and `concat->right`.
// Returns an array of 2 elements containing the left and right nodes.
std::array<CordRep*, 2> ClipConcat(CordRepConcat* concat) {
std::array<CordRep*, 2> result{concat->left, concat->right};
if (concat->refcount.IsOne()) {
delete concat;
} else {
CordRep::Ref(result[0]);
CordRep::Ref(result[1]);
CordRep::Unref(concat);
}
return result;
}
void Consume(bool forward, CordRep* rep, ConsumeFn consume_fn) { void Consume(CordRep* rep, ConsumeFn consume_fn) {
size_t offset = 0; size_t offset = 0;
size_t length = rep->length; size_t length = rep->length;
struct Entry {
CordRep* rep;
size_t offset;
size_t length;
};
absl::InlinedVector<Entry, 40> stack;
for (;;) {
if (rep->IsConcat()) {
std::array<CordRep*, 2> res = ClipConcat(rep->concat());
CordRep* left = res[0];
CordRep* right = res[1];
if (left->length <= offset) { if (rep->tag == SUBSTRING) {
// Don't need left node
offset -= left->length;
CordRep::Unref(left);
rep = right;
continue;
}
size_t length_left = left->length - offset;
if (length_left >= length) {
// Don't need right node
CordRep::Unref(right);
rep = left;
continue;
}
// Need both nodes
size_t length_right = length - length_left;
if (forward) {
stack.push_back({right, 0, length_right});
rep = left;
length = length_left;
} else {
stack.push_back({left, offset, length_left});
rep = right;
offset = 0;
length = length_right;
}
} else if (rep->tag == SUBSTRING) {
offset += rep->substring()->start; offset += rep->substring()->start;
rep = ClipSubstring(rep->substring()); rep = ClipSubstring(rep->substring());
} else {
consume_fn(rep, offset, length);
if (stack.empty()) return;
rep = stack.back().rep;
offset = stack.back().offset;
length = stack.back().length;
stack.pop_back();
}
} }
} consume_fn(rep, offset, length);
} // namespace
void Consume(CordRep* rep, ConsumeFn consume_fn) {
return Consume(true, rep, std::move(consume_fn));
} }
void ReverseConsume(CordRep* rep, ConsumeFn consume_fn) { void ReverseConsume(CordRep* rep, ConsumeFn consume_fn) {
return Consume(false, rep, std::move(consume_fn)); return Consume(rep, std::move(consume_fn));
} }
} // namespace cord_internal } // namespace cord_internal
......
...@@ -73,9 +73,11 @@ static_assert(AllocatedSizeToTagUnchecked(kMinFlatSize) == FLAT, ""); ...@@ -73,9 +73,11 @@ static_assert(AllocatedSizeToTagUnchecked(kMinFlatSize) == FLAT, "");
static_assert(AllocatedSizeToTagUnchecked(kMaxLargeFlatSize) == MAX_FLAT_TAG, static_assert(AllocatedSizeToTagUnchecked(kMaxLargeFlatSize) == MAX_FLAT_TAG,
""); "");
// Helper functions for rounded div, and rounding to exact sizes. // RoundUp logically performs `((n + m - 1) / m) * m` to round up to the nearest
constexpr size_t DivUp(size_t n, size_t m) { return (n + m - 1) / m; } // multiple of `m`, optimized for the invariant that `m` is a power of 2.
constexpr size_t RoundUp(size_t n, size_t m) { return DivUp(n, m) * m; } constexpr size_t RoundUp(size_t n, size_t m) {
return (n + m - 1) & (0 - m);
}
// Returns the size to the nearest equal or larger value that can be // Returns the size to the nearest equal or larger value that can be
// expressed exactly as a tag value. // expressed exactly as a tag value.
......
...@@ -114,9 +114,6 @@ inline void CordVisitReps(cord_internal::CordRep* rep, Fn&& fn) { ...@@ -114,9 +114,6 @@ inline void CordVisitReps(cord_internal::CordRep* rep, Fn&& fn) {
for (cord_internal::CordRep* edge : rep->btree()->Edges()) { for (cord_internal::CordRep* edge : rep->btree()->Edges()) {
CordVisitReps(edge, fn); CordVisitReps(edge, fn);
} }
} else if (rep->IsConcat()) {
CordVisitReps(rep->concat()->left, fn);
CordVisitReps(rep->concat()->right, fn);
} }
} }
......
...@@ -98,8 +98,6 @@ class CordRepAnalyzer { ...@@ -98,8 +98,6 @@ class CordRepAnalyzer {
AnalyzeRing(repref); AnalyzeRing(repref);
} else if (repref.rep->tag == BTREE) { } else if (repref.rep->tag == BTREE) {
AnalyzeBtree(repref); AnalyzeBtree(repref);
} else if (repref.rep->IsConcat()) {
AnalyzeConcat(repref);
} else { } else {
// We should have either a concat, btree, or ring node if not null. // We should have either a concat, btree, or ring node if not null.
assert(false); assert(false);
...@@ -141,14 +139,6 @@ class CordRepAnalyzer { ...@@ -141,14 +139,6 @@ class CordRepAnalyzer {
} }
}; };
// Returns `rr` if `rr.rep` is not null and a CONCAT type.
// Asserts that `rr.rep` is a concat node or null.
static RepRef AssertConcat(RepRef repref) {
const CordRep* rep = repref.rep;
assert(rep == nullptr || rep->IsConcat());
return (rep != nullptr && rep->IsConcat()) ? repref : RepRef{nullptr, 0};
}
// Counts a flat of the provide allocated size // Counts a flat of the provide allocated size
void CountFlat(size_t size) { void CountFlat(size_t size) {
statistics_.node_count++; statistics_.node_count++;
...@@ -201,34 +191,6 @@ class CordRepAnalyzer { ...@@ -201,34 +191,6 @@ class CordRepAnalyzer {
return rep; return rep;
} }
// Analyzes the provided concat node in a flattened recursive way.
void AnalyzeConcat(RepRef rep) {
absl::InlinedVector<RepRef, 47> pending;
while (rep.rep != nullptr) {
const CordRepConcat* concat = rep.rep->concat();
RepRef left = rep.Child(concat->left);
RepRef right = rep.Child(concat->right);
statistics_.node_count++;
statistics_.node_counts.concat++;
memory_usage_.Add(sizeof(CordRepConcat), rep.refcount);
right = AssertConcat(CountLinearReps(right, memory_usage_));
rep = AssertConcat(CountLinearReps(left, memory_usage_));
if (rep.rep != nullptr) {
if (right.rep != nullptr) {
pending.push_back(right);
}
} else if (right.rep != nullptr) {
rep = right;
} else if (!pending.empty()) {
rep = pending.back();
pending.pop_back();
}
}
}
// Analyzes the provided ring. // Analyzes the provided ring.
void AnalyzeRing(RepRef rep) { void AnalyzeRing(RepRef rep) {
statistics_.node_count++; statistics_.node_count++;
......
...@@ -148,10 +148,6 @@ double FairShareImpl(CordRep* rep, size_t ref) { ...@@ -148,10 +148,6 @@ double FairShareImpl(CordRep* rep, size_t ref) {
rep->ring()->ForEach([&](CordRepRing::index_type i) { rep->ring()->ForEach([&](CordRepRing::index_type i) {
self += FairShareImpl(rep->ring()->entry_child(i), 1); self += FairShareImpl(rep->ring()->entry_child(i), 1);
}); });
} else if (rep->IsConcat()) {
self = SizeOf(rep->concat());
children = FairShareImpl(rep->concat()->left, ref) +
FairShareImpl(rep->concat()->right, ref);
} else { } else {
assert(false); assert(false);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment