mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 12:07:05 +08:00
Export of internal Abseil changes
-- 730bb88bee556aa11fa19aa33e1434cb6fa78985 by Evan Brown <ezb@google.com>: Support missing allocator-related constructors in b-tree. See [reference](https://en.cppreference.com/w/cpp/container/set/set). Also use allocator_traits::select_on_container_copy_construction() to get allocator for copy construction. PiperOrigin-RevId: 339058322 -- b6cc121689ae3e452d1db2d66122cb198d25142b by Derek Mauro <dmauro@google.com>: Fix more sign-compare warnings PiperOrigin-RevId: 339057920 -- 0e2c62da1dcaf6529abab952bdcc96c6de2d9506 by Abseil Team <absl-team@google.com>: Add missing <limits> include PiperOrigin-RevId: 339054753 -- d5a9ec2d1e40fe6359e720942e4955009ee415ec by Derek Mauro <dmauro@google.com>: Stop disabling sign-compare warnings for non-test targets. Our users complain about these. This does not catch issues in header-only libraries (like btree.h) but we may work on those in the future PiperOrigin-RevId: 338967089 -- 0c062c542a4c61ea0f65d25811827c0858e3adde by Abseil Team <absl-team@google.com>: Improve cache-locality for ThreadIdentity and PerThreadSynch. This is a change based on an observation in RPC benchmarks that shows significant cycles being spent in waking up a thread, 99.8% of which was on cache misses. Investigating this a bit more, it turns out to be due to sharing the cache line with the waiter state. To fix this issue, the following changes are introduced: - Reorder fields in PerThreadSync so that it fits in a single cache line The size of this structure was 80 bytes before this change. Note: Manually inspected all booleans to make sure they are not modified by multiple threads concurrently. PiperOrigin-RevId: 338852058 -- a90d6f2b2346385017e32dd8ae1b5ca691a5863f by Derek Mauro <dmauro@google.com>: Delete GCC 4.9 test script. It is no longer supported PiperOrigin-RevId: 338779452 -- 7274008d4757e88869110be9db39d03d911ae2b5 by Abseil Team <absl-team@google.com>: Fix the usage example in which SetFlag should take a pointer. PiperOrigin-RevId: 338744529 GitOrigin-RevId: 730bb88bee556aa11fa19aa33e1434cb6fa78985 Change-Id: Iff99594c4022e60e482a392d334b376c7ae8883e
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include "absl/base/config.h"
|
#include "absl/base/config.h"
|
||||||
#include "absl/base/internal/per_thread_tls.h"
|
#include "absl/base/internal/per_thread_tls.h"
|
||||||
|
#include "absl/base/optimization.h"
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
ABSL_NAMESPACE_BEGIN
|
ABSL_NAMESPACE_BEGIN
|
||||||
@@ -69,30 +70,28 @@ struct PerThreadSynch {
|
|||||||
// is using this PerThreadSynch as a terminator. Its
|
// is using this PerThreadSynch as a terminator. Its
|
||||||
// skip field must not be filled in because the loop
|
// skip field must not be filled in because the loop
|
||||||
// might then skip over the terminator.
|
// might then skip over the terminator.
|
||||||
|
bool wake; // This thread is to be woken from a Mutex.
|
||||||
// The wait parameters of the current wait. waitp is null if the
|
// If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the
|
||||||
// thread is not waiting. Transitions from null to non-null must
|
// waiter is waiting on the mutex as part of a CV Wait or Mutex Await.
|
||||||
// occur before the enqueue commit point (state = kQueued in
|
//
|
||||||
// Enqueue() and CondVarEnqueue()). Transitions from non-null to
|
// The value of "x->cond_waiter" is meaningless if "x" is not on a
|
||||||
// null must occur after the wait is finished (state = kAvailable in
|
// Mutex waiter list.
|
||||||
// Mutex::Block() and CondVar::WaitCommon()). This field may be
|
bool cond_waiter;
|
||||||
// changed only by the thread that describes this PerThreadSynch. A
|
bool maybe_unlocking; // Valid at head of Mutex waiter queue;
|
||||||
// special case is Fer(), which calls Enqueue() on another thread,
|
// true if UnlockSlow could be searching
|
||||||
// but with an identical SynchWaitParams pointer, thus leaving the
|
// for a waiter to wake. Used for an optimization
|
||||||
// pointer unchanged.
|
// in Enqueue(). true is always a valid value.
|
||||||
SynchWaitParams *waitp;
|
// Can be reset to false when the unlocker or any
|
||||||
|
// writer releases the lock, or a reader fully
|
||||||
bool suppress_fatal_errors; // If true, try to proceed even in the face of
|
// releases the lock. It may not be set to false
|
||||||
// broken invariants. This is used within fatal
|
// by a reader that decrements the count to
|
||||||
// signal handlers to improve the chances of
|
// non-zero. protected by mutex spinlock
|
||||||
// debug logging information being output
|
bool suppress_fatal_errors; // If true, try to proceed even in the face
|
||||||
// successfully.
|
// of broken invariants. This is used within
|
||||||
|
// fatal signal handlers to improve the
|
||||||
intptr_t readers; // Number of readers in mutex.
|
// chances of debug logging information being
|
||||||
int priority; // Priority of thread (updated every so often).
|
// output successfully.
|
||||||
|
int priority; // Priority of thread (updated every so often).
|
||||||
// When priority will next be read (cycles).
|
|
||||||
int64_t next_priority_read_cycles;
|
|
||||||
|
|
||||||
// State values:
|
// State values:
|
||||||
// kAvailable: This PerThreadSynch is available.
|
// kAvailable: This PerThreadSynch is available.
|
||||||
@@ -111,30 +110,30 @@ struct PerThreadSynch {
|
|||||||
};
|
};
|
||||||
std::atomic<State> state;
|
std::atomic<State> state;
|
||||||
|
|
||||||
bool maybe_unlocking; // Valid at head of Mutex waiter queue;
|
// The wait parameters of the current wait. waitp is null if the
|
||||||
// true if UnlockSlow could be searching
|
// thread is not waiting. Transitions from null to non-null must
|
||||||
// for a waiter to wake. Used for an optimization
|
// occur before the enqueue commit point (state = kQueued in
|
||||||
// in Enqueue(). true is always a valid value.
|
// Enqueue() and CondVarEnqueue()). Transitions from non-null to
|
||||||
// Can be reset to false when the unlocker or any
|
// null must occur after the wait is finished (state = kAvailable in
|
||||||
// writer releases the lock, or a reader fully releases
|
// Mutex::Block() and CondVar::WaitCommon()). This field may be
|
||||||
// the lock. It may not be set to false by a reader
|
// changed only by the thread that describes this PerThreadSynch. A
|
||||||
// that decrements the count to non-zero.
|
// special case is Fer(), which calls Enqueue() on another thread,
|
||||||
// protected by mutex spinlock
|
// but with an identical SynchWaitParams pointer, thus leaving the
|
||||||
|
// pointer unchanged.
|
||||||
|
SynchWaitParams* waitp;
|
||||||
|
|
||||||
bool wake; // This thread is to be woken from a Mutex.
|
intptr_t readers; // Number of readers in mutex.
|
||||||
|
|
||||||
// If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the
|
// When priority will next be read (cycles).
|
||||||
// waiter is waiting on the mutex as part of a CV Wait or Mutex Await.
|
int64_t next_priority_read_cycles;
|
||||||
//
|
|
||||||
// The value of "x->cond_waiter" is meaningless if "x" is not on a
|
|
||||||
// Mutex waiter list.
|
|
||||||
bool cond_waiter;
|
|
||||||
|
|
||||||
// Locks held; used during deadlock detection.
|
// Locks held; used during deadlock detection.
|
||||||
// Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity().
|
// Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity().
|
||||||
SynchLocksHeld *all_locks;
|
SynchLocksHeld *all_locks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The instances of this class are allocated in NewThreadIdentity() with an
|
||||||
|
// alignment of PerThreadSynch::kAlignment.
|
||||||
struct ThreadIdentity {
|
struct ThreadIdentity {
|
||||||
// Must be the first member. The Mutex implementation requires that
|
// Must be the first member. The Mutex implementation requires that
|
||||||
// the PerThreadSynch object associated with each thread is
|
// the PerThreadSynch object associated with each thread is
|
||||||
|
|||||||
@@ -2709,6 +2709,101 @@ TEST(Btree, MultiKeyEqualRange) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Btree, AllocConstructor) {
|
||||||
|
using Alloc = CountingAllocator<int>;
|
||||||
|
using Set = absl::btree_set<int, std::less<int>, Alloc>;
|
||||||
|
int64_t bytes_used = 0;
|
||||||
|
Alloc alloc(&bytes_used);
|
||||||
|
Set set(alloc);
|
||||||
|
|
||||||
|
set.insert({1, 2, 3});
|
||||||
|
|
||||||
|
EXPECT_THAT(set, ElementsAre(1, 2, 3));
|
||||||
|
EXPECT_GT(bytes_used, set.size() * sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Btree, AllocInitializerListConstructor) {
|
||||||
|
using Alloc = CountingAllocator<int>;
|
||||||
|
using Set = absl::btree_set<int, std::less<int>, Alloc>;
|
||||||
|
int64_t bytes_used = 0;
|
||||||
|
Alloc alloc(&bytes_used);
|
||||||
|
Set set({1, 2, 3}, alloc);
|
||||||
|
|
||||||
|
EXPECT_THAT(set, ElementsAre(1, 2, 3));
|
||||||
|
EXPECT_GT(bytes_used, set.size() * sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Btree, AllocRangeConstructor) {
|
||||||
|
using Alloc = CountingAllocator<int>;
|
||||||
|
using Set = absl::btree_set<int, std::less<int>, Alloc>;
|
||||||
|
int64_t bytes_used = 0;
|
||||||
|
Alloc alloc(&bytes_used);
|
||||||
|
std::vector<int> v = {1, 2, 3};
|
||||||
|
Set set(v.begin(), v.end(), alloc);
|
||||||
|
|
||||||
|
EXPECT_THAT(set, ElementsAre(1, 2, 3));
|
||||||
|
EXPECT_GT(bytes_used, set.size() * sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Btree, AllocCopyConstructor) {
|
||||||
|
using Alloc = CountingAllocator<int>;
|
||||||
|
using Set = absl::btree_set<int, std::less<int>, Alloc>;
|
||||||
|
int64_t bytes_used1 = 0;
|
||||||
|
Alloc alloc1(&bytes_used1);
|
||||||
|
Set set1(alloc1);
|
||||||
|
|
||||||
|
set1.insert({1, 2, 3});
|
||||||
|
|
||||||
|
int64_t bytes_used2 = 0;
|
||||||
|
Alloc alloc2(&bytes_used2);
|
||||||
|
Set set2(set1, alloc2);
|
||||||
|
|
||||||
|
EXPECT_THAT(set1, ElementsAre(1, 2, 3));
|
||||||
|
EXPECT_THAT(set2, ElementsAre(1, 2, 3));
|
||||||
|
EXPECT_GT(bytes_used1, set1.size() * sizeof(int));
|
||||||
|
EXPECT_EQ(bytes_used1, bytes_used2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Btree, AllocMoveConstructor_SameAlloc) {
|
||||||
|
using Alloc = CountingAllocator<int>;
|
||||||
|
using Set = absl::btree_set<int, std::less<int>, Alloc>;
|
||||||
|
int64_t bytes_used = 0;
|
||||||
|
Alloc alloc(&bytes_used);
|
||||||
|
Set set1(alloc);
|
||||||
|
|
||||||
|
set1.insert({1, 2, 3});
|
||||||
|
|
||||||
|
const int64_t original_bytes_used = bytes_used;
|
||||||
|
EXPECT_GT(original_bytes_used, set1.size() * sizeof(int));
|
||||||
|
|
||||||
|
Set set2(std::move(set1), alloc);
|
||||||
|
|
||||||
|
EXPECT_THAT(set2, ElementsAre(1, 2, 3));
|
||||||
|
EXPECT_EQ(bytes_used, original_bytes_used);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Btree, AllocMoveConstructor_DifferentAlloc) {
|
||||||
|
using Alloc = CountingAllocator<int>;
|
||||||
|
using Set = absl::btree_set<int, std::less<int>, Alloc>;
|
||||||
|
int64_t bytes_used1 = 0;
|
||||||
|
Alloc alloc1(&bytes_used1);
|
||||||
|
Set set1(alloc1);
|
||||||
|
|
||||||
|
set1.insert({1, 2, 3});
|
||||||
|
|
||||||
|
const int64_t original_bytes_used = bytes_used1;
|
||||||
|
EXPECT_GT(original_bytes_used, set1.size() * sizeof(int));
|
||||||
|
|
||||||
|
int64_t bytes_used2 = 0;
|
||||||
|
Alloc alloc2(&bytes_used2);
|
||||||
|
Set set2(std::move(set1), alloc2);
|
||||||
|
|
||||||
|
EXPECT_THAT(set2, ElementsAre(1, 2, 3));
|
||||||
|
// We didn't free these bytes allocated by `set1` yet.
|
||||||
|
EXPECT_EQ(bytes_used1, original_bytes_used);
|
||||||
|
EXPECT_EQ(bytes_used2, original_bytes_used);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace container_internal
|
} // namespace container_internal
|
||||||
ABSL_NAMESPACE_END
|
ABSL_NAMESPACE_END
|
||||||
|
|||||||
@@ -1141,21 +1141,35 @@ class btree {
|
|||||||
// before this method is called. This method is used in copy construction,
|
// before this method is called. This method is used in copy construction,
|
||||||
// copy assignment, and move assignment.
|
// copy assignment, and move assignment.
|
||||||
template <typename Btree>
|
template <typename Btree>
|
||||||
void copy_or_move_values_in_order(Btree *other);
|
void copy_or_move_values_in_order(Btree &other);
|
||||||
|
|
||||||
// Validates that various assumptions/requirements are true at compile time.
|
// Validates that various assumptions/requirements are true at compile time.
|
||||||
constexpr static bool static_assert_validation();
|
constexpr static bool static_assert_validation();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
btree(const key_compare &comp, const allocator_type &alloc);
|
btree(const key_compare &comp, const allocator_type &alloc)
|
||||||
|
: root_(comp, alloc, EmptyNode()), rightmost_(EmptyNode()), size_(0) {}
|
||||||
|
|
||||||
btree(const btree &other);
|
btree(const btree &other) : btree(other, other.allocator()) {}
|
||||||
|
btree(const btree &other, const allocator_type &alloc)
|
||||||
|
: btree(other.key_comp(), alloc) {
|
||||||
|
copy_or_move_values_in_order(other);
|
||||||
|
}
|
||||||
btree(btree &&other) noexcept
|
btree(btree &&other) noexcept
|
||||||
: root_(std::move(other.root_)),
|
: root_(std::move(other.root_)),
|
||||||
rightmost_(absl::exchange(other.rightmost_, EmptyNode())),
|
rightmost_(absl::exchange(other.rightmost_, EmptyNode())),
|
||||||
size_(absl::exchange(other.size_, 0)) {
|
size_(absl::exchange(other.size_, 0)) {
|
||||||
other.mutable_root() = EmptyNode();
|
other.mutable_root() = EmptyNode();
|
||||||
}
|
}
|
||||||
|
btree(btree &&other, const allocator_type &alloc)
|
||||||
|
: btree(other.key_comp(), alloc) {
|
||||||
|
if (alloc == other.allocator()) {
|
||||||
|
swap(other);
|
||||||
|
} else {
|
||||||
|
// Move values from `other` one at a time when allocators are different.
|
||||||
|
copy_or_move_values_in_order(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
~btree() {
|
~btree() {
|
||||||
// Put static_asserts in destructor to avoid triggering them before the type
|
// Put static_asserts in destructor to avoid triggering them before the type
|
||||||
@@ -1851,7 +1865,7 @@ void btree_iterator<N, R, P>::decrement_slow() {
|
|||||||
// btree methods
|
// btree methods
|
||||||
template <typename P>
|
template <typename P>
|
||||||
template <typename Btree>
|
template <typename Btree>
|
||||||
void btree<P>::copy_or_move_values_in_order(Btree *other) {
|
void btree<P>::copy_or_move_values_in_order(Btree &other) {
|
||||||
static_assert(std::is_same<btree, Btree>::value ||
|
static_assert(std::is_same<btree, Btree>::value ||
|
||||||
std::is_same<const btree, Btree>::value,
|
std::is_same<const btree, Btree>::value,
|
||||||
"Btree type must be same or const.");
|
"Btree type must be same or const.");
|
||||||
@@ -1859,11 +1873,11 @@ void btree<P>::copy_or_move_values_in_order(Btree *other) {
|
|||||||
|
|
||||||
// We can avoid key comparisons because we know the order of the
|
// We can avoid key comparisons because we know the order of the
|
||||||
// values is the same order we'll store them in.
|
// values is the same order we'll store them in.
|
||||||
auto iter = other->begin();
|
auto iter = other.begin();
|
||||||
if (iter == other->end()) return;
|
if (iter == other.end()) return;
|
||||||
insert_multi(maybe_move_from_iterator(iter));
|
insert_multi(maybe_move_from_iterator(iter));
|
||||||
++iter;
|
++iter;
|
||||||
for (; iter != other->end(); ++iter) {
|
for (; iter != other.end(); ++iter) {
|
||||||
// If the btree is not empty, we can just insert the new value at the end
|
// If the btree is not empty, we can just insert the new value at the end
|
||||||
// of the tree.
|
// of the tree.
|
||||||
internal_emplace(end(), maybe_move_from_iterator(iter));
|
internal_emplace(end(), maybe_move_from_iterator(iter));
|
||||||
@@ -1901,16 +1915,6 @@ constexpr bool btree<P>::static_assert_validation() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename P>
|
|
||||||
btree<P>::btree(const key_compare &comp, const allocator_type &alloc)
|
|
||||||
: root_(comp, alloc, EmptyNode()), rightmost_(EmptyNode()), size_(0) {}
|
|
||||||
|
|
||||||
template <typename P>
|
|
||||||
btree<P>::btree(const btree &other)
|
|
||||||
: btree(other.key_comp(), other.allocator()) {
|
|
||||||
copy_or_move_values_in_order(&other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename P>
|
template <typename P>
|
||||||
template <typename K>
|
template <typename K>
|
||||||
auto btree<P>::equal_range(const K &key) -> std::pair<iterator, iterator> {
|
auto btree<P>::equal_range(const K &key) -> std::pair<iterator, iterator> {
|
||||||
@@ -2068,7 +2072,7 @@ auto btree<P>::operator=(const btree &other) -> btree & {
|
|||||||
*mutable_allocator() = other.allocator();
|
*mutable_allocator() = other.allocator();
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_or_move_values_in_order(&other);
|
copy_or_move_values_in_order(other);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -2098,7 +2102,7 @@ auto btree<P>::operator=(btree &&other) noexcept -> btree & {
|
|||||||
// comparator while moving the values so we can't swap the key
|
// comparator while moving the values so we can't swap the key
|
||||||
// comparators.
|
// comparators.
|
||||||
*mutable_key_comp() = other.key_comp();
|
*mutable_key_comp() = other.key_comp();
|
||||||
copy_or_move_values_in_order(&other);
|
copy_or_move_values_in_order(other);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "absl/base/internal/throw_delegate.h"
|
#include "absl/base/internal/throw_delegate.h"
|
||||||
#include "absl/container/internal/btree.h" // IWYU pragma: export
|
#include "absl/container/internal/btree.h" // IWYU pragma: export
|
||||||
#include "absl/container/internal/common.h"
|
#include "absl/container/internal/common.h"
|
||||||
|
#include "absl/memory/memory.h"
|
||||||
#include "absl/meta/type_traits.h"
|
#include "absl/meta/type_traits.h"
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
@@ -68,8 +69,21 @@ class btree_container {
|
|||||||
explicit btree_container(const key_compare &comp,
|
explicit btree_container(const key_compare &comp,
|
||||||
const allocator_type &alloc = allocator_type())
|
const allocator_type &alloc = allocator_type())
|
||||||
: tree_(comp, alloc) {}
|
: tree_(comp, alloc) {}
|
||||||
btree_container(const btree_container &other) = default;
|
explicit btree_container(const allocator_type &alloc)
|
||||||
btree_container(btree_container &&other) noexcept = default;
|
: tree_(key_compare(), alloc) {}
|
||||||
|
|
||||||
|
btree_container(const btree_container &other)
|
||||||
|
: btree_container(other, absl::allocator_traits<allocator_type>::
|
||||||
|
select_on_container_copy_construction(
|
||||||
|
other.get_allocator())) {}
|
||||||
|
btree_container(const btree_container &other, const allocator_type &alloc)
|
||||||
|
: tree_(other.tree_, alloc) {}
|
||||||
|
|
||||||
|
btree_container(btree_container &&other) noexcept(
|
||||||
|
std::is_nothrow_move_constructible<Tree>::value) = default;
|
||||||
|
btree_container(btree_container &&other, const allocator_type &alloc)
|
||||||
|
: tree_(std::move(other.tree_), alloc) {}
|
||||||
|
|
||||||
btree_container &operator=(const btree_container &other) = default;
|
btree_container &operator=(const btree_container &other) = default;
|
||||||
btree_container &operator=(btree_container &&other) noexcept(
|
btree_container &operator=(btree_container &&other) noexcept(
|
||||||
std::is_nothrow_move_assignable<Tree>::value) = default;
|
std::is_nothrow_move_assignable<Tree>::value) = default;
|
||||||
@@ -234,7 +248,7 @@ class btree_set_container : public btree_container<Tree> {
|
|||||||
using super_type::super_type;
|
using super_type::super_type;
|
||||||
btree_set_container() {}
|
btree_set_container() {}
|
||||||
|
|
||||||
// Range constructor.
|
// Range constructors.
|
||||||
template <class InputIterator>
|
template <class InputIterator>
|
||||||
btree_set_container(InputIterator b, InputIterator e,
|
btree_set_container(InputIterator b, InputIterator e,
|
||||||
const key_compare &comp = key_compare(),
|
const key_compare &comp = key_compare(),
|
||||||
@@ -242,12 +256,19 @@ class btree_set_container : public btree_container<Tree> {
|
|||||||
: super_type(comp, alloc) {
|
: super_type(comp, alloc) {
|
||||||
insert(b, e);
|
insert(b, e);
|
||||||
}
|
}
|
||||||
|
template <class InputIterator>
|
||||||
|
btree_set_container(InputIterator b, InputIterator e,
|
||||||
|
const allocator_type &alloc)
|
||||||
|
: btree_set_container(b, e, key_compare(), alloc) {}
|
||||||
|
|
||||||
// Initializer list constructor.
|
// Initializer list constructors.
|
||||||
btree_set_container(std::initializer_list<init_type> init,
|
btree_set_container(std::initializer_list<init_type> init,
|
||||||
const key_compare &comp = key_compare(),
|
const key_compare &comp = key_compare(),
|
||||||
const allocator_type &alloc = allocator_type())
|
const allocator_type &alloc = allocator_type())
|
||||||
: btree_set_container(init.begin(), init.end(), comp, alloc) {}
|
: btree_set_container(init.begin(), init.end(), comp, alloc) {}
|
||||||
|
btree_set_container(std::initializer_list<init_type> init,
|
||||||
|
const allocator_type &alloc)
|
||||||
|
: btree_set_container(init.begin(), init.end(), alloc) {}
|
||||||
|
|
||||||
// Lookup routines.
|
// Lookup routines.
|
||||||
template <typename K = key_type>
|
template <typename K = key_type>
|
||||||
@@ -535,7 +556,7 @@ class btree_multiset_container : public btree_container<Tree> {
|
|||||||
using super_type::super_type;
|
using super_type::super_type;
|
||||||
btree_multiset_container() {}
|
btree_multiset_container() {}
|
||||||
|
|
||||||
// Range constructor.
|
// Range constructors.
|
||||||
template <class InputIterator>
|
template <class InputIterator>
|
||||||
btree_multiset_container(InputIterator b, InputIterator e,
|
btree_multiset_container(InputIterator b, InputIterator e,
|
||||||
const key_compare &comp = key_compare(),
|
const key_compare &comp = key_compare(),
|
||||||
@@ -543,12 +564,19 @@ class btree_multiset_container : public btree_container<Tree> {
|
|||||||
: super_type(comp, alloc) {
|
: super_type(comp, alloc) {
|
||||||
insert(b, e);
|
insert(b, e);
|
||||||
}
|
}
|
||||||
|
template <class InputIterator>
|
||||||
|
btree_multiset_container(InputIterator b, InputIterator e,
|
||||||
|
const allocator_type &alloc)
|
||||||
|
: btree_multiset_container(b, e, key_compare(), alloc) {}
|
||||||
|
|
||||||
// Initializer list constructor.
|
// Initializer list constructors.
|
||||||
btree_multiset_container(std::initializer_list<init_type> init,
|
btree_multiset_container(std::initializer_list<init_type> init,
|
||||||
const key_compare &comp = key_compare(),
|
const key_compare &comp = key_compare(),
|
||||||
const allocator_type &alloc = allocator_type())
|
const allocator_type &alloc = allocator_type())
|
||||||
: btree_multiset_container(init.begin(), init.end(), comp, alloc) {}
|
: btree_multiset_container(init.begin(), init.end(), comp, alloc) {}
|
||||||
|
btree_multiset_container(std::initializer_list<init_type> init,
|
||||||
|
const allocator_type &alloc)
|
||||||
|
: btree_multiset_container(init.begin(), init.end(), alloc) {}
|
||||||
|
|
||||||
// Lookup routines.
|
// Lookup routines.
|
||||||
template <typename K = key_type>
|
template <typename K = key_type>
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ list(APPEND ABSL_CLANG_CL_FLAGS
|
|||||||
"-Wno-extra-semi-stmt"
|
"-Wno-extra-semi-stmt"
|
||||||
"-Wno-packed"
|
"-Wno-packed"
|
||||||
"-Wno-padded"
|
"-Wno-padded"
|
||||||
"-Wno-sign-compare"
|
|
||||||
"-Wno-float-conversion"
|
"-Wno-float-conversion"
|
||||||
"-Wno-float-equal"
|
"-Wno-float-equal"
|
||||||
"-Wno-format-nonliteral"
|
"-Wno-format-nonliteral"
|
||||||
@@ -88,7 +87,6 @@ list(APPEND ABSL_GCC_FLAGS
|
|||||||
"-Wvla"
|
"-Wvla"
|
||||||
"-Wwrite-strings"
|
"-Wwrite-strings"
|
||||||
"-Wno-missing-field-initializers"
|
"-Wno-missing-field-initializers"
|
||||||
"-Wno-sign-compare"
|
|
||||||
"-DNOMINMAX"
|
"-DNOMINMAX"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -117,7 +115,6 @@ list(APPEND ABSL_LLVM_FLAGS
|
|||||||
"-Wno-extra-semi-stmt"
|
"-Wno-extra-semi-stmt"
|
||||||
"-Wno-packed"
|
"-Wno-packed"
|
||||||
"-Wno-padded"
|
"-Wno-padded"
|
||||||
"-Wno-sign-compare"
|
|
||||||
"-Wno-float-conversion"
|
"-Wno-float-conversion"
|
||||||
"-Wno-float-equal"
|
"-Wno-float-equal"
|
||||||
"-Wno-format-nonliteral"
|
"-Wno-format-nonliteral"
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ ABSL_CLANG_CL_FLAGS = [
|
|||||||
"-Wno-extra-semi-stmt",
|
"-Wno-extra-semi-stmt",
|
||||||
"-Wno-packed",
|
"-Wno-packed",
|
||||||
"-Wno-padded",
|
"-Wno-padded",
|
||||||
"-Wno-sign-compare",
|
|
||||||
"-Wno-float-conversion",
|
"-Wno-float-conversion",
|
||||||
"-Wno-float-equal",
|
"-Wno-float-equal",
|
||||||
"-Wno-format-nonliteral",
|
"-Wno-format-nonliteral",
|
||||||
@@ -89,7 +88,6 @@ ABSL_GCC_FLAGS = [
|
|||||||
"-Wvla",
|
"-Wvla",
|
||||||
"-Wwrite-strings",
|
"-Wwrite-strings",
|
||||||
"-Wno-missing-field-initializers",
|
"-Wno-missing-field-initializers",
|
||||||
"-Wno-sign-compare",
|
|
||||||
"-DNOMINMAX",
|
"-DNOMINMAX",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -118,7 +116,6 @@ ABSL_LLVM_FLAGS = [
|
|||||||
"-Wno-extra-semi-stmt",
|
"-Wno-extra-semi-stmt",
|
||||||
"-Wno-packed",
|
"-Wno-packed",
|
||||||
"-Wno-padded",
|
"-Wno-padded",
|
||||||
"-Wno-sign-compare",
|
|
||||||
"-Wno-float-conversion",
|
"-Wno-float-conversion",
|
||||||
"-Wno-float-equal",
|
"-Wno-float-equal",
|
||||||
"-Wno-format-nonliteral",
|
"-Wno-format-nonliteral",
|
||||||
|
|||||||
@@ -41,10 +41,6 @@ LLVM_DISABLE_WARNINGS_FLAGS = [
|
|||||||
"-Wno-packed",
|
"-Wno-packed",
|
||||||
"-Wno-padded",
|
"-Wno-padded",
|
||||||
###
|
###
|
||||||
# Google style does not use unsigned integers, though STL containers
|
|
||||||
# have unsigned types.
|
|
||||||
"-Wno-sign-compare",
|
|
||||||
###
|
|
||||||
"-Wno-float-conversion",
|
"-Wno-float-conversion",
|
||||||
"-Wno-float-equal",
|
"-Wno-float-equal",
|
||||||
"-Wno-format-nonliteral",
|
"-Wno-format-nonliteral",
|
||||||
@@ -138,9 +134,6 @@ COPT_VARS = {
|
|||||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750
|
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750
|
||||||
# Remove when gcc-4.x is no longer supported.
|
# Remove when gcc-4.x is no longer supported.
|
||||||
"-Wno-missing-field-initializers",
|
"-Wno-missing-field-initializers",
|
||||||
# Google style does not use unsigned integers, though STL containers
|
|
||||||
# have unsigned types.
|
|
||||||
"-Wno-sign-compare",
|
|
||||||
# Don't define min and max macros (Build on Windows using gcc)
|
# Don't define min and max macros (Build on Windows using gcc)
|
||||||
"-DNOMINMAX",
|
"-DNOMINMAX",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1281,7 +1281,7 @@ static bool MaybeInitializeObjFile(ObjFile *obj) {
|
|||||||
const int phnum = obj->elf_header.e_phnum;
|
const int phnum = obj->elf_header.e_phnum;
|
||||||
const int phentsize = obj->elf_header.e_phentsize;
|
const int phentsize = obj->elf_header.e_phentsize;
|
||||||
size_t phoff = obj->elf_header.e_phoff;
|
size_t phoff = obj->elf_header.e_phoff;
|
||||||
int num_executable_load_segments = 0;
|
size_t num_executable_load_segments = 0;
|
||||||
for (int j = 0; j < phnum; j++) {
|
for (int j = 0; j < phnum; j++) {
|
||||||
ElfW(Phdr) phdr;
|
ElfW(Phdr) phdr;
|
||||||
if (!ReadFromOffsetExact(obj->fd, &phdr, sizeof(phdr), phoff)) {
|
if (!ReadFromOffsetExact(obj->fd, &phdr, sizeof(phdr), phoff)) {
|
||||||
@@ -1342,7 +1342,7 @@ const char *Symbolizer::GetSymbol(const void *const pc) {
|
|||||||
// Note: some binaries have multiple "rx" LOAD segments. We must
|
// Note: some binaries have multiple "rx" LOAD segments. We must
|
||||||
// find the right one.
|
// find the right one.
|
||||||
ElfW(Phdr) *phdr = nullptr;
|
ElfW(Phdr) *phdr = nullptr;
|
||||||
for (int j = 0; j < obj->phdr.size(); j++) {
|
for (size_t j = 0; j < obj->phdr.size(); j++) {
|
||||||
ElfW(Phdr) &p = obj->phdr[j];
|
ElfW(Phdr) &p = obj->phdr[j];
|
||||||
if (p.p_type != PT_LOAD) {
|
if (p.p_type != PT_LOAD) {
|
||||||
// We only expect PT_LOADs. This must be PT_NULL that we didn't
|
// We only expect PT_LOADs. This must be PT_NULL that we didn't
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> GetAllFlags();
|
|||||||
// void MyFunc() {
|
// void MyFunc() {
|
||||||
// absl::FlagSaver fs;
|
// absl::FlagSaver fs;
|
||||||
// ...
|
// ...
|
||||||
// absl::SetFlag(FLAGS_myFlag, otherValue);
|
// absl::SetFlag(&FLAGS_myFlag, otherValue);
|
||||||
// ...
|
// ...
|
||||||
// } // scope of FlagSaver left, flags return to previous state
|
// } // scope of FlagSaver left, flags return to previous state
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -246,8 +246,8 @@ constexpr int DigitMagnitude<16>() {
|
|||||||
// ConsumeDigits does not protect against overflow on *out; max_digits must
|
// ConsumeDigits does not protect against overflow on *out; max_digits must
|
||||||
// be chosen with respect to type T to avoid the possibility of overflow.
|
// be chosen with respect to type T to avoid the possibility of overflow.
|
||||||
template <int base, typename T>
|
template <int base, typename T>
|
||||||
std::size_t ConsumeDigits(const char* begin, const char* end, int max_digits,
|
int ConsumeDigits(const char* begin, const char* end, int max_digits, T* out,
|
||||||
T* out, bool* dropped_nonzero_digit) {
|
bool* dropped_nonzero_digit) {
|
||||||
if (base == 10) {
|
if (base == 10) {
|
||||||
assert(max_digits <= std::numeric_limits<T>::digits10);
|
assert(max_digits <= std::numeric_limits<T>::digits10);
|
||||||
} else if (base == 16) {
|
} else if (base == 16) {
|
||||||
@@ -282,7 +282,7 @@ std::size_t ConsumeDigits(const char* begin, const char* end, int max_digits,
|
|||||||
*dropped_nonzero_digit = true;
|
*dropped_nonzero_digit = true;
|
||||||
}
|
}
|
||||||
*out = accumulator;
|
*out = accumulator;
|
||||||
return begin - original_begin;
|
return static_cast<int>(begin - original_begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if `v` is one of the chars allowed inside parentheses following
|
// Returns true if `v` is one of the chars allowed inside parentheses following
|
||||||
@@ -372,7 +372,7 @@ strings_internal::ParsedFloat ParseFloat(const char* begin, const char* end,
|
|||||||
|
|
||||||
int exponent_adjustment = 0;
|
int exponent_adjustment = 0;
|
||||||
bool mantissa_is_inexact = false;
|
bool mantissa_is_inexact = false;
|
||||||
std::size_t pre_decimal_digits = ConsumeDigits<base>(
|
int pre_decimal_digits = ConsumeDigits<base>(
|
||||||
begin, end, MantissaDigitsMax<base>(), &mantissa, &mantissa_is_inexact);
|
begin, end, MantissaDigitsMax<base>(), &mantissa, &mantissa_is_inexact);
|
||||||
begin += pre_decimal_digits;
|
begin += pre_decimal_digits;
|
||||||
int digits_left;
|
int digits_left;
|
||||||
@@ -398,14 +398,14 @@ strings_internal::ParsedFloat ParseFloat(const char* begin, const char* end,
|
|||||||
while (begin < end && *begin == '0') {
|
while (begin < end && *begin == '0') {
|
||||||
++begin;
|
++begin;
|
||||||
}
|
}
|
||||||
std::size_t zeros_skipped = begin - begin_zeros;
|
int zeros_skipped = static_cast<int>(begin - begin_zeros);
|
||||||
if (zeros_skipped >= DigitLimit<base>()) {
|
if (zeros_skipped >= DigitLimit<base>()) {
|
||||||
// refuse to parse pathological inputs
|
// refuse to parse pathological inputs
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
exponent_adjustment -= static_cast<int>(zeros_skipped);
|
exponent_adjustment -= static_cast<int>(zeros_skipped);
|
||||||
}
|
}
|
||||||
int64_t post_decimal_digits = ConsumeDigits<base>(
|
int post_decimal_digits = ConsumeDigits<base>(
|
||||||
begin, end, digits_left, &mantissa, &mantissa_is_inexact);
|
begin, end, digits_left, &mantissa, &mantissa_is_inexact);
|
||||||
begin += post_decimal_digits;
|
begin += post_decimal_digits;
|
||||||
|
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ int FprintF(std::FILE* output, const UntypedFormatSpecImpl format,
|
|||||||
errno = sink.error();
|
errno = sink.error();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (sink.count() > std::numeric_limits<int>::max()) {
|
if (sink.count() > static_cast<size_t>(std::numeric_limits<int>::max())) {
|
||||||
errno = EFBIG;
|
errno = EFBIG;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ class BinaryToDecimal {
|
|||||||
assert(exp > 0);
|
assert(exp > 0);
|
||||||
assert(exp <= std::numeric_limits<long double>::max_exponent);
|
assert(exp <= std::numeric_limits<long double>::max_exponent);
|
||||||
static_assert(
|
static_assert(
|
||||||
StackArray::kMaxCapacity >=
|
static_cast<int>(StackArray::kMaxCapacity) >=
|
||||||
ChunksNeeded(std::numeric_limits<long double>::max_exponent),
|
ChunksNeeded(std::numeric_limits<long double>::max_exponent),
|
||||||
"");
|
"");
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <limits>
|
||||||
#include "absl/base/internal/hide_ptr.h"
|
#include "absl/base/internal/hide_ptr.h"
|
||||||
#include "absl/base/internal/raw_logging.h"
|
#include "absl/base/internal/raw_logging.h"
|
||||||
#include "absl/base/internal/spinlock.h"
|
#include "absl/base/internal/spinlock.h"
|
||||||
|
|||||||
@@ -19,4 +19,3 @@ readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20191016"
|
|||||||
readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20201008"
|
readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20201008"
|
||||||
readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20201008"
|
readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20201008"
|
||||||
readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20201015"
|
readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20201015"
|
||||||
readonly LINUX_GCC_49_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-4.9:20191018"
|
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Copyright 2019 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.
|
|
||||||
|
|
||||||
# This script that can be invoked to test abseil-cpp in a hermetic environment
|
|
||||||
# using a Docker image on Linux. You must have Docker installed to use this
|
|
||||||
# script.
|
|
||||||
|
|
||||||
set -euox pipefail
|
|
||||||
|
|
||||||
if [[ -z ${ABSEIL_ROOT:-} ]]; then
|
|
||||||
ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z ${STD:-} ]]; then
|
|
||||||
STD="c++11 c++14"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z ${COMPILATION_MODE:-} ]]; then
|
|
||||||
COMPILATION_MODE="fastbuild opt"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
|
|
||||||
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
|
||||||
fi
|
|
||||||
|
|
||||||
source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
|
|
||||||
readonly DOCKER_CONTAINER=${LINUX_GCC_49_CONTAINER}
|
|
||||||
|
|
||||||
# USE_BAZEL_CACHE=1 only works on Kokoro.
|
|
||||||
# Without access to the credentials this won't work.
|
|
||||||
if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
|
|
||||||
DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
|
|
||||||
# Bazel doesn't track changes to tools outside of the workspace
|
|
||||||
# (e.g. /usr/bin/gcc), so by appending the docker container to the
|
|
||||||
# remote_http_cache url, we make changes to the container part of
|
|
||||||
# the cache key. Hashing the key is to make it shorter and url-safe.
|
|
||||||
container_key=$(echo ${DOCKER_CONTAINER} | sha256sum | head -c 16)
|
|
||||||
BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Avoid depending on external sites like GitHub by checking --distdir for
|
|
||||||
# external dependencies first.
|
|
||||||
# https://docs.bazel.build/versions/master/guide.html#distdir
|
|
||||||
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
|
|
||||||
DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
|
|
||||||
BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
for std in ${STD}; do
|
|
||||||
for compilation_mode in ${COMPILATION_MODE}; do
|
|
||||||
for exceptions_mode in ${EXCEPTIONS_MODE}; do
|
|
||||||
echo "--------------------------------------------------------------------"
|
|
||||||
time docker run \
|
|
||||||
--mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
|
|
||||||
--workdir=/abseil-cpp \
|
|
||||||
--cap-add=SYS_PTRACE \
|
|
||||||
--rm \
|
|
||||||
-e CC="/usr/bin/gcc-4.9" \
|
|
||||||
-e BAZEL_CXXOPTS="-std=${std}" \
|
|
||||||
${DOCKER_EXTRA_ARGS:-} \
|
|
||||||
${DOCKER_CONTAINER} \
|
|
||||||
/usr/local/bin/bazel test ... \
|
|
||||||
--compilation_mode="${compilation_mode}" \
|
|
||||||
--copt="${exceptions_mode}" \
|
|
||||||
--copt=-Werror \
|
|
||||||
--define="absl=1" \
|
|
||||||
--keep_going \
|
|
||||||
--show_timestamps \
|
|
||||||
--test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" \
|
|
||||||
--test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \
|
|
||||||
--test_output=errors \
|
|
||||||
--test_tag_filters=-benchmark \
|
|
||||||
${BAZEL_EXTRA_ARGS:-}
|
|
||||||
done
|
|
||||||
done
|
|
||||||
done
|
|
||||||
Reference in New Issue
Block a user