|
|
|
// 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.
|
|
|
|
|
|
|
|
#ifndef ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_
|
|
|
|
#define ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_
|
|
|
|
|
|
|
|
#include <atomic>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <type_traits>
|
|
|
|
|
|
|
|
#include "absl/base/config.h"
|
|
|
|
#include "absl/base/internal/endian.h"
|
|
|
|
#include "absl/base/internal/invoke.h"
|
|
|
|
#include "absl/base/optimization.h"
|
|
|
|
#include "absl/container/internal/compressed_tuple.h"
|
|
|
|
#include "absl/meta/type_traits.h"
|
|
|
|
#include "absl/strings/string_view.h"
|
|
|
|
|
|
|
|
namespace absl {
|
|
|
|
ABSL_NAMESPACE_BEGIN
|
|
|
|
namespace cord_internal {
|
|
|
|
|
|
|
|
class CordzInfo;
|
|
|
|
|
|
|
|
// Default feature enable states for cord ring buffers
|
|
|
|
enum CordFeatureDefaults {
|
|
|
|
kCordEnableBtreeDefault = true,
|
|
|
|
kCordEnableRingBufferDefault = false,
|
|
|
|
kCordShallowSubcordsDefault = false
|
|
|
|
};
|
|
|
|
|
Export of internal Abseil changes
--
007ce045d5d38a727ededdb5bf06e64785fd73bd by Martijn Vels <mvels@google.com>:
Add `cord_enable_btree` feature flag (default false).
PiperOrigin-RevId: 383729939
--
98e7dc6a0407b0fd7b8713d883cdb3a766e0583d by Benjamin Barenblat <bbaren@google.com>:
Eliminate some byte swapping from randen_slow
Stop swapping bytes when serializing randen_slow’s Vector128 into and
out of memory. Instead, simply index different bytes in the AES round
function. This requires byte swapping the te{0..3} lookup tables, but it
produces an 8% speedup on my Xeon W-2135.
PiperOrigin-RevId: 383689402
--
180b6bf45049188840d439b16a28e6b968669340 by Evan Brown <ezb@google.com>:
Minor simplification in drop_deletes_without_resize() - save probe_offset outside the lambda.
Also, add some consts, avoid an auto, and use lambda capture by value instead of reference.
I realized that the compiler can already optimize this - https://godbolt.org/z/Wxd9c4TfK, but I think this way makes the code a bit clearer.
PiperOrigin-RevId: 383646658
--
781706a974c4dc1c0abbb6b801fca0550229e883 by Martijn Vels <mvels@google.com>:
Change storage to contain 3 bytes.
As per the comments in the code, this allows us to utilize all available space in CordRep that may otherwise be 'lost' in padding in derived clases. For the upcoming CordrepBtree class, we want a strong guarantee on having a 64 bytes aligned implementation.
PiperOrigin-RevId: 383633963
--
8fe22ecf92492fa6649938a2215934ebfe01c714 by Derek Mauro <dmauro@google.com>:
Remove reference to str_format_arg.h, which no longer exists
PiperOrigin-RevId: 383517865
--
79397f3b18f18c1e2d7aea993b687329d626ce64 by Benjamin Barenblat <bbaren@google.com>:
Use absl::uint128 for AES random number generator
Replace randen’s internal 128-bit integer struct, u64x2, with
absl::uint128. This eliminates some code and improves support for
big-endian platforms.
PiperOrigin-RevId: 383475671
GitOrigin-RevId: 007ce045d5d38a727ededdb5bf06e64785fd73bd
Change-Id: Ia9d9c40de557221f1744fb0d6d4d6ca7ac569070
4 years ago
|
|
|
extern std::atomic<bool> cord_btree_enabled;
|
|
|
|
extern std::atomic<bool> cord_ring_buffer_enabled;
|
|
|
|
extern std::atomic<bool> shallow_subcords_enabled;
|
|
|
|
|
|
|
|
// `cord_btree_exhaustive_validation` can be set to force exhaustive validation
|
|
|
|
// in debug assertions, and code that calls `IsValid()` explicitly. By default,
|
|
|
|
// assertions should be relatively cheap and AssertValid() can easily lead to
|
|
|
|
// O(n^2) complexity as recursive / full tree validation is O(n).
|
|
|
|
extern std::atomic<bool> cord_btree_exhaustive_validation;
|
|
|
|
|
Export of internal Abseil changes
--
007ce045d5d38a727ededdb5bf06e64785fd73bd by Martijn Vels <mvels@google.com>:
Add `cord_enable_btree` feature flag (default false).
PiperOrigin-RevId: 383729939
--
98e7dc6a0407b0fd7b8713d883cdb3a766e0583d by Benjamin Barenblat <bbaren@google.com>:
Eliminate some byte swapping from randen_slow
Stop swapping bytes when serializing randen_slow’s Vector128 into and
out of memory. Instead, simply index different bytes in the AES round
function. This requires byte swapping the te{0..3} lookup tables, but it
produces an 8% speedup on my Xeon W-2135.
PiperOrigin-RevId: 383689402
--
180b6bf45049188840d439b16a28e6b968669340 by Evan Brown <ezb@google.com>:
Minor simplification in drop_deletes_without_resize() - save probe_offset outside the lambda.
Also, add some consts, avoid an auto, and use lambda capture by value instead of reference.
I realized that the compiler can already optimize this - https://godbolt.org/z/Wxd9c4TfK, but I think this way makes the code a bit clearer.
PiperOrigin-RevId: 383646658
--
781706a974c4dc1c0abbb6b801fca0550229e883 by Martijn Vels <mvels@google.com>:
Change storage to contain 3 bytes.
As per the comments in the code, this allows us to utilize all available space in CordRep that may otherwise be 'lost' in padding in derived clases. For the upcoming CordrepBtree class, we want a strong guarantee on having a 64 bytes aligned implementation.
PiperOrigin-RevId: 383633963
--
8fe22ecf92492fa6649938a2215934ebfe01c714 by Derek Mauro <dmauro@google.com>:
Remove reference to str_format_arg.h, which no longer exists
PiperOrigin-RevId: 383517865
--
79397f3b18f18c1e2d7aea993b687329d626ce64 by Benjamin Barenblat <bbaren@google.com>:
Use absl::uint128 for AES random number generator
Replace randen’s internal 128-bit integer struct, u64x2, with
absl::uint128. This eliminates some code and improves support for
big-endian platforms.
PiperOrigin-RevId: 383475671
GitOrigin-RevId: 007ce045d5d38a727ededdb5bf06e64785fd73bd
Change-Id: Ia9d9c40de557221f1744fb0d6d4d6ca7ac569070
4 years ago
|
|
|
inline void enable_cord_btree(bool enable) {
|
|
|
|
cord_btree_enabled.store(enable, std::memory_order_relaxed);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void enable_cord_ring_buffer(bool enable) {
|
|
|
|
cord_ring_buffer_enabled.store(enable, std::memory_order_relaxed);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void enable_shallow_subcords(bool enable) {
|
|
|
|
shallow_subcords_enabled.store(enable, std::memory_order_relaxed);
|
|
|
|
}
|
|
|
|
|
|
|
|
enum Constants {
|
|
|
|
// The inlined size to use with absl::InlinedVector.
|
|
|
|
//
|
|
|
|
// Note: The InlinedVectors in this file (and in cord.h) do not need to use
|
|
|
|
// the same value for their inlined size. The fact that they do is historical.
|
|
|
|
// It may be desirable for each to use a different inlined size optimized for
|
|
|
|
// that InlinedVector's usage.
|
|
|
|
//
|
|
|
|
// TODO(jgm): Benchmark to see if there's a more optimal value than 47 for
|
|
|
|
// the inlined vector size (47 exists for backward compatibility).
|
|
|
|
kInlinedVectorSize = 47,
|
|
|
|
|
|
|
|
// Prefer copying blocks of at most this size, otherwise reference count.
|
|
|
|
kMaxBytesToCopy = 511
|
|
|
|
};
|
|
|
|
|
|
|
|
// Compact class for tracking the reference count and state flags for CordRep
|
|
|
|
// instances. Data is stored in an atomic int32_t for compactness and speed.
|
|
|
|
class RefcountAndFlags {
|
|
|
|
public:
|
|
|
|
constexpr RefcountAndFlags() : count_{kRefIncrement} {}
|
|
|
|
struct Immortal {};
|
|
|
|
explicit constexpr RefcountAndFlags(Immortal) : count_(kImmortalFlag) {}
|
Export of internal Abseil changes
--
f49e405201d2ffd5955503fa8ad0f08ec0cdfb2b by Martijn Vels <mvels@google.com>:
Add common [container.requirements] type definitions to `CharRange` and `ChunkRange`
The presence of these allow these range classes to be used in various utility functions which require some minimum type of container. For example, this change allows tests to use `EXPECT_THAT(cord.Chunks(), ElementsAre(...))`
PiperOrigin-RevId: 406941278
--
0c195f073632e21d9a4bce158047b2ba8551c2d1 by Evan Brown <ezb@google.com>:
Use explicit exponential growth in SubstituteAndAppendArray.
PiperOrigin-RevId: 406931952
--
afb043bccd809a55cab78abadb7548a057d9eda0 by Jorg Brown <jorg@google.com>:
Use longer var names in macro to avoid clang-tidy warning
PiperOrigin-RevId: 406930978
--
80397e2604e6b3d929a34742c3a32581b34d3ac4 by Martijn Vels <mvels@google.com>:
Add future kAppendBuffer and kPrependBuffer API trackers for Cordz sampling
PiperOrigin-RevId: 406912759
--
e910ce919ef83933f08a690e8b7325c7cc5b6d5d by Martijn Vels <mvels@google.com>:
Implement Prepend(string_view) in terms of PrependArray(string_view, MethodIdentifier).
PiperOrigin-RevId: 406891665
--
c9cff43d4c0568ed01f2fca0f6ef038ae03112b5 by Martijn Vels <mvels@google.com>:
Add 'Rebuild' logic to CordRepBtree
There are btree hostile scenarios where an application could perform repeated split/insert/merge operations on a cord leading to a tree exceeding the maximum height. While this should be rare in practice, this change adds a Rebuild() method that will rebuild a tree with a 100% fill factor, and we will invoke this rebuild when a tree exceeds the maximum height. This basically follows the similar 'balance' logic in Concat trees (although the latter is common in Concat uses)
PiperOrigin-RevId: 406875739
--
5b2b8fb88f1ebfdc1c670088152da2cb2ea4c376 by Martijn Vels <mvels@google.com>:
Add 'in place' enabled RemoveSuffix
An in-place RemoveSuffix is more efficient than SubTree() as it can directly modify privately owned nodes and flats allowing easy re-use of free capacity in right-most flats that may turn into Substring edges when using SubTree.
PiperOrigin-RevId: 406431230
--
f09903c0a3d7344f59aaf1380a16ea10829217d4 by Derek Mauro <dmauro@google.com>:
Internal change
PiperOrigin-RevId: 406430373
--
9957af575c33bb18dc170572a4ee8cc5901df6b2 by Greg Falcon <gfalcon@google.com>:
Initial groundwork to allow storing checksum data inside CordRep instances.
This uses a RefcountAndFlags bit that was reserved for this purpose, and will be leveraged in a follow-up change to allow attaching checksums to a Cord's value.
This change splits RefcountAndFlags::IsOne() into two distinct operations:
* IsOne(): This returns true when the associated CordRep is not shared with other threads. This is useful for functions that consume CordRep instances; for example, code that consumes an unshared CordRep can assume ownership of its children without modifying those refcounts.
* IsMutable(): This returns true when the associated CordRep reference is not shared with other threads, *and* does not store an associated checksum value. This is useful for functions that modify a CordRep's contents: code may modify the bytes of a mutable-unshared CordRep without fear of races with other threads, or of invalidating a stored checksum.
The tricky part of this CL is ensuring that the correct choice between IsMutable() and IsOne() was made at each point. An incorrect application of IsOne() could lead to correctness bugs in the future. Code conditioned on IsOne() may delete the CordRep in question, or assume ownership of its children, but must not modify the CordRep's data without explicitly adjusting the CRC.
PiperOrigin-RevId: 406191103
--
686544814079e5ab6d4593cca0c068b510be400a by Martijn Vels <mvels@google.com>:
Reduce the size in the LargeString test when running with Sanitizers
PiperOrigin-RevId: 406186945
--
735b4490bdb695c35731f06ce4b8de14ce2be6ed by Alex Strelnikov <strel@google.com>:
Release absl::SimpleHexAtoi.
PiperOrigin-RevId: 406143188
GitOrigin-RevId: f49e405201d2ffd5955503fa8ad0f08ec0cdfb2b
Change-Id: Ic6527ac40fa03ea02ca813e8bb7868a219544de4
3 years ago
|
|
|
struct WithCrc {};
|
|
|
|
explicit constexpr RefcountAndFlags(WithCrc)
|
|
|
|
: count_(kCrcFlag | kRefIncrement) {}
|
|
|
|
|
|
|
|
// Increments the reference count. Imposes no memory ordering.
|
|
|
|
inline void Increment() {
|
|
|
|
count_.fetch_add(kRefIncrement, std::memory_order_relaxed);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Asserts that the current refcount is greater than 0. If the refcount is
|
|
|
|
// greater than 1, decrements the reference count.
|
|
|
|
//
|
|
|
|
// Returns false if there are no references outstanding; true otherwise.
|
|
|
|
// Inserts barriers to ensure that state written before this method returns
|
|
|
|
// false will be visible to a thread that just observed this method returning
|
|
|
|
// false. Always returns false when the immortal bit is set.
|
|
|
|
inline bool Decrement() {
|
|
|
|
int32_t refcount = count_.load(std::memory_order_acquire) & kRefcountMask;
|
|
|
|
assert(refcount > 0 || refcount & kImmortalFlag);
|
|
|
|
return refcount != kRefIncrement &&
|
|
|
|
(count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) &
|
|
|
|
kRefcountMask) != kRefIncrement;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Same as Decrement but expect that refcount is greater than 1.
|
|
|
|
inline bool DecrementExpectHighRefcount() {
|
|
|
|
int32_t refcount =
|
|
|
|
count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) &
|
|
|
|
kRefcountMask;
|
|
|
|
assert(refcount > 0 || refcount & kImmortalFlag);
|
|
|
|
return refcount != kRefIncrement;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the current reference count using acquire semantics.
|
|
|
|
inline int32_t Get() const {
|
|
|
|
return count_.load(std::memory_order_acquire) >> kNumFlags;
|
|
|
|
}
|
|
|
|
|
Export of internal Abseil changes
--
f49e405201d2ffd5955503fa8ad0f08ec0cdfb2b by Martijn Vels <mvels@google.com>:
Add common [container.requirements] type definitions to `CharRange` and `ChunkRange`
The presence of these allow these range classes to be used in various utility functions which require some minimum type of container. For example, this change allows tests to use `EXPECT_THAT(cord.Chunks(), ElementsAre(...))`
PiperOrigin-RevId: 406941278
--
0c195f073632e21d9a4bce158047b2ba8551c2d1 by Evan Brown <ezb@google.com>:
Use explicit exponential growth in SubstituteAndAppendArray.
PiperOrigin-RevId: 406931952
--
afb043bccd809a55cab78abadb7548a057d9eda0 by Jorg Brown <jorg@google.com>:
Use longer var names in macro to avoid clang-tidy warning
PiperOrigin-RevId: 406930978
--
80397e2604e6b3d929a34742c3a32581b34d3ac4 by Martijn Vels <mvels@google.com>:
Add future kAppendBuffer and kPrependBuffer API trackers for Cordz sampling
PiperOrigin-RevId: 406912759
--
e910ce919ef83933f08a690e8b7325c7cc5b6d5d by Martijn Vels <mvels@google.com>:
Implement Prepend(string_view) in terms of PrependArray(string_view, MethodIdentifier).
PiperOrigin-RevId: 406891665
--
c9cff43d4c0568ed01f2fca0f6ef038ae03112b5 by Martijn Vels <mvels@google.com>:
Add 'Rebuild' logic to CordRepBtree
There are btree hostile scenarios where an application could perform repeated split/insert/merge operations on a cord leading to a tree exceeding the maximum height. While this should be rare in practice, this change adds a Rebuild() method that will rebuild a tree with a 100% fill factor, and we will invoke this rebuild when a tree exceeds the maximum height. This basically follows the similar 'balance' logic in Concat trees (although the latter is common in Concat uses)
PiperOrigin-RevId: 406875739
--
5b2b8fb88f1ebfdc1c670088152da2cb2ea4c376 by Martijn Vels <mvels@google.com>:
Add 'in place' enabled RemoveSuffix
An in-place RemoveSuffix is more efficient than SubTree() as it can directly modify privately owned nodes and flats allowing easy re-use of free capacity in right-most flats that may turn into Substring edges when using SubTree.
PiperOrigin-RevId: 406431230
--
f09903c0a3d7344f59aaf1380a16ea10829217d4 by Derek Mauro <dmauro@google.com>:
Internal change
PiperOrigin-RevId: 406430373
--
9957af575c33bb18dc170572a4ee8cc5901df6b2 by Greg Falcon <gfalcon@google.com>:
Initial groundwork to allow storing checksum data inside CordRep instances.
This uses a RefcountAndFlags bit that was reserved for this purpose, and will be leveraged in a follow-up change to allow attaching checksums to a Cord's value.
This change splits RefcountAndFlags::IsOne() into two distinct operations:
* IsOne(): This returns true when the associated CordRep is not shared with other threads. This is useful for functions that consume CordRep instances; for example, code that consumes an unshared CordRep can assume ownership of its children without modifying those refcounts.
* IsMutable(): This returns true when the associated CordRep reference is not shared with other threads, *and* does not store an associated checksum value. This is useful for functions that modify a CordRep's contents: code may modify the bytes of a mutable-unshared CordRep without fear of races with other threads, or of invalidating a stored checksum.
The tricky part of this CL is ensuring that the correct choice between IsMutable() and IsOne() was made at each point. An incorrect application of IsOne() could lead to correctness bugs in the future. Code conditioned on IsOne() may delete the CordRep in question, or assume ownership of its children, but must not modify the CordRep's data without explicitly adjusting the CRC.
PiperOrigin-RevId: 406191103
--
686544814079e5ab6d4593cca0c068b510be400a by Martijn Vels <mvels@google.com>:
Reduce the size in the LargeString test when running with Sanitizers
PiperOrigin-RevId: 406186945
--
735b4490bdb695c35731f06ce4b8de14ce2be6ed by Alex Strelnikov <strel@google.com>:
Release absl::SimpleHexAtoi.
PiperOrigin-RevId: 406143188
GitOrigin-RevId: f49e405201d2ffd5955503fa8ad0f08ec0cdfb2b
Change-Id: Ic6527ac40fa03ea02ca813e8bb7868a219544de4
3 years ago
|
|
|
// Returns true if the referenced object carries a CRC value.
|
|
|
|
bool HasCrc() const {
|
|
|
|
return (count_.load(std::memory_order_relaxed) & kCrcFlag) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true iff the atomic integer is 1 and this node does not store
|
|
|
|
// a CRC. When both these conditions are met, the current thread owns
|
|
|
|
// the reference and no other thread shares it, so its contents may be
|
|
|
|
// safely mutated.
|
|
|
|
//
|
|
|
|
// If the referenced item is shared, carries a CRC, or is immortal,
|
|
|
|
// it should not be modified in-place, and this function returns false.
|
|
|
|
//
|
|
|
|
// This call performs the memory barrier needed for the owning thread
|
|
|
|
// to act on the object, so that if it returns true, it may safely
|
|
|
|
// assume exclusive access to the object.
|
|
|
|
inline bool IsMutable() {
|
|
|
|
return (count_.load(std::memory_order_acquire)) == kRefIncrement;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns whether the atomic integer is 1. Similar to IsMutable(),
|
|
|
|
// but does not check for a stored CRC. (An unshared node with a CRC is not
|
|
|
|
// mutable, because changing its data would invalidate the CRC.)
|
|
|
|
//
|
|
|
|
// When this returns true, there are no other references, and data sinks
|
|
|
|
// may safely adopt the children of the CordRep.
|
|
|
|
inline bool IsOne() {
|
|
|
|
return (count_.load(std::memory_order_acquire) & kRefcountMask) ==
|
|
|
|
kRefIncrement;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsImmortal() const {
|
|
|
|
return (count_.load(std::memory_order_relaxed) & kImmortalFlag) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
// We reserve the bottom bits for flags.
|
|
|
|
// kImmortalBit indicates that this entity should never be collected; it is
|
|
|
|
// used for the StringConstant constructor to avoid collecting immutable
|
|
|
|
// constant cords.
|
|
|
|
// kReservedFlag is reserved for future use.
|
|
|
|
enum {
|
|
|
|
kNumFlags = 2,
|
|
|
|
|
|
|
|
kImmortalFlag = 0x1,
|
Export of internal Abseil changes
--
f49e405201d2ffd5955503fa8ad0f08ec0cdfb2b by Martijn Vels <mvels@google.com>:
Add common [container.requirements] type definitions to `CharRange` and `ChunkRange`
The presence of these allow these range classes to be used in various utility functions which require some minimum type of container. For example, this change allows tests to use `EXPECT_THAT(cord.Chunks(), ElementsAre(...))`
PiperOrigin-RevId: 406941278
--
0c195f073632e21d9a4bce158047b2ba8551c2d1 by Evan Brown <ezb@google.com>:
Use explicit exponential growth in SubstituteAndAppendArray.
PiperOrigin-RevId: 406931952
--
afb043bccd809a55cab78abadb7548a057d9eda0 by Jorg Brown <jorg@google.com>:
Use longer var names in macro to avoid clang-tidy warning
PiperOrigin-RevId: 406930978
--
80397e2604e6b3d929a34742c3a32581b34d3ac4 by Martijn Vels <mvels@google.com>:
Add future kAppendBuffer and kPrependBuffer API trackers for Cordz sampling
PiperOrigin-RevId: 406912759
--
e910ce919ef83933f08a690e8b7325c7cc5b6d5d by Martijn Vels <mvels@google.com>:
Implement Prepend(string_view) in terms of PrependArray(string_view, MethodIdentifier).
PiperOrigin-RevId: 406891665
--
c9cff43d4c0568ed01f2fca0f6ef038ae03112b5 by Martijn Vels <mvels@google.com>:
Add 'Rebuild' logic to CordRepBtree
There are btree hostile scenarios where an application could perform repeated split/insert/merge operations on a cord leading to a tree exceeding the maximum height. While this should be rare in practice, this change adds a Rebuild() method that will rebuild a tree with a 100% fill factor, and we will invoke this rebuild when a tree exceeds the maximum height. This basically follows the similar 'balance' logic in Concat trees (although the latter is common in Concat uses)
PiperOrigin-RevId: 406875739
--
5b2b8fb88f1ebfdc1c670088152da2cb2ea4c376 by Martijn Vels <mvels@google.com>:
Add 'in place' enabled RemoveSuffix
An in-place RemoveSuffix is more efficient than SubTree() as it can directly modify privately owned nodes and flats allowing easy re-use of free capacity in right-most flats that may turn into Substring edges when using SubTree.
PiperOrigin-RevId: 406431230
--
f09903c0a3d7344f59aaf1380a16ea10829217d4 by Derek Mauro <dmauro@google.com>:
Internal change
PiperOrigin-RevId: 406430373
--
9957af575c33bb18dc170572a4ee8cc5901df6b2 by Greg Falcon <gfalcon@google.com>:
Initial groundwork to allow storing checksum data inside CordRep instances.
This uses a RefcountAndFlags bit that was reserved for this purpose, and will be leveraged in a follow-up change to allow attaching checksums to a Cord's value.
This change splits RefcountAndFlags::IsOne() into two distinct operations:
* IsOne(): This returns true when the associated CordRep is not shared with other threads. This is useful for functions that consume CordRep instances; for example, code that consumes an unshared CordRep can assume ownership of its children without modifying those refcounts.
* IsMutable(): This returns true when the associated CordRep reference is not shared with other threads, *and* does not store an associated checksum value. This is useful for functions that modify a CordRep's contents: code may modify the bytes of a mutable-unshared CordRep without fear of races with other threads, or of invalidating a stored checksum.
The tricky part of this CL is ensuring that the correct choice between IsMutable() and IsOne() was made at each point. An incorrect application of IsOne() could lead to correctness bugs in the future. Code conditioned on IsOne() may delete the CordRep in question, or assume ownership of its children, but must not modify the CordRep's data without explicitly adjusting the CRC.
PiperOrigin-RevId: 406191103
--
686544814079e5ab6d4593cca0c068b510be400a by Martijn Vels <mvels@google.com>:
Reduce the size in the LargeString test when running with Sanitizers
PiperOrigin-RevId: 406186945
--
735b4490bdb695c35731f06ce4b8de14ce2be6ed by Alex Strelnikov <strel@google.com>:
Release absl::SimpleHexAtoi.
PiperOrigin-RevId: 406143188
GitOrigin-RevId: f49e405201d2ffd5955503fa8ad0f08ec0cdfb2b
Change-Id: Ic6527ac40fa03ea02ca813e8bb7868a219544de4
3 years ago
|
|
|
kCrcFlag = 0x2,
|
|
|
|
kRefIncrement = (1 << kNumFlags),
|
|
|
|
|
|
|
|
// Bitmask to use when checking refcount by equality. This masks out
|
|
|
|
// all flags except kImmortalFlag, which is part of the refcount for
|
|
|
|
// purposes of equality. (A refcount of 0 or 1 does not count as 0 or 1
|
|
|
|
// if the immortal bit is set.)
|
Export of internal Abseil changes
--
f49e405201d2ffd5955503fa8ad0f08ec0cdfb2b by Martijn Vels <mvels@google.com>:
Add common [container.requirements] type definitions to `CharRange` and `ChunkRange`
The presence of these allow these range classes to be used in various utility functions which require some minimum type of container. For example, this change allows tests to use `EXPECT_THAT(cord.Chunks(), ElementsAre(...))`
PiperOrigin-RevId: 406941278
--
0c195f073632e21d9a4bce158047b2ba8551c2d1 by Evan Brown <ezb@google.com>:
Use explicit exponential growth in SubstituteAndAppendArray.
PiperOrigin-RevId: 406931952
--
afb043bccd809a55cab78abadb7548a057d9eda0 by Jorg Brown <jorg@google.com>:
Use longer var names in macro to avoid clang-tidy warning
PiperOrigin-RevId: 406930978
--
80397e2604e6b3d929a34742c3a32581b34d3ac4 by Martijn Vels <mvels@google.com>:
Add future kAppendBuffer and kPrependBuffer API trackers for Cordz sampling
PiperOrigin-RevId: 406912759
--
e910ce919ef83933f08a690e8b7325c7cc5b6d5d by Martijn Vels <mvels@google.com>:
Implement Prepend(string_view) in terms of PrependArray(string_view, MethodIdentifier).
PiperOrigin-RevId: 406891665
--
c9cff43d4c0568ed01f2fca0f6ef038ae03112b5 by Martijn Vels <mvels@google.com>:
Add 'Rebuild' logic to CordRepBtree
There are btree hostile scenarios where an application could perform repeated split/insert/merge operations on a cord leading to a tree exceeding the maximum height. While this should be rare in practice, this change adds a Rebuild() method that will rebuild a tree with a 100% fill factor, and we will invoke this rebuild when a tree exceeds the maximum height. This basically follows the similar 'balance' logic in Concat trees (although the latter is common in Concat uses)
PiperOrigin-RevId: 406875739
--
5b2b8fb88f1ebfdc1c670088152da2cb2ea4c376 by Martijn Vels <mvels@google.com>:
Add 'in place' enabled RemoveSuffix
An in-place RemoveSuffix is more efficient than SubTree() as it can directly modify privately owned nodes and flats allowing easy re-use of free capacity in right-most flats that may turn into Substring edges when using SubTree.
PiperOrigin-RevId: 406431230
--
f09903c0a3d7344f59aaf1380a16ea10829217d4 by Derek Mauro <dmauro@google.com>:
Internal change
PiperOrigin-RevId: 406430373
--
9957af575c33bb18dc170572a4ee8cc5901df6b2 by Greg Falcon <gfalcon@google.com>:
Initial groundwork to allow storing checksum data inside CordRep instances.
This uses a RefcountAndFlags bit that was reserved for this purpose, and will be leveraged in a follow-up change to allow attaching checksums to a Cord's value.
This change splits RefcountAndFlags::IsOne() into two distinct operations:
* IsOne(): This returns true when the associated CordRep is not shared with other threads. This is useful for functions that consume CordRep instances; for example, code that consumes an unshared CordRep can assume ownership of its children without modifying those refcounts.
* IsMutable(): This returns true when the associated CordRep reference is not shared with other threads, *and* does not store an associated checksum value. This is useful for functions that modify a CordRep's contents: code may modify the bytes of a mutable-unshared CordRep without fear of races with other threads, or of invalidating a stored checksum.
The tricky part of this CL is ensuring that the correct choice between IsMutable() and IsOne() was made at each point. An incorrect application of IsOne() could lead to correctness bugs in the future. Code conditioned on IsOne() may delete the CordRep in question, or assume ownership of its children, but must not modify the CordRep's data without explicitly adjusting the CRC.
PiperOrigin-RevId: 406191103
--
686544814079e5ab6d4593cca0c068b510be400a by Martijn Vels <mvels@google.com>:
Reduce the size in the LargeString test when running with Sanitizers
PiperOrigin-RevId: 406186945
--
735b4490bdb695c35731f06ce4b8de14ce2be6ed by Alex Strelnikov <strel@google.com>:
Release absl::SimpleHexAtoi.
PiperOrigin-RevId: 406143188
GitOrigin-RevId: f49e405201d2ffd5955503fa8ad0f08ec0cdfb2b
Change-Id: Ic6527ac40fa03ea02ca813e8bb7868a219544de4
3 years ago
|
|
|
kRefcountMask = ~kCrcFlag,
|
|
|
|
};
|
|
|
|
|
|
|
|
std::atomic<int32_t> count_;
|
|
|
|
};
|
|
|
|
|
|
|
|
// The overhead of a vtable is too much for Cord, so we roll our own subclasses
|
|
|
|
// using only a single byte to differentiate classes from each other - the "tag"
|
|
|
|
// byte. Define the subclasses first so we can provide downcasting helper
|
|
|
|
// functions in the base class.
|
|
|
|
|
|
|
|
struct CordRepConcat;
|
|
|
|
struct CordRepExternal;
|
|
|
|
struct CordRepFlat;
|
|
|
|
struct CordRepSubstring;
|
|
|
|
class CordRepRing;
|
Export of internal Abseil changes
--
1620e8ffaa93ef24510ca60c7fff2a07248ac9f6 by Abseil Team <absl-team@google.com>:
Update comment.
PiperOrigin-RevId: 382858259
--
20db116f28469149d10e0f7f8b976cb903dd4879 by Gennadiy Rozental <rogeeff@google.com>:
Add benchmark running on multiple flags.
Update size_tester to include cost of absl::GetFlag call.
Add size_tester invocation for bool flag.
New benchmark better represent GetFlag usage.
PiperOrigin-RevId: 382820341
--
2e097ad3811c4e329f75b98877a5e74c1d3d84fd by Abseil Team <absl-team@google.com>:
Avoid 64x64->128 multiplication in absl::Hash's mix on AArch64
On AArch64, calculating a 128-bit product is inefficient, because it requires a sequence of two instructions to calculate the upper and lower halves of the result. So calculate a 64-bit product instead.
Making MultType 64-bits means the upper 32 bits of the result do not participate in shift/xor, but the add/multiply gives us sufficient mixing.
PiperOrigin-RevId: 382625931
--
f3ae3f32cb53168c8dc91b766f2932dc87cec503 by Abseil Team <absl-team@google.com>:
Remove homegrown Round implementation
absl/time/duration.cc defined a Round implementation to accommodate old
versions of MSVC that lacked std::round(long double). Abseil no longer
supports those MSVCs, so we don’t need the homegrown implementation
anymore. Remove it, and replace calls to it with std::rint.
PiperOrigin-RevId: 382605191
--
a13631c91bf5478289e1a512ce215c85501a26f7 by Martijn Vels <mvels@google.com>:
Move the Consume() conversion functions out of cord_rep_ring into cord_rep_consume.
This makes these functions generic, so we can repurpose these for the new Btree conversion functions.
PiperOrigin-RevId: 382594902
--
7394c737500c2d8371fcf913b21ad1b321ba499d by Benjamin Barenblat <bbaren@google.com>:
Remove homegrown Round implementation
absl/time/duration.cc defined a Round implementation to accommodate old
versions of MSVC that lacked std::round(long double). Abseil no longer
supports those MSVCs, so we don’t need the homegrown implementation
anymore. Remove it, and replace calls to it with std::rint.
PiperOrigin-RevId: 382569900
--
d72a761f43dc5c9b9510c3a1363177ed26646b5d by Abseil Team <absl-team@google.com>:
Prefer `getentropy` for Emscripten.
It needs a different header, so I've separated it out from the GLIBC
check above.
PiperOrigin-RevId: 382332475
--
74e261dbb467741b2ddd8b490e04c531fdd2f559 by Martijn Vels <mvels@google.com>:
Add BTREE tag for CordRepNode implementing a Btree cord.
This change only forward declared the CordRepBtree class (not implemented yet) and defines the enum value BTREE. While RING and BTREE should never co-exist, we define a new value for BTREE so as not to make transitioning between RING and BTREE harder than it needs to be. This changes shifts the FLAT value / computation from FLAT = 4 to FLAT =5
PiperOrigin-RevId: 382326710
GitOrigin-RevId: 1620e8ffaa93ef24510ca60c7fff2a07248ac9f6
Change-Id: Ia8f99dde3874808f56062bd37ab3e63764099734
4 years ago
|
|
|
class CordRepBtree;
|
|
|
|
|
|
|
|
// Various representations that we allow
|
|
|
|
enum CordRepKind {
|
|
|
|
CONCAT = 0,
|
Export of internal Abseil changes
--
b1fc72630aaa81c8395c3b22ba267d938fe29a2e by Derek Mauro <dmauro@google.com>:
Fix -Wdeprecated-copy warnings from Clang 13.
Example:
error: definition of implicit copy assignment operator for 'UDT' is deprecated because it has a user-declared copy constructor [-Werror,-Wdeprecated-copy]
PiperOrigin-RevId: 380058303
--
0422744812b1a2010d9eea5b17fbe89f3441b66b by Evan Brown <ezb@google.com>:
Change the "full table!" asserts in raw_hash_set to use `<= capacity` instead of `< capacity`.
If we add support for non-power-of-two-minus-one capacities, this is the correct thing to assert. For example, consider: Group::kWidth = 8, capacity_ = 8, ctrl_ = {kEmpty, 1, 2, 3, 4, 5, 6, 7, kSentinel, kEmpty, 1, 2, 3, 4, 5, 6}. In this case, if we do an unsuccessful lookup with H2 mapping to slot 1, then the first Group will contain {1, 2, 3, 4, 5, 6, 7, kSentinel} so we need to continue to the second Group (at which point seq.index() == 8 == capacity_) to find a kEmpty.
Note: this is a no-op change for now since we never have `capacity % Group::kWidth == 0`.
PiperOrigin-RevId: 380033480
--
40628c34d540356de65fabb16c1439c0ec7a0764 by Abseil Team <absl-team@google.com>:
Drop out-of-date documentation about `absl::FixedArray`'s allocator support
PiperOrigin-RevId: 379811653
--
e7ad047863ae55c9b7aec0753cfc527a4ea614bc by Evan Brown <ezb@google.com>:
Fix a bug in ConvertDeletedToEmptyAndFullToDeleted in which we were copying 1 more cloned control byte than actually exists.
When alignof(slot_type)>1, this wouldn't cause a problem because the extra byte is padding.
Also change loop bounds to not rely on the fact that capacity_+1 is a multiple of Group::kWidth.
PiperOrigin-RevId: 379311830
--
1a3ba500fb2c33205854eb9258cd6e0fb1061bca by Martijn Vels <mvels@google.com>:
Change Ring, EXTERNAL and FLAT tag values to be consecutive values
The purpose of this change is to have FLAT = EXTERNAL + 1. Especially in the ring and btree alternative code, there is a common check if a node is a 'plain' edge (EXTERNAL or FLAT), or 'something else'. This change can make that check a single branch, i.e., instead of 'tag == EXTERNAL || tag >= FLAT', we can simply check for 'tag >= EXTERNAL'. Likewise we have some cases where we check for RING, EXTERNAL or FLAT, so we align RING + 1 with EXTERNAL.
PiperOrigin-RevId: 379291576
--
0c78e65ca4d85244b106c3f8e24cf268e09e72a3 by Benjamin Barenblat <bbaren@google.com>:
Round a double multiplication before casting it to integer
The code
static_cast<int>(x * y)
(for double x and y) performs a double multiplication into a temporary
that, by standard, may have excess precision. The subsequent cast to int
discards the excess precision. However, the cast may examine the excess
precision during conversion, producing surprising results like
static_cast<int>(1.7 * 10) == 16
on certain systems. Correct this case by explicitly rounding 1.7 * 10
before casting it.
PiperOrigin-RevId: 378922064
GitOrigin-RevId: b1fc72630aaa81c8395c3b22ba267d938fe29a2e
Change-Id: Ica708a006921118673e78d5fd2d61fe0fb0894d1
4 years ago
|
|
|
SUBSTRING = 1,
|
Export of internal Abseil changes
--
1620e8ffaa93ef24510ca60c7fff2a07248ac9f6 by Abseil Team <absl-team@google.com>:
Update comment.
PiperOrigin-RevId: 382858259
--
20db116f28469149d10e0f7f8b976cb903dd4879 by Gennadiy Rozental <rogeeff@google.com>:
Add benchmark running on multiple flags.
Update size_tester to include cost of absl::GetFlag call.
Add size_tester invocation for bool flag.
New benchmark better represent GetFlag usage.
PiperOrigin-RevId: 382820341
--
2e097ad3811c4e329f75b98877a5e74c1d3d84fd by Abseil Team <absl-team@google.com>:
Avoid 64x64->128 multiplication in absl::Hash's mix on AArch64
On AArch64, calculating a 128-bit product is inefficient, because it requires a sequence of two instructions to calculate the upper and lower halves of the result. So calculate a 64-bit product instead.
Making MultType 64-bits means the upper 32 bits of the result do not participate in shift/xor, but the add/multiply gives us sufficient mixing.
PiperOrigin-RevId: 382625931
--
f3ae3f32cb53168c8dc91b766f2932dc87cec503 by Abseil Team <absl-team@google.com>:
Remove homegrown Round implementation
absl/time/duration.cc defined a Round implementation to accommodate old
versions of MSVC that lacked std::round(long double). Abseil no longer
supports those MSVCs, so we don’t need the homegrown implementation
anymore. Remove it, and replace calls to it with std::rint.
PiperOrigin-RevId: 382605191
--
a13631c91bf5478289e1a512ce215c85501a26f7 by Martijn Vels <mvels@google.com>:
Move the Consume() conversion functions out of cord_rep_ring into cord_rep_consume.
This makes these functions generic, so we can repurpose these for the new Btree conversion functions.
PiperOrigin-RevId: 382594902
--
7394c737500c2d8371fcf913b21ad1b321ba499d by Benjamin Barenblat <bbaren@google.com>:
Remove homegrown Round implementation
absl/time/duration.cc defined a Round implementation to accommodate old
versions of MSVC that lacked std::round(long double). Abseil no longer
supports those MSVCs, so we don’t need the homegrown implementation
anymore. Remove it, and replace calls to it with std::rint.
PiperOrigin-RevId: 382569900
--
d72a761f43dc5c9b9510c3a1363177ed26646b5d by Abseil Team <absl-team@google.com>:
Prefer `getentropy` for Emscripten.
It needs a different header, so I've separated it out from the GLIBC
check above.
PiperOrigin-RevId: 382332475
--
74e261dbb467741b2ddd8b490e04c531fdd2f559 by Martijn Vels <mvels@google.com>:
Add BTREE tag for CordRepNode implementing a Btree cord.
This change only forward declared the CordRepBtree class (not implemented yet) and defines the enum value BTREE. While RING and BTREE should never co-exist, we define a new value for BTREE so as not to make transitioning between RING and BTREE harder than it needs to be. This changes shifts the FLAT value / computation from FLAT = 4 to FLAT =5
PiperOrigin-RevId: 382326710
GitOrigin-RevId: 1620e8ffaa93ef24510ca60c7fff2a07248ac9f6
Change-Id: Ia8f99dde3874808f56062bd37ab3e63764099734
4 years ago
|
|
|
BTREE = 2,
|
|
|
|
RING = 3,
|
|
|
|
EXTERNAL = 4,
|
|
|
|
|
|
|
|
// We have different tags for different sized flat arrays,
|
Export of internal Abseil changes
--
1620e8ffaa93ef24510ca60c7fff2a07248ac9f6 by Abseil Team <absl-team@google.com>:
Update comment.
PiperOrigin-RevId: 382858259
--
20db116f28469149d10e0f7f8b976cb903dd4879 by Gennadiy Rozental <rogeeff@google.com>:
Add benchmark running on multiple flags.
Update size_tester to include cost of absl::GetFlag call.
Add size_tester invocation for bool flag.
New benchmark better represent GetFlag usage.
PiperOrigin-RevId: 382820341
--
2e097ad3811c4e329f75b98877a5e74c1d3d84fd by Abseil Team <absl-team@google.com>:
Avoid 64x64->128 multiplication in absl::Hash's mix on AArch64
On AArch64, calculating a 128-bit product is inefficient, because it requires a sequence of two instructions to calculate the upper and lower halves of the result. So calculate a 64-bit product instead.
Making MultType 64-bits means the upper 32 bits of the result do not participate in shift/xor, but the add/multiply gives us sufficient mixing.
PiperOrigin-RevId: 382625931
--
f3ae3f32cb53168c8dc91b766f2932dc87cec503 by Abseil Team <absl-team@google.com>:
Remove homegrown Round implementation
absl/time/duration.cc defined a Round implementation to accommodate old
versions of MSVC that lacked std::round(long double). Abseil no longer
supports those MSVCs, so we don’t need the homegrown implementation
anymore. Remove it, and replace calls to it with std::rint.
PiperOrigin-RevId: 382605191
--
a13631c91bf5478289e1a512ce215c85501a26f7 by Martijn Vels <mvels@google.com>:
Move the Consume() conversion functions out of cord_rep_ring into cord_rep_consume.
This makes these functions generic, so we can repurpose these for the new Btree conversion functions.
PiperOrigin-RevId: 382594902
--
7394c737500c2d8371fcf913b21ad1b321ba499d by Benjamin Barenblat <bbaren@google.com>:
Remove homegrown Round implementation
absl/time/duration.cc defined a Round implementation to accommodate old
versions of MSVC that lacked std::round(long double). Abseil no longer
supports those MSVCs, so we don’t need the homegrown implementation
anymore. Remove it, and replace calls to it with std::rint.
PiperOrigin-RevId: 382569900
--
d72a761f43dc5c9b9510c3a1363177ed26646b5d by Abseil Team <absl-team@google.com>:
Prefer `getentropy` for Emscripten.
It needs a different header, so I've separated it out from the GLIBC
check above.
PiperOrigin-RevId: 382332475
--
74e261dbb467741b2ddd8b490e04c531fdd2f559 by Martijn Vels <mvels@google.com>:
Add BTREE tag for CordRepNode implementing a Btree cord.
This change only forward declared the CordRepBtree class (not implemented yet) and defines the enum value BTREE. While RING and BTREE should never co-exist, we define a new value for BTREE so as not to make transitioning between RING and BTREE harder than it needs to be. This changes shifts the FLAT value / computation from FLAT = 4 to FLAT =5
PiperOrigin-RevId: 382326710
GitOrigin-RevId: 1620e8ffaa93ef24510ca60c7fff2a07248ac9f6
Change-Id: Ia8f99dde3874808f56062bd37ab3e63764099734
4 years ago
|
|
|
// starting with FLAT, and limited to MAX_FLAT_TAG. The 225 value is based on
|
|
|
|
// the current 'size to tag' encoding of 8 / 32 bytes. If a new tag is needed
|
|
|
|
// in the future, then 'FLAT' and 'MAX_FLAT_TAG' should be adjusted as well
|
|
|
|
// as the Tag <---> Size logic so that FLAT stil represents the minimum flat
|
|
|
|
// allocation size. (32 bytes as of now).
|
Export of internal Abseil changes
--
1620e8ffaa93ef24510ca60c7fff2a07248ac9f6 by Abseil Team <absl-team@google.com>:
Update comment.
PiperOrigin-RevId: 382858259
--
20db116f28469149d10e0f7f8b976cb903dd4879 by Gennadiy Rozental <rogeeff@google.com>:
Add benchmark running on multiple flags.
Update size_tester to include cost of absl::GetFlag call.
Add size_tester invocation for bool flag.
New benchmark better represent GetFlag usage.
PiperOrigin-RevId: 382820341
--
2e097ad3811c4e329f75b98877a5e74c1d3d84fd by Abseil Team <absl-team@google.com>:
Avoid 64x64->128 multiplication in absl::Hash's mix on AArch64
On AArch64, calculating a 128-bit product is inefficient, because it requires a sequence of two instructions to calculate the upper and lower halves of the result. So calculate a 64-bit product instead.
Making MultType 64-bits means the upper 32 bits of the result do not participate in shift/xor, but the add/multiply gives us sufficient mixing.
PiperOrigin-RevId: 382625931
--
f3ae3f32cb53168c8dc91b766f2932dc87cec503 by Abseil Team <absl-team@google.com>:
Remove homegrown Round implementation
absl/time/duration.cc defined a Round implementation to accommodate old
versions of MSVC that lacked std::round(long double). Abseil no longer
supports those MSVCs, so we don’t need the homegrown implementation
anymore. Remove it, and replace calls to it with std::rint.
PiperOrigin-RevId: 382605191
--
a13631c91bf5478289e1a512ce215c85501a26f7 by Martijn Vels <mvels@google.com>:
Move the Consume() conversion functions out of cord_rep_ring into cord_rep_consume.
This makes these functions generic, so we can repurpose these for the new Btree conversion functions.
PiperOrigin-RevId: 382594902
--
7394c737500c2d8371fcf913b21ad1b321ba499d by Benjamin Barenblat <bbaren@google.com>:
Remove homegrown Round implementation
absl/time/duration.cc defined a Round implementation to accommodate old
versions of MSVC that lacked std::round(long double). Abseil no longer
supports those MSVCs, so we don’t need the homegrown implementation
anymore. Remove it, and replace calls to it with std::rint.
PiperOrigin-RevId: 382569900
--
d72a761f43dc5c9b9510c3a1363177ed26646b5d by Abseil Team <absl-team@google.com>:
Prefer `getentropy` for Emscripten.
It needs a different header, so I've separated it out from the GLIBC
check above.
PiperOrigin-RevId: 382332475
--
74e261dbb467741b2ddd8b490e04c531fdd2f559 by Martijn Vels <mvels@google.com>:
Add BTREE tag for CordRepNode implementing a Btree cord.
This change only forward declared the CordRepBtree class (not implemented yet) and defines the enum value BTREE. While RING and BTREE should never co-exist, we define a new value for BTREE so as not to make transitioning between RING and BTREE harder than it needs to be. This changes shifts the FLAT value / computation from FLAT = 4 to FLAT =5
PiperOrigin-RevId: 382326710
GitOrigin-RevId: 1620e8ffaa93ef24510ca60c7fff2a07248ac9f6
Change-Id: Ia8f99dde3874808f56062bd37ab3e63764099734
4 years ago
|
|
|
FLAT = 5,
|
|
|
|
MAX_FLAT_TAG = 225
|
|
|
|
};
|
|
|
|
|
Export of internal Abseil changes
--
b1fc72630aaa81c8395c3b22ba267d938fe29a2e by Derek Mauro <dmauro@google.com>:
Fix -Wdeprecated-copy warnings from Clang 13.
Example:
error: definition of implicit copy assignment operator for 'UDT' is deprecated because it has a user-declared copy constructor [-Werror,-Wdeprecated-copy]
PiperOrigin-RevId: 380058303
--
0422744812b1a2010d9eea5b17fbe89f3441b66b by Evan Brown <ezb@google.com>:
Change the "full table!" asserts in raw_hash_set to use `<= capacity` instead of `< capacity`.
If we add support for non-power-of-two-minus-one capacities, this is the correct thing to assert. For example, consider: Group::kWidth = 8, capacity_ = 8, ctrl_ = {kEmpty, 1, 2, 3, 4, 5, 6, 7, kSentinel, kEmpty, 1, 2, 3, 4, 5, 6}. In this case, if we do an unsuccessful lookup with H2 mapping to slot 1, then the first Group will contain {1, 2, 3, 4, 5, 6, 7, kSentinel} so we need to continue to the second Group (at which point seq.index() == 8 == capacity_) to find a kEmpty.
Note: this is a no-op change for now since we never have `capacity % Group::kWidth == 0`.
PiperOrigin-RevId: 380033480
--
40628c34d540356de65fabb16c1439c0ec7a0764 by Abseil Team <absl-team@google.com>:
Drop out-of-date documentation about `absl::FixedArray`'s allocator support
PiperOrigin-RevId: 379811653
--
e7ad047863ae55c9b7aec0753cfc527a4ea614bc by Evan Brown <ezb@google.com>:
Fix a bug in ConvertDeletedToEmptyAndFullToDeleted in which we were copying 1 more cloned control byte than actually exists.
When alignof(slot_type)>1, this wouldn't cause a problem because the extra byte is padding.
Also change loop bounds to not rely on the fact that capacity_+1 is a multiple of Group::kWidth.
PiperOrigin-RevId: 379311830
--
1a3ba500fb2c33205854eb9258cd6e0fb1061bca by Martijn Vels <mvels@google.com>:
Change Ring, EXTERNAL and FLAT tag values to be consecutive values
The purpose of this change is to have FLAT = EXTERNAL + 1. Especially in the ring and btree alternative code, there is a common check if a node is a 'plain' edge (EXTERNAL or FLAT), or 'something else'. This change can make that check a single branch, i.e., instead of 'tag == EXTERNAL || tag >= FLAT', we can simply check for 'tag >= EXTERNAL'. Likewise we have some cases where we check for RING, EXTERNAL or FLAT, so we align RING + 1 with EXTERNAL.
PiperOrigin-RevId: 379291576
--
0c78e65ca4d85244b106c3f8e24cf268e09e72a3 by Benjamin Barenblat <bbaren@google.com>:
Round a double multiplication before casting it to integer
The code
static_cast<int>(x * y)
(for double x and y) performs a double multiplication into a temporary
that, by standard, may have excess precision. The subsequent cast to int
discards the excess precision. However, the cast may examine the excess
precision during conversion, producing surprising results like
static_cast<int>(1.7 * 10) == 16
on certain systems. Correct this case by explicitly rounding 1.7 * 10
before casting it.
PiperOrigin-RevId: 378922064
GitOrigin-RevId: b1fc72630aaa81c8395c3b22ba267d938fe29a2e
Change-Id: Ica708a006921118673e78d5fd2d61fe0fb0894d1
4 years ago
|
|
|
// There are various locations where we want to check if some rep is a 'plain'
|
|
|
|
// data edge, i.e. an external or flat rep. By having FLAT == EXTERNAL + 1, we
|
|
|
|
// can perform this check in a single branch as 'tag >= EXTERNAL'
|
|
|
|
// Likewise, we have some locations where we check for 'ring or external/flat',
|
|
|
|
// so likewise align RING to EXTERNAL.
|
|
|
|
// Note that we can leave this optimization to the compiler. The compiler will
|
|
|
|
// DTRT when it sees a condition like `tag == EXTERNAL || tag >= FLAT`.
|
Export of internal Abseil changes
--
1620e8ffaa93ef24510ca60c7fff2a07248ac9f6 by Abseil Team <absl-team@google.com>:
Update comment.
PiperOrigin-RevId: 382858259
--
20db116f28469149d10e0f7f8b976cb903dd4879 by Gennadiy Rozental <rogeeff@google.com>:
Add benchmark running on multiple flags.
Update size_tester to include cost of absl::GetFlag call.
Add size_tester invocation for bool flag.
New benchmark better represent GetFlag usage.
PiperOrigin-RevId: 382820341
--
2e097ad3811c4e329f75b98877a5e74c1d3d84fd by Abseil Team <absl-team@google.com>:
Avoid 64x64->128 multiplication in absl::Hash's mix on AArch64
On AArch64, calculating a 128-bit product is inefficient, because it requires a sequence of two instructions to calculate the upper and lower halves of the result. So calculate a 64-bit product instead.
Making MultType 64-bits means the upper 32 bits of the result do not participate in shift/xor, but the add/multiply gives us sufficient mixing.
PiperOrigin-RevId: 382625931
--
f3ae3f32cb53168c8dc91b766f2932dc87cec503 by Abseil Team <absl-team@google.com>:
Remove homegrown Round implementation
absl/time/duration.cc defined a Round implementation to accommodate old
versions of MSVC that lacked std::round(long double). Abseil no longer
supports those MSVCs, so we don’t need the homegrown implementation
anymore. Remove it, and replace calls to it with std::rint.
PiperOrigin-RevId: 382605191
--
a13631c91bf5478289e1a512ce215c85501a26f7 by Martijn Vels <mvels@google.com>:
Move the Consume() conversion functions out of cord_rep_ring into cord_rep_consume.
This makes these functions generic, so we can repurpose these for the new Btree conversion functions.
PiperOrigin-RevId: 382594902
--
7394c737500c2d8371fcf913b21ad1b321ba499d by Benjamin Barenblat <bbaren@google.com>:
Remove homegrown Round implementation
absl/time/duration.cc defined a Round implementation to accommodate old
versions of MSVC that lacked std::round(long double). Abseil no longer
supports those MSVCs, so we don’t need the homegrown implementation
anymore. Remove it, and replace calls to it with std::rint.
PiperOrigin-RevId: 382569900
--
d72a761f43dc5c9b9510c3a1363177ed26646b5d by Abseil Team <absl-team@google.com>:
Prefer `getentropy` for Emscripten.
It needs a different header, so I've separated it out from the GLIBC
check above.
PiperOrigin-RevId: 382332475
--
74e261dbb467741b2ddd8b490e04c531fdd2f559 by Martijn Vels <mvels@google.com>:
Add BTREE tag for CordRepNode implementing a Btree cord.
This change only forward declared the CordRepBtree class (not implemented yet) and defines the enum value BTREE. While RING and BTREE should never co-exist, we define a new value for BTREE so as not to make transitioning between RING and BTREE harder than it needs to be. This changes shifts the FLAT value / computation from FLAT = 4 to FLAT =5
PiperOrigin-RevId: 382326710
GitOrigin-RevId: 1620e8ffaa93ef24510ca60c7fff2a07248ac9f6
Change-Id: Ia8f99dde3874808f56062bd37ab3e63764099734
4 years ago
|
|
|
static_assert(RING == BTREE + 1, "BTREE and RING not consecutive");
|
|
|
|
static_assert(EXTERNAL == RING + 1, "BTREE and EXTERNAL not consecutive");
|
|
|
|
static_assert(FLAT == EXTERNAL + 1, "EXTERNAL and FLAT not consecutive");
|
Export of internal Abseil changes
--
b1fc72630aaa81c8395c3b22ba267d938fe29a2e by Derek Mauro <dmauro@google.com>:
Fix -Wdeprecated-copy warnings from Clang 13.
Example:
error: definition of implicit copy assignment operator for 'UDT' is deprecated because it has a user-declared copy constructor [-Werror,-Wdeprecated-copy]
PiperOrigin-RevId: 380058303
--
0422744812b1a2010d9eea5b17fbe89f3441b66b by Evan Brown <ezb@google.com>:
Change the "full table!" asserts in raw_hash_set to use `<= capacity` instead of `< capacity`.
If we add support for non-power-of-two-minus-one capacities, this is the correct thing to assert. For example, consider: Group::kWidth = 8, capacity_ = 8, ctrl_ = {kEmpty, 1, 2, 3, 4, 5, 6, 7, kSentinel, kEmpty, 1, 2, 3, 4, 5, 6}. In this case, if we do an unsuccessful lookup with H2 mapping to slot 1, then the first Group will contain {1, 2, 3, 4, 5, 6, 7, kSentinel} so we need to continue to the second Group (at which point seq.index() == 8 == capacity_) to find a kEmpty.
Note: this is a no-op change for now since we never have `capacity % Group::kWidth == 0`.
PiperOrigin-RevId: 380033480
--
40628c34d540356de65fabb16c1439c0ec7a0764 by Abseil Team <absl-team@google.com>:
Drop out-of-date documentation about `absl::FixedArray`'s allocator support
PiperOrigin-RevId: 379811653
--
e7ad047863ae55c9b7aec0753cfc527a4ea614bc by Evan Brown <ezb@google.com>:
Fix a bug in ConvertDeletedToEmptyAndFullToDeleted in which we were copying 1 more cloned control byte than actually exists.
When alignof(slot_type)>1, this wouldn't cause a problem because the extra byte is padding.
Also change loop bounds to not rely on the fact that capacity_+1 is a multiple of Group::kWidth.
PiperOrigin-RevId: 379311830
--
1a3ba500fb2c33205854eb9258cd6e0fb1061bca by Martijn Vels <mvels@google.com>:
Change Ring, EXTERNAL and FLAT tag values to be consecutive values
The purpose of this change is to have FLAT = EXTERNAL + 1. Especially in the ring and btree alternative code, there is a common check if a node is a 'plain' edge (EXTERNAL or FLAT), or 'something else'. This change can make that check a single branch, i.e., instead of 'tag == EXTERNAL || tag >= FLAT', we can simply check for 'tag >= EXTERNAL'. Likewise we have some cases where we check for RING, EXTERNAL or FLAT, so we align RING + 1 with EXTERNAL.
PiperOrigin-RevId: 379291576
--
0c78e65ca4d85244b106c3f8e24cf268e09e72a3 by Benjamin Barenblat <bbaren@google.com>:
Round a double multiplication before casting it to integer
The code
static_cast<int>(x * y)
(for double x and y) performs a double multiplication into a temporary
that, by standard, may have excess precision. The subsequent cast to int
discards the excess precision. However, the cast may examine the excess
precision during conversion, producing surprising results like
static_cast<int>(1.7 * 10) == 16
on certain systems. Correct this case by explicitly rounding 1.7 * 10
before casting it.
PiperOrigin-RevId: 378922064
GitOrigin-RevId: b1fc72630aaa81c8395c3b22ba267d938fe29a2e
Change-Id: Ica708a006921118673e78d5fd2d61fe0fb0894d1
4 years ago
|
|
|
|
|
|
|
struct CordRep {
|
|
|
|
CordRep() = default;
|
|
|
|
constexpr CordRep(RefcountAndFlags::Immortal immortal, size_t l)
|
|
|
|
: length(l), refcount(immortal), tag(EXTERNAL), storage{} {}
|
|
|
|
|
|
|
|
// The following three fields have to be less than 32 bytes since
|
|
|
|
// that is the smallest supported flat node size.
|
|
|
|
size_t length;
|
|
|
|
RefcountAndFlags refcount;
|
|
|
|
// If tag < FLAT, it represents CordRepKind and indicates the type of node.
|
|
|
|
// Otherwise, the node type is CordRepFlat and the tag is the encoded size.
|
|
|
|
uint8_t tag;
|
Export of internal Abseil changes
--
007ce045d5d38a727ededdb5bf06e64785fd73bd by Martijn Vels <mvels@google.com>:
Add `cord_enable_btree` feature flag (default false).
PiperOrigin-RevId: 383729939
--
98e7dc6a0407b0fd7b8713d883cdb3a766e0583d by Benjamin Barenblat <bbaren@google.com>:
Eliminate some byte swapping from randen_slow
Stop swapping bytes when serializing randen_slow’s Vector128 into and
out of memory. Instead, simply index different bytes in the AES round
function. This requires byte swapping the te{0..3} lookup tables, but it
produces an 8% speedup on my Xeon W-2135.
PiperOrigin-RevId: 383689402
--
180b6bf45049188840d439b16a28e6b968669340 by Evan Brown <ezb@google.com>:
Minor simplification in drop_deletes_without_resize() - save probe_offset outside the lambda.
Also, add some consts, avoid an auto, and use lambda capture by value instead of reference.
I realized that the compiler can already optimize this - https://godbolt.org/z/Wxd9c4TfK, but I think this way makes the code a bit clearer.
PiperOrigin-RevId: 383646658
--
781706a974c4dc1c0abbb6b801fca0550229e883 by Martijn Vels <mvels@google.com>:
Change storage to contain 3 bytes.
As per the comments in the code, this allows us to utilize all available space in CordRep that may otherwise be 'lost' in padding in derived clases. For the upcoming CordrepBtree class, we want a strong guarantee on having a 64 bytes aligned implementation.
PiperOrigin-RevId: 383633963
--
8fe22ecf92492fa6649938a2215934ebfe01c714 by Derek Mauro <dmauro@google.com>:
Remove reference to str_format_arg.h, which no longer exists
PiperOrigin-RevId: 383517865
--
79397f3b18f18c1e2d7aea993b687329d626ce64 by Benjamin Barenblat <bbaren@google.com>:
Use absl::uint128 for AES random number generator
Replace randen’s internal 128-bit integer struct, u64x2, with
absl::uint128. This eliminates some code and improves support for
big-endian platforms.
PiperOrigin-RevId: 383475671
GitOrigin-RevId: 007ce045d5d38a727ededdb5bf06e64785fd73bd
Change-Id: Ia9d9c40de557221f1744fb0d6d4d6ca7ac569070
4 years ago
|
|
|
|
|
|
|
// `storage` provides two main purposes:
|
|
|
|
// - the starting point for FlatCordRep.Data() [flexible-array-member]
|
|
|
|
// - 3 bytes of additional storage for use by derived classes.
|
|
|
|
// The latter is used by CordrepConcat and CordRepBtree. CordRepConcat stores
|
|
|
|
// a 'depth' value in storage[0], and the (future) CordRepBtree class stores
|
|
|
|
// `height`, `begin` and `end` in the 3 entries. Otherwise we would need to
|
|
|
|
// allocate room for these in the derived class, as not all compilers reuse
|
|
|
|
// padding space from the base class (clang and gcc do, MSVC does not, etc)
|
|
|
|
uint8_t storage[3];
|
|
|
|
|
|
|
|
// Returns true if this instance's tag matches the requested type.
|
|
|
|
constexpr bool IsRing() const { return tag == RING; }
|
|
|
|
constexpr bool IsConcat() const { return tag == CONCAT; }
|
|
|
|
constexpr bool IsSubstring() const { return tag == SUBSTRING; }
|
|
|
|
constexpr bool IsExternal() const { return tag == EXTERNAL; }
|
|
|
|
constexpr bool IsFlat() const { return tag >= FLAT; }
|
|
|
|
constexpr bool IsBtree() const { return tag == BTREE; }
|
|
|
|
|
|
|
|
inline CordRepRing* ring();
|
|
|
|
inline const CordRepRing* ring() const;
|
|
|
|
inline CordRepConcat* concat();
|
|
|
|
inline const CordRepConcat* concat() const;
|
|
|
|
inline CordRepSubstring* substring();
|
|
|
|
inline const CordRepSubstring* substring() const;
|
|
|
|
inline CordRepExternal* external();
|
|
|
|
inline const CordRepExternal* external() const;
|
|
|
|
inline CordRepFlat* flat();
|
|
|
|
inline const CordRepFlat* flat() const;
|
Export of internal Abseil changes
--
1620e8ffaa93ef24510ca60c7fff2a07248ac9f6 by Abseil Team <absl-team@google.com>:
Update comment.
PiperOrigin-RevId: 382858259
--
20db116f28469149d10e0f7f8b976cb903dd4879 by Gennadiy Rozental <rogeeff@google.com>:
Add benchmark running on multiple flags.
Update size_tester to include cost of absl::GetFlag call.
Add size_tester invocation for bool flag.
New benchmark better represent GetFlag usage.
PiperOrigin-RevId: 382820341
--
2e097ad3811c4e329f75b98877a5e74c1d3d84fd by Abseil Team <absl-team@google.com>:
Avoid 64x64->128 multiplication in absl::Hash's mix on AArch64
On AArch64, calculating a 128-bit product is inefficient, because it requires a sequence of two instructions to calculate the upper and lower halves of the result. So calculate a 64-bit product instead.
Making MultType 64-bits means the upper 32 bits of the result do not participate in shift/xor, but the add/multiply gives us sufficient mixing.
PiperOrigin-RevId: 382625931
--
f3ae3f32cb53168c8dc91b766f2932dc87cec503 by Abseil Team <absl-team@google.com>:
Remove homegrown Round implementation
absl/time/duration.cc defined a Round implementation to accommodate old
versions of MSVC that lacked std::round(long double). Abseil no longer
supports those MSVCs, so we don’t need the homegrown implementation
anymore. Remove it, and replace calls to it with std::rint.
PiperOrigin-RevId: 382605191
--
a13631c91bf5478289e1a512ce215c85501a26f7 by Martijn Vels <mvels@google.com>:
Move the Consume() conversion functions out of cord_rep_ring into cord_rep_consume.
This makes these functions generic, so we can repurpose these for the new Btree conversion functions.
PiperOrigin-RevId: 382594902
--
7394c737500c2d8371fcf913b21ad1b321ba499d by Benjamin Barenblat <bbaren@google.com>:
Remove homegrown Round implementation
absl/time/duration.cc defined a Round implementation to accommodate old
versions of MSVC that lacked std::round(long double). Abseil no longer
supports those MSVCs, so we don’t need the homegrown implementation
anymore. Remove it, and replace calls to it with std::rint.
PiperOrigin-RevId: 382569900
--
d72a761f43dc5c9b9510c3a1363177ed26646b5d by Abseil Team <absl-team@google.com>:
Prefer `getentropy` for Emscripten.
It needs a different header, so I've separated it out from the GLIBC
check above.
PiperOrigin-RevId: 382332475
--
74e261dbb467741b2ddd8b490e04c531fdd2f559 by Martijn Vels <mvels@google.com>:
Add BTREE tag for CordRepNode implementing a Btree cord.
This change only forward declared the CordRepBtree class (not implemented yet) and defines the enum value BTREE. While RING and BTREE should never co-exist, we define a new value for BTREE so as not to make transitioning between RING and BTREE harder than it needs to be. This changes shifts the FLAT value / computation from FLAT = 4 to FLAT =5
PiperOrigin-RevId: 382326710
GitOrigin-RevId: 1620e8ffaa93ef24510ca60c7fff2a07248ac9f6
Change-Id: Ia8f99dde3874808f56062bd37ab3e63764099734
4 years ago
|
|
|
inline CordRepBtree* btree();
|
|
|
|
inline const CordRepBtree* btree() const;
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Memory management
|
|
|
|
|
|
|
|
// Destroys the provided `rep`.
|
|
|
|
static void Destroy(CordRep* rep);
|
|
|
|
|
|
|
|
// Increments the reference count of `rep`.
|
|
|
|
// Requires `rep` to be a non-null pointer value.
|
|
|
|
static inline CordRep* Ref(CordRep* rep);
|
|
|
|
|
|
|
|
// Decrements the reference count of `rep`. Destroys rep if count reaches
|
|
|
|
// zero. Requires `rep` to be a non-null pointer value.
|
|
|
|
static inline void Unref(CordRep* rep);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct CordRepConcat : public CordRep {
|
|
|
|
CordRep* left;
|
|
|
|
CordRep* right;
|
|
|
|
|
Export of internal Abseil changes
--
007ce045d5d38a727ededdb5bf06e64785fd73bd by Martijn Vels <mvels@google.com>:
Add `cord_enable_btree` feature flag (default false).
PiperOrigin-RevId: 383729939
--
98e7dc6a0407b0fd7b8713d883cdb3a766e0583d by Benjamin Barenblat <bbaren@google.com>:
Eliminate some byte swapping from randen_slow
Stop swapping bytes when serializing randen_slow’s Vector128 into and
out of memory. Instead, simply index different bytes in the AES round
function. This requires byte swapping the te{0..3} lookup tables, but it
produces an 8% speedup on my Xeon W-2135.
PiperOrigin-RevId: 383689402
--
180b6bf45049188840d439b16a28e6b968669340 by Evan Brown <ezb@google.com>:
Minor simplification in drop_deletes_without_resize() - save probe_offset outside the lambda.
Also, add some consts, avoid an auto, and use lambda capture by value instead of reference.
I realized that the compiler can already optimize this - https://godbolt.org/z/Wxd9c4TfK, but I think this way makes the code a bit clearer.
PiperOrigin-RevId: 383646658
--
781706a974c4dc1c0abbb6b801fca0550229e883 by Martijn Vels <mvels@google.com>:
Change storage to contain 3 bytes.
As per the comments in the code, this allows us to utilize all available space in CordRep that may otherwise be 'lost' in padding in derived clases. For the upcoming CordrepBtree class, we want a strong guarantee on having a 64 bytes aligned implementation.
PiperOrigin-RevId: 383633963
--
8fe22ecf92492fa6649938a2215934ebfe01c714 by Derek Mauro <dmauro@google.com>:
Remove reference to str_format_arg.h, which no longer exists
PiperOrigin-RevId: 383517865
--
79397f3b18f18c1e2d7aea993b687329d626ce64 by Benjamin Barenblat <bbaren@google.com>:
Use absl::uint128 for AES random number generator
Replace randen’s internal 128-bit integer struct, u64x2, with
absl::uint128. This eliminates some code and improves support for
big-endian platforms.
PiperOrigin-RevId: 383475671
GitOrigin-RevId: 007ce045d5d38a727ededdb5bf06e64785fd73bd
Change-Id: Ia9d9c40de557221f1744fb0d6d4d6ca7ac569070
4 years ago
|
|
|
uint8_t depth() const { return storage[0]; }
|
|
|
|
void set_depth(uint8_t depth) { storage[0] = depth; }
|
|
|
|
};
|
|
|
|
|
|
|
|
struct CordRepSubstring : public CordRep {
|
|
|
|
size_t start; // Starting offset of substring in child
|
|
|
|
CordRep* child;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Type for function pointer that will invoke the releaser function and also
|
|
|
|
// delete the `CordRepExternalImpl` corresponding to the passed in
|
|
|
|
// `CordRepExternal`.
|
|
|
|
using ExternalReleaserInvoker = void (*)(CordRepExternal*);
|
|
|
|
|
|
|
|
// External CordReps are allocated together with a type erased releaser. The
|
|
|
|
// releaser is stored in the memory directly following the CordRepExternal.
|
|
|
|
struct CordRepExternal : public CordRep {
|
|
|
|
CordRepExternal() = default;
|
|
|
|
explicit constexpr CordRepExternal(absl::string_view str)
|
|
|
|
: CordRep(RefcountAndFlags::Immortal{}, str.size()),
|
|
|
|
base(str.data()),
|
|
|
|
releaser_invoker(nullptr) {}
|
|
|
|
|
|
|
|
const char* base;
|
|
|
|
// Pointer to function that knows how to call and destroy the releaser.
|
|
|
|
ExternalReleaserInvoker releaser_invoker;
|
|
|
|
|
|
|
|
// Deletes (releases) the external rep.
|
|
|
|
// Requires rep != nullptr and rep->IsExternal()
|
|
|
|
static void Delete(CordRep* rep);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Rank1 {};
|
|
|
|
struct Rank0 : Rank1 {};
|
|
|
|
|
|
|
|
template <typename Releaser, typename = ::absl::base_internal::invoke_result_t<
|
|
|
|
Releaser, absl::string_view>>
|
|
|
|
void InvokeReleaser(Rank0, Releaser&& releaser, absl::string_view data) {
|
|
|
|
::absl::base_internal::invoke(std::forward<Releaser>(releaser), data);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Releaser,
|
|
|
|
typename = ::absl::base_internal::invoke_result_t<Releaser>>
|
|
|
|
void InvokeReleaser(Rank1, Releaser&& releaser, absl::string_view) {
|
|
|
|
::absl::base_internal::invoke(std::forward<Releaser>(releaser));
|
|
|
|
}
|
|
|
|
|
|
|
|
// We use CompressedTuple so that we can benefit from EBCO.
|
|
|
|
template <typename Releaser>
|
|
|
|
struct CordRepExternalImpl
|
|
|
|
: public CordRepExternal,
|
|
|
|
public ::absl::container_internal::CompressedTuple<Releaser> {
|
|
|
|
// The extra int arg is so that we can avoid interfering with copy/move
|
|
|
|
// constructors while still benefitting from perfect forwarding.
|
|
|
|
template <typename T>
|
|
|
|
CordRepExternalImpl(T&& releaser, int)
|
|
|
|
: CordRepExternalImpl::CompressedTuple(std::forward<T>(releaser)) {
|
|
|
|
this->releaser_invoker = &Release;
|
|
|
|
}
|
|
|
|
|
|
|
|
~CordRepExternalImpl() {
|
|
|
|
InvokeReleaser(Rank0{}, std::move(this->template get<0>()),
|
|
|
|
absl::string_view(base, length));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Release(CordRepExternal* rep) {
|
|
|
|
delete static_cast<CordRepExternalImpl*>(rep);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
inline void CordRepExternal::Delete(CordRep* rep) {
|
|
|
|
assert(rep != nullptr && rep->IsExternal());
|
|
|
|
auto* rep_external = static_cast<CordRepExternal*>(rep);
|
|
|
|
assert(rep_external->releaser_invoker != nullptr);
|
|
|
|
rep_external->releaser_invoker(rep_external);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Str>
|
|
|
|
struct ConstInitExternalStorage {
|
|
|
|
ABSL_CONST_INIT static CordRepExternal value;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename Str>
|
|
|
|
CordRepExternal ConstInitExternalStorage<Str>::value(Str::value);
|
|
|
|
|
|
|
|
enum {
|
|
|
|
kMaxInline = 15,
|
|
|
|
};
|
|
|
|
|
|
|
|
constexpr char GetOrNull(absl::string_view data, size_t pos) {
|
|
|
|
return pos < data.size() ? data[pos] : '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
// We store cordz_info as 64 bit pointer value in big endian format. This
|
|
|
|
// guarantees that the least significant byte of cordz_info matches the last
|
|
|
|
// byte of the inline data representation in as_chars_, which holds the inlined
|
|
|
|
// size or the 'is_tree' bit.
|
|
|
|
using cordz_info_t = int64_t;
|
|
|
|
|
|
|
|
// Assert that the `cordz_info` pointer value perfectly overlaps the last half
|
|
|
|
// of `as_chars_` and can hold a pointer value.
|
|
|
|
static_assert(sizeof(cordz_info_t) * 2 == kMaxInline + 1, "");
|
|
|
|
static_assert(sizeof(cordz_info_t) >= sizeof(intptr_t), "");
|
|
|
|
|
|
|
|
// BigEndianByte() creates a big endian representation of 'value', i.e.: a big
|
|
|
|
// endian value where the last byte in the host's representation holds 'value`,
|
|
|
|
// with all other bytes being 0.
|
|
|
|
static constexpr cordz_info_t BigEndianByte(unsigned char value) {
|
|
|
|
#if defined(ABSL_IS_BIG_ENDIAN)
|
|
|
|
return value;
|
|
|
|
#else
|
|
|
|
return static_cast<cordz_info_t>(value) << ((sizeof(cordz_info_t) - 1) * 8);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
class InlineData {
|
|
|
|
public:
|
|
|
|
// DefaultInitType forces the use of the default initialization constructor.
|
|
|
|
enum DefaultInitType { kDefaultInit };
|
|
|
|
|
|
|
|
// kNullCordzInfo holds the big endian representation of intptr_t(1)
|
|
|
|
// This is the 'null' / initial value of 'cordz_info'. The null value
|
|
|
|
// is specifically big endian 1 as with 64-bit pointers, the last
|
|
|
|
// byte of cordz_info overlaps with the last byte holding the tag.
|
|
|
|
static constexpr cordz_info_t kNullCordzInfo = BigEndianByte(1);
|
|
|
|
|
|
|
|
constexpr InlineData() : as_chars_{0} {}
|
|
|
|
explicit InlineData(DefaultInitType) {}
|
|
|
|
explicit constexpr InlineData(CordRep* rep) : as_tree_(rep) {}
|
|
|
|
explicit constexpr InlineData(absl::string_view chars)
|
|
|
|
: as_chars_{
|
|
|
|
GetOrNull(chars, 0), GetOrNull(chars, 1),
|
|
|
|
GetOrNull(chars, 2), GetOrNull(chars, 3),
|
|
|
|
GetOrNull(chars, 4), GetOrNull(chars, 5),
|
|
|
|
GetOrNull(chars, 6), GetOrNull(chars, 7),
|
|
|
|
GetOrNull(chars, 8), GetOrNull(chars, 9),
|
|
|
|
GetOrNull(chars, 10), GetOrNull(chars, 11),
|
|
|
|
GetOrNull(chars, 12), GetOrNull(chars, 13),
|
|
|
|
GetOrNull(chars, 14), static_cast<char>((chars.size() << 1))} {}
|
|
|
|
|
|
|
|
// Returns true if the current instance is empty.
|
|
|
|
// The 'empty value' is an inlined data value of zero length.
|
|
|
|
bool is_empty() const { return tag() == 0; }
|
|
|
|
|
|
|
|
// Returns true if the current instance holds a tree value.
|
|
|
|
bool is_tree() const { return (tag() & 1) != 0; }
|
|
|
|
|
|
|
|
// Returns true if the current instance holds a cordz_info value.
|
|
|
|
// Requires the current instance to hold a tree value.
|
|
|
|
bool is_profiled() const {
|
|
|
|
assert(is_tree());
|
|
|
|
return as_tree_.cordz_info != kNullCordzInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true if either of the provided instances hold a cordz_info value.
|
|
|
|
// This method is more efficient than the equivalent `data1.is_profiled() ||
|
|
|
|
// data2.is_profiled()`. Requires both arguments to hold a tree.
|
|
|
|
static bool is_either_profiled(const InlineData& data1,
|
|
|
|
const InlineData& data2) {
|
|
|
|
assert(data1.is_tree() && data2.is_tree());
|
|
|
|
return (data1.as_tree_.cordz_info | data2.as_tree_.cordz_info) !=
|
|
|
|
kNullCordzInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the cordz_info sampling instance for this instance, or nullptr
|
|
|
|
// if the current instance is not sampled and does not have CordzInfo data.
|
|
|
|
// Requires the current instance to hold a tree value.
|
|
|
|
CordzInfo* cordz_info() const {
|
|
|
|
assert(is_tree());
|
|
|
|
intptr_t info =
|
|
|
|
static_cast<intptr_t>(absl::big_endian::ToHost64(as_tree_.cordz_info));
|
|
|
|
assert(info & 1);
|
|
|
|
return reinterpret_cast<CordzInfo*>(info - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sets the current cordz_info sampling instance for this instance, or nullptr
|
|
|
|
// if the current instance is not sampled and does not have CordzInfo data.
|
|
|
|
// Requires the current instance to hold a tree value.
|
|
|
|
void set_cordz_info(CordzInfo* cordz_info) {
|
|
|
|
assert(is_tree());
|
|
|
|
intptr_t info = reinterpret_cast<intptr_t>(cordz_info) | 1;
|
|
|
|
as_tree_.cordz_info = absl::big_endian::FromHost64(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resets the current cordz_info to null / empty.
|
|
|
|
void clear_cordz_info() {
|
|
|
|
assert(is_tree());
|
|
|
|
as_tree_.cordz_info = kNullCordzInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a read only pointer to the character data inside this instance.
|
|
|
|
// Requires the current instance to hold inline data.
|
|
|
|
const char* as_chars() const {
|
|
|
|
assert(!is_tree());
|
|
|
|
return as_chars_;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a mutable pointer to the character data inside this instance.
|
|
|
|
// Should be used for 'write only' operations setting an inlined value.
|
|
|
|
// Applications can set the value of inlined data either before or after
|
|
|
|
// setting the inlined size, i.e., both of the below are valid:
|
|
|
|
//
|
|
|
|
// // Set inlined data and inline size
|
|
|
|
// memcpy(data_.as_chars(), data, size);
|
|
|
|
// data_.set_inline_size(size);
|
|
|
|
//
|
|
|
|
// // Set inlined size and inline data
|
|
|
|
// data_.set_inline_size(size);
|
|
|
|
// memcpy(data_.as_chars(), data, size);
|
|
|
|
//
|
|
|
|
// It's an error to read from the returned pointer without a preceding write
|
|
|
|
// if the current instance does not hold inline data, i.e.: is_tree() == true.
|
|
|
|
char* as_chars() { return as_chars_; }
|
|
|
|
|
|
|
|
// Returns the tree value of this value.
|
|
|
|
// Requires the current instance to hold a tree value.
|
|
|
|
CordRep* as_tree() const {
|
|
|
|
assert(is_tree());
|
|
|
|
return as_tree_.rep;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize this instance to holding the tree value `rep`,
|
|
|
|
// initializing the cordz_info to null, i.e.: 'not profiled'.
|
|
|
|
void make_tree(CordRep* rep) {
|
|
|
|
as_tree_.rep = rep;
|
|
|
|
as_tree_.cordz_info = kNullCordzInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the tree value of this instance to 'rep`.
|
|
|
|
// Requires the current instance to already hold a tree value.
|
|
|
|
// Does not affect the value of cordz_info.
|
|
|
|
void set_tree(CordRep* rep) {
|
|
|
|
assert(is_tree());
|
|
|
|
as_tree_.rep = rep;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the size of the inlined character data inside this instance.
|
|
|
|
// Requires the current instance to hold inline data.
|
|
|
|
size_t inline_size() const {
|
|
|
|
assert(!is_tree());
|
|
|
|
return tag() >> 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sets the size of the inlined character data inside this instance.
|
|
|
|
// Requires `size` to be <= kMaxInline.
|
|
|
|
// See the documentation on 'as_chars()' for more information and examples.
|
|
|
|
void set_inline_size(size_t size) {
|
|
|
|
ABSL_ASSERT(size <= kMaxInline);
|
|
|
|
tag() = static_cast<char>(size << 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
// See cordz_info_t for forced alignment and size of `cordz_info` details.
|
|
|
|
struct AsTree {
|
|
|
|
explicit constexpr AsTree(absl::cord_internal::CordRep* tree)
|
|
|
|
: rep(tree), cordz_info(kNullCordzInfo) {}
|
|
|
|
// This union uses up extra space so that whether rep is 32 or 64 bits,
|
|
|
|
// cordz_info will still start at the eighth byte, and the last
|
|
|
|
// byte of cordz_info will still be the last byte of InlineData.
|
|
|
|
union {
|
|
|
|
absl::cord_internal::CordRep* rep;
|
|
|
|
cordz_info_t unused_aligner;
|
|
|
|
};
|
|
|
|
cordz_info_t cordz_info;
|
|
|
|
};
|
|
|
|
|
|
|
|
char& tag() { return reinterpret_cast<char*>(this)[kMaxInline]; }
|
|
|
|
char tag() const { return reinterpret_cast<const char*>(this)[kMaxInline]; }
|
|
|
|
|
|
|
|
// If the data has length <= kMaxInline, we store it in `as_chars_`, and
|
|
|
|
// store the size in the last char of `as_chars_` shifted left + 1.
|
|
|
|
// Else we store it in a tree and store a pointer to that tree in
|
|
|
|
// `as_tree_.rep` and store a tag in `tagged_size`.
|
|
|
|
union {
|
|
|
|
char as_chars_[kMaxInline + 1];
|
|
|
|
AsTree as_tree_;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
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() {
|
|
|
|
assert(IsSubstring());
|
|
|
|
return static_cast<CordRepSubstring*>(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const CordRepSubstring* CordRep::substring() const {
|
|
|
|
assert(IsSubstring());
|
|
|
|
return static_cast<const CordRepSubstring*>(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline CordRepExternal* CordRep::external() {
|
|
|
|
assert(IsExternal());
|
|
|
|
return static_cast<CordRepExternal*>(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const CordRepExternal* CordRep::external() const {
|
|
|
|
assert(IsExternal());
|
|
|
|
return static_cast<const CordRepExternal*>(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline CordRep* CordRep::Ref(CordRep* rep) {
|
|
|
|
assert(rep != nullptr);
|
|
|
|
rep->refcount.Increment();
|
|
|
|
return rep;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void CordRep::Unref(CordRep* rep) {
|
|
|
|
assert(rep != nullptr);
|
|
|
|
// Expect refcount to be 0. Avoiding the cost of an atomic decrement should
|
|
|
|
// typically outweigh the cost of an extra branch checking for ref == 1.
|
|
|
|
if (ABSL_PREDICT_FALSE(!rep->refcount.DecrementExpectHighRefcount())) {
|
|
|
|
Destroy(rep);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace cord_internal
|
|
|
|
|
|
|
|
ABSL_NAMESPACE_END
|
|
|
|
} // namespace absl
|
|
|
|
#endif // ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_
|