Export of internal Abseil changes
-- 2ba0e41a21fbdab36b2f4f3b0dd4b112bd788604 by Derek Mauro <dmauro@google.com>: Remove the include of <intsafe.h>, which is missing on some versions of MinGW. DWORD is easily replaced by uint32_t. PiperOrigin-RevId: 282576177 -- 238fd41114b3e83fcb91d2afe1e6dcce7cfd53b0 by Samuel Benzaquen <sbenza@google.com>: Remove assertion in erase(iterator) that tries to use the comparator. Add missing this-> qualifier. Fix bug where node elements are not being destroyed properly. PiperOrigin-RevId: 282427096 -- 6b9446e3b38ed97451c010933e86a572ab659ab2 by Derek Mauro <dmauro@google.com>: Improves/fixes feature detection in thread_identity Only use ABSL_PER_THREAD_TLS_KEYWORD when it is supported (previously on some platforms it evaluated to nothing, which completely breaks everything), but prefer it to thread_local since benchmarks indicate it is slightly faster in this critical code path. Disable the calls to pthread_sigmask on MinGW where it is not supported. PiperOrigin-RevId: 282425291 GitOrigin-RevId: 2ba0e41a21fbdab36b2f4f3b0dd4b112bd788604 Change-Id: I34073ecbb4a43ad71f54161c136d88fc728888f1
This commit is contained in:
parent
7f4fe64af8
commit
0514227d25
8 changed files with 120 additions and 49 deletions
|
@ -277,7 +277,7 @@ double NominalCPUFrequency() {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
pid_t GetTID() {
|
pid_t GetTID() {
|
||||||
return GetCurrentThreadId();
|
return pid_t{GetCurrentThreadId()};
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
|
|
|
@ -26,10 +26,10 @@
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#else
|
|
||||||
#include <intsafe.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
#include "absl/base/port.h"
|
#include "absl/base/port.h"
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
|
@ -51,9 +51,10 @@ int NumCPUs();
|
||||||
// On Linux, you may send a signal to the resulting ID with kill(). However,
|
// On Linux, you may send a signal to the resulting ID with kill(). However,
|
||||||
// it is recommended for portability that you use pthread_kill() instead.
|
// it is recommended for portability that you use pthread_kill() instead.
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// On Windows, process id and thread id are of the same type according to
|
// On Windows, process id and thread id are of the same type according to the
|
||||||
// the return types of GetProcessId() and GetThreadId() are both DWORD.
|
// return types of GetProcessId() and GetThreadId() are both DWORD, an unsigned
|
||||||
using pid_t = DWORD;
|
// 32-bit type.
|
||||||
|
using pid_t = uint32_t;
|
||||||
#endif
|
#endif
|
||||||
pid_t GetTID();
|
pid_t GetTID();
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,12 @@ void AllocateThreadIdentityKey(ThreadIdentityReclaimerFunction reclaimer) {
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
__attribute__((visibility("protected")))
|
__attribute__((visibility("protected")))
|
||||||
#endif // __GNUC__
|
#endif // __GNUC__
|
||||||
ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr;
|
#if ABSL_PER_THREAD_TLS
|
||||||
|
// Prefer __thread to thread_local as benchmarks indicate it is a bit faster.
|
||||||
|
ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr = nullptr;
|
||||||
|
#elif defined(ABSL_HAVE_THREAD_LOCAL)
|
||||||
|
thread_local ThreadIdentity* thread_identity_ptr = nullptr;
|
||||||
|
#endif // ABSL_PER_THREAD_TLS
|
||||||
#endif // TLS or CPP11
|
#endif // TLS or CPP11
|
||||||
|
|
||||||
void SetCurrentThreadIdentity(
|
void SetCurrentThreadIdentity(
|
||||||
|
@ -69,8 +74,8 @@ void SetCurrentThreadIdentity(
|
||||||
absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
|
absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
|
||||||
reclaimer);
|
reclaimer);
|
||||||
|
|
||||||
#ifdef __EMSCRIPTEN__
|
#if defined(__EMSCRIPTEN__) || defined(__MINGW32__)
|
||||||
// Emscripten PThread implementation does not support signals.
|
// Emscripten and MinGW pthread implementations does not support signals.
|
||||||
// See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html
|
// See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html
|
||||||
// for more information.
|
// for more information.
|
||||||
pthread_setspecific(thread_identity_pthread_key,
|
pthread_setspecific(thread_identity_pthread_key,
|
||||||
|
@ -89,7 +94,7 @@ void SetCurrentThreadIdentity(
|
||||||
pthread_setspecific(thread_identity_pthread_key,
|
pthread_setspecific(thread_identity_pthread_key,
|
||||||
reinterpret_cast<void*>(identity));
|
reinterpret_cast<void*>(identity));
|
||||||
pthread_sigmask(SIG_SETMASK, &curr_signals, nullptr);
|
pthread_sigmask(SIG_SETMASK, &curr_signals, nullptr);
|
||||||
#endif // !__EMSCRIPTEN__
|
#endif // !__EMSCRIPTEN__ && !__MINGW32__
|
||||||
|
|
||||||
#elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS
|
#elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS
|
||||||
// NOTE: Not async-safe. But can be open-coded.
|
// NOTE: Not async-safe. But can be open-coded.
|
||||||
|
|
|
@ -224,7 +224,14 @@ void ClearCurrentThreadIdentity();
|
||||||
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
|
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
|
||||||
ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
|
ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
|
||||||
|
|
||||||
extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr;
|
#if ABSL_PER_THREAD_TLS
|
||||||
|
ABSL_CONST_INIT extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity*
|
||||||
|
thread_identity_ptr;
|
||||||
|
#elif defined(ABSL_HAVE_THREAD_LOCAL)
|
||||||
|
ABSL_CONST_INIT extern thread_local ThreadIdentity* thread_identity_ptr;
|
||||||
|
#else
|
||||||
|
#error Thread-local storage not detected on this platform
|
||||||
|
#endif
|
||||||
|
|
||||||
inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
|
inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
|
||||||
return thread_identity_ptr;
|
return thread_identity_ptr;
|
||||||
|
|
|
@ -45,6 +45,7 @@ namespace absl {
|
||||||
namespace container_internal {
|
namespace container_internal {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using ::absl::test_internal::CopyableMovableInstance;
|
||||||
using ::absl::test_internal::InstanceTracker;
|
using ::absl::test_internal::InstanceTracker;
|
||||||
using ::absl::test_internal::MovableOnlyInstance;
|
using ::absl::test_internal::MovableOnlyInstance;
|
||||||
using ::testing::ElementsAre;
|
using ::testing::ElementsAre;
|
||||||
|
@ -1823,25 +1824,80 @@ TEST(Btree, ExtractAndInsertNodeHandleSet) {
|
||||||
EXPECT_EQ(res.node.value(), 3);
|
EXPECT_EQ(res.node.value(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Deref {
|
template <typename Set>
|
||||||
bool operator()(const std::unique_ptr<int> &lhs,
|
void TestExtractWithTrackingForSet() {
|
||||||
const std::unique_ptr<int> &rhs) const {
|
InstanceTracker tracker;
|
||||||
return *lhs < *rhs;
|
{
|
||||||
|
Set s;
|
||||||
|
// Add enough elements to make sure we test internal nodes too.
|
||||||
|
const size_t kSize = 1000;
|
||||||
|
while (s.size() < kSize) {
|
||||||
|
s.insert(MovableOnlyInstance(s.size()));
|
||||||
}
|
}
|
||||||
};
|
for (int i = 0; i < kSize; ++i) {
|
||||||
|
// Extract with key
|
||||||
TEST(Btree, ExtractWithUniquePtr) {
|
auto nh = s.extract(MovableOnlyInstance(i));
|
||||||
absl::btree_set<std::unique_ptr<int>, Deref> s;
|
EXPECT_EQ(s.size(), kSize - 1);
|
||||||
s.insert(absl::make_unique<int>(1));
|
EXPECT_EQ(nh.value().value(), i);
|
||||||
s.insert(absl::make_unique<int>(2));
|
// Insert with node
|
||||||
s.insert(absl::make_unique<int>(3));
|
|
||||||
s.insert(absl::make_unique<int>(4));
|
|
||||||
s.insert(absl::make_unique<int>(5));
|
|
||||||
auto nh = s.extract(s.find(absl::make_unique<int>(3)));
|
|
||||||
EXPECT_EQ(s.size(), 4);
|
|
||||||
EXPECT_EQ(*nh.value(), 3);
|
|
||||||
s.insert(std::move(nh));
|
s.insert(std::move(nh));
|
||||||
EXPECT_EQ(s.size(), 5);
|
EXPECT_EQ(s.size(), kSize);
|
||||||
|
|
||||||
|
// Extract with iterator
|
||||||
|
auto it = s.find(MovableOnlyInstance(i));
|
||||||
|
nh = s.extract(it);
|
||||||
|
EXPECT_EQ(s.size(), kSize - 1);
|
||||||
|
EXPECT_EQ(nh.value().value(), i);
|
||||||
|
// Insert with node and hint
|
||||||
|
s.insert(s.begin(), std::move(nh));
|
||||||
|
EXPECT_EQ(s.size(), kSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_EQ(0, tracker.instances());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Map>
|
||||||
|
void TestExtractWithTrackingForMap() {
|
||||||
|
InstanceTracker tracker;
|
||||||
|
{
|
||||||
|
Map m;
|
||||||
|
// Add enough elements to make sure we test internal nodes too.
|
||||||
|
const size_t kSize = 1000;
|
||||||
|
while (m.size() < kSize) {
|
||||||
|
m.insert(
|
||||||
|
{CopyableMovableInstance(m.size()), MovableOnlyInstance(m.size())});
|
||||||
|
}
|
||||||
|
for (int i = 0; i < kSize; ++i) {
|
||||||
|
// Extract with key
|
||||||
|
auto nh = m.extract(CopyableMovableInstance(i));
|
||||||
|
EXPECT_EQ(m.size(), kSize - 1);
|
||||||
|
EXPECT_EQ(nh.key().value(), i);
|
||||||
|
EXPECT_EQ(nh.mapped().value(), i);
|
||||||
|
// Insert with node
|
||||||
|
m.insert(std::move(nh));
|
||||||
|
EXPECT_EQ(m.size(), kSize);
|
||||||
|
|
||||||
|
// Extract with iterator
|
||||||
|
auto it = m.find(CopyableMovableInstance(i));
|
||||||
|
nh = m.extract(it);
|
||||||
|
EXPECT_EQ(m.size(), kSize - 1);
|
||||||
|
EXPECT_EQ(nh.key().value(), i);
|
||||||
|
EXPECT_EQ(nh.mapped().value(), i);
|
||||||
|
// Insert with node and hint
|
||||||
|
m.insert(m.begin(), std::move(nh));
|
||||||
|
EXPECT_EQ(m.size(), kSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_EQ(0, tracker.instances());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Btree, ExtractTracking) {
|
||||||
|
TestExtractWithTrackingForSet<absl::btree_set<MovableOnlyInstance>>();
|
||||||
|
TestExtractWithTrackingForSet<absl::btree_multiset<MovableOnlyInstance>>();
|
||||||
|
TestExtractWithTrackingForMap<
|
||||||
|
absl::btree_map<CopyableMovableInstance, MovableOnlyInstance>>();
|
||||||
|
TestExtractWithTrackingForMap<
|
||||||
|
absl::btree_multimap<CopyableMovableInstance, MovableOnlyInstance>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Btree, ExtractAndInsertNodeHandleMultiSet) {
|
TEST(Btree, ExtractAndInsertNodeHandleMultiSet) {
|
||||||
|
|
|
@ -2031,7 +2031,6 @@ auto btree<P>::erase(iterator iter) -> iterator {
|
||||||
iterator internal_iter(iter);
|
iterator internal_iter(iter);
|
||||||
--iter;
|
--iter;
|
||||||
assert(iter.node->leaf());
|
assert(iter.node->leaf());
|
||||||
assert(!compare_keys(internal_iter.key(), iter.key()));
|
|
||||||
params_type::move(mutable_allocator(), iter.node->slot(iter.position),
|
params_type::move(mutable_allocator(), iter.node->slot(iter.position),
|
||||||
internal_iter.node->slot(internal_iter.position));
|
internal_iter.node->slot(internal_iter.position));
|
||||||
internal_delete = true;
|
internal_delete = true;
|
||||||
|
|
|
@ -296,9 +296,10 @@ class btree_set_container : public btree_container<Tree> {
|
||||||
insert_return_type insert(node_type &&node) {
|
insert_return_type insert(node_type &&node) {
|
||||||
if (!node) return {this->end(), false, node_type()};
|
if (!node) return {this->end(), false, node_type()};
|
||||||
std::pair<iterator, bool> res =
|
std::pair<iterator, bool> res =
|
||||||
insert(std::move(params_type::element(CommonAccess::GetSlot(node))));
|
this->tree_.insert_unique(params_type::key(CommonAccess::GetSlot(node)),
|
||||||
|
CommonAccess::GetSlot(node));
|
||||||
if (res.second) {
|
if (res.second) {
|
||||||
CommonAccess::Reset(&node);
|
CommonAccess::Destroy(&node);
|
||||||
return {res.first, true, node_type()};
|
return {res.first, true, node_type()};
|
||||||
} else {
|
} else {
|
||||||
return {res.first, false, std::move(node)};
|
return {res.first, false, std::move(node)};
|
||||||
|
@ -308,8 +309,8 @@ class btree_set_container : public btree_container<Tree> {
|
||||||
if (!node) return this->end();
|
if (!node) return this->end();
|
||||||
std::pair<iterator, bool> res = this->tree_.insert_hint_unique(
|
std::pair<iterator, bool> res = this->tree_.insert_hint_unique(
|
||||||
iterator(hint), params_type::key(CommonAccess::GetSlot(node)),
|
iterator(hint), params_type::key(CommonAccess::GetSlot(node)),
|
||||||
std::move(params_type::element(CommonAccess::GetSlot(node))));
|
CommonAccess::GetSlot(node));
|
||||||
if (res.second) CommonAccess::Reset(&node);
|
if (res.second) CommonAccess::Destroy(&node);
|
||||||
return res.first;
|
return res.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +324,7 @@ class btree_set_container : public btree_container<Tree> {
|
||||||
// Node extraction routines.
|
// Node extraction routines.
|
||||||
template <typename K = key_type>
|
template <typename K = key_type>
|
||||||
node_type extract(const key_arg<K> &key) {
|
node_type extract(const key_arg<K> &key) {
|
||||||
auto it = find(key);
|
auto it = this->find(key);
|
||||||
return it == this->end() ? node_type() : extract(it);
|
return it == this->end() ? node_type() : extract(it);
|
||||||
}
|
}
|
||||||
using super_type::extract;
|
using super_type::extract;
|
||||||
|
@ -523,24 +524,21 @@ class btree_multiset_container : public btree_container<Tree> {
|
||||||
return this->tree_.insert_hint_multi(
|
return this->tree_.insert_hint_multi(
|
||||||
iterator(position), init_type(std::forward<Args>(args)...));
|
iterator(position), init_type(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
iterator insert(node_type &&node) {
|
||||||
private:
|
|
||||||
template <typename... Args>
|
|
||||||
iterator insert_node_helper(node_type &&node, Args &&... args) {
|
|
||||||
if (!node) return this->end();
|
if (!node) return this->end();
|
||||||
iterator res =
|
iterator res =
|
||||||
insert(std::forward<Args>(args)...,
|
this->tree_.insert_multi(params_type::key(CommonAccess::GetSlot(node)),
|
||||||
std::move(params_type::element(CommonAccess::GetSlot(node))));
|
CommonAccess::GetSlot(node));
|
||||||
CommonAccess::Reset(&node);
|
CommonAccess::Destroy(&node);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
iterator insert(node_type &&node) {
|
|
||||||
return insert_node_helper(std::move(node));
|
|
||||||
}
|
|
||||||
iterator insert(const_iterator hint, node_type &&node) {
|
iterator insert(const_iterator hint, node_type &&node) {
|
||||||
return insert_node_helper(std::move(node), hint);
|
if (!node) return this->end();
|
||||||
|
iterator res = this->tree_.insert_hint_multi(
|
||||||
|
iterator(hint),
|
||||||
|
std::move(params_type::element(CommonAccess::GetSlot(node))));
|
||||||
|
CommonAccess::Destroy(&node);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletion routines.
|
// Deletion routines.
|
||||||
|
@ -553,7 +551,7 @@ class btree_multiset_container : public btree_container<Tree> {
|
||||||
// Node extraction routines.
|
// Node extraction routines.
|
||||||
template <typename K = key_type>
|
template <typename K = key_type>
|
||||||
node_type extract(const key_arg<K> &key) {
|
node_type extract(const key_arg<K> &key) {
|
||||||
auto it = find(key);
|
auto it = this->find(key);
|
||||||
return it == this->end() ? node_type() : extract(it);
|
return it == this->end() ? node_type() : extract(it);
|
||||||
}
|
}
|
||||||
using super_type::extract;
|
using super_type::extract;
|
||||||
|
|
|
@ -166,6 +166,11 @@ struct CommonAccess {
|
||||||
return node.slot();
|
return node.slot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Node>
|
||||||
|
static void Destroy(Node* node) {
|
||||||
|
node->destroy();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
static void Reset(Node* node) {
|
static void Reset(Node* node) {
|
||||||
node->reset();
|
node->reset();
|
||||||
|
|
Loading…
Reference in a new issue