From 37dd2562ec830d547a1524bb306be313ac3f2556 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 28 Jan 2020 11:50:11 -0800 Subject: Export of internal Abseil changes -- 8bdb2020150ed0fd4a4e520e454dc5f54e33f776 by Eric Fiselier : Workaround bug in GCC 9.2 and after. PiperOrigin-RevId: 291982551 -- 47ff4820e595f96c082a90d733725f6882d83e3b by Abseil Team : Improve ABSL_ATTRIBUTE_PACKED documentation Recommend to apply ABSL_ATTRIBUTE_PACKED to structure members instead of to an entire structure because applying this attribute to an entire structure may cause the compiler to generate suboptimal code. It reduces the alignment of the data structure from a value larger than one to one. When applied to a structure, ABSL_ATTRIBUTE_PACKED reduces the alignment of a structure (alignof()) to 1. As a result, the compiler can no longer assume that e.g. uint32 members are aligned on a four byte boundary and hence is forced to use single-byte load and store instructions on CPU architectures that do not support non-aligned loads or stores. PiperOrigin-RevId: 291977920 -- 902b7a86f860da699d3a2e5c738be5ef73ede3b4 by Mark Barolak : Internal change PiperOrigin-RevId: 291963048 -- bb3bd3247e376d53a3080b105f13ec7566d3ae50 by Abseil Team : Support the C++17 insert_or_assign() API in btree_map. PiperOrigin-RevId: 291945474 -- ff3b3cfcbbc64f086f95501f48d49426bcde356f by Gennadiy Rozental : Import of CCTZ from GitHub. PiperOrigin-RevId: 291861110 -- fd465cd9cbbacd3962f67a7346d6462edaddd809 by Derek Mauro : Add flaky=1 to beta_distribution_test. PiperOrigin-RevId: 291757364 -- 3603adfb59c4128c542b670952cce250d59e1f67 by Derek Mauro : Separate the initialization of NumCPUs() and NominalCPUFrequency() The OSS version of Abseil never needs to call NominalCPUFrequency(). In some configurations, initializing NominalCPUFrequency() requires spending at least 3ms measuring the CPU frequency. By separating the initialization from NumCPUs(), which is called in most configurations, we can save at least 3ms of program startup time. PiperOrigin-RevId: 291737273 -- bea9e4a6bff5a0351d340deab966641867e08c4d by Abseil Team : Change the cmake library names not to have a redundant `absl_` prefix. PiperOrigin-RevId: 291640501 -- 501b602ef260cd7c8c527342581ceffb3c5b6d4c by Gennadiy Rozental : Introducing benchmark for absl::GetFlag. PiperOrigin-RevId: 291433394 -- 4eeaddc788da4b91c272a8adca77ca6dbbbc1d44 by Xiaoyi Zhang : fix: Add support for more ARM processors detection Import of https://github.com/abseil/abseil-cpp/pull/608 PiperOrigin-RevId: 291420397 -- a3087a8e883c5d71de7d9bd4ec8f4db5142dfcf5 by Derek Mauro : Removes the flaky raw_hash_set prefetch test PiperOrigin-RevId: 291197079 -- aad6c2121c102ac36216e771c83227cf3e3bfd66 by Andy Soffer : Enable building Abseil as a DLL. This is currently experimental and unsupported. This CL does a few things: 1. Adds the ABSL_DLL macro to any class holding a static data member, or to global constants in headers. 2. Adds a whitelist of all files in the DLL and all the build targets that are conglomerated into the DLL. 3. When BUILD_SHARED_LIBS is specified, any build target that would be in the DLL still exists, but we swap out all of it's dependencies so it just depends on abseil_dll PiperOrigin-RevId: 291192055 -- 5e888cd6f2a7722805d41f872108a03a84e421c7 by Mark Barolak : Move absl/strings/internal/escaping.{cc,h} into internal build targets. This puts absl/strings/internal/escaping.h behind a whitelist and it also resolves https://github.com/abseil/abseil-cpp/issues/604. PiperOrigin-RevId: 291173320 -- 166836d24970da87587c1728036f53f05a28f0af by Eric Fiselier : Internal Change. PiperOrigin-RevId: 291012718 -- 996ddb3dffda02440fa93f30ca5d71b14b688875 by Abseil Team : Fix shared libraries log spam for built-in types in absl::GetFlag PiperOrigin-RevId: 290772743 GitOrigin-RevId: 8bdb2020150ed0fd4a4e520e454dc5f54e33f776 Change-Id: I8bf2265dd14ebbace220a1b6b982bb5040ad2a26 --- absl/flags/flag_benchmark.cc | 111 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 absl/flags/flag_benchmark.cc (limited to 'absl/flags/flag_benchmark.cc') diff --git a/absl/flags/flag_benchmark.cc b/absl/flags/flag_benchmark.cc new file mode 100644 index 00000000..87f73170 --- /dev/null +++ b/absl/flags/flag_benchmark.cc @@ -0,0 +1,111 @@ +// +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/flags/flag.h" +#include "absl/time/time.h" +#include "absl/types/optional.h" +#include "benchmark/benchmark.h" + +namespace { +using String = std::string; +using VectorOfStrings = std::vector; +using AbslDuration = absl::Duration; + +// We do not want to take over marshalling for the types absl::optional, +// absl::optional which we do not own. Instead we introduce unique +// "aliases" to these types, which we do. +using AbslOptionalInt = absl::optional; +struct OptionalInt : AbslOptionalInt { + using AbslOptionalInt::AbslOptionalInt; +}; +// Next two functions represent Abseil Flags marshalling for OptionalInt. +bool AbslParseFlag(absl::string_view src, OptionalInt* flag, + std::string* error) { + int val; + if (src.empty()) + flag->reset(); + else if (!absl::ParseFlag(src, &val, error)) + return false; + *flag = val; + return true; +} +std::string AbslUnparseFlag(const OptionalInt& flag) { + return !flag ? "" : absl::UnparseFlag(*flag); +} + +using AbslOptionalString = absl::optional; +struct OptionalString : AbslOptionalString { + using AbslOptionalString::AbslOptionalString; +}; +// Next two functions represent Abseil Flags marshalling for OptionalString. +bool AbslParseFlag(absl::string_view src, OptionalString* flag, + std::string* error) { + std::string val; + if (src.empty()) + flag->reset(); + else if (!absl::ParseFlag(src, &val, error)) + return false; + *flag = val; + return true; +} +std::string AbslUnparseFlag(const OptionalString& flag) { + return !flag ? "" : absl::UnparseFlag(*flag); +} + +struct UDT { + UDT() = default; + UDT(const UDT&) {} + UDT& operator=(const UDT&) { return *this; } +}; +// Next two functions represent Abseil Flags marshalling for UDT. +bool AbslParseFlag(absl::string_view, UDT*, std::string*) { return true; } +std::string AbslUnparseFlag(const UDT&) { return ""; } + +} // namespace + +#define BENCHMARKED_TYPES(A) \ + A(bool) \ + A(int16_t) \ + A(uint16_t) \ + A(int32_t) \ + A(uint32_t) \ + A(int64_t) \ + A(uint64_t) \ + A(double) \ + A(float) \ + A(String) \ + A(VectorOfStrings) \ + A(OptionalInt) \ + A(OptionalString) \ + A(AbslDuration) \ + A(UDT) + +#define FLAG_DEF(T) ABSL_FLAG(T, T##_flag, {}, ""); + +BENCHMARKED_TYPES(FLAG_DEF) + +namespace { + +#define BM_GetFlag(T) \ + void BM_GetFlag_##T(benchmark::State& state) { \ + for (auto _ : state) { \ + benchmark::DoNotOptimize(absl::GetFlag(FLAGS_##T##_flag)); \ + } \ + } \ + BENCHMARK(BM_GetFlag_##T); + +BENCHMARKED_TYPES(BM_GetFlag) + +} // namespace -- cgit v1.2.3 From b19ba96766db08b1f32605cb4424a0e7ea0c7584 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 3 Mar 2020 11:22:10 -0800 Subject: Export of internal Abseil changes -- a3e58c1870a9626039f4d178d2d599319bd9f8a8 by Matt Kulukundis : Allow MakeCordFromExternal to take a zero arg releaser. PiperOrigin-RevId: 298650274 -- 01897c4a9bb99f3dc329a794019498ad345ddebd by Samuel Benzaquen : Reduce library bloat for absl::Flag by moving the definition of base virtual functions to a .cc file. This removes the duplicate symbols in user translation units and has the side effect of moving the vtable definition too (re key function) PiperOrigin-RevId: 298617920 -- 190f0d3782c63aed01046886d7fbc1be5bca2de9 by Derek Mauro : Import GitHub #596: Unbreak stacktrace code for UWP apps PiperOrigin-RevId: 298600834 -- cd5cf6f8c87b35b85a9584e94da2a99057345b73 by Gennadiy Rozental : Use union of heap allocated pointer, one word atomic and two word atomic to represent flags value. Any type T, which is trivially copy-able and with with sizeof(T) <= 8, will be stored in atomic int64_t. Any type T, which is trivially copy-able and with with 8 < sizeof(T) <= 16, will be stored in atomic AlignedTwoWords. We also introducing value storage type to distinguish these cases. PiperOrigin-RevId: 298497200 -- f8fe7bd53bfed601f002f521e34ab4bc083fc28b by Matthew Brown : Ensure a deep copy and proper equality on absl::Status::ErasePayload PiperOrigin-RevId: 298482742 -- a5c9ccddf4b04f444e3f7e27dbc14faf1fcb5373 by Gennadiy Rozental : Change ChunkIterator implementation to use fixed capacity collection of CordRep*. We can now assume that depth never exceeds 91. That makes comparison operator exception safe. I've tested that with this CL we do not observe an overhead of chunk_end. Compiler optimized this iterator completely. PiperOrigin-RevId: 298458472 -- 327ea5e8910bc388b03389c730763f9823abfce5 by Abseil Team : Minor cleanups in b-tree code: - Rename some variables: fix issues of different param names between definition/declaration, move away from `x` as a default meaningless variable name. - Make init_leaf/init_internal be non-static methods (they already take the node as the first parameter). - In internal_emplace/try_shrink, update root/rightmost the same way as in insert_unique/insert_multi. - Replace a TODO with a comment. PiperOrigin-RevId: 298432836 -- 8020ce9ec8558ee712d9733ae3d660ac1d3ffe1a by Abseil Team : Guard against unnecessary copy in case the buffer is empty. This is important in cases were the user is explicitly tuning their chunks to match PiecewiseChunkSize(). PiperOrigin-RevId: 298366044 -- 89324441d1c0c697c90ba7d8fc63639805fcaa9d by Abseil Team : Internal change PiperOrigin-RevId: 298219363 GitOrigin-RevId: a3e58c1870a9626039f4d178d2d599319bd9f8a8 Change-Id: I28dffc684b6fd0292b94807b88ec6664d5d0e183 --- absl/base/log_severity_test.cc | 2 +- absl/container/btree_benchmark.cc | 24 +-- absl/container/btree_map.h | 4 +- absl/container/btree_set.h | 4 +- absl/container/btree_test.cc | 50 ++--- absl/container/internal/btree.h | 214 ++++++++++---------- absl/container/internal/btree_container.h | 42 ++-- absl/debugging/internal/stacktrace_win32-inl.inc | 12 +- absl/flags/BUILD.bazel | 4 + absl/flags/CMakeLists.txt | 3 + absl/flags/flag.h | 1 - absl/flags/flag_benchmark.cc | 8 + absl/flags/flag_test.cc | 143 ++++++++++---- absl/flags/internal/commandlineflag.cc | 30 +++ absl/flags/internal/commandlineflag.h | 6 +- absl/flags/internal/flag.cc | 107 +++++++--- absl/flags/internal/flag.h | 208 +++++++++---------- absl/hash/internal/hash.h | 15 +- absl/random/internal/BUILD.bazel | 1 + absl/status/status.cc | 8 + absl/status/status_test.cc | 57 ++++++ absl/strings/cord.cc | 242 +++++++++++------------ absl/strings/cord.h | 100 +++++++++- absl/strings/cord_test.cc | 56 ++++++ 24 files changed, 841 insertions(+), 500 deletions(-) create mode 100644 absl/flags/internal/commandlineflag.cc (limited to 'absl/flags/flag_benchmark.cc') diff --git a/absl/base/log_severity_test.cc b/absl/base/log_severity_test.cc index 2302aa12..2c6872b0 100644 --- a/absl/base/log_severity_test.cc +++ b/absl/base/log_severity_test.cc @@ -53,7 +53,7 @@ TEST(StreamTest, Works) { } static_assert( - absl::flags_internal::IsAtomicFlagTypeTrait::value, + absl::flags_internal::FlagUseOneWordStorage::value, "Flags of type absl::LogSeverity ought to be lock-free."); using ParseFlagFromOutOfRangeIntegerTest = TestWithParam; diff --git a/absl/container/btree_benchmark.cc b/absl/container/btree_benchmark.cc index 4af92f9f..420cfa0d 100644 --- a/absl/container/btree_benchmark.cc +++ b/absl/container/btree_benchmark.cc @@ -538,19 +538,19 @@ struct BigType { BigType() : BigType(0) {} explicit BigType(int x) { std::iota(values.begin(), values.end(), x); } - void Copy(const BigType& x) { - for (int i = 0; i < Size && i < Copies; ++i) values[i] = x.values[i]; + void Copy(const BigType& other) { + for (int i = 0; i < Size && i < Copies; ++i) values[i] = other.values[i]; // If Copies > Size, do extra copies. for (int i = Size, idx = 0; i < Copies; ++i) { - int64_t tmp = x.values[idx]; + int64_t tmp = other.values[idx]; benchmark::DoNotOptimize(tmp); idx = idx + 1 == Size ? 0 : idx + 1; } } - BigType(const BigType& x) { Copy(x); } - BigType& operator=(const BigType& x) { - Copy(x); + BigType(const BigType& other) { Copy(other); } + BigType& operator=(const BigType& other) { + Copy(other); return *this; } @@ -641,14 +641,14 @@ struct BigTypePtr { explicit BigTypePtr(int x) { ptr = absl::make_unique>(x); } - BigTypePtr(const BigTypePtr& x) { - ptr = absl::make_unique>(*x.ptr); + BigTypePtr(const BigTypePtr& other) { + ptr = absl::make_unique>(*other.ptr); } - BigTypePtr(BigTypePtr&& x) noexcept = default; - BigTypePtr& operator=(const BigTypePtr& x) { - ptr = absl::make_unique>(*x.ptr); + BigTypePtr(BigTypePtr&& other) noexcept = default; + BigTypePtr& operator=(const BigTypePtr& other) { + ptr = absl::make_unique>(*other.ptr); } - BigTypePtr& operator=(BigTypePtr&& x) noexcept = default; + BigTypePtr& operator=(BigTypePtr&& other) noexcept = default; bool operator<(const BigTypePtr& other) const { return *ptr < *other.ptr; } bool operator==(const BigTypePtr& other) const { return *ptr == *other.ptr; } diff --git a/absl/container/btree_map.h b/absl/container/btree_map.h index d23f4ee5..bb450ead 100644 --- a/absl/container/btree_map.h +++ b/absl/container/btree_map.h @@ -318,7 +318,7 @@ class btree_map // Extracts the element at the indicated position and returns a node handle // owning that extracted data. // - // template node_type extract(const K& x): + // template node_type extract(const K& k): // // Extracts the element with the key matching the passed key value and // returns a node handle owning that extracted data. If the `btree_map` @@ -645,7 +645,7 @@ class btree_multimap // Extracts the element at the indicated position and returns a node handle // owning that extracted data. // - // template node_type extract(const K& x): + // template node_type extract(const K& k): // // Extracts the element with the key matching the passed key value and // returns a node handle owning that extracted data. If the `btree_multimap` diff --git a/absl/container/btree_set.h b/absl/container/btree_set.h index 127fb940..d3e78866 100644 --- a/absl/container/btree_set.h +++ b/absl/container/btree_set.h @@ -263,7 +263,7 @@ class btree_set // Extracts the element at the indicated position and returns a node handle // owning that extracted data. // - // template node_type extract(const K& x): + // template node_type extract(const K& k): // // Extracts the element with the key matching the passed key value and // returns a node handle owning that extracted data. If the `btree_set` @@ -567,7 +567,7 @@ class btree_multiset // Extracts the element at the indicated position and returns a node handle // owning that extracted data. // - // template node_type extract(const K& x): + // template node_type extract(const K& k): // // Extracts the element with the key matching the passed key value and // returns a node handle owning that extracted data. If the `btree_multiset` diff --git a/absl/container/btree_test.cc b/absl/container/btree_test.cc index 9edf38f9..ce12e819 100644 --- a/absl/container/btree_test.cc +++ b/absl/container/btree_test.cc @@ -89,8 +89,8 @@ class base_checker { public: base_checker() : const_tree_(tree_) {} - base_checker(const base_checker &x) - : tree_(x.tree_), const_tree_(tree_), checker_(x.checker_) {} + base_checker(const base_checker &other) + : tree_(other.tree_), const_tree_(tree_), checker_(other.checker_) {} template base_checker(InputIterator b, InputIterator e) : tree_(b, e), const_tree_(tree_), checker_(b, e) {} @@ -124,11 +124,11 @@ class base_checker { } return tree_iter; } - void value_check(const value_type &x) { + void value_check(const value_type &v) { typename KeyOfValue::type key_of_value; - const key_type &key = key_of_value(x); - CheckPairEquals(*find(key), x); + const key_type &key = key_of_value(v); + CheckPairEquals(*find(key), v); lower_bound(key); upper_bound(key); equal_range(key); @@ -187,9 +187,9 @@ class base_checker { return res; } - base_checker &operator=(const base_checker &x) { - tree_ = x.tree_; - checker_ = x.checker_; + base_checker &operator=(const base_checker &other) { + tree_ = other.tree_; + checker_ = other.checker_; return *this; } @@ -250,9 +250,9 @@ class base_checker { tree_.clear(); checker_.clear(); } - void swap(base_checker &x) { - tree_.swap(x.tree_); - checker_.swap(x.checker_); + void swap(base_checker &other) { + tree_.swap(other.tree_); + checker_.swap(other.checker_); } void verify() const { @@ -323,28 +323,28 @@ class unique_checker : public base_checker { public: unique_checker() : super_type() {} - unique_checker(const unique_checker &x) : super_type(x) {} + unique_checker(const unique_checker &other) : super_type(other) {} template unique_checker(InputIterator b, InputIterator e) : super_type(b, e) {} unique_checker &operator=(const unique_checker &) = default; // Insertion routines. - std::pair insert(const value_type &x) { + std::pair insert(const value_type &v) { int size = this->tree_.size(); std::pair checker_res = - this->checker_.insert(x); - std::pair tree_res = this->tree_.insert(x); + this->checker_.insert(v); + std::pair tree_res = this->tree_.insert(v); CheckPairEquals(*tree_res.first, *checker_res.first); EXPECT_EQ(tree_res.second, checker_res.second); EXPECT_EQ(this->tree_.size(), this->checker_.size()); EXPECT_EQ(this->tree_.size(), size + tree_res.second); return tree_res; } - iterator insert(iterator position, const value_type &x) { + iterator insert(iterator position, const value_type &v) { int size = this->tree_.size(); std::pair checker_res = - this->checker_.insert(x); - iterator tree_res = this->tree_.insert(position, x); + this->checker_.insert(v); + iterator tree_res = this->tree_.insert(position, v); CheckPairEquals(*tree_res, *checker_res.first); EXPECT_EQ(this->tree_.size(), this->checker_.size()); EXPECT_EQ(this->tree_.size(), size + checker_res.second); @@ -371,25 +371,25 @@ class multi_checker : public base_checker { public: multi_checker() : super_type() {} - multi_checker(const multi_checker &x) : super_type(x) {} + multi_checker(const multi_checker &other) : super_type(other) {} template multi_checker(InputIterator b, InputIterator e) : super_type(b, e) {} multi_checker &operator=(const multi_checker &) = default; // Insertion routines. - iterator insert(const value_type &x) { + iterator insert(const value_type &v) { int size = this->tree_.size(); - auto checker_res = this->checker_.insert(x); - iterator tree_res = this->tree_.insert(x); + auto checker_res = this->checker_.insert(v); + iterator tree_res = this->tree_.insert(v); CheckPairEquals(*tree_res, *checker_res); EXPECT_EQ(this->tree_.size(), this->checker_.size()); EXPECT_EQ(this->tree_.size(), size + 1); return tree_res; } - iterator insert(iterator position, const value_type &x) { + iterator insert(iterator position, const value_type &v) { int size = this->tree_.size(); - auto checker_res = this->checker_.insert(x); - iterator tree_res = this->tree_.insert(position, x); + auto checker_res = this->checker_.insert(v); + iterator tree_res = this->tree_.insert(position, v); CheckPairEquals(*tree_res, *checker_res); EXPECT_EQ(this->tree_.size(), this->checker_.size()); EXPECT_EQ(this->tree_.size(), size + 1); diff --git a/absl/container/internal/btree.h b/absl/container/internal/btree.h index fd5c0e7a..2a5c7314 100644 --- a/absl/container/internal/btree.h +++ b/absl/container/internal/btree.h @@ -252,9 +252,9 @@ struct map_params : common_paramssecond; } }; @@ -315,8 +315,8 @@ struct set_params : common_params struct upper_bound_adapter { explicit upper_bound_adapter(const Compare &c) : comp(c) {} - template - bool operator()(const K &a, const LK &b) const { + template + bool operator()(const K1 &a, const K2 &b) const { // Returns true when a is not greater than b. return !compare_internal::compare_result_as_less_than(comp(b, a)); } @@ -736,32 +736,28 @@ class btree_node { // Merges a node with its right sibling, moving all of the values and the // delimiting key in the parent node onto itself. - void merge(btree_node *sibling, allocator_type *alloc); + void merge(btree_node *src, allocator_type *alloc); - // Swap the contents of "this" and "src". - void swap(btree_node *src, allocator_type *alloc); + // Swaps the contents of `this` and `other`. + void swap(btree_node *other, allocator_type *alloc); // Node allocation/deletion routines. - static btree_node *init_leaf(btree_node *n, btree_node *parent, - int max_count) { - n->set_parent(parent); - n->set_position(0); - n->set_start(0); - n->set_finish(0); - n->set_max_count(max_count); + void init_leaf(btree_node *parent, int max_count) { + set_parent(parent); + set_position(0); + set_start(0); + set_finish(0); + set_max_count(max_count); absl::container_internal::SanitizerPoisonMemoryRegion( - n->start_slot(), max_count * sizeof(slot_type)); - return n; + start_slot(), max_count * sizeof(slot_type)); } - static btree_node *init_internal(btree_node *n, btree_node *parent) { - init_leaf(n, parent, kNodeValues); + void init_internal(btree_node *parent) { + init_leaf(parent, kNodeValues); // Set `max_count` to a sentinel value to indicate that this node is // internal. - n->set_max_count(kInternalNodeMaxCount); + set_max_count(kInternalNodeMaxCount); absl::container_internal::SanitizerPoisonMemoryRegion( - &n->mutable_child(n->start()), - (kNodeValues + 1) * sizeof(btree_node *)); - return n; + &mutable_child(start()), (kNodeValues + 1) * sizeof(btree_node *)); } void destroy(allocator_type *alloc) { for (int i = start(); i < finish(); ++i) { @@ -787,13 +783,13 @@ class btree_node { } // Move n values starting at value i in this node into the values starting at - // value j in node x. + // value j in dest_node. void uninitialized_move_n(const size_type n, const size_type i, - const size_type j, btree_node *x, + const size_type j, btree_node *dest_node, allocator_type *alloc) { absl::container_internal::SanitizerUnpoisonMemoryRegion( - x->slot(j), n * sizeof(slot_type)); - for (slot_type *src = slot(i), *end = src + n, *dest = x->slot(j); + dest_node->slot(j), n * sizeof(slot_type)); + for (slot_type *src = slot(i), *end = src + n, *dest = dest_node->slot(j); src != end; ++src, ++dest) { params_type::construct(alloc, dest, src); } @@ -856,8 +852,8 @@ struct btree_iterator { std::is_same, iterator>::value && std::is_same::value, int> = 0> - btree_iterator(const btree_iterator &x) // NOLINT - : node(x.node), position(x.position) {} + btree_iterator(const btree_iterator &other) // NOLINT + : node(other.node), position(other.position) {} private: // This SFINAE allows explicit conversions from const_iterator to @@ -869,8 +865,8 @@ struct btree_iterator { std::is_same, const_iterator>::value && std::is_same::value, int> = 0> - explicit btree_iterator(const btree_iterator &x) - : node(const_cast(x.node)), position(x.position) {} + explicit btree_iterator(const btree_iterator &other) + : node(const_cast(other.node)), position(other.position) {} // Increment/decrement the iterator. void increment() { @@ -890,11 +886,11 @@ struct btree_iterator { void decrement_slow(); public: - bool operator==(const const_iterator &x) const { - return node == x.node && position == x.position; + bool operator==(const const_iterator &other) const { + return node == other.node && position == other.position; } - bool operator!=(const const_iterator &x) const { - return node != x.node || position != x.position; + bool operator!=(const const_iterator &other) const { + return node != other.node || position != other.position; } // Accessors for the key/value the iterator is pointing at. @@ -942,7 +938,8 @@ struct btree_iterator { // The node in the tree the iterator is pointing at. Node *node; // The position within the node of the tree the iterator is pointing at. - // TODO(ezb): make this a field_type + // NOTE: this is an int rather than a field_type because iterators can point + // to invalid positions (such as -1) in certain circumstances. int position; }; @@ -994,9 +991,9 @@ class btree { node_stats(size_type l, size_type i) : leaf_nodes(l), internal_nodes(i) {} - node_stats &operator+=(const node_stats &x) { - leaf_nodes += x.leaf_nodes; - internal_nodes += x.internal_nodes; + node_stats &operator+=(const node_stats &other) { + leaf_nodes += other.leaf_nodes; + internal_nodes += other.internal_nodes; return *this; } @@ -1028,15 +1025,15 @@ class btree { private: // For use in copy_or_move_values_in_order. - const value_type &maybe_move_from_iterator(const_iterator x) { return *x; } - value_type &&maybe_move_from_iterator(iterator x) { return std::move(*x); } + const value_type &maybe_move_from_iterator(const_iterator it) { return *it; } + value_type &&maybe_move_from_iterator(iterator it) { return std::move(*it); } // Copies or moves (depending on the template parameter) the values in - // x into this btree in their order in x. This btree must be empty before this - // method is called. This method is used in copy construction, copy - // assignment, and move assignment. + // other into this btree in their order in other. This btree must be empty + // before this method is called. This method is used in copy construction, + // copy assignment, and move assignment. template - void copy_or_move_values_in_order(Btree *x); + void copy_or_move_values_in_order(Btree *other); // Validates that various assumptions/requirements are true at compile time. constexpr static bool static_assert_validation(); @@ -1044,12 +1041,12 @@ class btree { public: btree(const key_compare &comp, const allocator_type &alloc); - btree(const btree &x); - btree(btree &&x) noexcept - : root_(std::move(x.root_)), - rightmost_(absl::exchange(x.rightmost_, EmptyNode())), - size_(absl::exchange(x.size_, 0)) { - x.mutable_root() = EmptyNode(); + btree(const btree &other); + btree(btree &&other) noexcept + : root_(std::move(other.root_)), + rightmost_(absl::exchange(other.rightmost_, EmptyNode())), + size_(absl::exchange(other.size_, 0)) { + other.mutable_root() = EmptyNode(); } ~btree() { @@ -1059,9 +1056,9 @@ class btree { clear(); } - // Assign the contents of x to *this. - btree &operator=(const btree &x); - btree &operator=(btree &&x) noexcept; + // Assign the contents of other to *this. + btree &operator=(const btree &other); + btree &operator=(btree &&other) noexcept; iterator begin() { return iterator(leftmost()); } const_iterator begin() const { return const_iterator(leftmost()); } @@ -1204,15 +1201,15 @@ class btree { // Clear the btree, deleting all of the values it contains. void clear(); - // Swap the contents of *this and x. - void swap(btree &x); + // Swaps the contents of `this` and `other`. + void swap(btree &other); const key_compare &key_comp() const noexcept { return root_.template get<0>(); } - template - bool compare_keys(const K &x, const LK &y) const { - return compare_internal::compare_result_as_less_than(key_comp()(x, y)); + template + bool compare_keys(const K1 &a, const K2 &b) const { + return compare_internal::compare_result_as_less_than(key_comp()(a, b)); } value_compare value_comp() const { return value_compare(key_comp()); } @@ -1322,16 +1319,19 @@ class btree { // Node creation/deletion routines. node_type *new_internal_node(node_type *parent) { - node_type *p = allocate(node_type::InternalSize()); - return node_type::init_internal(p, parent); + node_type *n = allocate(node_type::InternalSize()); + n->init_internal(parent); + return n; } node_type *new_leaf_node(node_type *parent) { - node_type *p = allocate(node_type::LeafSize()); - return node_type::init_leaf(p, parent, kNodeValues); + node_type *n = allocate(node_type::LeafSize()); + n->init_leaf(parent, kNodeValues); + return n; } node_type *new_leaf_root_node(const int max_count) { - node_type *p = allocate(node_type::LeafSize(max_count)); - return node_type::init_leaf(p, p, max_count); + node_type *n = allocate(node_type::LeafSize(max_count)); + n->init_leaf(/*parent=*/n, max_count); + return n; } // Deletion helper routines. @@ -1715,12 +1715,12 @@ void btree_node

::merge(btree_node *src, allocator_type *alloc) { } template -void btree_node

::swap(btree_node *x, allocator_type *alloc) { +void btree_node

::swap(btree_node *other, allocator_type *alloc) { using std::swap; - assert(leaf() == x->leaf()); + assert(leaf() == other->leaf()); // Determine which is the smaller/larger node. - btree_node *smaller = this, *larger = x; + btree_node *smaller = this, *larger = other; if (smaller->count() > larger->count()) { swap(smaller, larger); } @@ -1759,7 +1759,7 @@ void btree_node

::swap(btree_node *x, allocator_type *alloc) { // Swap the `finish`s. // TODO(ezb): with floating storage, will also need to swap starts. - swap(mutable_finish(), x->mutable_finish()); + swap(mutable_finish(), other->mutable_finish()); } //// @@ -1814,7 +1814,7 @@ void btree_iterator::decrement_slow() { // btree methods template template -void btree

::copy_or_move_values_in_order(Btree *x) { +void btree

::copy_or_move_values_in_order(Btree *other) { static_assert(std::is_same::value || std::is_same::value, "Btree type must be same or const."); @@ -1822,11 +1822,11 @@ void btree

::copy_or_move_values_in_order(Btree *x) { // We can avoid key comparisons because we know the order of the // values is the same order we'll store them in. - auto iter = x->begin(); - if (iter == x->end()) return; + auto iter = other->begin(); + if (iter == other->end()) return; insert_multi(maybe_move_from_iterator(iter)); ++iter; - for (; iter != x->end(); ++iter) { + for (; iter != other->end(); ++iter) { // If the btree is not empty, we can just insert the new value at the end // of the tree. internal_emplace(end(), maybe_move_from_iterator(iter)); @@ -1869,8 +1869,9 @@ btree

::btree(const key_compare &comp, const allocator_type &alloc) : root_(comp, alloc, EmptyNode()), rightmost_(EmptyNode()), size_(0) {} template -btree

::btree(const btree &x) : btree(x.key_comp(), x.allocator()) { - copy_or_move_values_in_order(&x); +btree

::btree(const btree &other) + : btree(other.key_comp(), other.allocator()) { + copy_or_move_values_in_order(&other); } template @@ -1977,46 +1978,47 @@ void btree

::insert_iterator_multi(InputIterator b, InputIterator e) { } template -auto btree

::operator=(const btree &x) -> btree & { - if (this != &x) { +auto btree

::operator=(const btree &other) -> btree & { + if (this != &other) { clear(); - *mutable_key_comp() = x.key_comp(); + *mutable_key_comp() = other.key_comp(); if (absl::allocator_traits< allocator_type>::propagate_on_container_copy_assignment::value) { - *mutable_allocator() = x.allocator(); + *mutable_allocator() = other.allocator(); } - copy_or_move_values_in_order(&x); + copy_or_move_values_in_order(&other); } return *this; } template -auto btree

::operator=(btree &&x) noexcept -> btree & { - if (this != &x) { +auto btree

::operator=(btree &&other) noexcept -> btree & { + if (this != &other) { clear(); using std::swap; if (absl::allocator_traits< allocator_type>::propagate_on_container_copy_assignment::value) { // Note: `root_` also contains the allocator and the key comparator. - swap(root_, x.root_); - swap(rightmost_, x.rightmost_); - swap(size_, x.size_); + swap(root_, other.root_); + swap(rightmost_, other.rightmost_); + swap(size_, other.size_); } else { - if (allocator() == x.allocator()) { - swap(mutable_root(), x.mutable_root()); - swap(*mutable_key_comp(), *x.mutable_key_comp()); - swap(rightmost_, x.rightmost_); - swap(size_, x.size_); + if (allocator() == other.allocator()) { + swap(mutable_root(), other.mutable_root()); + swap(*mutable_key_comp(), *other.mutable_key_comp()); + swap(rightmost_, other.rightmost_); + swap(size_, other.size_); } else { // We aren't allowed to propagate the allocator and the allocator is // different so we can't take over its memory. We must move each element - // individually. We need both `x` and `this` to have `x`s key comparator - // while moving the values so we can't swap the key comparators. - *mutable_key_comp() = x.key_comp(); - copy_or_move_values_in_order(&x); + // individually. We need both `other` and `this` to have `other`s key + // comparator while moving the values so we can't swap the key + // comparators. + *mutable_key_comp() = other.key_comp(); + copy_or_move_values_in_order(&other); } } } @@ -2215,20 +2217,20 @@ void btree

::clear() { } template -void btree

::swap(btree &x) { +void btree

::swap(btree &other) { using std::swap; if (absl::allocator_traits< allocator_type>::propagate_on_container_swap::value) { // Note: `root_` also contains the allocator and the key comparator. - swap(root_, x.root_); + swap(root_, other.root_); } else { // It's undefined behavior if the allocators are unequal here. - assert(allocator() == x.allocator()); - swap(mutable_root(), x.mutable_root()); - swap(*mutable_key_comp(), *x.mutable_key_comp()); + assert(allocator() == other.allocator()); + swap(mutable_root(), other.mutable_root()); + swap(*mutable_key_comp(), *other.mutable_key_comp()); } - swap(rightmost_, x.rightmost_); - swap(size_, x.size_); + swap(rightmost_, other.rightmost_); + swap(size_, other.size_); } template @@ -2417,8 +2419,7 @@ void btree

::try_shrink() { if (root()->leaf()) { assert(size() == 0); delete_leaf_node(root()); - mutable_root() = EmptyNode(); - rightmost_ = EmptyNode(); + mutable_root() = rightmost_ = EmptyNode(); } else { node_type *child = root()->start_child(); child->make_root(); @@ -2463,8 +2464,7 @@ inline auto btree

::internal_emplace(iterator iter, Args &&... args) new_leaf_root_node((std::min)(kNodeValues, 2 * max_count)); iter.node->swap(root(), mutable_allocator()); delete_leaf_node(root()); - mutable_root() = iter.node; - rightmost_ = iter.node; + mutable_root() = rightmost_ = iter.node; } else { rebalance_or_split(&iter); } diff --git a/absl/container/internal/btree_container.h b/absl/container/internal/btree_container.h index f2e4c3a5..734c90ef 100644 --- a/absl/container/internal/btree_container.h +++ b/absl/container/internal/btree_container.h @@ -68,10 +68,10 @@ class btree_container { explicit btree_container(const key_compare &comp, const allocator_type &alloc = allocator_type()) : tree_(comp, alloc) {} - btree_container(const btree_container &x) = default; - btree_container(btree_container &&x) noexcept = default; - btree_container &operator=(const btree_container &x) = default; - btree_container &operator=(btree_container &&x) noexcept( + btree_container(const btree_container &other) = default; + btree_container(btree_container &&other) noexcept = default; + btree_container &operator=(const btree_container &other) = default; + btree_container &operator=(btree_container &&other) noexcept( std::is_nothrow_move_assignable::value) = default; // Iterator routines. @@ -154,7 +154,7 @@ class btree_container { public: // Utility routines. void clear() { tree_.clear(); } - void swap(btree_container &x) { tree_.swap(x.tree_); } + void swap(btree_container &other) { tree_.swap(other.tree_); } void verify() const { tree_.verify(); } // Size routines. @@ -257,26 +257,26 @@ class btree_set_container : public btree_container { } // Insertion routines. - std::pair insert(const value_type &x) { - return this->tree_.insert_unique(params_type::key(x), x); + std::pair insert(const value_type &v) { + return this->tree_.insert_unique(params_type::key(v), v); } - std::pair insert(value_type &&x) { - return this->tree_.insert_unique(params_type::key(x), std::move(x)); + std::pair insert(value_type &&v) { + return this->tree_.insert_unique(params_type::key(v), std::move(v)); } template std::pair emplace(Args &&... args) { init_type v(std::forward(args)...); return this->tree_.insert_unique(params_type::key(v), std::move(v)); } - iterator insert(const_iterator position, const value_type &x) { + iterator insert(const_iterator position, const value_type &v) { return this->tree_ - .insert_hint_unique(iterator(position), params_type::key(x), x) + .insert_hint_unique(iterator(position), params_type::key(v), v) .first; } - iterator insert(const_iterator position, value_type &&x) { + iterator insert(const_iterator position, value_type &&v) { return this->tree_ - .insert_hint_unique(iterator(position), params_type::key(x), - std::move(x)) + .insert_hint_unique(iterator(position), params_type::key(v), + std::move(v)) .first; } template @@ -562,15 +562,15 @@ class btree_multiset_container : public btree_container { } // Insertion routines. - iterator insert(const value_type &x) { return this->tree_.insert_multi(x); } - iterator insert(value_type &&x) { - return this->tree_.insert_multi(std::move(x)); + iterator insert(const value_type &v) { return this->tree_.insert_multi(v); } + iterator insert(value_type &&v) { + return this->tree_.insert_multi(std::move(v)); } - iterator insert(const_iterator position, const value_type &x) { - return this->tree_.insert_hint_multi(iterator(position), x); + iterator insert(const_iterator position, const value_type &v) { + return this->tree_.insert_hint_multi(iterator(position), v); } - iterator insert(const_iterator position, value_type &&x) { - return this->tree_.insert_hint_multi(iterator(position), std::move(x)); + iterator insert(const_iterator position, value_type &&v) { + return this->tree_.insert_hint_multi(iterator(position), std::move(v)); } template void insert(InputIterator b, InputIterator e) { diff --git a/absl/debugging/internal/stacktrace_win32-inl.inc b/absl/debugging/internal/stacktrace_win32-inl.inc index af4578a5..1c666c8b 100644 --- a/absl/debugging/internal/stacktrace_win32-inl.inc +++ b/absl/debugging/internal/stacktrace_win32-inl.inc @@ -46,9 +46,9 @@ typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( OUT PVOID *backtrace, OUT PULONG backtrace_hash); -// It is not possible to load RtlCaptureStackBackTrace at static init time in -// UWP. CaptureStackBackTrace is the public version of RtlCaptureStackBackTrace -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \ +// It is not possible to load RtlCaptureStackBackTrace at static init time in +// UWP. CaptureStackBackTrace is the public version of RtlCaptureStackBackTrace +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \ !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = &::CaptureStackBackTrace; @@ -56,9 +56,9 @@ static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = // Load the function we need at static init time, where we don't have // to worry about someone else holding the loader's lock. static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = - (RtlCaptureStackBackTrace_Function*) - GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace"); -#endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP + (RtlCaptureStackBackTrace_Function*)GetProcAddress( + GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace"); +#endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP template static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index cdb4e7e8..9166f74c 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -45,6 +45,7 @@ cc_library( "//absl/base:config", "//absl/base:core_headers", "//absl/memory", + "//absl/meta:type_traits", "//absl/strings", "//absl/synchronization", ], @@ -130,6 +131,9 @@ cc_library( cc_library( name = "handle", + srcs = [ + "internal/commandlineflag.cc", + ], hdrs = [ "internal/commandlineflag.h", ], diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt index 1d25f0de..01cf09b1 100644 --- a/absl/flags/CMakeLists.txt +++ b/absl/flags/CMakeLists.txt @@ -33,6 +33,7 @@ absl_cc_library( absl::flags_handle absl::flags_registry absl::synchronization + absl::meta PUBLIC ) @@ -117,6 +118,8 @@ absl_cc_library( absl_cc_library( NAME flags_handle + SRCS + "internal/commandlineflag.cc" HDRS "internal/commandlineflag.h" COPTS diff --git a/absl/flags/flag.h b/absl/flags/flag.h index cff02c1f..bb917654 100644 --- a/absl/flags/flag.h +++ b/absl/flags/flag.h @@ -148,7 +148,6 @@ class Flag { return GetImpl()->template IsOfType(); } T Get() const { return GetImpl()->Get(); } - bool AtomicGet(T* v) const { return GetImpl()->AtomicGet(v); } void Set(const T& v) { GetImpl()->Set(v); } void SetCallback(const flags_internal::FlagCallbackFunc mutation_callback) { GetImpl()->SetCallback(mutation_callback); diff --git a/absl/flags/flag_benchmark.cc b/absl/flags/flag_benchmark.cc index 87f73170..ff95bb5d 100644 --- a/absl/flags/flag_benchmark.cc +++ b/absl/flags/flag_benchmark.cc @@ -109,3 +109,11 @@ namespace { BENCHMARKED_TYPES(BM_GetFlag) } // namespace + +#define InvokeGetFlag(T) \ + T AbslInvokeGetFlag##T() { return absl::GetFlag(FLAGS_##T##_flag); } \ + int odr##T = (benchmark::DoNotOptimize(AbslInvokeGetFlag##T), 1); + +BENCHMARKED_TYPES(InvokeGetFlag) + +// To veiw disassembly use: gdb ${BINARY} -batch -ex "disassemble /s $FUNC" diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc index 4984d284..1e01b49c 100644 --- a/absl/flags/flag_test.cc +++ b/absl/flags/flag_test.cc @@ -49,28 +49,6 @@ void* TestMakeDflt() { } void TestCallback() {} -template -bool TestConstructionFor() { - constexpr flags::FlagHelpArg help_arg{flags::FlagHelpMsg("literal help"), - flags::FlagHelpKind::kLiteral}; - constexpr flags::Flag f1("f1", "file", help_arg, &TestMakeDflt); - EXPECT_EQ(f1.Name(), "f1"); - EXPECT_EQ(f1.Help(), "literal help"); - EXPECT_EQ(f1.Filename(), "file"); - - ABSL_CONST_INIT static flags::Flag f2( - "f2", "file", - {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, - &TestMakeDflt); - flags::FlagRegistrar(&f2).OnUpdate(TestCallback); - - EXPECT_EQ(f2.Name(), "f2"); - EXPECT_EQ(f2.Help(), "dynamic help"); - EXPECT_EQ(f2.Filename(), "file"); - - return true; -} - struct UDT { UDT() = default; UDT(const UDT&) = default; @@ -98,19 +76,103 @@ class FlagTest : public testing::Test { } }; +struct S1 { + S1() = default; + S1(const S1&) = default; + int32_t f1; + int64_t f2; +}; + +struct S2 { + S2() = default; + S2(const S2&) = default; + int64_t f1; + double f2; +}; + +TEST_F(FlagTest, Traits) { + EXPECT_EQ(flags::FlagValue::Kind(), + flags::FlagValueStorageKind::kOneWordAtomic); + EXPECT_EQ(flags::FlagValue::Kind(), + flags::FlagValueStorageKind::kOneWordAtomic); + EXPECT_EQ(flags::FlagValue::Kind(), + flags::FlagValueStorageKind::kOneWordAtomic); + EXPECT_EQ(flags::FlagValue::Kind(), + flags::FlagValueStorageKind::kOneWordAtomic); + +#if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD) + EXPECT_EQ(flags::FlagValue::Kind(), + flags::FlagValueStorageKind::kTwoWordsAtomic); + EXPECT_EQ(flags::FlagValue::Kind(), + flags::FlagValueStorageKind::kTwoWordsAtomic); +#else + EXPECT_EQ(flags::FlagValue::Kind(), + flags::FlagValueStorageKind::kHeapAllocated); + EXPECT_EQ(flags::FlagValue::Kind(), + flags::FlagValueStorageKind::kHeapAllocated); +#endif + + EXPECT_EQ(flags::FlagValue::Kind(), + flags::FlagValueStorageKind::kHeapAllocated); + EXPECT_EQ(flags::FlagValue::Kind>(), + flags::FlagValueStorageKind::kHeapAllocated); +} + +// -------------------------------------------------------------------- + +constexpr flags::FlagHelpArg help_arg{flags::FlagHelpMsg("literal help"), + flags::FlagHelpKind::kLiteral}; + +using String = std::string; + +#define DEFINE_CONSTRUCTED_FLAG(T) \ + constexpr flags::Flag f1##T("f1", "file", help_arg, &TestMakeDflt); \ + ABSL_CONST_INIT flags::Flag f2##T( \ + "f2", "file", \ + {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \ + &TestMakeDflt) + +#define TEST_CONSTRUCTED_FLAG(T) TestConstructionFor(f1##T, &f2##T); + +DEFINE_CONSTRUCTED_FLAG(bool); +DEFINE_CONSTRUCTED_FLAG(int16_t); +DEFINE_CONSTRUCTED_FLAG(uint16_t); +DEFINE_CONSTRUCTED_FLAG(int32_t); +DEFINE_CONSTRUCTED_FLAG(uint32_t); +DEFINE_CONSTRUCTED_FLAG(int64_t); +DEFINE_CONSTRUCTED_FLAG(uint64_t); +DEFINE_CONSTRUCTED_FLAG(float); +DEFINE_CONSTRUCTED_FLAG(double); +DEFINE_CONSTRUCTED_FLAG(String); +DEFINE_CONSTRUCTED_FLAG(UDT); + +template +bool TestConstructionFor(const flags::Flag& f1, flags::Flag* f2) { + EXPECT_EQ(f1.Name(), "f1"); + EXPECT_EQ(f1.Help(), "literal help"); + EXPECT_EQ(f1.Filename(), "file"); + + flags::FlagRegistrar(f2).OnUpdate(TestCallback); + + EXPECT_EQ(f2->Name(), "f2"); + EXPECT_EQ(f2->Help(), "dynamic help"); + EXPECT_EQ(f2->Filename(), "file"); + + return true; +} + TEST_F(FlagTest, TestConstruction) { - TestConstructionFor(); - TestConstructionFor(); - TestConstructionFor(); - TestConstructionFor(); - TestConstructionFor(); - TestConstructionFor(); - TestConstructionFor(); - TestConstructionFor(); - TestConstructionFor(); - TestConstructionFor(); - - TestConstructionFor(); + TEST_CONSTRUCTED_FLAG(bool); + TEST_CONSTRUCTED_FLAG(int16_t); + TEST_CONSTRUCTED_FLAG(uint16_t); + TEST_CONSTRUCTED_FLAG(int32_t); + TEST_CONSTRUCTED_FLAG(uint32_t); + TEST_CONSTRUCTED_FLAG(int64_t); + TEST_CONSTRUCTED_FLAG(uint64_t); + TEST_CONSTRUCTED_FLAG(float); + TEST_CONSTRUCTED_FLAG(double); + TEST_CONSTRUCTED_FLAG(String); + TEST_CONSTRUCTED_FLAG(UDT); } // -------------------------------------------------------------------- @@ -391,17 +453,18 @@ TEST_F(FlagTest, TestCustomUDT) { using FlagDeathTest = FlagTest; TEST_F(FlagDeathTest, TestTypeMismatchValidations) { - EXPECT_DEBUG_DEATH( - static_cast(absl::GetFlag(FLAGS_mistyped_int_flag)), - "Flag 'mistyped_int_flag' is defined as one type and declared " - "as another"); - EXPECT_DEATH(absl::SetFlag(&FLAGS_mistyped_int_flag, 1), +#if !defined(NDEBUG) + EXPECT_DEATH(static_cast(absl::GetFlag(FLAGS_mistyped_int_flag)), "Flag 'mistyped_int_flag' is defined as one type and declared " "as another"); - EXPECT_DEATH(static_cast(absl::GetFlag(FLAGS_mistyped_string_flag)), "Flag 'mistyped_string_flag' is defined as one type and " "declared as another"); +#endif + + EXPECT_DEATH(absl::SetFlag(&FLAGS_mistyped_int_flag, 1), + "Flag 'mistyped_int_flag' is defined as one type and declared " + "as another"); EXPECT_DEATH( absl::SetFlag(&FLAGS_mistyped_string_flag, std::vector{}), "Flag 'mistyped_string_flag' is defined as one type and declared as " diff --git a/absl/flags/internal/commandlineflag.cc b/absl/flags/internal/commandlineflag.cc new file mode 100644 index 00000000..90765a3e --- /dev/null +++ b/absl/flags/internal/commandlineflag.cc @@ -0,0 +1,30 @@ +// +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/flags/internal/commandlineflag.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace flags_internal { + +FlagStateInterface::~FlagStateInterface() {} + +bool CommandLineFlag::IsRetired() const { return false; } +bool CommandLineFlag::IsAbseilFlag() const { return true; } + +} // namespace flags_internal +ABSL_NAMESPACE_END +} // namespace absl + diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h index 6363c661..e91ddde6 100644 --- a/absl/flags/internal/commandlineflag.h +++ b/absl/flags/internal/commandlineflag.h @@ -77,7 +77,7 @@ enum ValueSource { // of a flag produced this flag state from method CommandLineFlag::SaveState(). class FlagStateInterface { public: - virtual ~FlagStateInterface() {} + virtual ~FlagStateInterface(); // Restores the flag originated this object to the saved state. virtual void Restore() const = 0; @@ -146,9 +146,9 @@ class CommandLineFlag { // Returns help message associated with this flag. virtual std::string Help() const = 0; // Returns true iff this object corresponds to retired flag. - virtual bool IsRetired() const { return false; } + virtual bool IsRetired() const; // Returns true iff this is a handle to an Abseil Flag. - virtual bool IsAbseilFlag() const { return true; } + virtual bool IsAbseilFlag() const; // Returns id of the flag's value type. virtual FlagStaticTypeId TypeId() const = 0; virtual bool IsModified() const = 0; diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc index 5a921e28..a944e16e 100644 --- a/absl/flags/internal/flag.cc +++ b/absl/flags/internal/flag.cc @@ -77,19 +77,33 @@ class MutexRelock { void FlagImpl::Init() { new (&data_guard_) absl::Mutex; - absl::MutexLock lock(reinterpret_cast(&data_guard_)); - - value_.dynamic = MakeInitValue().release(); - StoreAtomic(); + // At this point the default_value_ always points to gen_func. + std::unique_ptr init_value( + (*default_value_.gen_func)(), DynValueDeleter{op_}); + switch (ValueStorageKind()) { + case FlagValueStorageKind::kHeapAllocated: + value_.dynamic = init_value.release(); + break; + case FlagValueStorageKind::kOneWordAtomic: { + int64_t atomic_value; + std::memcpy(&atomic_value, init_value.get(), Sizeof(op_)); + value_.one_word_atomic.store(atomic_value, std::memory_order_release); + break; + } + case FlagValueStorageKind::kTwoWordsAtomic: { + AlignedTwoWords atomic_value{0, 0}; + std::memcpy(&atomic_value, init_value.get(), Sizeof(op_)); + value_.two_words_atomic.store(atomic_value, std::memory_order_release); + break; + } + } } -// Ensures that the lazily initialized data is initialized, -// and returns pointer to the mutex guarding flags data. absl::Mutex* FlagImpl::DataGuard() const { absl::call_once(const_cast(this)->init_control_, &FlagImpl::Init, const_cast(this)); - // data_guard_ is initialized. + // data_guard_ is initialized inside Init. return reinterpret_cast(&data_guard_); } @@ -129,8 +143,24 @@ std::unique_ptr FlagImpl::MakeInitValue() const { } void FlagImpl::StoreValue(const void* src) { - flags_internal::Copy(op_, src, value_.dynamic); - StoreAtomic(); + switch (ValueStorageKind()) { + case FlagValueStorageKind::kHeapAllocated: + Copy(op_, src, value_.dynamic); + break; + case FlagValueStorageKind::kOneWordAtomic: { + int64_t one_word_val; + std::memcpy(&one_word_val, src, Sizeof(op_)); + value_.one_word_atomic.store(one_word_val, std::memory_order_release); + break; + } + case FlagValueStorageKind::kTwoWordsAtomic: { + AlignedTwoWords two_words_val{0, 0}; + std::memcpy(&two_words_val, src, Sizeof(op_)); + value_.two_words_atomic.store(two_words_val, std::memory_order_release); + break; + } + } + modified_ = true; ++counter_; InvokeCallback(); @@ -165,9 +195,25 @@ std::string FlagImpl::DefaultValue() const { } std::string FlagImpl::CurrentValue() const { - absl::MutexLock l(DataGuard()); + DataGuard(); // Make sure flag initialized + switch (ValueStorageKind()) { + case FlagValueStorageKind::kHeapAllocated: { + absl::MutexLock l(DataGuard()); + return flags_internal::Unparse(op_, value_.dynamic); + } + case FlagValueStorageKind::kOneWordAtomic: { + const auto one_word_val = + value_.one_word_atomic.load(std::memory_order_acquire); + return flags_internal::Unparse(op_, &one_word_val); + } + case FlagValueStorageKind::kTwoWordsAtomic: { + const auto two_words_val = + value_.two_words_atomic.load(std::memory_order_acquire); + return flags_internal::Unparse(op_, &two_words_val); + } + } - return flags_internal::Unparse(op_, value_.dynamic); + return ""; } void FlagImpl::SetCallback(const FlagCallbackFunc mutation_callback) { @@ -244,26 +290,27 @@ std::unique_ptr FlagImpl::TryParse( } void FlagImpl::Read(void* dst) const { - absl::ReaderMutexLock l(DataGuard()); + DataGuard(); // Make sure flag initialized + switch (ValueStorageKind()) { + case FlagValueStorageKind::kHeapAllocated: { + absl::MutexLock l(DataGuard()); - flags_internal::CopyConstruct(op_, value_.dynamic, dst); -} - -void FlagImpl::StoreAtomic() { - size_t data_size = flags_internal::Sizeof(op_); - - if (data_size <= sizeof(int64_t)) { - int64_t t = 0; - std::memcpy(&t, value_.dynamic, data_size); - value_.atomics.small_atomic.store(t, std::memory_order_release); - } -#if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD) - else if (data_size <= sizeof(FlagsInternalTwoWordsType)) { - FlagsInternalTwoWordsType t{0, 0}; - std::memcpy(&t, value_.dynamic, data_size); - value_.atomics.big_atomic.store(t, std::memory_order_release); + flags_internal::CopyConstruct(op_, value_.dynamic, dst); + break; + } + case FlagValueStorageKind::kOneWordAtomic: { + const auto one_word_val = + value_.one_word_atomic.load(std::memory_order_acquire); + std::memcpy(dst, &one_word_val, Sizeof(op_)); + break; + } + case FlagValueStorageKind::kTwoWordsAtomic: { + const auto two_words_val = + value_.two_words_atomic.load(std::memory_order_acquire); + std::memcpy(dst, &two_words_val, Sizeof(op_)); + break; + } } -#endif } void FlagImpl::Write(const void* src) { @@ -339,7 +386,7 @@ bool FlagImpl::SetFromString(absl::string_view value, FlagSettingMode set_mode, } if (!modified_) { - // Need to set both default value *and* current, in this case + // Need to set both default value *and* current, in this case. StoreValue(default_value_.dynamic_value); modified_ = false; } diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h index 35a148cf..307b7377 100644 --- a/absl/flags/internal/flag.h +++ b/absl/flags/internal/flag.h @@ -31,6 +31,7 @@ #include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/registry.h" #include "absl/memory/memory.h" +#include "absl/meta/type_traits.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" @@ -249,95 +250,66 @@ enum class FlagDefaultKind : uint8_t { kDynamicValue = 0, kGenFunc = 1 }; /////////////////////////////////////////////////////////////////////////////// // Flag current value auxiliary structs. -// The minimum atomic size we believe to generate lock free code, i.e. all -// trivially copyable types not bigger this size generate lock free code. -static constexpr int kMinLockFreeAtomicSize = 8; +constexpr int64_t UninitializedFlagValue() { return 0xababababababababll; } -// The same as kMinLockFreeAtomicSize but maximum atomic size. As double words -// might use two registers, we want to dispatch the logic for them. -#if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD) -static constexpr int kMaxLockFreeAtomicSize = 16; -#else -static constexpr int kMaxLockFreeAtomicSize = 8; -#endif - -// We can use atomic in cases when it fits in the register, trivially copyable -// in order to make memcpy operations. template -struct IsAtomicFlagTypeTrait { - static constexpr bool value = - (sizeof(T) <= kMaxLockFreeAtomicSize && - type_traits_internal::is_trivially_copyable::value); -}; +using FlagUseOneWordStorage = std::integral_constant< + bool, absl::type_traits_internal::is_trivially_copyable::value && + (sizeof(T) <= 8)>; +#if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD) // Clang does not always produce cmpxchg16b instruction when alignment of a 16 // bytes type is not 16. -struct alignas(16) FlagsInternalTwoWordsType { +struct alignas(16) AlignedTwoWords { int64_t first; int64_t second; }; -constexpr bool operator==(const FlagsInternalTwoWordsType& that, - const FlagsInternalTwoWordsType& other) { - return that.first == other.first && that.second == other.second; -} -constexpr bool operator!=(const FlagsInternalTwoWordsType& that, - const FlagsInternalTwoWordsType& other) { - return !(that == other); -} - -constexpr int64_t SmallAtomicInit() { return 0xababababababababll; } - -template -struct BestAtomicType { - using type = int64_t; - static constexpr int64_t AtomicInit() { return SmallAtomicInit(); } +template +using FlagUseTwoWordsStorage = std::integral_constant< + bool, absl::type_traits_internal::is_trivially_copyable::value && + (sizeof(T) > 8) && (sizeof(T) <= 16)>; +#else +// This is actually unused and only here to avoid ifdefs in other palces. +struct AlignedTwoWords { + constexpr AlignedTwoWords() = default; + constexpr AlignedTwoWords(int64_t, int64_t) {} }; +// This trait should be type dependent, otherwise SFINAE below will fail template -struct BestAtomicType< - T, typename std::enable_if<(kMinLockFreeAtomicSize < sizeof(T) && - sizeof(T) <= kMaxLockFreeAtomicSize), - void>::type> { - using type = FlagsInternalTwoWordsType; - static constexpr FlagsInternalTwoWordsType AtomicInit() { - return {SmallAtomicInit(), SmallAtomicInit()}; - } +using FlagUseTwoWordsStorage = + std::integral_constant; +#endif + +template +using FlagUseHeapStorage = + std::integral_constant::value && + !FlagUseTwoWordsStorage::value>; + +enum class FlagValueStorageKind : uint8_t { + kHeapAllocated = 0, + kOneWordAtomic = 1, + kTwoWordsAtomic = 2 }; -struct FlagValue { - // Heap allocated value. - void* dynamic = nullptr; - // For some types, a copy of the current value is kept in an atomically - // accessible field. - union Atomics { - // Using small atomic for small types. - std::atomic small_atomic; - template ::type> - int64_t load() const { - return small_atomic.load(std::memory_order_acquire); - } +union FlagValue { + constexpr explicit FlagValue(int64_t v) : one_word_atomic(v) {} -#if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD) - // Using big atomics for big types. - std::atomic big_atomic; - template ::type> - FlagsInternalTwoWordsType load() const { - return big_atomic.load(std::memory_order_acquire); - } - constexpr Atomics() - : big_atomic{FlagsInternalTwoWordsType{SmallAtomicInit(), - SmallAtomicInit()}} {} -#else - constexpr Atomics() : small_atomic{SmallAtomicInit()} {} -#endif - }; - Atomics atomics{}; + template + static constexpr FlagValueStorageKind Kind() { + return FlagUseHeapStorage::value + ? FlagValueStorageKind::kHeapAllocated + : FlagUseOneWordStorage::value + ? FlagValueStorageKind::kOneWordAtomic + : FlagUseTwoWordsStorage::value + ? FlagValueStorageKind::kTwoWordsAtomic + : FlagValueStorageKind::kHeapAllocated; + } + + void* dynamic; + std::atomic one_word_atomic; + std::atomic two_words_atomic; }; /////////////////////////////////////////////////////////////////////////////// @@ -369,18 +341,21 @@ struct DynValueDeleter { class FlagImpl { public: constexpr FlagImpl(const char* name, const char* filename, FlagOpFn op, - FlagHelpArg help, FlagDfltGenFunc default_value_gen) + FlagHelpArg help, FlagValueStorageKind value_kind, + FlagDfltGenFunc default_value_gen) : name_(name), filename_(filename), op_(op), help_(help.source), help_source_kind_(static_cast(help.kind)), + value_storage_kind_(static_cast(value_kind)), def_kind_(static_cast(FlagDefaultKind::kGenFunc)), modified_(false), on_command_line_(false), counter_(0), callback_(nullptr), default_value_(default_value_gen), + value_(flags_internal::UninitializedFlagValue()), data_guard_{} {} // Constant access methods @@ -393,34 +368,29 @@ class FlagImpl { std::string CurrentValue() const ABSL_LOCKS_EXCLUDED(*DataGuard()); void Read(void* dst) const ABSL_LOCKS_EXCLUDED(*DataGuard()); - template ::value, int>::type = 0> + template ::value, + int>::type = 0> void Get(T* dst) const { - AssertValidType(&flags_internal::FlagStaticTypeIdGen); Read(dst); } - // Overload for `GetFlag()` for types that support lock-free reads. - template ::value, + template ::value, int>::type = 0> void Get(T* dst) const { - // For flags of types which can be accessed "atomically" we want to avoid - // slowing down flag value access due to type validation. That's why - // this validation is hidden behind !NDEBUG -#ifndef NDEBUG - AssertValidType(&flags_internal::FlagStaticTypeIdGen); -#endif - using U = flags_internal::BestAtomicType; - typename U::type r = value_.atomics.template load(); - if (r != U::AtomicInit()) { - std::memcpy(static_cast(dst), &r, sizeof(T)); - } else { - Read(dst); + int64_t one_word_val = + value_.one_word_atomic.load(std::memory_order_acquire); + if (ABSL_PREDICT_FALSE(one_word_val == UninitializedFlagValue())) { + DataGuard(); // Make sure flag initialized + one_word_val = value_.one_word_atomic.load(std::memory_order_acquire); } + std::memcpy(dst, static_cast(&one_word_val), sizeof(T)); } - template - void Set(const T& src) { - AssertValidType(&flags_internal::FlagStaticTypeIdGen); - Write(&src); + template ::value, int>::type = 0> + void Get(T* dst) const { + DataGuard(); // Make sure flag initialized + const auto two_words_val = + value_.two_words_atomic.load(std::memory_order_acquire); + std::memcpy(dst, &two_words_val, sizeof(T)); } // Mutating access methods @@ -428,9 +398,6 @@ class FlagImpl { bool SetFromString(absl::string_view value, FlagSettingMode set_mode, ValueSource source, std::string* err) ABSL_LOCKS_EXCLUDED(*DataGuard()); - // If possible, updates copy of the Flag's value that is stored in an - // atomic word. - void StoreAtomic() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); // Interfaces to operate on callbacks. void SetCallback(const FlagCallbackFunc mutation_callback) @@ -456,6 +423,14 @@ class FlagImpl { bool ValidateInputValue(absl::string_view value) const ABSL_LOCKS_EXCLUDED(*DataGuard()); + // Used in read/write operations to validate source/target has correct type. + // For example if flag is declared as absl::Flag FLAGS_foo, a call to + // absl::GetFlag(FLAGS_foo) validates that the type of FLAGS_foo is indeed + // int. To do that we pass the "assumed" type id (which is deduced from type + // int) as an argument `op`, which is in turn is validated against the type id + // stored in flag object by flag definition statement. + void AssertValidType(FlagStaticTypeId type_id) const; + private: // Ensures that `data_guard_` is initialized and returns it. absl::Mutex* DataGuard() const ABSL_LOCK_RETURNED((absl::Mutex*)&data_guard_); @@ -475,17 +450,13 @@ class FlagImpl { FlagHelpKind HelpSourceKind() const { return static_cast(help_source_kind_); } + FlagValueStorageKind ValueStorageKind() const { + return static_cast(value_storage_kind_); + } FlagDefaultKind DefaultKind() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()) { return static_cast(def_kind_); } - // Used in read/write operations to validate source/target has correct type. - // For example if flag is declared as absl::Flag FLAGS_foo, a call to - // absl::GetFlag(FLAGS_foo) validates that the type of FLAGS_foo is indeed - // int. To do that we pass the "assumed" type id (which is deduced from type - // int) as an argument `op`, which is in turn is validated against the type id - // stored in flag object by flag definition statement. - void AssertValidType(FlagStaticTypeId type_id) const; // Immutable flag's state. @@ -499,6 +470,8 @@ class FlagImpl { const FlagHelpMsg help_; // Indicates if help message was supplied as literal or generator func. const uint8_t help_source_kind_ : 1; + // Kind of storage this flag is using for the flag's value. + const uint8_t value_storage_kind_ : 2; // ------------------------------------------------------------------------ // The bytes containing the const bitfields must not be shared with bytes @@ -530,8 +503,13 @@ class FlagImpl { // value specified in ABSL_FLAG or pointer to the dynamically set default // value via SetCommandLineOptionWithMode. def_kind_ is used to distinguish // these two cases. - FlagDefaultSrc default_value_ ABSL_GUARDED_BY(*DataGuard()); - // Current Flag Value + FlagDefaultSrc default_value_; + + // Atomically mutable flag's state + + // Flag's value. This can be either the atomically stored small value or + // pointer to the heap allocated dynamic value. value_storage_kind_ is used + // to distinguish these cases. FlagValue value_; // This is reserved space for an absl::Mutex to guard flag data. It will be @@ -553,7 +531,8 @@ class Flag final : public flags_internal::CommandLineFlag { public: constexpr Flag(const char* name, const char* filename, const FlagHelpArg help, const FlagDfltGenFunc default_value_gen) - : impl_(name, filename, &FlagOps, help, default_value_gen) {} + : impl_(name, filename, &FlagOps, help, FlagValue::Kind(), + default_value_gen) {} T Get() const { // See implementation notes in CommandLineFlag::Get(). @@ -564,10 +543,17 @@ class Flag final : public flags_internal::CommandLineFlag { }; U u; +#if !defined(NDEBUG) + impl_.AssertValidType(&flags_internal::FlagStaticTypeIdGen); +#endif + impl_.Get(&u.value); return std::move(u.value); } - void Set(const T& v) { impl_.Set(v); } + void Set(const T& v) { + impl_.AssertValidType(&flags_internal::FlagStaticTypeIdGen); + impl_.Write(&v); + } void SetCallback(const FlagCallbackFunc mutation_callback) { impl_.SetCallback(mutation_callback); } @@ -619,7 +605,7 @@ class Flag final : public flags_internal::CommandLineFlag { }; template -inline void FlagState::Restore() const { +void FlagState::Restore() const { if (flag_->RestoreState(*this)) { ABSL_INTERNAL_LOG(INFO, absl::StrCat("Restore saved value of ", flag_->Name(), diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h index ae7a60cd..1cc2c5e5 100644 --- a/absl/hash/internal/hash.h +++ b/absl/hash/internal/hash.h @@ -955,12 +955,15 @@ H PiecewiseCombiner::add_buffer(H state, const unsigned char* data, return state; } - // Complete the buffer and hash it - const size_t bytes_needed = PiecewiseChunkSize() - position_; - memcpy(buf_ + position_, data, bytes_needed); - state = H::combine_contiguous(std::move(state), buf_, PiecewiseChunkSize()); - data += bytes_needed; - size -= bytes_needed; + // If the buffer is partially filled we need to complete the buffer + // and hash it. + if (position_ != 0) { + const size_t bytes_needed = PiecewiseChunkSize() - position_; + memcpy(buf_ + position_, data, bytes_needed); + state = H::combine_contiguous(std::move(state), buf_, PiecewiseChunkSize()); + data += bytes_needed; + size -= bytes_needed; + } // Hash whatever chunks we can without copying while (size >= PiecewiseChunkSize()) { diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel index d7ad4efe..1c9dabb5 100644 --- a/absl/random/internal/BUILD.bazel +++ b/absl/random/internal/BUILD.bazel @@ -705,6 +705,7 @@ cc_test( cc_test( name = "randen_benchmarks", size = "medium", + timeout = "long", srcs = ["randen_benchmarks.cc"], copts = ABSL_TEST_COPTS + ABSL_RANDOM_RANDEN_COPTS, flaky = 1, diff --git a/absl/status/status.cc b/absl/status/status.cc index bbc1895e..df3b740f 100644 --- a/absl/status/status.cc +++ b/absl/status/status.cc @@ -147,7 +147,15 @@ void Status::SetPayload(absl::string_view type_url, absl::Cord payload) { bool Status::ErasePayload(absl::string_view type_url) { int index = status_internal::FindPayloadIndexByUrl(GetPayloads(), type_url); if (index != -1) { + PrepareToModify(); GetPayloads()->erase(GetPayloads()->begin() + index); + if (GetPayloads()->empty() && message().empty()) { + // Special case: If this can be represented inlined, it MUST be + // inlined (EqualsSlow depends on this behavior). + StatusCode c = static_cast(raw_code()); + Unref(rep_); + rep_ = CodeToInlinedRep(c); + } return true; } diff --git a/absl/status/status_test.cc b/absl/status/status_test.cc index 7cc65e45..ca9488ad 100644 --- a/absl/status/status_test.cc +++ b/absl/status/status_test.cc @@ -204,6 +204,25 @@ TEST(Status, TestComparePayloads) { EXPECT_EQ(bad_status1, bad_status2); } +TEST(Status, TestComparePayloadsAfterErase) { + absl::Status payload_status(absl::StatusCode::kInternal, ""); + payload_status.SetPayload(kUrl1, absl::Cord(kPayload1)); + payload_status.SetPayload(kUrl2, absl::Cord(kPayload2)); + + absl::Status empty_status(absl::StatusCode::kInternal, ""); + + // Different payloads, not equal + EXPECT_NE(payload_status, empty_status); + EXPECT_TRUE(payload_status.ErasePayload(kUrl1)); + + // Still Different payloads, still not equal. + EXPECT_NE(payload_status, empty_status); + EXPECT_TRUE(payload_status.ErasePayload(kUrl2)); + + // Both empty payloads, should be equal + EXPECT_EQ(payload_status, empty_status); +} + PayloadsVec AllVisitedPayloads(const absl::Status& s) { PayloadsVec result; @@ -261,6 +280,36 @@ TEST(Status, ToString) { HasSubstr("[bar='\\xff']"))); } +absl::Status EraseAndReturn(const absl::Status& base) { + absl::Status copy = base; + EXPECT_TRUE(copy.ErasePayload(kUrl1)); + return copy; +} + +TEST(Status, CopyOnWriteForErasePayload) { + { + absl::Status base(absl::StatusCode::kInvalidArgument, "fail"); + base.SetPayload(kUrl1, absl::Cord(kPayload1)); + EXPECT_TRUE(base.GetPayload(kUrl1).has_value()); + absl::Status copy = EraseAndReturn(base); + EXPECT_TRUE(base.GetPayload(kUrl1).has_value()); + EXPECT_FALSE(copy.GetPayload(kUrl1).has_value()); + } + { + absl::Status base(absl::StatusCode::kInvalidArgument, "fail"); + base.SetPayload(kUrl1, absl::Cord(kPayload1)); + absl::Status copy = base; + + EXPECT_TRUE(base.GetPayload(kUrl1).has_value()); + EXPECT_TRUE(copy.GetPayload(kUrl1).has_value()); + + EXPECT_TRUE(base.ErasePayload(kUrl1)); + + EXPECT_FALSE(base.GetPayload(kUrl1).has_value()); + EXPECT_TRUE(copy.GetPayload(kUrl1).has_value()); + } +} + TEST(Status, CopyConstructor) { { absl::Status status; @@ -300,6 +349,14 @@ TEST(Status, CopyAssignment) { } } +TEST(Status, CopyAssignmentIsNotRef) { + const absl::Status status_orig(absl::StatusCode::kInvalidArgument, "message"); + absl::Status status_copy = status_orig; + EXPECT_EQ(status_orig, status_copy); + status_copy.SetPayload(kUrl1, absl::Cord(kPayload1)); + EXPECT_NE(status_orig, status_copy); +} + TEST(Status, MoveConstructor) { { absl::Status status; diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index 5cc68539..9b32b3cc 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc @@ -30,7 +30,6 @@ #include "absl/base/internal/raw_logging.h" #include "absl/base/port.h" #include "absl/container/fixed_array.h" -#include "absl/container/inlined_vector.h" #include "absl/strings/escaping.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/resize_uninitialized.h" @@ -132,6 +131,14 @@ inline const CordRepExternal* CordRep::external() const { return static_cast(this); } +using CordTreeConstPath = CordTreePath; + +// This type is used to store the list of pending nodes during re-balancing. +// Its maximum size is 2 * MaxCordDepth() because the tree has a maximum +// possible depth of MaxCordDepth() and every concat node along a tree path +// could theoretically be split during rebalancing. +using RebalancingStack = CordTreePath; + } // namespace cord_internal static const size_t kFlatOverhead = offsetof(CordRep, data); @@ -180,8 +187,8 @@ static constexpr size_t TagToLength(uint8_t tag) { // Enforce that kMaxFlatSize maps to a well-known exact tag value. static_assert(TagToAllocatedSize(224) == kMaxFlatSize, "Bad tag logic"); -constexpr uint64_t Fibonacci(unsigned char n, uint64_t a = 0, uint64_t b = 1) { - return n == 0 ? a : Fibonacci(n - 1, b, a + b); +constexpr uint64_t Fibonacci(uint8_t n, uint64_t a = 0, uint64_t b = 1) { + return n == 0 ? a : n == 1 ? b : Fibonacci(n - 1, b, a + b); } static_assert(Fibonacci(63) == 6557470319842, @@ -189,89 +196,68 @@ static_assert(Fibonacci(63) == 6557470319842, // Minimum length required for a given depth tree -- a tree is considered // balanced if -// length(t) >= min_length[depth(t)] -// The root node depth is allowed to become twice as large to reduce rebalancing -// for larger strings (see IsRootBalanced). -static constexpr uint64_t min_length[] = { - Fibonacci(2), - Fibonacci(3), - Fibonacci(4), - Fibonacci(5), - Fibonacci(6), - Fibonacci(7), - Fibonacci(8), - Fibonacci(9), - Fibonacci(10), - Fibonacci(11), - Fibonacci(12), - Fibonacci(13), - Fibonacci(14), - Fibonacci(15), - Fibonacci(16), - Fibonacci(17), - Fibonacci(18), - Fibonacci(19), - Fibonacci(20), - Fibonacci(21), - Fibonacci(22), - Fibonacci(23), - Fibonacci(24), - Fibonacci(25), - Fibonacci(26), - Fibonacci(27), - Fibonacci(28), - Fibonacci(29), - Fibonacci(30), - Fibonacci(31), - Fibonacci(32), - Fibonacci(33), - Fibonacci(34), - Fibonacci(35), - Fibonacci(36), - Fibonacci(37), - Fibonacci(38), - Fibonacci(39), - Fibonacci(40), - Fibonacci(41), - Fibonacci(42), - Fibonacci(43), - Fibonacci(44), - Fibonacci(45), - Fibonacci(46), - Fibonacci(47), - 0xffffffffffffffffull, // Avoid overflow -}; - -static const int kMinLengthSize = ABSL_ARRAYSIZE(min_length); - -// 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). -static const int kInlinedVectorSize = 47; - -static inline bool IsRootBalanced(CordRep* node) { - if (node->tag != CONCAT) { - return true; - } else if (node->concat()->depth() <= 15) { - return true; - } else if (node->concat()->depth() > kMinLengthSize) { - return false; - } else { - // Allow depth to become twice as large as implied by fibonacci rule to - // reduce rebalancing for larger strings. - return (node->length >= min_length[node->concat()->depth() / 2]); - } +// length(t) >= kMinLength[depth(t)] +// The node depth is allowed to become larger to reduce rebalancing +// for larger strings (see ShouldRebalance). +constexpr uint64_t kMinLength[] = { + Fibonacci(2), Fibonacci(3), Fibonacci(4), Fibonacci(5), Fibonacci(6), + Fibonacci(7), Fibonacci(8), Fibonacci(9), Fibonacci(10), Fibonacci(11), + Fibonacci(12), Fibonacci(13), Fibonacci(14), Fibonacci(15), Fibonacci(16), + Fibonacci(17), Fibonacci(18), Fibonacci(19), Fibonacci(20), Fibonacci(21), + Fibonacci(22), Fibonacci(23), Fibonacci(24), Fibonacci(25), Fibonacci(26), + Fibonacci(27), Fibonacci(28), Fibonacci(29), Fibonacci(30), Fibonacci(31), + Fibonacci(32), Fibonacci(33), Fibonacci(34), Fibonacci(35), Fibonacci(36), + Fibonacci(37), Fibonacci(38), Fibonacci(39), Fibonacci(40), Fibonacci(41), + Fibonacci(42), Fibonacci(43), Fibonacci(44), Fibonacci(45), Fibonacci(46), + Fibonacci(47), Fibonacci(48), Fibonacci(49), Fibonacci(50), Fibonacci(51), + Fibonacci(52), Fibonacci(53), Fibonacci(54), Fibonacci(55), Fibonacci(56), + Fibonacci(57), Fibonacci(58), Fibonacci(59), Fibonacci(60), Fibonacci(61), + Fibonacci(62), Fibonacci(63), Fibonacci(64), Fibonacci(65), Fibonacci(66), + Fibonacci(67), Fibonacci(68), Fibonacci(69), Fibonacci(70), Fibonacci(71), + Fibonacci(72), Fibonacci(73), Fibonacci(74), Fibonacci(75), Fibonacci(76), + Fibonacci(77), Fibonacci(78), Fibonacci(79), Fibonacci(80), Fibonacci(81), + Fibonacci(82), Fibonacci(83), Fibonacci(84), Fibonacci(85), Fibonacci(86), + Fibonacci(87), Fibonacci(88), Fibonacci(89), Fibonacci(90), Fibonacci(91), + Fibonacci(92), Fibonacci(93)}; + +static_assert(sizeof(kMinLength) / sizeof(uint64_t) == + (cord_internal::MaxCordDepth() + 1), + "Not enough elements in kMinLength array to cover all the " + "supported Cord depth(s)"); + +inline bool ShouldRebalance(const CordRep* node) { + if (node->tag != CONCAT) return false; + + size_t node_depth = node->concat()->depth(); + + if (node_depth <= 15) return false; + + // Rebalancing Cords is expensive, so we reduce how often rebalancing occurs + // by allowing shallow Cords to have twice the depth that the Fibonacci rule + // would otherwise imply. Deep Cords need to follow the rule more closely, + // however to ensure algorithm correctness. We implement this with linear + // interpolation. Cords of depth 16 are treated as though they have a depth + // of 16 * 1/2, and Cords of depth MaxCordDepth() interpolate to + // MaxCordDepth() * 1. + return node->length < + kMinLength[(node_depth * (cord_internal::MaxCordDepth() - 16)) / + (2 * cord_internal::MaxCordDepth() - 16 - node_depth)]; +} + +// Unlike root balancing condition this one is part of the re-balancing +// algorithm and has to be always matching against right depth for +// algorithm to be correct. +inline bool IsNodeBalanced(const CordRep* node) { + if (node->tag != CONCAT) return true; + + size_t node_depth = node->concat()->depth(); + + return node->length >= kMinLength[node_depth]; } static CordRep* Rebalance(CordRep* node); -static void DumpNode(CordRep* rep, bool include_data, std::ostream* os); -static bool VerifyNode(CordRep* root, CordRep* start_node, +static void DumpNode(const CordRep* rep, bool include_data, std::ostream* os); +static bool VerifyNode(const CordRep* root, const CordRep* start_node, bool full_validation); static inline CordRep* VerifyTree(CordRep* node) { @@ -318,7 +304,8 @@ __attribute__((preserve_most)) static void UnrefInternal(CordRep* rep) { assert(rep != nullptr); - absl::InlinedVector pending; + cord_internal::RebalancingStack pending; + while (true) { if (rep->tag == CONCAT) { CordRepConcat* rep_concat = rep->concat(); @@ -400,6 +387,11 @@ static void SetConcatChildren(CordRepConcat* concat, CordRep* left, concat->length = left->length + right->length; concat->set_depth(1 + std::max(Depth(left), Depth(right))); + + ABSL_INTERNAL_CHECK(concat->depth() <= cord_internal::MaxCordDepth(), + "Cord depth exceeds max"); + ABSL_INTERNAL_CHECK(concat->length >= left->length, "Cord is too long"); + ABSL_INTERNAL_CHECK(concat->length >= right->length, "Cord is too long"); } // Create a concatenation of the specified nodes. @@ -425,7 +417,7 @@ static CordRep* RawConcat(CordRep* left, CordRep* right) { static CordRep* Concat(CordRep* left, CordRep* right) { CordRep* rep = RawConcat(left, right); - if (rep != nullptr && !IsRootBalanced(rep)) { + if (rep != nullptr && ShouldRebalance(rep)) { rep = Rebalance(rep); } return VerifyTree(rep); @@ -916,7 +908,7 @@ void Cord::Prepend(absl::string_view src) { static CordRep* RemovePrefixFrom(CordRep* node, size_t n) { if (n >= node->length) return nullptr; if (n == 0) return Ref(node); - absl::InlinedVector rhs_stack; + cord_internal::CordTreeMutablePath rhs_stack; while (node->tag == CONCAT) { assert(n <= node->length); @@ -957,7 +949,7 @@ static CordRep* RemovePrefixFrom(CordRep* node, size_t n) { static CordRep* RemoveSuffixFrom(CordRep* node, size_t n) { if (n >= node->length) return nullptr; if (n == 0) return Ref(node); - absl::InlinedVector lhs_stack; + absl::cord_internal::CordTreeMutablePath lhs_stack; bool inplace_ok = node->refcount.IsOne(); while (node->tag == CONCAT) { @@ -1028,6 +1020,7 @@ void Cord::RemoveSuffix(size_t n) { // Work item for NewSubRange(). struct SubRange { + SubRange() = default; SubRange(CordRep* a_node, size_t a_pos, size_t a_n) : node(a_node), pos(a_pos), n(a_n) {} CordRep* node; // nullptr means concat last 2 results. @@ -1036,8 +1029,11 @@ struct SubRange { }; static CordRep* NewSubRange(CordRep* node, size_t pos, size_t n) { - absl::InlinedVector results; - absl::InlinedVector todo; + cord_internal::CordTreeMutablePath results; + // The algorithm below in worst case scenario adds up to 3 nodes to the `todo` + // list, but we also pop one out on every cycle. If original tree has depth d + // todo list can grew up to 2*d in size. + cord_internal::CordTreePath todo; todo.push_back(SubRange(node, pos, n)); do { const SubRange& sr = todo.back(); @@ -1074,7 +1070,7 @@ static CordRep* NewSubRange(CordRep* node, size_t pos, size_t n) { } } while (!todo.empty()); assert(results.size() == 1); - return results[0]; + return results.back(); } Cord Cord::Subcord(size_t pos, size_t new_size) const { @@ -1113,11 +1109,12 @@ Cord Cord::Subcord(size_t pos, size_t new_size) const { class CordForest { public: - explicit CordForest(size_t length) - : root_length_(length), trees_(kMinLengthSize, nullptr) {} + explicit CordForest(size_t length) : root_length_(length), trees_({}) {} void Build(CordRep* cord_root) { - std::vector pending = {cord_root}; + // We are adding up to two nodes to the `pending` list, but we also popping + // one, so the size of `pending` will never exceed `MaxCordDepth()`. + cord_internal::CordTreeMutablePath pending(cord_root); while (!pending.empty()) { CordRep* node = pending.back(); @@ -1129,21 +1126,20 @@ class CordForest { } CordRepConcat* concat_node = node->concat(); - if (concat_node->depth() >= kMinLengthSize || - concat_node->length < min_length[concat_node->depth()]) { - pending.push_back(concat_node->right); - pending.push_back(concat_node->left); - - if (concat_node->refcount.IsOne()) { - concat_node->left = concat_freelist_; - concat_freelist_ = concat_node; - } else { - Ref(concat_node->right); - Ref(concat_node->left); - Unref(concat_node); - } - } else { + if (IsNodeBalanced(concat_node)) { AddNode(node); + continue; + } + pending.push_back(concat_node->right); + pending.push_back(concat_node->left); + + if (concat_node->refcount.IsOne()) { + concat_node->left = concat_freelist_; + concat_freelist_ = concat_node; + } else { + Ref(concat_node->right); + Ref(concat_node->left); + Unref(concat_node); } } } @@ -1175,7 +1171,7 @@ class CordForest { // Collect together everything with which we will merge node int i = 0; - for (; node->length > min_length[i + 1]; ++i) { + for (; node->length > kMinLength[i + 1]; ++i) { auto& tree_at_i = trees_[i]; if (tree_at_i == nullptr) continue; @@ -1186,7 +1182,7 @@ class CordForest { sum = AppendNode(node, sum); // Insert sum into appropriate place in the forest - for (; sum->length >= min_length[i]; ++i) { + for (; sum->length >= kMinLength[i]; ++i) { auto& tree_at_i = trees_[i]; if (tree_at_i == nullptr) continue; @@ -1194,7 +1190,7 @@ class CordForest { tree_at_i = nullptr; } - // min_length[0] == 1, which means sum->length >= min_length[0] + // kMinLength[0] == 1, which means sum->length >= kMinLength[0] assert(i > 0); trees_[i - 1] = sum; } @@ -1227,9 +1223,7 @@ class CordForest { } size_t root_length_; - - // use an inlined vector instead of a flat array to get bounds checking - absl::InlinedVector trees_; + std::array trees_; // List of concat nodes we can re-use for Cord balancing. CordRepConcat* concat_freelist_ = nullptr; @@ -1841,18 +1835,18 @@ absl::string_view Cord::FlattenSlowPath() { } } -static void DumpNode(CordRep* rep, bool include_data, std::ostream* os) { +static void DumpNode(const CordRep* rep, bool include_data, std::ostream* os) { const int kIndentStep = 1; int indent = 0; - absl::InlinedVector stack; - absl::InlinedVector indents; + cord_internal::CordTreeConstPath stack; + cord_internal::CordTreePath indents; for (;;) { *os << std::setw(3) << rep->refcount.Get(); *os << " " << std::setw(7) << rep->length; *os << " ["; - if (include_data) *os << static_cast(rep); + if (include_data) *os << static_cast(rep); *os << "]"; - *os << " " << (IsRootBalanced(rep) ? 'b' : 'u'); + *os << " " << (IsNodeBalanced(rep) ? 'b' : 'u'); *os << " " << std::setw(indent) << ""; if (rep->tag == CONCAT) { *os << "CONCAT depth=" << Depth(rep) << "\n"; @@ -1873,7 +1867,7 @@ static void DumpNode(CordRep* rep, bool include_data, std::ostream* os) { } else { *os << "FLAT cap=" << TagToLength(rep->tag) << " ["; if (include_data) - *os << absl::CEscape(std::string(rep->data, rep->length)); + *os << absl::CEscape(absl::string_view(rep->data, rep->length)); *os << "]\n"; } if (stack.empty()) break; @@ -1886,19 +1880,19 @@ static void DumpNode(CordRep* rep, bool include_data, std::ostream* os) { ABSL_INTERNAL_CHECK(indents.empty(), ""); } -static std::string ReportError(CordRep* root, CordRep* node) { +static std::string ReportError(const CordRep* root, const CordRep* node) { std::ostringstream buf; buf << "Error at node " << node << " in:"; DumpNode(root, true, &buf); return buf.str(); } -static bool VerifyNode(CordRep* root, CordRep* start_node, +static bool VerifyNode(const CordRep* root, const CordRep* start_node, bool full_validation) { - absl::InlinedVector worklist; + cord_internal::CordTreeConstPath worklist; worklist.push_back(start_node); do { - CordRep* node = worklist.back(); + const CordRep* node = worklist.back(); worklist.pop_back(); ABSL_INTERNAL_CHECK(node != nullptr, ReportError(root, node)); @@ -1948,7 +1942,7 @@ static bool VerifyNode(CordRep* root, CordRep* start_node, // Iterate over the tree. cur_node is never a leaf node and leaf nodes will // never be appended to tree_stack. This reduces overhead from manipulating // tree_stack. - absl::InlinedVector tree_stack; + cord_internal::CordTreeConstPath tree_stack; const CordRep* cur_node = rep; while (true) { const CordRep* next_node = nullptr; diff --git a/absl/strings/cord.h b/absl/strings/cord.h index 40566cba..68a7e52f 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h @@ -41,13 +41,13 @@ #include #include #include +#include #include "absl/base/internal/endian.h" #include "absl/base/internal/invoke.h" #include "absl/base/internal/per_thread_tls.h" #include "absl/base/macros.h" #include "absl/base/port.h" -#include "absl/container/inlined_vector.h" #include "absl/functional/function_ref.h" #include "absl/meta/type_traits.h" #include "absl/strings/internal/cord_internal.h" @@ -66,6 +66,73 @@ template H HashFragmentedCord(H, const Cord&); } +namespace cord_internal { + +// It's expensive to keep a tree perfectly balanced, so instead we keep trees +// approximately balanced. A tree node N of depth D(N) that contains a string +// of L(N) characters is considered balanced if L >= Fibonacci(D + 2). +// The "+ 2" is used to ensure that every leaf node contains at least one +// character. Here we presume that +// Fibonacci(0) = 0 +// Fibonacci(1) = 1 +// Fibonacci(2) = 1 +// Fibonacci(3) = 2 +// ... +// +// Fibonacci numbers are convenient because it means when two balanced trees of +// the same depth are made the children of a new node, the resulting tree is +// guaranteed to also be balanced: +// +// +// L(left) >= Fibonacci(D(left) + 2) +// L(right) >= Fibonacci(D(right) + 2) +// +// L(left) + L(right) >= Fibonacci(D(left) + 2) + Fibonacci(D(right) + 2) +// L(left) + L(right) == L(new_tree) +// +// L(new_tree) >= 2 * Fibonacci(D(child) + 2) +// D(child) == D(new_tree) - 1 +// +// L(new_tree) >= 2 * Fibonacci(D(new_tree) + 1) +// 2 * Fibonacci(N) >= Fibonacci(N + 1) +// +// L(new_tree) >= Fibonacci(D(new_tree) + 2) +// +// +// The 93rd Fibonacci number is the largest Fibonacci number that can be +// represented in 64 bits, so the size of a balanced Cord of depth 92 is too big +// for an unsigned 64 bit integer to hold. Therefore we can safely assume that +// the maximum depth of a Cord is 91. +constexpr size_t MaxCordDepth() { return 91; } + +// This class models fixed max size stack of CordRep pointers. +// The elements are being pushed back and popped from the back. +template +class CordTreePath { + public: + CordTreePath() {} + explicit CordTreePath(CordRepPtr root) { push_back(root); } + + bool empty() const { return size_ == 0; } + size_t size() const { return size_; } + void clear() { size_ = 0; } + + CordRepPtr back() { return data_[size_ - 1]; } + + void pop_back() { + --size_; + assert(size_ < N); + } + void push_back(CordRepPtr elem) { data_[size_++] = elem; } + + private: + CordRepPtr data_[N]; + size_t size_ = 0; +}; + +using CordTreeMutablePath = CordTreePath; +} // namespace cord_internal + // A Cord is a sequence of characters. class Cord { private: @@ -114,7 +181,8 @@ class Cord { // finished with `data`. The data must remain live and unchanging until the // releaser is called. The requirements for the releaser are that it: // * is move constructible, - // * supports `void operator()(absl::string_view) const`, + // * supports `void operator()(absl::string_view) const` or + // `void operator()() const`, // * does not have alignment requirement greater than what is guaranteed by // ::operator new. This is dictated by alignof(std::max_align_t) before // C++17 and __STDCPP_DEFAULT_NEW_ALIGNMENT__ if compiling with C++17 or @@ -127,8 +195,8 @@ class Cord { // FillBlock(block); // return absl::MakeCordFromExternal( // block->ToStringView(), - // [pool, block](absl::string_view /*ignored*/) { - // pool->FreeBlock(block); + // [pool, block](absl::string_view v) { + // pool->FreeBlock(block, v); // }); // } // @@ -282,8 +350,7 @@ class Cord { absl::cord_internal::CordRep* current_leaf_ = nullptr; // The number of bytes left in the `Cord` over which we are iterating. size_t bytes_remaining_ = 0; - absl::InlinedVector - stack_of_right_children_; + absl::cord_internal::CordTreeMutablePath stack_of_right_children_; }; // Returns an iterator to the first chunk of the `Cord`. @@ -667,6 +734,21 @@ ExternalRepReleaserPair NewExternalWithUninitializedReleaser( absl::string_view data, ExternalReleaserInvoker invoker, size_t releaser_size); +struct Rank1 {}; +struct Rank0 : Rank1 {}; + +template > +void InvokeReleaser(Rank0, Releaser&& releaser, absl::string_view data) { + ::absl::base_internal::Invoke(std::forward(releaser), data); +} + +template > +void InvokeReleaser(Rank1, Releaser&& releaser, absl::string_view) { + ::absl::base_internal::Invoke(std::forward(releaser)); +} + // Creates a new `CordRep` that owns `data` and `releaser` and returns a pointer // to it, or `nullptr` if `data` was empty. template @@ -684,14 +766,14 @@ CordRep* NewExternalRep(absl::string_view data, Releaser&& releaser) { using ReleaserType = absl::decay_t; if (data.empty()) { // Never create empty external nodes. - ::absl::base_internal::Invoke( - ReleaserType(std::forward(releaser)), data); + InvokeReleaser(Rank0{}, ReleaserType(std::forward(releaser)), + data); return nullptr; } auto releaser_invoker = [](void* type_erased_releaser, absl::string_view d) { auto* my_releaser = static_cast(type_erased_releaser); - ::absl::base_internal::Invoke(std::move(*my_releaser), d); + InvokeReleaser(Rank0{}, std::move(*my_releaser), d); my_releaser->~ReleaserType(); return sizeof(Releaser); }; diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc index 434f3a24..68515cbf 100644 --- a/absl/strings/cord_test.cc +++ b/absl/strings/cord_test.cc @@ -1032,6 +1032,19 @@ TEST(ConstructFromExternal, MoveOnlyReleaser) { EXPECT_TRUE(invoked); } +TEST(ConstructFromExternal, NoArgLambda) { + bool invoked = false; + (void)absl::MakeCordFromExternal("dummy", [&invoked]() { invoked = true; }); + EXPECT_TRUE(invoked); +} + +TEST(ConstructFromExternal, StringViewArgLambda) { + bool invoked = false; + (void)absl::MakeCordFromExternal( + "dummy", [&invoked](absl::string_view) { invoked = true; }); + EXPECT_TRUE(invoked); +} + TEST(ConstructFromExternal, NonTrivialReleaserDestructor) { struct Releaser { explicit Releaser(bool* destroyed) : destroyed(destroyed) {} @@ -1346,6 +1359,49 @@ TEST(CordChunkIterator, Operations) { VerifyChunkIterator(subcords, 128); } +TEST(CordChunkIterator, MaxLengthFullTree) { + absl::Cord cord; + size_t size = 1; + AddExternalMemory("x", &cord); + EXPECT_EQ(cord.size(), size); + + for (int i = 0; i < 63; ++i) { + cord.Prepend(absl::Cord(cord)); + size <<= 1; + + EXPECT_EQ(cord.size(), size); + + auto chunk_it = cord.chunk_begin(); + EXPECT_EQ(*chunk_it, "x"); + } + + EXPECT_DEATH_IF_SUPPORTED( + (cord.Prepend(absl::Cord(cord)), *cord.chunk_begin()), + "Cord is too long"); +} + +TEST(CordChunkIterator, MaxDepth) { + // By reusing nodes, it's possible in pathological cases to build a Cord that + // exceeds both the maximum permissible length and depth. In this case, the + // violation of the maximum depth is reported. + absl::Cord left_child; + AddExternalMemory("x", &left_child); + absl::Cord root = left_child; + + for (int i = 0; i < 91; ++i) { + size_t new_size = left_child.size() + root.size(); + root.Prepend(left_child); + EXPECT_EQ(root.size(), new_size); + + auto chunk_it = root.chunk_begin(); + EXPECT_EQ(*chunk_it, "x"); + + std::swap(left_child, root); + } + + EXPECT_DEATH_IF_SUPPORTED(root.Prepend(left_child), "Cord depth exceeds max"); +} + TEST(CordCharIterator, Traits) { static_assert(std::is_copy_constructible::value, ""); -- cgit v1.2.3 From da3a87690c56f965705b6a233d25ba5a3294067c Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 2 Jun 2020 11:09:12 -0700 Subject: Export of internal Abseil changes -- b2b94b9f533e4f9ae2a2df9de56ccb3b18f31d0d by Gennadiy Rozental : Internal change PiperOrigin-RevId: 314366138 -- 7a5ac6be82741aec5b327d7b67efd14d69deed6a by Gennadiy Rozental : Introduce Abseil prefixed dynamic annotation macros. PiperOrigin-RevId: 314228914 -- 33e7c605cb1be9bd48bd3590b1eedccd68d3bd1b by Gennadiy Rozental : Fixing missing includes and remove unnecessary ones. PiperOrigin-RevId: 314217909 -- 6a3c5c26bfa13317bf0a880f13d0e4be0b971b76 by Gennadiy Rozental : Import of CCTZ from GitHub. PiperOrigin-RevId: 314209576 -- f7795aa68020af4a6b4905531ba951e04b88966a by Abseil Team : absl::FormatTime() and absl::ParseTime() format specifiers: - %EZ now accepts 'z' in addition to 'Z' as a synonym for +00:00. - %ET is introduced, producing 'T' on output, and accepting 'T' or 't' on input. This is for the RFC3339 date-time separator. PiperOrigin-RevId: 313945137 -- 87c437ce3aab3f59a7546e44a28cd1c8aaa152c3 by Laramie Leavitt : Rollback PiperOrigin-RevId: 313868206 -- 8049b74349486a0026932b86d29c380b195e1cba by Laramie Leavitt : Remove the MockingBitGenBase base class in favor of type-erasure in BitGenRef. In Abseil random, mocking was split across two different classes, MockingBitGenBase and MockingBitGen. This split existed because Google Mock is a test-only library that we don't link into production, so MockingBitGenBase provided a low-overhead scaffold used to lookup mocks when in test code, but which is unused in production code. That has been replaced by type-erasure which looks for a method named CallImpl with the correct signature. Weaken the coupling between MockingBitGen, DistributionCaller, and MockOverloadSet. Rename CallImpl to InvokeMock() Previously, the implementation of DistributionCaller was also split across different files using explicit instantiation of the DistributionCaller struct and some details in the Mocking classes. Now Distribution caller uses the presence of the InvokeMock() method to choose whether to use the mockable call path or the default call path. PiperOrigin-RevId: 313848695 -- 1741d80e08050e1939605f70ca6ff64809785c85 by Gennadiy Rozental : Introduce public interface to access reflection handle corresponding the flag. This interface will be the only official way to access flag reflection information from the flag object. The other internal methods will eventually disappear. PiperOrigin-RevId: 313734006 -- c375bead457de29d9c29595d16c66d3e5125b585 by Abseil Team : Improve documentation of absl::c_partial_sort_copy. This function takes no middle parameter, instead using the size of the result container to determine the size of the partial sort. PiperOrigin-RevId: 313656062 -- bbc759d43656b1b996ad558f23c852a9f14129d2 by Gennadiy Rozental : Eliminate dynamic annotation symbols in the library. PiperOrigin-RevId: 313650817 GitOrigin-RevId: b2b94b9f533e4f9ae2a2df9de56ccb3b18f31d0d Change-Id: Ic7a11bbcb723f3ff6a7e2f214bff0a92c6f8ab4d --- CMake/AbseilDll.cmake | 1 + CMakeLists.txt | 2 +- absl/algorithm/container.h | 7 +- absl/base/BUILD.bazel | 12 +- absl/base/CMakeLists.txt | 3 + absl/base/dynamic_annotations.cc | 75 +-- absl/base/dynamic_annotations.h | 766 +++++++++++++---------- absl/base/internal/dynamic_annotations.h | 403 ++++++++++++ absl/flags/BUILD.bazel | 23 +- absl/flags/CMakeLists.txt | 17 +- absl/flags/commandlineflag.cc | 6 + absl/flags/commandlineflag.h | 6 + absl/flags/commandlineflag_test.cc | 1 + absl/flags/declare.h | 1 - absl/flags/flag.h | 21 +- absl/flags/flag_benchmark.cc | 7 + absl/flags/flag_test.cc | 354 +++++++---- absl/flags/internal/commandlineflag.h | 7 +- absl/flags/internal/flag.cc | 11 +- absl/flags/internal/flag.h | 21 +- absl/flags/internal/parse.h | 1 + absl/flags/internal/path_util.h | 1 - absl/flags/internal/private_handle_accessor.cc | 8 + absl/flags/internal/private_handle_accessor.h | 6 + absl/flags/internal/registry.cc | 1 + absl/flags/internal/registry.h | 6 +- absl/flags/internal/type_erased.h | 1 + absl/flags/internal/type_erased_test.cc | 2 +- absl/flags/internal/usage.cc | 2 + absl/flags/internal/usage_test.cc | 2 - absl/flags/parse.cc | 1 + absl/flags/parse.h | 1 - absl/flags/usage_config.cc | 1 + absl/time/civil_time.cc | 12 +- absl/time/format.cc | 13 +- absl/time/format_benchmark.cc | 2 +- absl/time/internal/cctz/include/cctz/time_zone.h | 3 +- absl/time/time.h | 15 +- 38 files changed, 1244 insertions(+), 578 deletions(-) create mode 100644 absl/base/internal/dynamic_annotations.h (limited to 'absl/flags/flag_benchmark.cc') diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index ccd409f3..8e93e794 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -15,6 +15,7 @@ set(ABSL_INTERNAL_DLL_FILES "base/internal/cycleclock.cc" "base/internal/cycleclock.h" "base/internal/direct_mmap.h" + "base/internal/dynamic_annotations.h" "base/internal/endian.h" "base/internal/errno_saver.h" "base/internal/exponential_biased.cc" diff --git a/CMakeLists.txt b/CMakeLists.txt index c406616b..4d10710e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,5 +174,5 @@ if(ABSL_ENABLE_INSTALL) PATTERN "*.h" PATTERN "copts" EXCLUDE PATTERN "testdata" EXCLUDE - ) + ) endif() # ABSL_ENABLE_INSTALL diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h index d72532de..2457d78b 100644 --- a/absl/algorithm/container.h +++ b/absl/algorithm/container.h @@ -943,9 +943,10 @@ void c_partial_sort( // c_partial_sort_copy() // // Container-based version of the `std::partial_sort_copy()` -// function to sort elements within a container such that elements before -// `middle` are sorted in ascending order, and return the result within an -// iterator. +// function to sort the elements in the given range `result` within the larger +// `sequence` in ascending order (and using `result` as the output parameter). +// At most min(result.last - result.first, sequence.last - sequence.first) +// elements from the sequence will be stored in the result. template container_algorithm_internal::ContainerIter c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) { diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index 76122dab..35cb2e94 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel @@ -115,10 +115,18 @@ cc_library( cc_library( name = "dynamic_annotations", - srcs = ["dynamic_annotations.cc"], - hdrs = ["dynamic_annotations.h"], + srcs = [ + "dynamic_annotations.cc", + "internal/dynamic_annotations.h", + ], + hdrs = [ + "dynamic_annotations.h", + ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":config", + ], ) cc_library( diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index 292998b3..b7c01c99 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt @@ -106,8 +106,11 @@ absl_cc_library( "dynamic_annotations.h" SRCS "dynamic_annotations.cc" + "internal/dynamic_annotations.h" COPTS ${ABSL_DEFAULT_COPTS} + DEPS + absl::config PUBLIC ) diff --git a/absl/base/dynamic_annotations.cc b/absl/base/dynamic_annotations.cc index 21e822e5..f26e673e 100644 --- a/absl/base/dynamic_annotations.cc +++ b/absl/base/dynamic_annotations.cc @@ -17,72 +17,17 @@ #include "absl/base/dynamic_annotations.h" -#ifndef __has_feature -#define __has_feature(x) 0 -#endif - -/* Compiler-based ThreadSanitizer defines - DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1 - and provides its own definitions of the functions. */ +// Compiler-based ThreadSanitizer defines +// DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1 +// and provides its own definitions of the functions. #ifndef DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL # define DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL 0 #endif -/* Each function is empty and called (via a macro) only in debug mode. - The arguments are captured by dynamic tools at runtime. */ - #if DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 && !defined(__native_client__) -#if __has_feature(memory_sanitizer) -#include -#endif - -#ifdef __cplusplus extern "C" { -#endif - -void AnnotateRWLockCreate(const char *, int, - const volatile void *){} -void AnnotateRWLockDestroy(const char *, int, - const volatile void *){} -void AnnotateRWLockAcquired(const char *, int, - const volatile void *, long){} -void AnnotateRWLockReleased(const char *, int, - const volatile void *, long){} -void AnnotateBenignRace(const char *, int, - const volatile void *, - const char *){} -void AnnotateBenignRaceSized(const char *, int, - const volatile void *, - size_t, - const char *) {} -void AnnotateThreadName(const char *, int, - const char *){} -void AnnotateIgnoreReadsBegin(const char *, int){} -void AnnotateIgnoreReadsEnd(const char *, int){} -void AnnotateIgnoreWritesBegin(const char *, int){} -void AnnotateIgnoreWritesEnd(const char *, int){} -void AnnotateEnableRaceDetection(const char *, int, int){} -void AnnotateMemoryIsInitialized(const char *, int, - const volatile void *mem, size_t size) { -#if __has_feature(memory_sanitizer) - __msan_unpoison(mem, size); -#else - (void)mem; - (void)size; -#endif -} - -void AnnotateMemoryIsUninitialized(const char *, int, - const volatile void *mem, size_t size) { -#if __has_feature(memory_sanitizer) - __msan_allocated_memory(mem, size); -#else - (void)mem; - (void)size; -#endif -} static int GetRunningOnValgrind(void) { #ifdef RUNNING_ON_VALGRIND @@ -95,21 +40,21 @@ static int GetRunningOnValgrind(void) { return 0; } -/* See the comments in dynamic_annotations.h */ +// See the comments in dynamic_annotations.h int RunningOnValgrind(void) { static volatile int running_on_valgrind = -1; int local_running_on_valgrind = running_on_valgrind; - /* C doesn't have thread-safe initialization of statics, and we - don't want to depend on pthread_once here, so hack it. */ + // C doesn't have thread-safe initialization of statics, and we + // don't want to depend on pthread_once here, so hack it. ANNOTATE_BENIGN_RACE(&running_on_valgrind, "safe hack"); if (local_running_on_valgrind == -1) running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind(); return local_running_on_valgrind; } -/* See the comments in dynamic_annotations.h */ +// See the comments in dynamic_annotations.h double ValgrindSlowdown(void) { - /* Same initialization hack as in RunningOnValgrind(). */ + // Same initialization hack as in RunningOnValgrind(). static volatile double slowdown = 0.0; double local_slowdown = slowdown; ANNOTATE_BENIGN_RACE(&slowdown, "safe hack"); @@ -123,7 +68,5 @@ double ValgrindSlowdown(void) { return local_slowdown; } -#ifdef __cplusplus } // extern "C" -#endif -#endif /* DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */ +#endif // DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 diff --git a/absl/base/dynamic_annotations.h b/absl/base/dynamic_annotations.h index 2d985260..1444dc48 100644 --- a/absl/base/dynamic_annotations.h +++ b/absl/base/dynamic_annotations.h @@ -1,386 +1,504 @@ -/* - * Copyright 2017 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 file defines dynamic annotations for use with dynamic analysis - tool such as valgrind, PIN, etc. - - Dynamic annotation is a source code annotation that affects - the generated code (that is, the annotation is not a comment). - Each such annotation is attached to a particular - instruction and/or to a particular object (address) in the program. - - The annotations that should be used by users are macros in all upper-case - (e.g., ANNOTATE_THREAD_NAME). - - Actual implementation of these macros may differ depending on the - dynamic analysis tool being used. - - This file supports the following configurations: - - Dynamic Annotations enabled (with static thread-safety warnings disabled). - In this case, macros expand to functions implemented by Thread Sanitizer, - when building with TSan. When not provided an external implementation, - dynamic_annotations.cc provides no-op implementations. - - - Static Clang thread-safety warnings enabled. - When building with a Clang compiler that supports thread-safety warnings, - a subset of annotations can be statically-checked at compile-time. We - expand these macros to static-inline functions that can be analyzed for - thread-safety, but afterwards elided when building the final binary. - - - All annotations are disabled. - If neither Dynamic Annotations nor Clang thread-safety warnings are - enabled, then all annotation-macros expand to empty. */ +// Copyright 2017 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 file defines dynamic annotations for use with dynamic analysis tool +// such as valgrind, PIN, etc. +// +// Dynamic annotation is a source code annotation that affects the generated +// code (that is, the annotation is not a comment). Each such annotation is +// attached to a particular instruction and/or to a particular object (address) +// in the program. +// +// The annotations that should be used by users are macros in all upper-case +// (e.g., ABSL_ANNOTATE_THREAD_NAME). +// +// Actual implementation of these macros may differ depending on the dynamic +// analysis tool being used. +// +// This file supports the following configurations: +// - Dynamic Annotations enabled (with static thread-safety warnings disabled). +// In this case, macros expand to functions implemented by Thread Sanitizer, +// when building with TSan. When not provided an external implementation, +// dynamic_annotations.cc provides no-op implementations. +// +// - Static Clang thread-safety warnings enabled. +// When building with a Clang compiler that supports thread-safety warnings, +// a subset of annotations can be statically-checked at compile-time. We +// expand these macros to static-inline functions that can be analyzed for +// thread-safety, but afterwards elided when building the final binary. +// +// - All annotations are disabled. +// If neither Dynamic Annotations nor Clang thread-safety warnings are +// enabled, then all annotation-macros expand to empty. #ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ #define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ +#include + +#include "absl/base/config.h" + +// TODO(rogeeff): Remove after the backward compatibility period. +#include "absl/base/internal/dynamic_annotations.h" // IWYU pragma: export + +// ------------------------------------------------------------------------- +// Decide which features are enabled + #ifndef DYNAMIC_ANNOTATIONS_ENABLED -# define DYNAMIC_ANNOTATIONS_ENABLED 0 +#define DYNAMIC_ANNOTATIONS_ENABLED 0 +#endif + +#if defined(__clang__) && !defined(SWIG) +#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1 +#else +#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 0 #endif #if DYNAMIC_ANNOTATIONS_ENABLED != 0 - /* ------------------------------------------------------------- - Annotations that suppress errors. It is usually better to express the - program's synchronization using the other annotations, but these can - be used when all else fails. */ - - /* Report that we may have a benign race at "pointer", with size - "sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the - point where "pointer" has been allocated, preferably close to the point - where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC. */ - #define ANNOTATE_BENIGN_RACE(pointer, description) \ - AnnotateBenignRaceSized(__FILE__, __LINE__, pointer, \ - sizeof(*(pointer)), description) - - /* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to - the memory range [address, address+size). */ - #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ - AnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description) - - /* Enable (enable!=0) or disable (enable==0) race detection for all threads. - This annotation could be useful if you want to skip expensive race analysis - during some period of program execution, e.g. during initialization. */ - #define ANNOTATE_ENABLE_RACE_DETECTION(enable) \ - AnnotateEnableRaceDetection(__FILE__, __LINE__, enable) - - /* ------------------------------------------------------------- - Annotations useful for debugging. */ - - /* Report the current thread name to a race detector. */ - #define ANNOTATE_THREAD_NAME(name) \ - AnnotateThreadName(__FILE__, __LINE__, name) - - /* ------------------------------------------------------------- - Annotations useful when implementing locks. They are not - normally needed by modules that merely use locks. - The "lock" argument is a pointer to the lock object. */ - - /* Report that a lock has been created at address "lock". */ - #define ANNOTATE_RWLOCK_CREATE(lock) \ - AnnotateRWLockCreate(__FILE__, __LINE__, lock) - - /* Report that a linker initialized lock has been created at address "lock". - */ -#ifdef THREAD_SANITIZER - #define ANNOTATE_RWLOCK_CREATE_STATIC(lock) \ - AnnotateRWLockCreateStatic(__FILE__, __LINE__, lock) +#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1 +#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1 +#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1 +#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0 +#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1 + +#else + +#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0 +#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0 +#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0 + +// Clang provides limited support for static thread-safety analysis through a +// feature called Annotalysis. We configure macro-definitions according to +// whether Annotalysis support is available. When running in opt-mode, GCC +// will issue a warning, if these attributes are compiled. Only include them +// when compiling using Clang. + +// ANNOTALYSIS_ENABLED == 1 when IGNORE_READ_ATTRIBUTE_ENABLED == 1 +#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED \ + ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED +// Read/write annotations are enabled in Annotalysis mode; disabled otherwise. +#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \ + ABSL_INTERNAL_ANNOTALYSIS_ENABLED +#endif + +// Memory annotations are also made available to LLVM's Memory Sanitizer +#if defined(MEMORY_SANITIZER) && defined(__has_feature) && \ + !defined(__native_client__) +#if __has_feature(memory_sanitizer) +#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 1 +#endif +#endif + +#ifndef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED +#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 0 +#endif + +#ifdef __cplusplus +#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" { +#define ABSL_INTERNAL_END_EXTERN_C } // extern "C" +#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F +#define ABSL_INTERNAL_STATIC_INLINE inline #else - #define ANNOTATE_RWLOCK_CREATE_STATIC(lock) ANNOTATE_RWLOCK_CREATE(lock) +#define ABSL_INTERNAL_BEGIN_EXTERN_C // empty +#define ABSL_INTERNAL_END_EXTERN_C // empty +#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F +#define ABSL_INTERNAL_STATIC_INLINE static inline #endif - /* Report that the lock at address "lock" is about to be destroyed. */ - #define ANNOTATE_RWLOCK_DESTROY(lock) \ - AnnotateRWLockDestroy(__FILE__, __LINE__, lock) +// ------------------------------------------------------------------------- +// Define race annotations. + +#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1 + +// ------------------------------------------------------------- +// Annotations that suppress errors. It is usually better to express the +// program's synchronization using the other annotations, but these can be used +// when all else fails. + +// Report that we may have a benign race at `pointer`, with size +// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the +// point where `pointer` has been allocated, preferably close to the point +// where the race happens. See also ABSL_ANNOTATE_BENIGN_RACE_STATIC. +#define ABSL_ANNOTATE_BENIGN_RACE(pointer, description) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \ + (__FILE__, __LINE__, pointer, sizeof(*(pointer)), description) + +// Same as ABSL_ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to +// the memory range [`address`, `address`+`size`). +#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \ + (__FILE__, __LINE__, address, size, description) + +// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads. +// This annotation could be useful if you want to skip expensive race analysis +// during some period of program execution, e.g. during initialization. +#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \ + (__FILE__, __LINE__, enable) + +// ------------------------------------------------------------- +// Annotations useful for debugging. + +// Report the current thread `name` to a race detector. +#define ABSL_ANNOTATE_THREAD_NAME(name) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateThreadName)(__FILE__, __LINE__, name) + +// ------------------------------------------------------------- +// Annotations useful when implementing locks. They are not normally needed by +// modules that merely use locks. The `lock` argument is a pointer to the lock +// object. + +// Report that a lock has been created at address `lock`. +#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate)(__FILE__, __LINE__, lock) + +// Report that a linker initialized lock has been created at address `lock`. +#ifdef THREAD_SANITIZER +#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \ + (__FILE__, __LINE__, lock) +#else +#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \ + ABSL_ANNOTATE_RWLOCK_CREATE(lock) +#endif - /* Report that the lock at address "lock" has been acquired. - is_w=1 for writer lock, is_w=0 for reader lock. */ - #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ - AnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w) +// Report that the lock at address `lock` is about to be destroyed. +#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock) + +// Report that the lock at address `lock` has been acquired. +// `is_w`=1 for writer lock, `is_w`=0 for reader lock. +#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \ + (__FILE__, __LINE__, lock, is_w) + +// Report that the lock at address `lock` is about to be released. +// `is_w`=1 for writer lock, `is_w`=0 for reader lock. +#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \ + (__FILE__, __LINE__, lock, is_w) + +// Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`. +#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ + namespace { \ + class static_var##_annotator { \ + public: \ + static_var##_annotator() { \ + ABSL_ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \ + #static_var ": " description); \ + } \ + }; \ + static static_var##_annotator the##static_var##_annotator; \ + } // namespace + +// Function prototypes of annotations provided by the compiler-based sanitizer +// implementation. +ABSL_INTERNAL_BEGIN_EXTERN_C +void AnnotateRWLockCreate(const char* file, int line, + const volatile void* lock); +void AnnotateRWLockCreateStatic(const char* file, int line, + const volatile void* lock); +void AnnotateRWLockDestroy(const char* file, int line, + const volatile void* lock); +void AnnotateRWLockAcquired(const char* file, int line, + const volatile void* lock, long is_w); // NOLINT +void AnnotateRWLockReleased(const char* file, int line, + const volatile void* lock, long is_w); // NOLINT +void AnnotateBenignRace(const char* file, int line, + const volatile void* address, const char* description); +void AnnotateBenignRaceSized(const char* file, int line, + const volatile void* address, size_t size, + const char* description); +void AnnotateThreadName(const char* file, int line, const char* name); +void AnnotateEnableRaceDetection(const char* file, int line, int enable); +ABSL_INTERNAL_END_EXTERN_C + +#else // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0 + +#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) // empty +#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) // empty +#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) // empty +#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) // empty +#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) // empty +#define ABSL_ANNOTATE_BENIGN_RACE(address, description) // empty +#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) // empty +#define ABSL_ANNOTATE_THREAD_NAME(name) // empty +#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) // empty +#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) // empty + +#endif // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED + +// ------------------------------------------------------------------------- +// Define memory annotations. + +#if ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 1 + +#include + +#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \ + __msan_unpoison(address, size) + +#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \ + __msan_allocated_memory(address, size) + +#else // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 0 + +#if DYNAMIC_ANNOTATIONS_ENABLED == 1 +#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \ + do { \ + (void)(address); \ + (void)(size); \ + } while (0) +#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \ + do { \ + (void)(address); \ + (void)(size); \ + } while (0) +#else - /* Report that the lock at address "lock" is about to be released. */ - #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ - AnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w) +#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) // empty +#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) // empty -#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ +#endif - #define ANNOTATE_RWLOCK_CREATE(lock) /* empty */ - #define ANNOTATE_RWLOCK_CREATE_STATIC(lock) /* empty */ - #define ANNOTATE_RWLOCK_DESTROY(lock) /* empty */ - #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */ - #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */ - #define ANNOTATE_BENIGN_RACE(address, description) /* empty */ - #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */ - #define ANNOTATE_THREAD_NAME(name) /* empty */ - #define ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */ +#endif // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED -#endif /* DYNAMIC_ANNOTATIONS_ENABLED */ +// ------------------------------------------------------------------------- +// Define IGNORE_READS_BEGIN/_END attributes. -/* These annotations are also made available to LLVM's Memory Sanitizer */ -#if DYNAMIC_ANNOTATIONS_ENABLED == 1 || defined(MEMORY_SANITIZER) - #define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \ - AnnotateMemoryIsInitialized(__FILE__, __LINE__, address, size) +#if ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED == 1 - #define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \ - AnnotateMemoryIsUninitialized(__FILE__, __LINE__, address, size) -#else - #define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */ - #define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */ -#endif /* DYNAMIC_ANNOTATIONS_ENABLED || MEMORY_SANITIZER */ +#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \ + __attribute((exclusive_lock_function("*"))) +#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \ + __attribute((unlock_function("*"))) -#if defined(__clang__) && !defined(SWIG) +#else // ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED == 0 - #if DYNAMIC_ANNOTATIONS_ENABLED == 0 - #define ANNOTALYSIS_ENABLED - #endif +#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE // empty +#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE // empty - /* When running in opt-mode, GCC will issue a warning, if these attributes are - compiled. Only include them when compiling using Clang. */ - #define ATTRIBUTE_IGNORE_READS_BEGIN \ - __attribute((exclusive_lock_function("*"))) - #define ATTRIBUTE_IGNORE_READS_END \ - __attribute((unlock_function("*"))) -#else - #define ATTRIBUTE_IGNORE_READS_BEGIN /* empty */ - #define ATTRIBUTE_IGNORE_READS_END /* empty */ -#endif /* defined(__clang__) && ... */ +#endif // ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED -#if (DYNAMIC_ANNOTATIONS_ENABLED != 0) || defined(ANNOTALYSIS_ENABLED) - #define ANNOTATIONS_ENABLED -#endif +// ------------------------------------------------------------------------- +// Define IGNORE_READS_BEGIN/_END annotations. -#if (DYNAMIC_ANNOTATIONS_ENABLED != 0) +#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1 - /* Request the analysis tool to ignore all reads in the current thread - until ANNOTATE_IGNORE_READS_END is called. - Useful to ignore intentional racey reads, while still checking - other reads and all writes. - See also ANNOTATE_UNPROTECTED_READ. */ - #define ANNOTATE_IGNORE_READS_BEGIN() \ - AnnotateIgnoreReadsBegin(__FILE__, __LINE__) +// Request the analysis tool to ignore all reads in the current thread until +// ABSL_ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey +// reads, while still checking other reads and all writes. +// See also ABSL_ANNOTATE_UNPROTECTED_READ. +#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__) - /* Stop ignoring reads. */ - #define ANNOTATE_IGNORE_READS_END() \ - AnnotateIgnoreReadsEnd(__FILE__, __LINE__) +// Stop ignoring reads. +#define ABSL_ANNOTATE_IGNORE_READS_END() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__) - /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. */ - #define ANNOTATE_IGNORE_WRITES_BEGIN() \ - AnnotateIgnoreWritesBegin(__FILE__, __LINE__) +// Function prototypes of annotations provided by the compiler-based sanitizer +// implementation. +ABSL_INTERNAL_BEGIN_EXTERN_C +void AnnotateIgnoreReadsBegin(const char* file, int line) + ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE; +void AnnotateIgnoreReadsEnd(const char* file, + int line) ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE; +ABSL_INTERNAL_END_EXTERN_C - /* Stop ignoring writes. */ - #define ANNOTATE_IGNORE_WRITES_END() \ - AnnotateIgnoreWritesEnd(__FILE__, __LINE__) +#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED) -/* Clang provides limited support for static thread-safety analysis - through a feature called Annotalysis. We configure macro-definitions - according to whether Annotalysis support is available. */ -#elif defined(ANNOTALYSIS_ENABLED) +// When Annotalysis is enabled without Dynamic Annotations, the use of +// static-inline functions allows the annotations to be read at compile-time, +// while still letting the compiler elide the functions from the final build. +// +// TODO(delesley) -- The exclusive lock here ignores writes as well, but +// allows IGNORE_READS_AND_WRITES to work properly. - #define ANNOTATE_IGNORE_READS_BEGIN() \ - StaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__) +#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsBegin)() - #define ANNOTATE_IGNORE_READS_END() \ - StaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__) +#define ABSL_ANNOTATE_IGNORE_READS_END() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsEnd)() - #define ANNOTATE_IGNORE_WRITES_BEGIN() \ - StaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__) +ABSL_INTERNAL_STATIC_INLINE void AbslInternalAnnotateIgnoreReadsBegin() + ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE {} - #define ANNOTATE_IGNORE_WRITES_END() \ - StaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__) +ABSL_INTERNAL_STATIC_INLINE void AbslInternalAnnotateIgnoreReadsEnd() + ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE {} #else - #define ANNOTATE_IGNORE_READS_BEGIN() /* empty */ - #define ANNOTATE_IGNORE_READS_END() /* empty */ - #define ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */ - #define ANNOTATE_IGNORE_WRITES_END() /* empty */ + +#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() // empty +#define ABSL_ANNOTATE_IGNORE_READS_END() // empty + #endif -/* Implement the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more - primitive annotations defined above. */ -#if defined(ANNOTATIONS_ENABLED) +// ------------------------------------------------------------------------- +// Define IGNORE_WRITES_BEGIN/_END annotations. + +#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1 + +// Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. +#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__) - /* Start ignoring all memory accesses (both reads and writes). */ - #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ - do { \ - ANNOTATE_IGNORE_READS_BEGIN(); \ - ANNOTATE_IGNORE_WRITES_BEGIN(); \ - }while (0) +// Stop ignoring writes. +#define ABSL_ANNOTATE_IGNORE_WRITES_END() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__) - /* Stop ignoring both reads and writes. */ - #define ANNOTATE_IGNORE_READS_AND_WRITES_END() \ - do { \ - ANNOTATE_IGNORE_WRITES_END(); \ - ANNOTATE_IGNORE_READS_END(); \ - }while (0) +// Function prototypes of annotations provided by the compiler-based sanitizer +// implementation. +ABSL_INTERNAL_BEGIN_EXTERN_C +void AnnotateIgnoreWritesBegin(const char* file, int line); +void AnnotateIgnoreWritesEnd(const char* file, int line); +ABSL_INTERNAL_END_EXTERN_C #else - #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */ - #define ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */ -#endif -/* Use the macros above rather than using these functions directly. */ -#include -#ifdef __cplusplus -extern "C" { -#endif -void AnnotateRWLockCreate(const char *file, int line, - const volatile void *lock); -void AnnotateRWLockCreateStatic(const char *file, int line, - const volatile void *lock); -void AnnotateRWLockDestroy(const char *file, int line, - const volatile void *lock); -void AnnotateRWLockAcquired(const char *file, int line, - const volatile void *lock, long is_w); /* NOLINT */ -void AnnotateRWLockReleased(const char *file, int line, - const volatile void *lock, long is_w); /* NOLINT */ -void AnnotateBenignRace(const char *file, int line, - const volatile void *address, - const char *description); -void AnnotateBenignRaceSized(const char *file, int line, - const volatile void *address, - size_t size, - const char *description); -void AnnotateThreadName(const char *file, int line, - const char *name); -void AnnotateEnableRaceDetection(const char *file, int line, int enable); -void AnnotateMemoryIsInitialized(const char *file, int line, - const volatile void *mem, size_t size); -void AnnotateMemoryIsUninitialized(const char *file, int line, - const volatile void *mem, size_t size); - -/* Annotations expand to these functions, when Dynamic Annotations are enabled. - These functions are either implemented as no-op calls, if no Sanitizer is - attached, or provided with externally-linked implementations by a library - like ThreadSanitizer. */ -void AnnotateIgnoreReadsBegin(const char *file, int line) - ATTRIBUTE_IGNORE_READS_BEGIN; -void AnnotateIgnoreReadsEnd(const char *file, int line) - ATTRIBUTE_IGNORE_READS_END; -void AnnotateIgnoreWritesBegin(const char *file, int line); -void AnnotateIgnoreWritesEnd(const char *file, int line); - -#if defined(ANNOTALYSIS_ENABLED) -/* When Annotalysis is enabled without Dynamic Annotations, the use of - static-inline functions allows the annotations to be read at compile-time, - while still letting the compiler elide the functions from the final build. - - TODO(delesley) -- The exclusive lock here ignores writes as well, but - allows IGNORE_READS_AND_WRITES to work properly. */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -static inline void StaticAnnotateIgnoreReadsBegin(const char *file, int line) - ATTRIBUTE_IGNORE_READS_BEGIN { (void)file; (void)line; } -static inline void StaticAnnotateIgnoreReadsEnd(const char *file, int line) - ATTRIBUTE_IGNORE_READS_END { (void)file; (void)line; } -static inline void StaticAnnotateIgnoreWritesBegin( - const char *file, int line) { (void)file; (void)line; } -static inline void StaticAnnotateIgnoreWritesEnd( - const char *file, int line) { (void)file; (void)line; } -#pragma GCC diagnostic pop -#endif +#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() // empty +#define ABSL_ANNOTATE_IGNORE_WRITES_END() // empty -/* Return non-zero value if running under valgrind. - - If "valgrind.h" is included into dynamic_annotations.cc, - the regular valgrind mechanism will be used. - See http://valgrind.org/docs/manual/manual-core-adv.html about - RUNNING_ON_VALGRIND and other valgrind "client requests". - The file "valgrind.h" may be obtained by doing - svn co svn://svn.valgrind.org/valgrind/trunk/include - - If for some reason you can't use "valgrind.h" or want to fake valgrind, - there are two ways to make this function return non-zero: - - Use environment variable: export RUNNING_ON_VALGRIND=1 - - Make your tool intercept the function RunningOnValgrind() and - change its return value. - */ -int RunningOnValgrind(void); +#endif -/* ValgrindSlowdown returns: - * 1.0, if (RunningOnValgrind() == 0) - * 50.0, if (RunningOnValgrind() != 0 && getenv("VALGRIND_SLOWDOWN") == NULL) - * atof(getenv("VALGRIND_SLOWDOWN")) otherwise - This function can be used to scale timeout values: - EXAMPLE: - for (;;) { - DoExpensiveBackgroundTask(); - SleepForSeconds(5 * ValgrindSlowdown()); - } - */ -double ValgrindSlowdown(void); +// ------------------------------------------------------------------------- +// Define the ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more +// primitive annotations defined above. +// +// Instead of doing +// ABSL_ANNOTATE_IGNORE_READS_BEGIN(); +// ... = x; +// ABSL_ANNOTATE_IGNORE_READS_END(); +// one can use +// ... = ABSL_ANNOTATE_UNPROTECTED_READ(x); + +#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED) + +// Start ignoring all memory accesses (both reads and writes). +#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ + do { \ + ABSL_ANNOTATE_IGNORE_READS_BEGIN(); \ + ABSL_ANNOTATE_IGNORE_WRITES_BEGIN(); \ + } while (0) + +// Stop ignoring both reads and writes. +#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() \ + do { \ + ABSL_ANNOTATE_IGNORE_WRITES_END(); \ + ABSL_ANNOTATE_IGNORE_READS_END(); \ + } while (0) #ifdef __cplusplus -} -#endif +// ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. +#define ABSL_ANNOTATE_UNPROTECTED_READ(x) \ + absl::base_internal::AnnotateUnprotectedRead(x) -/* ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace base_internal { - Instead of doing - ANNOTATE_IGNORE_READS_BEGIN(); - ... = x; - ANNOTATE_IGNORE_READS_END(); - one can use - ... = ANNOTATE_UNPROTECTED_READ(x); */ -#if defined(__cplusplus) && defined(ANNOTATIONS_ENABLED) template -inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) { /* NOLINT */ - ANNOTATE_IGNORE_READS_BEGIN(); +inline T AnnotateUnprotectedRead(const volatile T& x) { // NOLINT + ABSL_ANNOTATE_IGNORE_READS_BEGIN(); T res = x; - ANNOTATE_IGNORE_READS_END(); + ABSL_ANNOTATE_IGNORE_READS_END(); return res; - } +} + +} // namespace base_internal +ABSL_NAMESPACE_END +} // namespace absl +#endif + #else - #define ANNOTATE_UNPROTECTED_READ(x) (x) + +#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() // empty +#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() // empty +#define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x) + #endif -#if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus) - /* Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable. */ - #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ - namespace { \ - class static_var ## _annotator { \ - public: \ - static_var ## _annotator() { \ - ANNOTATE_BENIGN_RACE_SIZED(&static_var, \ - sizeof(static_var), \ - # static_var ": " description); \ - } \ - }; \ - static static_var ## _annotator the ## static_var ## _annotator;\ - } // namespace -#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ - #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */ -#endif /* DYNAMIC_ANNOTATIONS_ENABLED */ +ABSL_INTERNAL_BEGIN_EXTERN_C + +// ------------------------------------------------------------------------- +// Return non-zero value if running under valgrind. +// +// If "valgrind.h" is included into dynamic_annotations.cc, +// the regular valgrind mechanism will be used. +// See http://valgrind.org/docs/manual/manual-core-adv.html about +// RUNNING_ON_VALGRIND and other valgrind "client requests". +// The file "valgrind.h" may be obtained by doing +// svn co svn://svn.valgrind.org/valgrind/trunk/include +// +// If for some reason you can't use "valgrind.h" or want to fake valgrind, +// there are two ways to make this function return non-zero: +// - Use environment variable: export RUNNING_ON_VALGRIND=1 +// - Make your tool intercept the function RunningOnValgrind() and +// change its return value. +// +int RunningOnValgrind(void); + +// ValgrindSlowdown returns: +// * 1.0, if (RunningOnValgrind() == 0) +// * 50.0, if (RunningOnValgrind() != 0 && getenv("VALGRIND_SLOWDOWN") == +// NULL) +// * atof(getenv("VALGRIND_SLOWDOWN")) otherwise +// This function can be used to scale timeout values: +// EXAMPLE: +// for (;;) { +// DoExpensiveBackgroundTask(); +// SleepForSeconds(5 * ValgrindSlowdown()); +// } +// +double ValgrindSlowdown(void); + +ABSL_INTERNAL_END_EXTERN_C + +// ------------------------------------------------------------------------- +// Address sanitizer annotations #ifdef ADDRESS_SANITIZER -/* Describe the current state of a contiguous container such as e.g. - * std::vector or std::string. For more details see - * sanitizer/common_interface_defs.h, which is provided by the compiler. */ +// Describe the current state of a contiguous container such as e.g. +// std::vector or std::string. For more details see +// sanitizer/common_interface_defs.h, which is provided by the compiler. #include -#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \ + +#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \ __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid) -#define ADDRESS_SANITIZER_REDZONE(name) \ - struct { char x[8] __attribute__ ((aligned (8))); } name +#define ABSL_ADDRESS_SANITIZER_REDZONE(name) \ + struct { \ + char x[8] __attribute__((aligned(8))); \ + } name + #else -#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) -#define ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "") + +#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) +#define ABSL_ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "") + #endif // ADDRESS_SANITIZER -/* Undefine the macros intended only in this file. */ -#undef ANNOTALYSIS_ENABLED -#undef ANNOTATIONS_ENABLED -#undef ATTRIBUTE_IGNORE_READS_BEGIN -#undef ATTRIBUTE_IGNORE_READS_END +// ------------------------------------------------------------------------- +// Undefine the macros intended only for this file. + +#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED +#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_BEGIN_EXTERN_C +#undef ABSL_INTERNAL_END_EXTERN_C +#undef ABSL_INTERNAL_STATIC_INLINE -#endif /* ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ */ +#endif // ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ diff --git a/absl/base/internal/dynamic_annotations.h b/absl/base/internal/dynamic_annotations.h new file mode 100644 index 00000000..7d80f41c --- /dev/null +++ b/absl/base/internal/dynamic_annotations.h @@ -0,0 +1,403 @@ +// Copyright 2017 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 file defines dynamic annotations for use with dynamic analysis tool +// such as valgrind, PIN, etc. +// +// Dynamic annotation is a source code annotation that affects the generated +// code (that is, the annotation is not a comment). Each such annotation is +// attached to a particular instruction and/or to a particular object (address) +// in the program. +// +// The annotations that should be used by users are macros in all upper-case +// (e.g., ANNOTATE_THREAD_NAME). +// +// Actual implementation of these macros may differ depending on the dynamic +// analysis tool being used. +// +// This file supports the following configurations: +// - Dynamic Annotations enabled (with static thread-safety warnings disabled). +// In this case, macros expand to functions implemented by Thread Sanitizer, +// when building with TSan. When not provided an external implementation, +// dynamic_annotations.cc provides no-op implementations. +// +// - Static Clang thread-safety warnings enabled. +// When building with a Clang compiler that supports thread-safety warnings, +// a subset of annotations can be statically-checked at compile-time. We +// expand these macros to static-inline functions that can be analyzed for +// thread-safety, but afterwards elided when building the final binary. +// +// - All annotations are disabled. +// If neither Dynamic Annotations nor Clang thread-safety warnings are +// enabled, then all annotation-macros expand to empty. + +#ifndef ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_ +#define ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_ + +#include + +#include "absl/base/config.h" + +// ------------------------------------------------------------------------- +// Decide which features are enabled + +#ifndef DYNAMIC_ANNOTATIONS_ENABLED +#define DYNAMIC_ANNOTATIONS_ENABLED 0 +#endif + +#if defined(__clang__) && !defined(SWIG) +#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1 +#else +#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 0 +#endif + +#if DYNAMIC_ANNOTATIONS_ENABLED != 0 + +#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1 +#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1 +#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1 +#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0 +#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1 + +#else + +#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0 +#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0 +#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0 + +// Clang provides limited support for static thread-safety analysis through a +// feature called Annotalysis. We configure macro-definitions according to +// whether Annotalysis support is available. When running in opt-mode, GCC +// will issue a warning, if these attributes are compiled. Only include them +// when compiling using Clang. + +// ANNOTALYSIS_ENABLED == 1 when IGNORE_READ_ATTRIBUTE_ENABLED == 1 +#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED \ + ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED +// Read/write annotations are enabled in Annotalysis mode; disabled otherwise. +#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \ + ABSL_INTERNAL_ANNOTALYSIS_ENABLED +#endif + +// Memory annotations are also made available to LLVM's Memory Sanitizer +#if defined(MEMORY_SANITIZER) && defined(__has_feature) && \ + !defined(__native_client__) +#if __has_feature(memory_sanitizer) +#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 1 +#endif +#endif + +#ifndef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED +#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 0 +#endif + +#ifdef __cplusplus +#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" { +#define ABSL_INTERNAL_END_EXTERN_C } // extern "C" +#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F +#define ABSL_INTERNAL_STATIC_INLINE inline +#else +#define ABSL_INTERNAL_BEGIN_EXTERN_C // empty +#define ABSL_INTERNAL_END_EXTERN_C // empty +#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F +#define ABSL_INTERNAL_STATIC_INLINE static inline +#endif + +// ------------------------------------------------------------------------- +// Define race annotations. + +#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1 + +// ------------------------------------------------------------- +// Annotations that suppress errors. It is usually better to express the +// program's synchronization using the other annotations, but these can be used +// when all else fails. + +// Report that we may have a benign race at `pointer`, with size +// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the +// point where `pointer` has been allocated, preferably close to the point +// where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC. +#define ANNOTATE_BENIGN_RACE(pointer, description) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \ + (__FILE__, __LINE__, pointer, sizeof(*(pointer)), description) + +// Same as ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to +// the memory range [`address`, `address`+`size`). +#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \ + (__FILE__, __LINE__, address, size, description) + +// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads. +// This annotation could be useful if you want to skip expensive race analysis +// during some period of program execution, e.g. during initialization. +#define ANNOTATE_ENABLE_RACE_DETECTION(enable) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \ + (__FILE__, __LINE__, enable) + +// ------------------------------------------------------------- +// Annotations useful for debugging. + +// Report the current thread `name` to a race detector. +#define ANNOTATE_THREAD_NAME(name) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateThreadName)(__FILE__, __LINE__, name) + +// ------------------------------------------------------------- +// Annotations useful when implementing locks. They are not normally needed by +// modules that merely use locks. The `lock` argument is a pointer to the lock +// object. + +// Report that a lock has been created at address `lock`. +#define ANNOTATE_RWLOCK_CREATE(lock) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate)(__FILE__, __LINE__, lock) + +// Report that a linker initialized lock has been created at address `lock`. +#ifdef THREAD_SANITIZER +#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \ + (__FILE__, __LINE__, lock) +#else +#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) ANNOTATE_RWLOCK_CREATE(lock) +#endif + +// Report that the lock at address `lock` is about to be destroyed. +#define ANNOTATE_RWLOCK_DESTROY(lock) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock) + +// Report that the lock at address `lock` has been acquired. +// `is_w`=1 for writer lock, `is_w`=0 for reader lock. +#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \ + (__FILE__, __LINE__, lock, is_w) + +// Report that the lock at address `lock` is about to be released. +// `is_w`=1 for writer lock, `is_w`=0 for reader lock. +#define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \ + (__FILE__, __LINE__, lock, is_w) + +// Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`. +#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ + namespace { \ + class static_var##_annotator { \ + public: \ + static_var##_annotator() { \ + ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \ + #static_var ": " description); \ + } \ + }; \ + static static_var##_annotator the##static_var##_annotator; \ + } // namespace + +#else // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0 + +#define ANNOTATE_RWLOCK_CREATE(lock) // empty +#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) // empty +#define ANNOTATE_RWLOCK_DESTROY(lock) // empty +#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) // empty +#define ANNOTATE_RWLOCK_RELEASED(lock, is_w) // empty +#define ANNOTATE_BENIGN_RACE(address, description) // empty +#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) // empty +#define ANNOTATE_THREAD_NAME(name) // empty +#define ANNOTATE_ENABLE_RACE_DETECTION(enable) // empty +#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) // empty + +#endif // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED + +// ------------------------------------------------------------------------- +// Define memory annotations. + +#if ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 1 + +#include + +#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \ + __msan_unpoison(address, size) + +#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \ + __msan_allocated_memory(address, size) + +#else // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 0 + +#if DYNAMIC_ANNOTATIONS_ENABLED == 1 +#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \ + do { \ + (void)(address); \ + (void)(size); \ + } while (0) +#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \ + do { \ + (void)(address); \ + (void)(size); \ + } while (0) +#else +#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) // empty +#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) // empty +#endif + +#endif // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED + +// ------------------------------------------------------------------------- +// Define IGNORE_READS_BEGIN/_END attributes. + +#if ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED == 1 + +#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \ + __attribute((exclusive_lock_function("*"))) +#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \ + __attribute((unlock_function("*"))) + +#else // ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED == 0 + +#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE // empty +#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE // empty + +#endif // ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED + +// ------------------------------------------------------------------------- +// Define IGNORE_READS_BEGIN/_END annotations. + +#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1 + +// Request the analysis tool to ignore all reads in the current thread until +// ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey +// reads, while still checking other reads and all writes. +// See also ANNOTATE_UNPROTECTED_READ. +#define ANNOTATE_IGNORE_READS_BEGIN() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__) + +// Stop ignoring reads. +#define ANNOTATE_IGNORE_READS_END() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__) + +#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED) + +// When Annotalysis is enabled without Dynamic Annotations, the use of +// static-inline functions allows the annotations to be read at compile-time, +// while still letting the compiler elide the functions from the final build. +// +// TODO(delesley) -- The exclusive lock here ignores writes as well, but +// allows IGNORE_READS_AND_WRITES to work properly. + +#define ANNOTATE_IGNORE_READS_BEGIN() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsBegin)() + +#define ANNOTATE_IGNORE_READS_END() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsEnd)() + +#else + +#define ANNOTATE_IGNORE_READS_BEGIN() // empty +#define ANNOTATE_IGNORE_READS_END() // empty + +#endif + +// ------------------------------------------------------------------------- +// Define IGNORE_WRITES_BEGIN/_END annotations. + +#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1 + +// Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. +#define ANNOTATE_IGNORE_WRITES_BEGIN() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__) + +// Stop ignoring writes. +#define ANNOTATE_IGNORE_WRITES_END() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__) + +#else + +#define ANNOTATE_IGNORE_WRITES_BEGIN() // empty +#define ANNOTATE_IGNORE_WRITES_END() // empty + +#endif + +// ------------------------------------------------------------------------- +// Define the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more +// primitive annotations defined above. +// +// Instead of doing +// ANNOTATE_IGNORE_READS_BEGIN(); +// ... = x; +// ANNOTATE_IGNORE_READS_END(); +// one can use +// ... = ANNOTATE_UNPROTECTED_READ(x); + +#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED) + +// Start ignoring all memory accesses (both reads and writes). +#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ + do { \ + ANNOTATE_IGNORE_READS_BEGIN(); \ + ANNOTATE_IGNORE_WRITES_BEGIN(); \ + } while (0) + +// Stop ignoring both reads and writes. +#define ANNOTATE_IGNORE_READS_AND_WRITES_END() \ + do { \ + ANNOTATE_IGNORE_WRITES_END(); \ + ANNOTATE_IGNORE_READS_END(); \ + } while (0) + +#ifdef __cplusplus +// ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. +#define ANNOTATE_UNPROTECTED_READ(x) \ + absl::base_internal::AnnotateUnprotectedRead(x) + +#endif + +#else + +#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() // empty +#define ANNOTATE_IGNORE_READS_AND_WRITES_END() // empty +#define ANNOTATE_UNPROTECTED_READ(x) (x) + +#endif + +// ------------------------------------------------------------------------- +// Address sanitizer annotations + +#ifdef ADDRESS_SANITIZER +// Describe the current state of a contiguous container such as e.g. +// std::vector or std::string. For more details see +// sanitizer/common_interface_defs.h, which is provided by the compiler. +#include + +#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \ + __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid) +#define ADDRESS_SANITIZER_REDZONE(name) \ + struct { \ + char x[8] __attribute__((aligned(8))); \ + } name + +#else + +#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) +#define ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "") + +#endif // ADDRESS_SANITIZER + +// ------------------------------------------------------------------------- +// Undefine the macros intended only for this file. + +#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED +#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_BEGIN_EXTERN_C +#undef ABSL_INTERNAL_END_EXTERN_C +#undef ABSL_INTERNAL_STATIC_INLINE + +#endif // ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_ diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index 2d6f799e..6ffd07ce 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -114,9 +114,7 @@ cc_library( visibility = ["//visibility:private"], deps = [ "//absl/base:config", - "//absl/base:core_headers", "//absl/base:fast_type_id", - "//absl/strings", ], ) @@ -132,6 +130,9 @@ cc_library( linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":commandlineflag_internal", + "//absl/base:config", + "//absl/base:fast_type_id", + "//absl/strings", "//absl/types:optional", ], ) @@ -149,7 +150,12 @@ cc_library( visibility = [ "//absl/flags:__pkg__", ], - deps = [":commandlineflag"], + deps = [ + ":commandlineflag", + ":commandlineflag_internal", + "//absl/base:config", + "//absl/strings", + ], ) cc_library( @@ -193,6 +199,7 @@ cc_library( visibility = ["//absl/base:__subpackages__"], deps = [ ":commandlineflag", + ":commandlineflag_internal", ":config", ":marshalling", ":registry", @@ -203,6 +210,7 @@ cc_library( "//absl/meta:type_traits", "//absl/strings", "//absl/synchronization", + "//absl/utility", ], ) @@ -220,7 +228,6 @@ cc_library( deps = [ ":config", ":flag_internal", - ":marshalling", ":registry", "//absl/base", "//absl/base:config", @@ -287,6 +294,7 @@ cc_library( linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":commandlineflag", + ":commandlineflag_internal", ":config", ":flag", ":flag_internal", @@ -315,6 +323,7 @@ cc_test( linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":commandlineflag", + ":commandlineflag_internal", ":config", ":flag", ":private_handle_accessor", @@ -352,6 +361,7 @@ cc_test( ":config", ":flag", ":flag_internal", + ":marshalling", ":registry", "//absl/base:core_headers", "//absl/base:malloc_internal", @@ -372,6 +382,8 @@ cc_binary( visibility = ["//visibility:private"], deps = [ ":flag", + ":marshalling", + "//absl/strings", "//absl/time", "//absl/types:optional", "@com_github_google_benchmark//:benchmark_main", @@ -450,8 +462,8 @@ cc_test( copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ + ":commandlineflag_internal", ":flag", - ":marshalling", ":registry", "//absl/memory", "@com_google_googletest//:gtest_main", @@ -492,7 +504,6 @@ cc_test( ":registry", ":usage", ":usage_internal", - "//absl/memory", "//absl/strings", "@com_google_googletest//:gtest", ], diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt index 6ecf3b48..2dc7cf45 100644 --- a/absl/flags/CMakeLists.txt +++ b/absl/flags/CMakeLists.txt @@ -103,9 +103,7 @@ absl_cc_library( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::config - absl::core_headers absl::fast_type_id - absl::strings ) absl_cc_library( @@ -120,8 +118,11 @@ absl_cc_library( LINKOPTS ${ABSL_DEFAULT_LINKOPTS} DEPS + absl::config + absl::fast_type_id absl::flags_commandlineflag_internal absl::optional + absl::strings ) # Internal-only target, do not depend on directly. @@ -137,7 +138,10 @@ absl_cc_library( LINKOPTS ${ABSL_DEFAULT_LINKOPTS} DEPS + absl::config absl::flags_commandlineflag + absl::flags_commandlineflag_internal + absl::strings ) # Internal-only target, do not depend on directly. @@ -180,11 +184,13 @@ absl_cc_library( DEPS absl::base absl::config + absl::flags_commandlineflag_internal absl::flags_config absl::flags_marshalling absl::flags_registry absl::synchronization absl::meta + absl::utility PUBLIC ) @@ -205,7 +211,6 @@ absl_cc_library( absl::flags_commandlineflag absl::flags_config absl::flags_internal - absl::flags_marshalling absl::flags_registry absl::base absl::core_headers @@ -275,6 +280,7 @@ absl_cc_library( absl::flags_config absl::flags absl::flags_commandlineflag + absl::flags_commandlineflag_internal absl::flags_internal absl::flags_private_handle_accessor absl::flags_program_name @@ -297,6 +303,7 @@ absl_cc_test( DEPS absl::flags absl::flags_commandlineflag + absl::flags_commandlineflag_internal absl::flags_config absl::flags_private_handle_accessor absl::flags_registry @@ -330,6 +337,7 @@ absl_cc_test( absl::flags absl::flags_config absl::flags_internal + absl::flags_marshalling absl::flags_registry absl::strings absl::time @@ -399,8 +407,8 @@ absl_cc_test( COPTS ${ABSL_TEST_COPTS} DEPS + absl::flags_commandlineflag_internal absl::flags - absl::flags_marshalling absl::flags_registry absl::memory absl::strings @@ -437,7 +445,6 @@ absl_cc_test( absl::flags_parse absl::flags_registry absl::flags_usage - absl::memory absl::strings gtest ) diff --git a/absl/flags/commandlineflag.cc b/absl/flags/commandlineflag.cc index cea57234..217b2d87 100644 --- a/absl/flags/commandlineflag.cc +++ b/absl/flags/commandlineflag.cc @@ -15,6 +15,12 @@ #include "absl/flags/commandlineflag.h" +#include + +#include "absl/base/config.h" +#include "absl/flags/internal/commandlineflag.h" +#include "absl/strings/string_view.h" + namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/absl/flags/commandlineflag.h b/absl/flags/commandlineflag.h index 43055d04..7e21d05d 100644 --- a/absl/flags/commandlineflag.h +++ b/absl/flags/commandlineflag.h @@ -26,7 +26,13 @@ #ifndef ABSL_FLAGS_COMMANDLINEFLAG_H_ #define ABSL_FLAGS_COMMANDLINEFLAG_H_ +#include +#include + +#include "absl/base/config.h" +#include "absl/base/internal/fast_type_id.h" #include "absl/flags/internal/commandlineflag.h" +#include "absl/strings/string_view.h" #include "absl/types/optional.h" namespace absl { diff --git a/absl/flags/commandlineflag_test.cc b/absl/flags/commandlineflag_test.cc index 4b9718e9..570bbe2f 100644 --- a/absl/flags/commandlineflag_test.cc +++ b/absl/flags/commandlineflag_test.cc @@ -20,6 +20,7 @@ #include "gtest/gtest.h" #include "absl/flags/flag.h" +#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/private_handle_accessor.h" #include "absl/flags/internal/registry.h" #include "absl/flags/usage_config.h" diff --git a/absl/flags/declare.h b/absl/flags/declare.h index 0f8cc6a5..b9794d8b 100644 --- a/absl/flags/declare.h +++ b/absl/flags/declare.h @@ -26,7 +26,6 @@ #define ABSL_FLAGS_DECLARE_H_ #include "absl/base/config.h" -#include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/absl/flags/flag.h b/absl/flags/flag.h index dd36e6c7..90dc2894 100644 --- a/absl/flags/flag.h +++ b/absl/flags/flag.h @@ -33,13 +33,11 @@ #include #include "absl/base/attributes.h" -#include "absl/base/casts.h" #include "absl/base/config.h" +#include "absl/base/optimization.h" #include "absl/flags/config.h" -#include "absl/flags/declare.h" #include "absl/flags/internal/flag.h" #include "absl/flags/internal/registry.h" -#include "absl/flags/marshalling.h" #include "absl/strings/string_view.h" namespace absl { @@ -150,6 +148,8 @@ class Flag { void Set(const T& v) { GetImpl().Set(v); } void InvokeCallback() { GetImpl().InvokeCallback(); } + const CommandLineFlag& Reflect() const { return GetImpl().Reflect(); } + // The data members are logically private, but they need to be public for // this to be an aggregate type. const char* name_; @@ -204,6 +204,21 @@ void SetFlag(absl::Flag* flag, const V& v) { flag->Set(value); } +// GetFlagReflectionHandle() +// +// Returns the reflection handle corresponding to specified Abseil Flag +// instance. Use this handle to access flag's reflection information, like name, +// location, default value etc. +// +// Example: +// +// std::string = absl::GetFlagReflectionHandle(FLAGS_count).DefaultValue(); + +template +const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag& f) { + return f.Reflect(); +} + ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/flags/flag_benchmark.cc b/absl/flags/flag_benchmark.cc index ff95bb5d..7b52c9bc 100644 --- a/absl/flags/flag_benchmark.cc +++ b/absl/flags/flag_benchmark.cc @@ -13,7 +13,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + +#include +#include + #include "absl/flags/flag.h" +#include "absl/flags/marshalling.h" +#include "absl/strings/string_view.h" #include "absl/time/time.h" #include "absl/types/optional.h" #include "benchmark/benchmark.h" diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc index 58a07999..71661d39 100644 --- a/absl/flags/flag_test.cc +++ b/absl/flags/flag_test.cc @@ -15,9 +15,11 @@ #include "absl/flags/flag.h" +#include #include #include +#include #include #include // NOLINT #include @@ -28,6 +30,7 @@ #include "absl/flags/declare.h" #include "absl/flags/internal/flag.h" #include "absl/flags/internal/registry.h" +#include "absl/flags/marshalling.h" #include "absl/flags/usage_config.h" #include "absl/strings/match.h" #include "absl/strings/numbers.h" @@ -44,6 +47,9 @@ namespace { namespace flags = absl::flags_internal; std::string TestHelpMsg() { return "dynamic help"; } +#if defined(_MSC_VER) && !defined(__clang__) +std::string TestLiteralHelpMsg() { return "literal help"; } +#endif template void TestMakeDflt(void* dst) { new (dst) T{}; @@ -127,15 +133,29 @@ constexpr flags::FlagHelpArg help_arg{flags::FlagHelpMsg("literal help"), using String = std::string; -#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind) \ - constexpr flags::FlagDefaultArg f1default##T{ \ - flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind}; \ - constexpr flags::Flag f1##T("f1", "file", help_arg, f1default##T); \ - ABSL_CONST_INIT flags::Flag f2##T( \ - "f2", "file", \ - {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \ - flags::FlagDefaultArg{flags::FlagDefaultSrc(&TestMakeDflt), \ - flags::FlagDefaultKind::kGenFunc}) +#if !defined(_MSC_VER) || defined(__clang__) +#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind) \ + constexpr flags::FlagDefaultArg f1default##T{ \ + flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind}; \ + constexpr absl::Flag f1##T{"f1", "file", help_arg, f1default##T}; \ + ABSL_CONST_INIT absl::Flag f2##T { \ + "f2", "file", \ + {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \ + flags::FlagDefaultArg { \ + flags::FlagDefaultSrc(&TestMakeDflt), \ + flags::FlagDefaultKind::kGenFunc \ + } \ + } +#else +#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind) \ + constexpr flags::FlagDefaultArg f1default##T{ \ + flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind}; \ + constexpr absl::Flag f1##T{"f1", "file", &TestLiteralHelpMsg, \ + &TestMakeDflt}; \ + ABSL_CONST_INIT absl::Flag f2##T { \ + "f2", "file", &TestHelpMsg, &TestMakeDflt \ + } +#endif DEFINE_CONSTRUCTED_FLAG(bool, true, kOneWord); DEFINE_CONSTRUCTED_FLAG(int16_t, 1, kOneWord); @@ -150,16 +170,17 @@ DEFINE_CONSTRUCTED_FLAG(String, &TestMakeDflt, kGenFunc); DEFINE_CONSTRUCTED_FLAG(UDT, &TestMakeDflt, kGenFunc); template -bool TestConstructionFor(const flags::Flag& f1, flags::Flag& f2) { - EXPECT_EQ(f1.Name(), "f1"); - EXPECT_EQ(f1.Help(), "literal help"); - EXPECT_EQ(f1.Filename(), "file"); +bool TestConstructionFor(const absl::Flag& f1, absl::Flag& f2) { + EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Name(), "f1"); + EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Help(), "literal help"); + EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Filename(), "file"); - flags::FlagRegistrar(f2).OnUpdate(TestCallback); + flags::FlagRegistrar(ABSL_FLAG_IMPL_FLAG_PTR(f2)) + .OnUpdate(TestCallback); - EXPECT_EQ(f2.Name(), "f2"); - EXPECT_EQ(f2.Help(), "dynamic help"); - EXPECT_EQ(f2.Filename(), "file"); + EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Name(), "f2"); + EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Help(), "dynamic help"); + EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Filename(), "file"); return true; } @@ -203,18 +224,30 @@ namespace { TEST_F(FlagTest, TestFlagDeclaration) { // test that we can access flag objects. - EXPECT_EQ(FLAGS_test_flag_01.Name(), "test_flag_01"); - EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02"); - EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03"); - EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04"); - EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05"); - EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06"); - EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07"); - EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08"); - EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09"); - EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10"); - EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11"); - EXPECT_EQ(FLAGS_test_flag_12.Name(), "test_flag_12"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(), + "test_flag_01"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Name(), + "test_flag_02"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Name(), + "test_flag_03"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Name(), + "test_flag_04"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Name(), + "test_flag_05"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Name(), + "test_flag_06"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Name(), + "test_flag_07"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Name(), + "test_flag_08"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Name(), + "test_flag_09"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Name(), + "test_flag_10"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Name(), + "test_flag_11"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(), + "test_flag_12"); } #endif // !ABSL_FLAGS_STRIP_NAMES @@ -241,96 +274,168 @@ namespace { TEST_F(FlagTest, TestFlagDefinition) { absl::string_view expected_file_name = "absl/flags/flag_test.cc"; - EXPECT_EQ(FLAGS_test_flag_01.Name(), "test_flag_01"); - EXPECT_EQ(FLAGS_test_flag_01.Help(), "test flag 01"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_01.Filename(), expected_file_name)) - << FLAGS_test_flag_01.Filename(); - - EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02"); - EXPECT_EQ(FLAGS_test_flag_02.Help(), "test flag 02"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_02.Filename(), expected_file_name)) - << FLAGS_test_flag_02.Filename(); - - EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03"); - EXPECT_EQ(FLAGS_test_flag_03.Help(), "test flag 03"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_03.Filename(), expected_file_name)) - << FLAGS_test_flag_03.Filename(); - - EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04"); - EXPECT_EQ(FLAGS_test_flag_04.Help(), "test flag 04"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_04.Filename(), expected_file_name)) - << FLAGS_test_flag_04.Filename(); - - EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05"); - EXPECT_EQ(FLAGS_test_flag_05.Help(), "test flag 05"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_05.Filename(), expected_file_name)) - << FLAGS_test_flag_05.Filename(); - - EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06"); - EXPECT_EQ(FLAGS_test_flag_06.Help(), "test flag 06"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_06.Filename(), expected_file_name)) - << FLAGS_test_flag_06.Filename(); - - EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07"); - EXPECT_EQ(FLAGS_test_flag_07.Help(), "test flag 07"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_07.Filename(), expected_file_name)) - << FLAGS_test_flag_07.Filename(); - - EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08"); - EXPECT_EQ(FLAGS_test_flag_08.Help(), "test flag 08"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_08.Filename(), expected_file_name)) - << FLAGS_test_flag_08.Filename(); - - EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09"); - EXPECT_EQ(FLAGS_test_flag_09.Help(), "test flag 09"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_09.Filename(), expected_file_name)) - << FLAGS_test_flag_09.Filename(); - - EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10"); - EXPECT_EQ(FLAGS_test_flag_10.Help(), "test flag 10"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_10.Filename(), expected_file_name)) - << FLAGS_test_flag_10.Filename(); - - EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11"); - EXPECT_EQ(FLAGS_test_flag_11.Help(), "test flag 11"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_11.Filename(), expected_file_name)) - << FLAGS_test_flag_11.Filename(); - - EXPECT_EQ(FLAGS_test_flag_12.Name(), "test_flag_12"); - EXPECT_EQ(FLAGS_test_flag_12.Help(), "test flag 12"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_12.Filename(), expected_file_name)) - << FLAGS_test_flag_12.Filename(); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(), + "test_flag_01"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Help(), + "test flag 01"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Name(), + "test_flag_02"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Help(), + "test flag 02"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Name(), + "test_flag_03"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Help(), + "test flag 03"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Name(), + "test_flag_04"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Help(), + "test flag 04"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Name(), + "test_flag_05"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Help(), + "test flag 05"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Name(), + "test_flag_06"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Help(), + "test flag 06"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Name(), + "test_flag_07"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Help(), + "test flag 07"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Name(), + "test_flag_08"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Help(), + "test flag 08"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Name(), + "test_flag_09"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Help(), + "test flag 09"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Name(), + "test_flag_10"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Help(), + "test flag 10"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Name(), + "test_flag_11"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Help(), + "test flag 11"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(), + "test_flag_12"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Help(), + "test flag 12"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename(); } #endif // !ABSL_FLAGS_STRIP_NAMES // -------------------------------------------------------------------- TEST_F(FlagTest, TestDefault) { - EXPECT_EQ(FLAGS_test_flag_01.DefaultValue(), "true"); - EXPECT_EQ(FLAGS_test_flag_02.DefaultValue(), "1234"); - EXPECT_EQ(FLAGS_test_flag_03.DefaultValue(), "-34"); - EXPECT_EQ(FLAGS_test_flag_04.DefaultValue(), "189"); - EXPECT_EQ(FLAGS_test_flag_05.DefaultValue(), "10765"); - EXPECT_EQ(FLAGS_test_flag_06.DefaultValue(), "40000"); - EXPECT_EQ(FLAGS_test_flag_07.DefaultValue(), "-1234567"); - EXPECT_EQ(FLAGS_test_flag_08.DefaultValue(), "9876543"); - EXPECT_EQ(FLAGS_test_flag_09.DefaultValue(), "-9.876e-50"); - EXPECT_EQ(FLAGS_test_flag_10.DefaultValue(), "1.234e+12"); - EXPECT_EQ(FLAGS_test_flag_11.DefaultValue(), ""); - EXPECT_EQ(FLAGS_test_flag_12.DefaultValue(), "10m"); - - EXPECT_EQ(FLAGS_test_flag_01.CurrentValue(), "true"); - EXPECT_EQ(FLAGS_test_flag_02.CurrentValue(), "1234"); - EXPECT_EQ(FLAGS_test_flag_03.CurrentValue(), "-34"); - EXPECT_EQ(FLAGS_test_flag_04.CurrentValue(), "189"); - EXPECT_EQ(FLAGS_test_flag_05.CurrentValue(), "10765"); - EXPECT_EQ(FLAGS_test_flag_06.CurrentValue(), "40000"); - EXPECT_EQ(FLAGS_test_flag_07.CurrentValue(), "-1234567"); - EXPECT_EQ(FLAGS_test_flag_08.CurrentValue(), "9876543"); - EXPECT_EQ(FLAGS_test_flag_09.CurrentValue(), "-9.876e-50"); - EXPECT_EQ(FLAGS_test_flag_10.CurrentValue(), "1.234e+12"); - EXPECT_EQ(FLAGS_test_flag_11.CurrentValue(), ""); - EXPECT_EQ(FLAGS_test_flag_12.CurrentValue(), "10m"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).DefaultValue(), + "true"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).DefaultValue(), + "1234"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).DefaultValue(), + "-34"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).DefaultValue(), + "189"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).DefaultValue(), + "10765"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).DefaultValue(), + "40000"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).DefaultValue(), + "-1234567"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).DefaultValue(), + "9876543"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).DefaultValue(), + "-9.876e-50"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).DefaultValue(), + "1.234e+12"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).DefaultValue(), + ""); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).DefaultValue(), + "10m"); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).CurrentValue(), + "true"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).CurrentValue(), + "1234"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).CurrentValue(), + "-34"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).CurrentValue(), + "189"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).CurrentValue(), + "10765"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).CurrentValue(), + "40000"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).CurrentValue(), + "-1234567"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).CurrentValue(), + "9876543"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).CurrentValue(), + "-9.876e-50"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).CurrentValue(), + "1.234e+12"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).CurrentValue(), + ""); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).CurrentValue(), + "10m"); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234); @@ -385,12 +490,18 @@ ABSL_FLAG(NonTriviallyCopyableAggregate, test_flag_eb_06, {}, ""); namespace { TEST_F(FlagTest, TestEmptyBracesDefault) { - EXPECT_EQ(FLAGS_test_flag_eb_01.DefaultValue(), "false"); - EXPECT_EQ(FLAGS_test_flag_eb_02.DefaultValue(), "0"); - EXPECT_EQ(FLAGS_test_flag_eb_03.DefaultValue(), "0"); - EXPECT_EQ(FLAGS_test_flag_eb_04.DefaultValue(), "0"); - EXPECT_EQ(FLAGS_test_flag_eb_05.DefaultValue(), ""); - EXPECT_EQ(FLAGS_test_flag_eb_06.DefaultValue(), "0"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_01).DefaultValue(), + "false"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_02).DefaultValue(), + "0"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_03).DefaultValue(), + "0"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_04).DefaultValue(), + "0"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_05).DefaultValue(), + ""); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_06).DefaultValue(), + "0"); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_01), false); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_02), 0); @@ -500,8 +611,9 @@ namespace { #if !ABSL_FLAGS_STRIP_HELP TEST_F(FlagTest, TestNonConstexprHelp) { - EXPECT_EQ(FLAGS_test_flag_with_non_const_help.Help(), - "test flag non const help"); + EXPECT_EQ( + absl::GetFlagReflectionHandle(FLAGS_test_flag_with_non_const_help).Help(), + "test flag non const help"); } #endif //! ABSL_FLAGS_STRIP_HELP diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h index 3c149788..cb46fe2e 100644 --- a/absl/flags/internal/commandlineflag.h +++ b/absl/flags/internal/commandlineflag.h @@ -16,13 +16,8 @@ #ifndef ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_ #define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_ -#include -#include - #include "absl/base/config.h" #include "absl/base/internal/fast_type_id.h" -#include "absl/base/macros.h" -#include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -33,7 +28,7 @@ namespace flags_internal { // cases this id is enough to uniquely identify the flag's value type. In a few // cases we'll have to resort to using actual RTTI implementation if it is // available. -using FlagFastTypeId = base_internal::FastTypeIdType; +using FlagFastTypeId = absl::base_internal::FastTypeIdType; // Options that control SetCommandLineOptionWithMode. enum FlagSettingMode { diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc index ee974244..1502e7f1 100644 --- a/absl/flags/internal/flag.cc +++ b/absl/flags/internal/flag.cc @@ -15,21 +15,26 @@ #include "absl/flags/internal/flag.h" +#include #include #include #include +#include #include #include +#include #include -#include +#include -#include "absl/base/attributes.h" +#include "absl/base/call_once.h" #include "absl/base/casts.h" #include "absl/base/config.h" -#include "absl/base/const_init.h" #include "absl/base/optimization.h" +#include "absl/flags/config.h" +#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/usage_config.h" +#include "absl/memory/memory.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h index e1885809..2cc44e00 100644 --- a/absl/flags/internal/flag.h +++ b/absl/flags/internal/flag.h @@ -16,31 +16,36 @@ #ifndef ABSL_FLAGS_INTERNAL_FLAG_H_ #define ABSL_FLAGS_INTERNAL_FLAG_H_ +#include #include #include #include #include +#include #include #include #include +#include "absl/base/attributes.h" #include "absl/base/call_once.h" #include "absl/base/config.h" +#include "absl/base/optimization.h" #include "absl/base/thread_annotations.h" #include "absl/flags/commandlineflag.h" #include "absl/flags/config.h" +#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/registry.h" #include "absl/flags/marshalling.h" -#include "absl/memory/memory.h" #include "absl/meta/type_traits.h" -#include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" +#include "absl/utility/utility.h" namespace absl { ABSL_NAMESPACE_BEGIN +/////////////////////////////////////////////////////////////////////////////// // Forward declaration of absl::Flag public API. namespace flags_internal { template @@ -64,12 +69,15 @@ void SetFlag(absl::Flag* flag, const T& v); template void SetFlag(absl::Flag* flag, const V& v); -namespace flags_internal { +template +const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag& f); /////////////////////////////////////////////////////////////////////////////// // Flag value type operations, eg., parsing, copying, etc. are provided // by function specific to that type with a signature matching FlagOpFn. +namespace flags_internal { + enum class FlagOp { kAlloc, kDelete, @@ -659,6 +667,13 @@ class Flag { impl_.Write(&v); } + template + friend const CommandLineFlag& absl::GetFlagReflectionHandle( + const absl::Flag& f); + + // Access to the reflection. + const CommandLineFlag& Reflect() const { return impl_; } + // Flag's data // The implementation depends on value_ field to be placed exactly after the // impl_ field, so that impl_ can figure out the offset to the value and diff --git a/absl/flags/internal/parse.h b/absl/flags/internal/parse.h index d259be73..de706c89 100644 --- a/absl/flags/internal/parse.h +++ b/absl/flags/internal/parse.h @@ -21,6 +21,7 @@ #include "absl/base/config.h" #include "absl/flags/declare.h" +#include "absl/strings/string_view.h" ABSL_DECLARE_FLAG(std::vector, flagfile); ABSL_DECLARE_FLAG(std::vector, fromenv); diff --git a/absl/flags/internal/path_util.h b/absl/flags/internal/path_util.h index 365c8305..a6594d33 100644 --- a/absl/flags/internal/path_util.h +++ b/absl/flags/internal/path_util.h @@ -17,7 +17,6 @@ #define ABSL_FLAGS_INTERNAL_PATH_UTIL_H_ #include "absl/base/config.h" -#include "absl/strings/match.h" #include "absl/strings/string_view.h" namespace absl { diff --git a/absl/flags/internal/private_handle_accessor.cc b/absl/flags/internal/private_handle_accessor.cc index 24b49136..a7eb58b6 100644 --- a/absl/flags/internal/private_handle_accessor.cc +++ b/absl/flags/internal/private_handle_accessor.cc @@ -15,6 +15,14 @@ #include "absl/flags/internal/private_handle_accessor.h" +#include +#include + +#include "absl/base/config.h" +#include "absl/flags/commandlineflag.h" +#include "absl/flags/internal/commandlineflag.h" +#include "absl/strings/string_view.h" + namespace absl { ABSL_NAMESPACE_BEGIN namespace flags_internal { diff --git a/absl/flags/internal/private_handle_accessor.h b/absl/flags/internal/private_handle_accessor.h index 9a327a07..c64435cd 100644 --- a/absl/flags/internal/private_handle_accessor.h +++ b/absl/flags/internal/private_handle_accessor.h @@ -16,7 +16,13 @@ #ifndef ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_ #define ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_ +#include +#include + +#include "absl/base/config.h" #include "absl/flags/commandlineflag.h" +#include "absl/flags/internal/commandlineflag.h" +#include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/absl/flags/internal/registry.cc b/absl/flags/internal/registry.cc index 4bcebfa9..e582d79d 100644 --- a/absl/flags/internal/registry.cc +++ b/absl/flags/internal/registry.cc @@ -29,6 +29,7 @@ #include "absl/base/internal/raw_logging.h" #include "absl/base/thread_annotations.h" #include "absl/flags/commandlineflag.h" +#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/private_handle_accessor.h" #include "absl/flags/usage_config.h" #include "absl/strings/str_cat.h" diff --git a/absl/flags/internal/registry.h b/absl/flags/internal/registry.h index a118865a..d207c225 100644 --- a/absl/flags/internal/registry.h +++ b/absl/flags/internal/registry.h @@ -17,11 +17,9 @@ #define ABSL_FLAGS_INTERNAL_REGISTRY_H_ #include -#include -#include #include "absl/base/config.h" -#include "absl/base/macros.h" +#include "absl/flags/commandlineflag.h" #include "absl/flags/internal/commandlineflag.h" #include "absl/strings/string_view.h" @@ -30,8 +28,6 @@ namespace absl { ABSL_NAMESPACE_BEGIN -class CommandLineFlag; - namespace flags_internal { CommandLineFlag* FindCommandLineFlag(absl::string_view name); diff --git a/absl/flags/internal/type_erased.h b/absl/flags/internal/type_erased.h index fd9663e2..437a8c28 100644 --- a/absl/flags/internal/type_erased.h +++ b/absl/flags/internal/type_erased.h @@ -20,6 +20,7 @@ #include "absl/base/config.h" #include "absl/flags/commandlineflag.h" +#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/registry.h" #include "absl/strings/string_view.h" diff --git a/absl/flags/internal/type_erased_test.cc b/absl/flags/internal/type_erased_test.cc index bb0ff23e..42f374dc 100644 --- a/absl/flags/internal/type_erased_test.cc +++ b/absl/flags/internal/type_erased_test.cc @@ -20,8 +20,8 @@ #include "gtest/gtest.h" #include "absl/flags/flag.h" +#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/registry.h" -#include "absl/flags/marshalling.h" #include "absl/memory/memory.h" ABSL_FLAG(int, int_flag, 1, "int_flag help"); diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc index 2a2231a7..35b6427b 100644 --- a/absl/flags/internal/usage.cc +++ b/absl/flags/internal/usage.cc @@ -15,6 +15,8 @@ #include "absl/flags/internal/usage.h" +#include + #include #include #include diff --git a/absl/flags/internal/usage_test.cc b/absl/flags/internal/usage_test.cc index 8dd3532e..53b4d983 100644 --- a/absl/flags/internal/usage_test.cc +++ b/absl/flags/internal/usage_test.cc @@ -21,7 +21,6 @@ #include #include "gtest/gtest.h" -#include "absl/flags/declare.h" #include "absl/flags/flag.h" #include "absl/flags/internal/parse.h" #include "absl/flags/internal/path_util.h" @@ -29,7 +28,6 @@ #include "absl/flags/internal/registry.h" #include "absl/flags/usage.h" #include "absl/flags/usage_config.h" -#include "absl/memory/memory.h" #include "absl/strings/match.h" #include "absl/strings/string_view.h" diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc index 15300786..f0a131f2 100644 --- a/absl/flags/parse.cc +++ b/absl/flags/parse.cc @@ -37,6 +37,7 @@ #include "absl/flags/commandlineflag.h" #include "absl/flags/config.h" #include "absl/flags/flag.h" +#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/flag.h" #include "absl/flags/internal/parse.h" #include "absl/flags/internal/private_handle_accessor.h" diff --git a/absl/flags/parse.h b/absl/flags/parse.h index f37b0602..929de2cb 100644 --- a/absl/flags/parse.h +++ b/absl/flags/parse.h @@ -23,7 +23,6 @@ #ifndef ABSL_FLAGS_PARSE_H_ #define ABSL_FLAGS_PARSE_H_ -#include #include #include "absl/base/config.h" diff --git a/absl/flags/usage_config.cc b/absl/flags/usage_config.cc index 0d21bce6..ae2f548a 100644 --- a/absl/flags/usage_config.cc +++ b/absl/flags/usage_config.cc @@ -15,6 +15,7 @@ #include "absl/flags/usage_config.h" +#include #include #include diff --git a/absl/time/civil_time.cc b/absl/time/civil_time.cc index c4202c73..bdfe9ce0 100644 --- a/absl/time/civil_time.cc +++ b/absl/time/civil_time.cc @@ -98,26 +98,26 @@ bool ParseLenient(string_view s, CivilT* c) { } // namespace std::string FormatCivilTime(CivilSecond c) { - return FormatYearAnd("-%m-%dT%H:%M:%S", c); + return FormatYearAnd("-%m-%d%ET%H:%M:%S", c); } std::string FormatCivilTime(CivilMinute c) { - return FormatYearAnd("-%m-%dT%H:%M", c); + return FormatYearAnd("-%m-%d%ET%H:%M", c); } std::string FormatCivilTime(CivilHour c) { - return FormatYearAnd("-%m-%dT%H", c); + return FormatYearAnd("-%m-%d%ET%H", c); } std::string FormatCivilTime(CivilDay c) { return FormatYearAnd("-%m-%d", c); } std::string FormatCivilTime(CivilMonth c) { return FormatYearAnd("-%m", c); } std::string FormatCivilTime(CivilYear c) { return FormatYearAnd("", c); } bool ParseCivilTime(string_view s, CivilSecond* c) { - return ParseYearAnd("-%m-%dT%H:%M:%S", s, c); + return ParseYearAnd("-%m-%d%ET%H:%M:%S", s, c); } bool ParseCivilTime(string_view s, CivilMinute* c) { - return ParseYearAnd("-%m-%dT%H:%M", s, c); + return ParseYearAnd("-%m-%d%ET%H:%M", s, c); } bool ParseCivilTime(string_view s, CivilHour* c) { - return ParseYearAnd("-%m-%dT%H", s, c); + return ParseYearAnd("-%m-%d%ET%H", s, c); } bool ParseCivilTime(string_view s, CivilDay* c) { return ParseYearAnd("-%m-%d", s, c); diff --git a/absl/time/format.cc b/absl/time/format.cc index 228940ed..4005fb70 100644 --- a/absl/time/format.cc +++ b/absl/time/format.cc @@ -27,14 +27,11 @@ namespace cctz = absl::time_internal::cctz; namespace absl { ABSL_NAMESPACE_BEGIN -ABSL_DLL extern const char RFC3339_full[] = - "%Y-%m-%dT%H:%M:%E*S%Ez"; -ABSL_DLL extern const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez"; - -ABSL_DLL extern const char RFC1123_full[] = - "%a, %d %b %E4Y %H:%M:%S %z"; -ABSL_DLL extern const char RFC1123_no_wday[] = - "%d %b %E4Y %H:%M:%S %z"; +ABSL_DLL extern const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez"; +ABSL_DLL extern const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez"; + +ABSL_DLL extern const char RFC1123_full[] = "%a, %d %b %E4Y %H:%M:%S %z"; +ABSL_DLL extern const char RFC1123_no_wday[] = "%d %b %E4Y %H:%M:%S %z"; namespace { diff --git a/absl/time/format_benchmark.cc b/absl/time/format_benchmark.cc index 249c51d8..19e481db 100644 --- a/absl/time/format_benchmark.cc +++ b/absl/time/format_benchmark.cc @@ -26,7 +26,7 @@ const char* const kFormats[] = { absl::RFC1123_no_wday, // 1 absl::RFC3339_full, // 2 absl::RFC3339_sec, // 3 - "%Y-%m-%dT%H:%M:%S", // 4 + "%Y-%m-%d%ET%H:%M:%S", // 4 "%Y-%m-%d", // 5 }; const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]); diff --git a/absl/time/internal/cctz/include/cctz/time_zone.h b/absl/time/internal/cctz/include/cctz/time_zone.h index b33e0c0a..5562a37b 100644 --- a/absl/time/internal/cctz/include/cctz/time_zone.h +++ b/absl/time/internal/cctz/include/cctz/time_zone.h @@ -322,7 +322,8 @@ inline std::string format(const std::string& fmt, const time_point& tp, // returns the corresponding time_point. Uses strftime()-like formatting // options, with the same extensions as cctz::format(), but with the // exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez -// and %E*z also accept the same inputs. %ET accepts either 'T' or 't'. +// and %E*z also accept the same inputs, which (along with %z) includes +// 'z' and 'Z' as synonyms for +00:00. %ET accepts either 'T' or 't'. // // %Y consumes as many numeric characters as it can, so the matching data // should always be terminated with a non-numeric. %E4Y always consumes diff --git a/absl/time/time.h b/absl/time/time.h index b456a13e..37f6131d 100644 --- a/absl/time/time.h +++ b/absl/time/time.h @@ -1203,18 +1203,15 @@ struct tm ToTM(Time t, TimeZone tz); // time with UTC offset. Also note the use of "%Y": RFC3339 mandates that // years have exactly four digits, but we allow them to take their natural // width. -ABSL_DLL extern const char - RFC3339_full[]; // %Y-%m-%dT%H:%M:%E*S%Ez -ABSL_DLL extern const char RFC3339_sec[]; // %Y-%m-%dT%H:%M:%S%Ez +ABSL_DLL extern const char RFC3339_full[]; // %Y-%m-%d%ET%H:%M:%E*S%Ez +ABSL_DLL extern const char RFC3339_sec[]; // %Y-%m-%d%ET%H:%M:%S%Ez // RFC1123_full // RFC1123_no_wday // // FormatTime()/ParseTime() format specifiers for RFC1123 date/time strings. -ABSL_DLL extern const char - RFC1123_full[]; // %a, %d %b %E4Y %H:%M:%S %z -ABSL_DLL extern const char - RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z +ABSL_DLL extern const char RFC1123_full[]; // %a, %d %b %E4Y %H:%M:%S %z +ABSL_DLL extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z // FormatTime() // @@ -1229,6 +1226,7 @@ ABSL_DLL extern const char // - %E#f - Fractional seconds with # digits of precision // - %E*f - Fractional seconds with full precision (a literal '*') // - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999) +// - %ET - The RFC3339 "date-time" separator "T" // // Note that %E0S behaves like %S, and %E0f produces no characters. In // contrast %E*f always produces at least one digit, which may be '0'. @@ -1271,7 +1269,8 @@ inline std::ostream& operator<<(std::ostream& os, Time t) { // returns the corresponding `absl::Time`. Uses strftime()-like formatting // options, with the same extensions as FormatTime(), but with the // exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez -// and %E*z also accept the same inputs. +// and %E*z also accept the same inputs, which (along with %z) includes +// 'z' and 'Z' as synonyms for +00:00. %ET accepts either 'T' or 't'. // // %Y consumes as many numeric characters as it can, so the matching data // should always be terminated with a non-numeric. %E4Y always consumes -- cgit v1.2.3 From 4b2fbb4adba905eede6c61b4494acfdb660a3bb7 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 12 Oct 2020 10:33:47 -0700 Subject: Export of internal Abseil changes -- a5af5874c1c5cc02bd2a748d455321f82b6f2a93 by Andy Getzendanner : fix compile fails with asan and -Wredundant-decls Import of https://github.com/abseil/abseil-cpp/pull/801 PiperOrigin-RevId: 336693223 -- ed9df42ab2b742386c6692c2bed015374c919d9c by Derek Mauro : Fix integer conversion warning Fixes #814 PiperOrigin-RevId: 336651814 -- 0ab4c23884e72dce17b67c1eb520f9dbb802565d by Derek Mauro : Internal change PiperOrigin-RevId: 336585378 -- eba0e3dccd52a6e91bcff84075bef0affc650b74 by Matt Kulukundis : Add bitset operations to Futex helper. PiperOrigin-RevId: 336409368 -- 8b0709a8b4500bf5f0af4b602d76a298d81645e8 by Abseil Team : Fix code indentation in a comment. PiperOrigin-RevId: 336368167 -- bc3961c87a7e7760c10319a5b0349c279f7ae3ad by Samuel Benzaquen : Improve performance of the registry: - Reduce contention - Reduce memory usage for each flag by `6*sizeof(void*)`. - Replace one immortal allocation per-flag with a single one for all the flags - Slightly improve single-threaded performance by avoiding the std::map indirections. PiperOrigin-RevId: 336365904 -- 264ad9f28f935aad8b6b1437f8bf804fa9104346 by Abseil Team : Fix typo in comment on absl::Condition. PiperOrigin-RevId: 336311680 -- b5b808a8c75ca0df7b09eff9a423ec171d80f771 by Derek Mauro : Add missing Apache license headers PiperOrigin-RevId: 336294980 -- 89446c3a4793df8b95060385cf3e219357c3db1d by Andy Soffer : Internal changes PiperOrigin-RevId: 336287465 -- 57c8be4e294881bc79a6a44b8e4bf7ecbb19b9b9 by Matt Kulukundis : Extract Futex from an implementation detail of Wait to a private interface. PiperOrigin-RevId: 336123209 GitOrigin-RevId: a5af5874c1c5cc02bd2a748d455321f82b6f2a93 Change-Id: Ie5a0ebe28e571814e3e11d4c05ca308523ccf311 --- CMake/AbseilDll.cmake | 1 + absl/algorithm/container.h | 2 +- absl/base/internal/unscaledcycleclock.cc | 4 +- absl/container/internal/layout_test.cc | 560 ++++++++++++--------- absl/container/internal/raw_hash_set_test.cc | 7 +- absl/debugging/internal/symbolize.h | 8 +- absl/flags/BUILD.bazel | 2 + absl/flags/flag_benchmark.cc | 33 ++ absl/flags/internal/registry.h | 5 +- absl/flags/parse.cc | 5 + absl/flags/reflection.cc | 68 ++- absl/hash/hash_test.cc | 8 +- absl/hash/internal/city.cc | 18 +- absl/hash/internal/city.h | 2 +- absl/random/internal/generate_real_test.cc | 4 +- absl/strings/cord_test.cc | 14 + absl/strings/internal/str_format/arg.cc | 14 + absl/strings/internal/str_format/arg.h | 14 + absl/strings/internal/str_format/bind.cc | 14 + absl/strings/internal/str_format/bind.h | 14 + absl/strings/internal/str_format/bind_test.cc | 14 + absl/strings/internal/str_format/checker.h | 14 + absl/strings/internal/str_format/checker_test.cc | 14 + absl/strings/internal/str_format/convert_test.cc | 14 + .../internal/str_format/float_conversion.cc | 14 + .../strings/internal/str_format/float_conversion.h | 14 + absl/strings/internal/str_format/parser.cc | 14 + absl/strings/internal/str_format/parser.h | 14 + absl/strings/internal/str_format/parser_test.cc | 14 + absl/strings/str_format_test.cc | 13 + absl/synchronization/BUILD.bazel | 1 + absl/synchronization/CMakeLists.txt | 1 + absl/synchronization/internal/futex.h | 139 +++++ absl/synchronization/internal/kernel_timeout.h | 3 +- absl/synchronization/internal/waiter.cc | 70 +-- absl/synchronization/mutex.cc | 9 +- absl/synchronization/mutex.h | 10 +- absl/time/clock.cc | 4 +- absl/time/duration.cc | 2 +- absl/time/time.cc | 7 +- absl/time/time.h | 12 +- absl/time/time_test.cc | 12 +- absl/types/internal/variant.h | 2 +- absl/types/variant_test.cc | 6 +- 44 files changed, 817 insertions(+), 397 deletions(-) create mode 100644 absl/synchronization/internal/futex.h (limited to 'absl/flags/flag_benchmark.cc') diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index cf6a8c9a..d67c4399 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -250,6 +250,7 @@ set(ABSL_INTERNAL_DLL_FILES "synchronization/notification.h" "synchronization/internal/create_thread_identity.cc" "synchronization/internal/create_thread_identity.h" + "synchronization/internal/futex.h" "synchronization/internal/graphcycles.cc" "synchronization/internal/graphcycles.h" "synchronization/internal/kernel_timeout.h" diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h index bb3d1c7c..09b91f74 100644 --- a/absl/algorithm/container.h +++ b/absl/algorithm/container.h @@ -93,7 +93,7 @@ using ContainerPointerType = // std::foo(begin(c), end(c)); // becomes // std::foo(container_algorithm_internal::begin(c), -// container_algorithm_internal::end(c)); +// container_algorithm_internal::end(c)); // These are meant for internal use only. template diff --git a/absl/base/internal/unscaledcycleclock.cc b/absl/base/internal/unscaledcycleclock.cc index f1e7bbef..1545288c 100644 --- a/absl/base/internal/unscaledcycleclock.cc +++ b/absl/base/internal/unscaledcycleclock.cc @@ -123,9 +123,7 @@ double UnscaledCycleClock::Frequency() { #pragma intrinsic(__rdtsc) -int64_t UnscaledCycleClock::Now() { - return __rdtsc(); -} +int64_t UnscaledCycleClock::Now() { return __rdtsc(); } double UnscaledCycleClock::Frequency() { return base_internal::NominalCPUFrequency(); diff --git a/absl/container/internal/layout_test.cc b/absl/container/internal/layout_test.cc index 757272f1..1d7158ff 100644 --- a/absl/container/internal/layout_test.cc +++ b/absl/container/internal/layout_test.cc @@ -128,8 +128,10 @@ TEST(Layout, ElementTypes) { { using L = Layout; SameType, L::ElementTypes>(); - SameType, decltype(L::Partial())::ElementTypes>(); - SameType, decltype(L::Partial(0))::ElementTypes>(); + SameType, + decltype(L::Partial())::ElementTypes>(); + SameType, + decltype(L::Partial(0))::ElementTypes>(); } { using L = Layout; @@ -368,18 +370,21 @@ TEST(Layout, PointerByIndex) { { using L = Layout; EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(3).Pointer<0>(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(3).Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type(L(3).Pointer<0>(p)))); } { using L = Layout; EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(3).Pointer<0>(p)))); - EXPECT_EQ(12, Distance(p, Type(L::Partial(3).Pointer<1>(p)))); EXPECT_EQ(0, - Distance(p, Type(L::Partial(3, 5).Pointer<0>(p)))); + Distance(p, Type(L::Partial(3).Pointer<0>(p)))); EXPECT_EQ(12, - Distance(p, Type(L::Partial(3, 5).Pointer<1>(p)))); + Distance(p, Type(L::Partial(3).Pointer<1>(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial(3, 5).Pointer<0>(p)))); + EXPECT_EQ( + 12, Distance(p, Type(L::Partial(3, 5).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L(3, 5).Pointer<0>(p)))); EXPECT_EQ(12, Distance(p, Type(L(3, 5).Pointer<1>(p)))); } @@ -387,39 +392,44 @@ TEST(Layout, PointerByIndex) { using L = Layout; EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(0).Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0).Pointer<1>(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(0).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(1).Pointer<0>(p)))); - EXPECT_EQ(4, Distance(p, Type(L::Partial(1).Pointer<1>(p)))); + EXPECT_EQ(4, + Distance(p, Type(L::Partial(1).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(5).Pointer<0>(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(5).Pointer<1>(p)))); + EXPECT_EQ(8, + Distance(p, Type(L::Partial(5).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0).Pointer<0>(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0, 0).Pointer<1>(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial(0, 0).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0).Pointer<2>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(1, 0).Pointer<0>(p)))); - EXPECT_EQ(4, - Distance(p, Type(L::Partial(1, 0).Pointer<1>(p)))); + EXPECT_EQ( + 4, Distance(p, Type(L::Partial(1, 0).Pointer<1>(p)))); EXPECT_EQ(8, Distance(p, Type(L::Partial(1, 0).Pointer<2>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(5, 3).Pointer<0>(p)))); - EXPECT_EQ(8, - Distance(p, Type(L::Partial(5, 3).Pointer<1>(p)))); + EXPECT_EQ( + 8, Distance(p, Type(L::Partial(5, 3).Pointer<1>(p)))); EXPECT_EQ(24, Distance(p, Type(L::Partial(5, 3).Pointer<2>(p)))); EXPECT_EQ( 0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<0>(p)))); EXPECT_EQ( - 0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<1>(p)))); + 0, + Distance(p, Type(L::Partial(0, 0, 0).Pointer<1>(p)))); EXPECT_EQ( 0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<2>(p)))); EXPECT_EQ( 0, Distance(p, Type(L::Partial(1, 0, 0).Pointer<0>(p)))); EXPECT_EQ( - 4, Distance(p, Type(L::Partial(1, 0, 0).Pointer<1>(p)))); + 4, + Distance(p, Type(L::Partial(1, 0, 0).Pointer<1>(p)))); EXPECT_EQ( 8, Distance(p, Type(L::Partial(1, 0, 0).Pointer<2>(p)))); EXPECT_EQ( @@ -428,7 +438,8 @@ TEST(Layout, PointerByIndex) { 24, Distance(p, Type(L::Partial(5, 3, 1).Pointer<2>(p)))); EXPECT_EQ( - 8, Distance(p, Type(L::Partial(5, 3, 1).Pointer<1>(p)))); + 8, + Distance(p, Type(L::Partial(5, 3, 1).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L(5, 3, 1).Pointer<0>(p)))); EXPECT_EQ(24, Distance(p, Type(L(5, 3, 1).Pointer<2>(p)))); EXPECT_EQ(8, Distance(p, Type(L(5, 3, 1).Pointer<1>(p)))); @@ -439,75 +450,78 @@ TEST(Layout, PointerByType) { alignas(max_align_t) const unsigned char p[100] = {}; { using L = Layout; - EXPECT_EQ(0, - Distance(p, Type(L::Partial().Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(3).Pointer(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial().Pointer(p)))); + EXPECT_EQ( + 0, + Distance(p, Type(L::Partial(3).Pointer(p)))); EXPECT_EQ(0, Distance(p, Type(L(3).Pointer(p)))); } { using L = Layout; - EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(1).Pointer(p)))); - EXPECT_EQ(4, - Distance(p, Type(L::Partial(1).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(5).Pointer(p)))); - EXPECT_EQ(8, - Distance(p, Type(L::Partial(5).Pointer(p)))); EXPECT_EQ( - 0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); + 0, Distance(p, Type(L::Partial().Pointer(p)))); EXPECT_EQ( - 0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); + 0, Distance(p, Type(L::Partial(0).Pointer(p)))); EXPECT_EQ( 0, - Distance(p, Type(L::Partial(0, 0).Pointer(p)))); - EXPECT_EQ( - 0, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); + Distance(p, Type(L::Partial(0).Pointer(p)))); EXPECT_EQ( - 4, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); + 0, Distance(p, Type(L::Partial(1).Pointer(p)))); EXPECT_EQ( - 8, - Distance(p, Type(L::Partial(1, 0).Pointer(p)))); + 4, + Distance(p, Type(L::Partial(1).Pointer(p)))); EXPECT_EQ( - 0, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); + 0, Distance(p, Type(L::Partial(5).Pointer(p)))); EXPECT_EQ( - 8, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); + 8, + Distance(p, Type(L::Partial(5).Pointer(p)))); EXPECT_EQ( - 24, - Distance(p, Type(L::Partial(5, 3).Pointer(p)))); + 0, + Distance(p, Type(L::Partial(0, 0).Pointer(p)))); + EXPECT_EQ(0, Distance(p, Type( + L::Partial(0, 0).Pointer(p)))); EXPECT_EQ( 0, - Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); + Distance(p, Type(L::Partial(0, 0).Pointer(p)))); EXPECT_EQ( 0, - Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type( - L::Partial(0, 0, 0).Pointer(p)))); + Distance(p, Type(L::Partial(1, 0).Pointer(p)))); + EXPECT_EQ(4, Distance(p, Type( + L::Partial(1, 0).Pointer(p)))); + EXPECT_EQ( + 8, + Distance(p, Type(L::Partial(1, 0).Pointer(p)))); EXPECT_EQ( 0, - Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); + Distance(p, Type(L::Partial(5, 3).Pointer(p)))); + EXPECT_EQ(8, Distance(p, Type( + L::Partial(5, 3).Pointer(p)))); EXPECT_EQ( - 4, - Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); + 24, + Distance(p, Type(L::Partial(5, 3).Pointer(p)))); + EXPECT_EQ(0, Distance(p, Type( + L::Partial(0, 0, 0).Pointer(p)))); + EXPECT_EQ(0, Distance(p, Type( + L::Partial(0, 0, 0).Pointer(p)))); + EXPECT_EQ(0, Distance(p, Type( + L::Partial(0, 0, 0).Pointer(p)))); + EXPECT_EQ(0, Distance(p, Type( + L::Partial(1, 0, 0).Pointer(p)))); + EXPECT_EQ(4, Distance(p, Type( + L::Partial(1, 0, 0).Pointer(p)))); EXPECT_EQ(8, Distance(p, Type( L::Partial(1, 0, 0).Pointer(p)))); - EXPECT_EQ( - 0, - Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); + EXPECT_EQ(0, Distance(p, Type( + L::Partial(5, 3, 1).Pointer(p)))); EXPECT_EQ(24, Distance(p, Type( L::Partial(5, 3, 1).Pointer(p)))); - EXPECT_EQ( - 8, - Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); + EXPECT_EQ(8, Distance(p, Type( + L::Partial(5, 3, 1).Pointer(p)))); EXPECT_EQ(24, Distance(p, Type(L(5, 3, 1).Pointer(p)))); - EXPECT_EQ(8, Distance(p, Type(L(5, 3, 1).Pointer(p)))); + EXPECT_EQ( + 8, Distance(p, Type(L(5, 3, 1).Pointer(p)))); } } @@ -548,15 +562,18 @@ TEST(Layout, MutablePointerByIndex) { EXPECT_EQ(8, Distance(p, Type(L::Partial(5, 3).Pointer<1>(p)))); EXPECT_EQ(24, Distance(p, Type(L::Partial(5, 3).Pointer<2>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<1>(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(0, 0, 0).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<2>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(1, 0, 0).Pointer<0>(p)))); - EXPECT_EQ(4, Distance(p, Type(L::Partial(1, 0, 0).Pointer<1>(p)))); + EXPECT_EQ(4, + Distance(p, Type(L::Partial(1, 0, 0).Pointer<1>(p)))); EXPECT_EQ(8, Distance(p, Type(L::Partial(1, 0, 0).Pointer<2>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(5, 3, 1).Pointer<0>(p)))); EXPECT_EQ(24, Distance(p, Type(L::Partial(5, 3, 1).Pointer<2>(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(5, 3, 1).Pointer<1>(p)))); + EXPECT_EQ(8, + Distance(p, Type(L::Partial(5, 3, 1).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L(5, 3, 1).Pointer<0>(p)))); EXPECT_EQ(24, Distance(p, Type(L(5, 3, 1).Pointer<2>(p)))); EXPECT_EQ(8, Distance(p, Type(L(5, 3, 1).Pointer<1>(p)))); @@ -568,48 +585,61 @@ TEST(Layout, MutablePointerByType) { { using L = Layout; EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(3).Pointer(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(3).Pointer(p)))); EXPECT_EQ(0, Distance(p, Type(L(3).Pointer(p)))); } { using L = Layout; EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(0).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0).Pointer(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(0).Pointer(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(1).Pointer(p)))); - EXPECT_EQ(4, Distance(p, Type(L::Partial(1).Pointer(p)))); + EXPECT_EQ(4, + Distance(p, Type(L::Partial(1).Pointer(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(5).Pointer(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(5).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); + EXPECT_EQ(8, + Distance(p, Type(L::Partial(5).Pointer(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(0, 0).Pointer(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); - EXPECT_EQ(4, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(1, 0).Pointer(p)))); + EXPECT_EQ( + 4, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); EXPECT_EQ(8, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(5, 3).Pointer(p)))); + EXPECT_EQ( + 8, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); EXPECT_EQ(24, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); + EXPECT_EQ( + 0, + Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); EXPECT_EQ( 0, Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); - EXPECT_EQ(4, - Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); + EXPECT_EQ( + 4, + Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); EXPECT_EQ( 8, Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); EXPECT_EQ( 24, Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); - EXPECT_EQ(8, - Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); + EXPECT_EQ( + 8, + Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); EXPECT_EQ(0, Distance(p, Type(L(5, 3, 1).Pointer(p)))); EXPECT_EQ(24, Distance(p, Type(L(5, 3, 1).Pointer(p)))); EXPECT_EQ(8, Distance(p, Type(L(5, 3, 1).Pointer(p)))); @@ -790,67 +820,72 @@ TEST(Layout, SliceByIndexData) { { using L = Layout; EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); + 0, Distance( + p, Type>(L::Partial(0).Slice<0>(p)).data())); EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); - EXPECT_EQ(0, Distance(p, Type>(L(3).Slice<0>(p)).data())); + 0, Distance( + p, Type>(L::Partial(3).Slice<0>(p)).data())); + EXPECT_EQ(0, + Distance(p, Type>(L(3).Slice<0>(p)).data())); } { using L = Layout; EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); + 0, Distance( + p, Type>(L::Partial(3).Slice<0>(p)).data())); EXPECT_EQ( 0, - Distance(p, - Type>(L::Partial(3, 5).Slice<0>(p)).data())); + Distance( + p, Type>(L::Partial(3, 5).Slice<0>(p)).data())); EXPECT_EQ( 12, - Distance(p, - Type>(L::Partial(3, 5).Slice<1>(p)).data())); - EXPECT_EQ(0, - Distance(p, Type>(L(3, 5).Slice<0>(p)).data())); - EXPECT_EQ(12, - Distance(p, Type>(L(3, 5).Slice<1>(p)).data())); + Distance( + p, Type>(L::Partial(3, 5).Slice<1>(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type>(L(3, 5).Slice<0>(p)).data())); + EXPECT_EQ( + 12, Distance(p, Type>(L(3, 5).Slice<1>(p)).data())); } { using L = Layout; EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(1).Slice<0>(p)).data())); + 0, Distance( + p, Type>(L::Partial(0).Slice<0>(p)).data())); EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(5).Slice<0>(p)).data())); + 0, Distance( + p, Type>(L::Partial(1).Slice<0>(p)).data())); EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(0, 0).Slice<0>(p)).data())); + p, Type>(L::Partial(5).Slice<0>(p)).data())); EXPECT_EQ( 0, - Distance(p, - Type>(L::Partial(0, 0).Slice<1>(p)).data())); + Distance( + p, Type>(L::Partial(0, 0).Slice<0>(p)).data())); EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(1, 0).Slice<0>(p)).data())); + 0, + Distance( + p, Type>(L::Partial(0, 0).Slice<1>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, Type>(L::Partial(1, 0).Slice<0>(p)).data())); EXPECT_EQ( 4, - Distance(p, - Type>(L::Partial(1, 0).Slice<1>(p)).data())); + Distance( + p, Type>(L::Partial(1, 0).Slice<1>(p)).data())); EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(5, 3).Slice<0>(p)).data())); + 0, + Distance( + p, Type>(L::Partial(5, 3).Slice<0>(p)).data())); EXPECT_EQ( 8, - Distance(p, - Type>(L::Partial(5, 3).Slice<1>(p)).data())); + Distance( + p, Type>(L::Partial(5, 3).Slice<1>(p)).data())); EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(0, 0, 0).Slice<0>(p)).data())); + p, + Type>(L::Partial(0, 0, 0).Slice<0>(p)).data())); EXPECT_EQ( 0, Distance( @@ -864,7 +899,8 @@ TEST(Layout, SliceByIndexData) { EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(1, 0, 0).Slice<0>(p)).data())); + p, + Type>(L::Partial(1, 0, 0).Slice<0>(p)).data())); EXPECT_EQ( 4, Distance( @@ -878,7 +914,8 @@ TEST(Layout, SliceByIndexData) { EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(5, 3, 1).Slice<0>(p)).data())); + p, + Type>(L::Partial(5, 3, 1).Slice<0>(p)).data())); EXPECT_EQ( 24, Distance( @@ -890,12 +927,14 @@ TEST(Layout, SliceByIndexData) { p, Type>(L::Partial(5, 3, 1).Slice<1>(p)).data())); EXPECT_EQ( - 0, Distance(p, Type>(L(5, 3, 1).Slice<0>(p)).data())); + 0, + Distance(p, Type>(L(5, 3, 1).Slice<0>(p)).data())); EXPECT_EQ( 24, Distance(p, Type>(L(5, 3, 1).Slice<2>(p)).data())); EXPECT_EQ( - 8, Distance(p, Type>(L(5, 3, 1).Slice<1>(p)).data())); + 8, + Distance(p, Type>(L(5, 3, 1).Slice<1>(p)).data())); } } @@ -906,98 +945,94 @@ TEST(Layout, SliceByTypeData) { EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(0).Slice(p)).data())); + p, + Type>(L::Partial(0).Slice(p)).data())); EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(3).Slice(p)).data())); + p, + Type>(L::Partial(3).Slice(p)).data())); EXPECT_EQ( - 0, Distance(p, Type>(L(3).Slice(p)).data())); + 0, + Distance(p, Type>(L(3).Slice(p)).data())); } { using L = Layout; - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(0).Slice(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(1).Slice(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(5).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, Type>(L::Partial(0, 0).Slice(p)).data())); EXPECT_EQ( 0, Distance( p, - Type>(L::Partial(0, 0).Slice(p)).data())); + Type>(L::Partial(0).Slice(p)).data())); EXPECT_EQ( 0, - Distance( - p, Type>(L::Partial(1, 0).Slice(p)).data())); - EXPECT_EQ( - 4, Distance( p, - Type>(L::Partial(1, 0).Slice(p)).data())); + Type>(L::Partial(1).Slice(p)).data())); EXPECT_EQ( 0, - Distance( - p, Type>(L::Partial(5, 3).Slice(p)).data())); - EXPECT_EQ( - 8, Distance( p, - Type>(L::Partial(5, 3).Slice(p)).data())); + Type>(L::Partial(5).Slice(p)).data())); EXPECT_EQ( 0, - Distance( - p, - Type>(L::Partial(0, 0, 0).Slice(p)).data())); + Distance(p, Type>(L::Partial(0, 0).Slice(p)) + .data())); + EXPECT_EQ(0, Distance(p, Type>( + L::Partial(0, 0).Slice(p)) + .data())); EXPECT_EQ( 0, - Distance(p, Type>(L::Partial(0, 0, 0).Slice(p)) + Distance(p, Type>(L::Partial(1, 0).Slice(p)) .data())); - EXPECT_EQ(0, Distance(p, Type>( - L::Partial(0, 0, 0).Slice(p)) + EXPECT_EQ(4, Distance(p, Type>( + L::Partial(1, 0).Slice(p)) .data())); EXPECT_EQ( 0, - Distance( - p, - Type>(L::Partial(1, 0, 0).Slice(p)).data())); - EXPECT_EQ( - 4, - Distance(p, Type>(L::Partial(1, 0, 0).Slice(p)) + Distance(p, Type>(L::Partial(5, 3).Slice(p)) .data())); + EXPECT_EQ(8, Distance(p, Type>( + L::Partial(5, 3).Slice(p)) + .data())); + EXPECT_EQ(0, Distance(p, Type>( + L::Partial(0, 0, 0).Slice(p)) + .data())); + EXPECT_EQ(0, Distance(p, Type>( + L::Partial(0, 0, 0).Slice(p)) + .data())); + EXPECT_EQ(0, Distance(p, Type>( + L::Partial(0, 0, 0).Slice(p)) + .data())); + EXPECT_EQ(0, Distance(p, Type>( + L::Partial(1, 0, 0).Slice(p)) + .data())); + EXPECT_EQ(4, Distance(p, Type>( + L::Partial(1, 0, 0).Slice(p)) + .data())); EXPECT_EQ(8, Distance(p, Type>( L::Partial(1, 0, 0).Slice(p)) .data())); - EXPECT_EQ( - 0, - Distance( - p, - Type>(L::Partial(5, 3, 1).Slice(p)).data())); + EXPECT_EQ(0, Distance(p, Type>( + L::Partial(5, 3, 1).Slice(p)) + .data())); EXPECT_EQ(24, Distance(p, Type>( L::Partial(5, 3, 1).Slice(p)) .data())); - EXPECT_EQ( - 8, - Distance(p, Type>(L::Partial(5, 3, 1).Slice(p)) - .data())); + EXPECT_EQ(8, Distance(p, Type>( + L::Partial(5, 3, 1).Slice(p)) + .data())); EXPECT_EQ( 0, - Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); + Distance(p, + Type>(L(5, 3, 1).Slice(p)).data())); EXPECT_EQ( 24, Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); EXPECT_EQ( - 8, Distance( - p, Type>(L(5, 3, 1).Slice(p)).data())); + 8, + Distance( + p, Type>(L(5, 3, 1).Slice(p)).data())); } } @@ -1005,18 +1040,19 @@ TEST(Layout, MutableSliceByIndexData) { alignas(max_align_t) unsigned char p[100]; { using L = Layout; - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); EXPECT_EQ(0, Distance(p, Type>(L(3).Slice<0>(p)).data())); } { using L = Layout; - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(3, 5).Slice<0>(p)).data())); + 0, Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type>(L::Partial(3, 5).Slice<0>(p)).data())); EXPECT_EQ( 12, Distance(p, Type>(L::Partial(3, 5).Slice<1>(p)).data())); @@ -1025,55 +1061,63 @@ TEST(Layout, MutableSliceByIndexData) { } { using L = Layout; - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(1).Slice<0>(p)).data())); - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(5).Slice<0>(p)).data())); - EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(0, 0).Slice<0>(p)).data())); EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(0, 0).Slice<1>(p)).data())); + 0, Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(1, 0).Slice<0>(p)).data())); + 0, Distance(p, Type>(L::Partial(1).Slice<0>(p)).data())); EXPECT_EQ( - 4, Distance(p, Type>(L::Partial(1, 0).Slice<1>(p)).data())); + 0, Distance(p, Type>(L::Partial(5).Slice<0>(p)).data())); EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(5, 3).Slice<0>(p)).data())); + 0, + Distance(p, Type>(L::Partial(0, 0).Slice<0>(p)).data())); EXPECT_EQ( - 8, Distance(p, Type>(L::Partial(5, 3).Slice<1>(p)).data())); + 0, + Distance(p, Type>(L::Partial(0, 0).Slice<1>(p)).data())); EXPECT_EQ( 0, - Distance(p, Type>(L::Partial(0, 0, 0).Slice<0>(p)).data())); + Distance(p, Type>(L::Partial(1, 0).Slice<0>(p)).data())); + EXPECT_EQ( + 4, + Distance(p, Type>(L::Partial(1, 0).Slice<1>(p)).data())); EXPECT_EQ( 0, - Distance(p, Type>(L::Partial(0, 0, 0).Slice<1>(p)).data())); + Distance(p, Type>(L::Partial(5, 3).Slice<0>(p)).data())); + EXPECT_EQ( + 8, + Distance(p, Type>(L::Partial(5, 3).Slice<1>(p)).data())); + EXPECT_EQ( + 0, Distance( + p, Type>(L::Partial(0, 0, 0).Slice<0>(p)).data())); + EXPECT_EQ( + 0, Distance( + p, Type>(L::Partial(0, 0, 0).Slice<1>(p)).data())); EXPECT_EQ( 0, Distance( p, Type>(L::Partial(0, 0, 0).Slice<2>(p)).data())); EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(1, 0, 0).Slice<0>(p)).data())); + 0, Distance( + p, Type>(L::Partial(1, 0, 0).Slice<0>(p)).data())); EXPECT_EQ( - 4, - Distance(p, Type>(L::Partial(1, 0, 0).Slice<1>(p)).data())); + 4, Distance( + p, Type>(L::Partial(1, 0, 0).Slice<1>(p)).data())); EXPECT_EQ( 8, Distance( p, Type>(L::Partial(1, 0, 0).Slice<2>(p)).data())); EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(5, 3, 1).Slice<0>(p)).data())); + 0, Distance( + p, Type>(L::Partial(5, 3, 1).Slice<0>(p)).data())); EXPECT_EQ( 24, Distance( p, Type>(L::Partial(5, 3, 1).Slice<2>(p)).data())); EXPECT_EQ( - 8, - Distance(p, Type>(L::Partial(5, 3, 1).Slice<1>(p)).data())); - EXPECT_EQ(0, Distance(p, Type>(L(5, 3, 1).Slice<0>(p)).data())); + 8, Distance( + p, Type>(L::Partial(5, 3, 1).Slice<1>(p)).data())); + EXPECT_EQ(0, + Distance(p, Type>(L(5, 3, 1).Slice<0>(p)).data())); EXPECT_EQ(24, Distance(p, Type>(L(5, 3, 1).Slice<2>(p)).data())); - EXPECT_EQ(8, Distance(p, Type>(L(5, 3, 1).Slice<1>(p)).data())); + EXPECT_EQ(8, + Distance(p, Type>(L(5, 3, 1).Slice<1>(p)).data())); } } @@ -1082,66 +1126,84 @@ TEST(Layout, MutableSliceByTypeData) { { using L = Layout; EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(0).Slice(p)).data())); + 0, Distance( + p, Type>(L::Partial(0).Slice(p)).data())); EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(3).Slice(p)).data())); - EXPECT_EQ(0, Distance(p, Type>(L(3).Slice(p)).data())); + 0, Distance( + p, Type>(L::Partial(3).Slice(p)).data())); + EXPECT_EQ(0, + Distance(p, Type>(L(3).Slice(p)).data())); } { using L = Layout; EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(0).Slice(p)).data())); + 0, + Distance(p, Type>(L::Partial(0).Slice(p)).data())); EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(1).Slice(p)).data())); + 0, + Distance(p, Type>(L::Partial(1).Slice(p)).data())); EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(5).Slice(p)).data())); + 0, + Distance(p, Type>(L::Partial(5).Slice(p)).data())); EXPECT_EQ( 0, - Distance(p, Type>(L::Partial(0, 0).Slice(p)).data())); + Distance(p, + Type>(L::Partial(0, 0).Slice(p)).data())); EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(0, 0).Slice(p)).data())); + 0, + Distance( + p, Type>(L::Partial(0, 0).Slice(p)).data())); EXPECT_EQ( 0, - Distance(p, Type>(L::Partial(1, 0).Slice(p)).data())); + Distance(p, + Type>(L::Partial(1, 0).Slice(p)).data())); EXPECT_EQ( - 4, Distance( - p, Type>(L::Partial(1, 0).Slice(p)).data())); + 4, + Distance( + p, Type>(L::Partial(1, 0).Slice(p)).data())); EXPECT_EQ( 0, - Distance(p, Type>(L::Partial(5, 3).Slice(p)).data())); + Distance(p, + Type>(L::Partial(5, 3).Slice(p)).data())); EXPECT_EQ( - 8, Distance( - p, Type>(L::Partial(5, 3).Slice(p)).data())); + 8, + Distance( + p, Type>(L::Partial(5, 3).Slice(p)).data())); EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(0, 0, 0).Slice(p)).data())); + 0, + Distance( + p, + Type>(L::Partial(0, 0, 0).Slice(p)).data())); EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(0, 0, 0).Slice(p)).data())); + p, + Type>(L::Partial(0, 0, 0).Slice(p)).data())); EXPECT_EQ( 0, Distance( p, Type>(L::Partial(0, 0, 0).Slice(p)).data())); EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(1, 0, 0).Slice(p)).data())); + 0, + Distance( + p, + Type>(L::Partial(1, 0, 0).Slice(p)).data())); EXPECT_EQ( 4, Distance( - p, Type>(L::Partial(1, 0, 0).Slice(p)).data())); + p, + Type>(L::Partial(1, 0, 0).Slice(p)).data())); EXPECT_EQ( 8, Distance( p, Type>(L::Partial(1, 0, 0).Slice(p)).data())); EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(5, 3, 1).Slice(p)).data())); + 0, + Distance( + p, + Type>(L::Partial(5, 3, 1).Slice(p)).data())); EXPECT_EQ( 24, Distance( @@ -1150,14 +1212,16 @@ TEST(Layout, MutableSliceByTypeData) { EXPECT_EQ( 8, Distance( - p, Type>(L::Partial(5, 3, 1).Slice(p)).data())); - EXPECT_EQ(0, - Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); + p, + Type>(L::Partial(5, 3, 1).Slice(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); EXPECT_EQ( 24, Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); EXPECT_EQ( - 8, Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); + 8, + Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); } } @@ -1256,17 +1320,17 @@ TEST(Layout, MutableSlices) { } { const auto x = L::Partial(1, 2, 3); - EXPECT_THAT( - (Type, Span, Span>>(x.Slices(p))), - Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), - IsSameSlice(x.Slice<2>(p)))); + EXPECT_THAT((Type, Span, Span>>( + x.Slices(p))), + Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), + IsSameSlice(x.Slice<2>(p)))); } { const L x(1, 2, 3); - EXPECT_THAT( - (Type, Span, Span>>(x.Slices(p))), - Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), - IsSameSlice(x.Slice<2>(p)))); + EXPECT_THAT((Type, Span, Span>>( + x.Slices(p))), + Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), + IsSameSlice(x.Slice<2>(p)))); } } @@ -1398,7 +1462,8 @@ TEST(Layout, DebugString) { x.DebugString()); } { - constexpr auto x = Layout::Partial(1, 2, 3); + constexpr auto x = + Layout::Partial(1, 2, 3); EXPECT_EQ( "@0(1)[1]; @4(4)[2]; @12(1)[3]; " "@16" + @@ -1406,7 +1471,8 @@ TEST(Layout, DebugString) { x.DebugString()); } { - constexpr auto x = Layout::Partial(1, 2, 3, 4); + constexpr auto x = + Layout::Partial(1, 2, 3, 4); EXPECT_EQ( "@0(1)[1]; @4(4)[2]; @12(1)[3]; " "@16" + diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index f5ae83c4..6210eb64 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc @@ -847,7 +847,8 @@ TEST(Table, EraseMaintainsValidIterator) { std::vector CollectBadMergeKeys(size_t N) { static constexpr int kGroupSize = Group::kWidth - 1; - auto topk_range = [](size_t b, size_t e, IntTable* t) -> std::vector { + auto topk_range = [](size_t b, size_t e, + IntTable* t) -> std::vector { for (size_t i = b; i != e; ++i) { t->emplace(i); } @@ -1001,8 +1002,8 @@ using ProbeStatsPerSize = std::map; // 1. Create new table and reserve it to keys.size() * 2 // 2. Insert all keys xored with seed // 3. Collect ProbeStats from final table. -ProbeStats CollectProbeStatsOnKeysXoredWithSeed(const std::vector& keys, - size_t num_iters) { +ProbeStats CollectProbeStatsOnKeysXoredWithSeed( + const std::vector& keys, size_t num_iters) { const size_t reserve_size = keys.size() * 2; ProbeStats stats; diff --git a/absl/debugging/internal/symbolize.h b/absl/debugging/internal/symbolize.h index b3729af7..4f26130f 100644 --- a/absl/debugging/internal/symbolize.h +++ b/absl/debugging/internal/symbolize.h @@ -118,16 +118,14 @@ bool RemoveAllSymbolDecorators(void); // filename != nullptr // // Returns true if the file was successfully registered. -bool RegisterFileMappingHint( - const void* start, const void* end, uint64_t offset, const char* filename); +bool RegisterFileMappingHint(const void* start, const void* end, + uint64_t offset, const char* filename); // Looks up the file mapping registered by RegisterFileMappingHint for an // address range. If there is one, the file name is stored in *filename and // *start and *end are modified to reflect the registered mapping. Returns // whether any hint was found. -bool GetFileMappingHint(const void** start, - const void** end, - uint64_t * offset, +bool GetFileMappingHint(const void** start, const void** end, uint64_t* offset, const char** filename); } // namespace debugging_internal diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index 9de9e223..2bd94780 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -381,6 +381,8 @@ cc_binary( deps = [ ":flag", ":marshalling", + ":parse", + ":reflection", "//absl/strings", "//absl/time", "//absl/types:optional", diff --git a/absl/flags/flag_benchmark.cc b/absl/flags/flag_benchmark.cc index 7b52c9bc..9982b604 100644 --- a/absl/flags/flag_benchmark.cc +++ b/absl/flags/flag_benchmark.cc @@ -20,6 +20,8 @@ #include "absl/flags/flag.h" #include "absl/flags/marshalling.h" +#include "absl/flags/parse.h" +#include "absl/flags/reflection.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" #include "absl/types/optional.h" @@ -103,6 +105,23 @@ std::string AbslUnparseFlag(const UDT&) { return ""; } BENCHMARKED_TYPES(FLAG_DEF) +// Register thousands of flags to bloat up the size of the registry. +// This mimics real life production binaries. +#define DEFINE_FLAG_0(name) ABSL_FLAG(int, name, 0, ""); +#define DEFINE_FLAG_1(name) DEFINE_FLAG_0(name##0) DEFINE_FLAG_0(name##1) +#define DEFINE_FLAG_2(name) DEFINE_FLAG_1(name##0) DEFINE_FLAG_1(name##1) +#define DEFINE_FLAG_3(name) DEFINE_FLAG_2(name##0) DEFINE_FLAG_2(name##1) +#define DEFINE_FLAG_4(name) DEFINE_FLAG_3(name##0) DEFINE_FLAG_3(name##1) +#define DEFINE_FLAG_5(name) DEFINE_FLAG_4(name##0) DEFINE_FLAG_4(name##1) +#define DEFINE_FLAG_6(name) DEFINE_FLAG_5(name##0) DEFINE_FLAG_5(name##1) +#define DEFINE_FLAG_7(name) DEFINE_FLAG_6(name##0) DEFINE_FLAG_6(name##1) +#define DEFINE_FLAG_8(name) DEFINE_FLAG_7(name##0) DEFINE_FLAG_7(name##1) +#define DEFINE_FLAG_9(name) DEFINE_FLAG_8(name##0) DEFINE_FLAG_8(name##1) +#define DEFINE_FLAG_10(name) DEFINE_FLAG_9(name##0) DEFINE_FLAG_9(name##1) +#define DEFINE_FLAG_11(name) DEFINE_FLAG_10(name##0) DEFINE_FLAG_10(name##1) +#define DEFINE_FLAG_12(name) DEFINE_FLAG_11(name##0) DEFINE_FLAG_11(name##1) +DEFINE_FLAG_12(bloat_flag_); + namespace { #define BM_GetFlag(T) \ @@ -115,6 +134,20 @@ namespace { BENCHMARKED_TYPES(BM_GetFlag) +void BM_ThreadedFindCommandLineFlag(benchmark::State& state) { + char dummy[] = "dummy"; + char* argv[] = {dummy}; + // We need to ensure that flags have been parsed. That is where the registry + // is finalized. + absl::ParseCommandLine(1, argv); + + for (auto s : state) { + benchmark::DoNotOptimize( + absl::FindCommandLineFlag("bloat_flag_010101010101")); + } +} +BENCHMARK(BM_ThreadedFindCommandLineFlag)->ThreadRange(1, 16); + } // namespace #define InvokeGetFlag(T) \ diff --git a/absl/flags/internal/registry.h b/absl/flags/internal/registry.h index 1df2db79..a8d9eb9c 100644 --- a/absl/flags/internal/registry.h +++ b/absl/flags/internal/registry.h @@ -30,9 +30,6 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace flags_internal { -// Executes specified visitor for each non-retired flag in the registry. -// Requires the caller hold the registry lock. -void ForEachFlagUnlocked(std::function visitor); // Executes specified visitor for each non-retired flag in the registry. While // callback are executed, the registry is locked and can't be changed. void ForEachFlag(std::function visitor); @@ -41,6 +38,8 @@ void ForEachFlag(std::function visitor); bool RegisterCommandLineFlag(CommandLineFlag&); +void FinalizeRegistry(); + //----------------------------------------------------------------------------- // Retired registrations: // diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc index 4f4bb3d5..1835a837 100644 --- a/absl/flags/parse.cc +++ b/absl/flags/parse.cc @@ -611,6 +611,11 @@ std::vector ParseCommandLineImpl(int argc, char* argv[], OnUndefinedFlag on_undef_flag) { ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]"); + // Once parsing has started we will not have more flag registrations. + // If we did, they would be missing during parsing, which is a problem on + // itself. + flags_internal::FinalizeRegistry(); + // This routine does not return anything since we abort on failure. CheckDefaultValuesParsingRoundtrip(); diff --git a/absl/flags/reflection.cc b/absl/flags/reflection.cc index d7060221..c6bf8aab 100644 --- a/absl/flags/reflection.cc +++ b/absl/flags/reflection.cc @@ -17,6 +17,7 @@ #include +#include #include #include @@ -56,21 +57,23 @@ class FlagRegistry { // Returns the flag object for the specified name, or nullptr if not found. // Will emit a warning if a 'retired' flag is specified. - CommandLineFlag* FindFlagLocked(absl::string_view name); + CommandLineFlag* FindFlag(absl::string_view name); static FlagRegistry& GlobalRegistry(); // returns a singleton registry private: friend class flags_internal::FlagSaverImpl; // reads all the flags in order // to copy them - friend void ForEachFlagUnlocked( - std::function visitor); + friend void ForEachFlag(std::function visitor); + friend void FinalizeRegistry(); - // The map from name to flag, for FindFlagLocked(). + // The map from name to flag, for FindFlag(). using FlagMap = std::map; using FlagIterator = FlagMap::iterator; using FlagConstIterator = FlagMap::const_iterator; FlagMap flags_; + std::vector flat_flags_; + std::atomic finalized_flags_{false}; absl::Mutex lock_; @@ -79,15 +82,6 @@ class FlagRegistry { FlagRegistry& operator=(const FlagRegistry&); }; -CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) { - FlagConstIterator i = flags_.find(name); - if (i == flags_.end()) { - return nullptr; - } - - return i->second; -} - namespace { class FlagRegistryLock { @@ -101,8 +95,24 @@ class FlagRegistryLock { } // namespace +CommandLineFlag* FlagRegistry::FindFlag(absl::string_view name) { + if (finalized_flags_.load(std::memory_order_acquire)) { + // We could save some gcus here if we make `Name()` be non-virtual. + // We could move the `const char*` name to the base class. + auto it = std::partition_point( + flat_flags_.begin(), flat_flags_.end(), + [=](CommandLineFlag* f) { return f->Name() < name; }); + if (it != flat_flags_.end() && (*it)->Name() == name) return *it; + } + + FlagRegistryLock frl(*this); + auto it = flags_.find(name); + return it != flags_.end() ? it->second : nullptr; +} + void FlagRegistry::RegisterFlag(CommandLineFlag& flag) { FlagRegistryLock registry_lock(*this); + std::pair ins = flags_.insert(FlagMap::value_type(flag.Name(), &flag)); if (ins.second == false) { // means the name was already in the map @@ -152,18 +162,15 @@ FlagRegistry& FlagRegistry::GlobalRegistry() { // -------------------------------------------------------------------- -void ForEachFlagUnlocked(std::function visitor) { +void ForEachFlag(std::function visitor) { FlagRegistry& registry = FlagRegistry::GlobalRegistry(); - for (FlagRegistry::FlagConstIterator i = registry.flags_.begin(); - i != registry.flags_.end(); ++i) { - visitor(*i->second); + + if (registry.finalized_flags_.load(std::memory_order_acquire)) { + for (const auto& i : registry.flat_flags_) visitor(*i); } -} -void ForEachFlag(std::function visitor) { - FlagRegistry& registry = FlagRegistry::GlobalRegistry(); FlagRegistryLock frl(registry); - ForEachFlagUnlocked(visitor); + for (const auto& i : registry.flags_) visitor(*i.second); } // -------------------------------------------------------------------- @@ -173,6 +180,21 @@ bool RegisterCommandLineFlag(CommandLineFlag& flag) { return true; } +void FinalizeRegistry() { + auto& registry = FlagRegistry::GlobalRegistry(); + FlagRegistryLock frl(registry); + if (registry.finalized_flags_.load(std::memory_order_relaxed)) { + // Was already finalized. Ignore the second time. + return; + } + registry.flat_flags_.reserve(registry.flags_.size()); + for (const auto& f : registry.flags_) { + registry.flat_flags_.push_back(f.second); + } + registry.flags_.clear(); + registry.finalized_flags_.store(true, std::memory_order_release); +} + // -------------------------------------------------------------------- namespace { @@ -298,9 +320,7 @@ CommandLineFlag* FindCommandLineFlag(absl::string_view name) { if (name.empty()) return nullptr; flags_internal::FlagRegistry& registry = flags_internal::FlagRegistry::GlobalRegistry(); - flags_internal::FlagRegistryLock frl(registry); - - return registry.FindFlagLocked(name); + return registry.FindFlag(name); } // -------------------------------------------------------------------- diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc index 39ba24a8..1d2e6cf0 100644 --- a/absl/hash/hash_test.cc +++ b/absl/hash/hash_test.cc @@ -82,8 +82,8 @@ TYPED_TEST_P(HashValueIntTest, FastPath) { } REGISTER_TYPED_TEST_CASE_P(HashValueIntTest, BasicUsage, FastPath); -using IntTypes = testing::Types; +using IntTypes = testing::Types; INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueIntTest, IntTypes); enum LegacyEnum { kValue1, kValue2, kValue3 }; @@ -819,8 +819,8 @@ TYPED_TEST_P(HashIntTest, BasicUsage) { } REGISTER_TYPED_TEST_CASE_P(HashIntTest, BasicUsage); -using IntTypes = testing::Types; +using IntTypes = testing::Types; INSTANTIATE_TYPED_TEST_CASE_P(My, HashIntTest, IntTypes); struct StructWithPadding { diff --git a/absl/hash/internal/city.cc b/absl/hash/internal/city.cc index e122c184..58d4bcb1 100644 --- a/absl/hash/internal/city.cc +++ b/absl/hash/internal/city.cc @@ -253,9 +253,8 @@ static uint64_t HashLen17to32(const char *s, size_t len) { // Return a 16-byte hash for 48 bytes. Quick and dirty. // Callers do best to use "random-looking" values for a and b. -static std::pair WeakHashLen32WithSeeds(uint64_t w, uint64_t x, - uint64_t y, uint64_t z, - uint64_t a, uint64_t b) { +static std::pair WeakHashLen32WithSeeds( + uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b) { a += w; b = Rotate(b + a + z, 21); uint64_t c = a; @@ -266,8 +265,9 @@ static std::pair WeakHashLen32WithSeeds(uint64_t w, uint64_t } // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. -static std::pair WeakHashLen32WithSeeds(const char *s, uint64_t a, - uint64_t b) { +static std::pair WeakHashLen32WithSeeds(const char *s, + uint64_t a, + uint64_t b) { return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a, b); } @@ -310,8 +310,10 @@ uint64_t CityHash64(const char *s, size_t len) { uint64_t x = Fetch64(s + len - 40); uint64_t y = Fetch64(s + len - 16) + Fetch64(s + len - 56); uint64_t z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24)); - std::pair v = WeakHashLen32WithSeeds(s + len - 64, len, z); - std::pair w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x); + std::pair v = + WeakHashLen32WithSeeds(s + len - 64, len, z); + std::pair w = + WeakHashLen32WithSeeds(s + len - 32, y + k1, x); x = x * k1 + Fetch64(s); // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks. @@ -337,7 +339,7 @@ uint64_t CityHash64WithSeed(const char *s, size_t len, uint64_t seed) { } uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0, - uint64_t seed1) { + uint64_t seed1) { return HashLen16(CityHash64(s, len) - seed0, seed1); } diff --git a/absl/hash/internal/city.h b/absl/hash/internal/city.h index 161c7748..9c1e7a57 100644 --- a/absl/hash/internal/city.h +++ b/absl/hash/internal/city.h @@ -71,7 +71,7 @@ uint64_t CityHash64WithSeed(const char *s, size_t len, uint64_t seed); // Hash function for a byte array. For convenience, two seeds are also // hashed into the result. uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0, - uint64_t seed1); + uint64_t seed1); // Hash function for a byte array. Most useful in 32-bit binaries. uint32_t CityHash32(const char *s, size_t len); diff --git a/absl/random/internal/generate_real_test.cc b/absl/random/internal/generate_real_test.cc index aa02f0c2..4bdc4534 100644 --- a/absl/random/internal/generate_real_test.cc +++ b/absl/random/internal/generate_real_test.cc @@ -419,8 +419,8 @@ TEST(GenerateRealTest, ExhaustiveFloat) { }; // Rely on RandU64ToFloat generating values from greatest to least when - // supplied with uint64_t values from greatest (0xfff...) to least (0x0). Thus, - // this algorithm stores the previous value, and if the new value is at + // supplied with uint64_t values from greatest (0xfff...) to least (0x0). + // Thus, this algorithm stores the previous value, and if the new value is at // greater than or equal to the previous value, then there is a collision in // the generation algorithm. // diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc index 4443c828..dbed3e9a 100644 --- a/absl/strings/cord_test.cc +++ b/absl/strings/cord_test.cc @@ -1,3 +1,17 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "absl/strings/cord.h" #include diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc index 9feb2248..e28a29b1 100644 --- a/absl/strings/internal/str_format/arg.cc +++ b/absl/strings/internal/str_format/arg.cc @@ -1,3 +1,17 @@ +// Copyright 2020 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. + // // POSIX spec: // http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h index 3dbc1526..7040c866 100644 --- a/absl/strings/internal/str_format/arg.h +++ b/absl/strings/internal/str_format/arg.h @@ -1,3 +1,17 @@ +// Copyright 2020 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_STR_FORMAT_ARG_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ diff --git a/absl/strings/internal/str_format/bind.cc b/absl/strings/internal/str_format/bind.cc index 6980ed1d..194e21af 100644 --- a/absl/strings/internal/str_format/bind.cc +++ b/absl/strings/internal/str_format/bind.cc @@ -1,3 +1,17 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "absl/strings/internal/str_format/bind.h" #include diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h index 585246e7..727b2115 100644 --- a/absl/strings/internal/str_format/bind.h +++ b/absl/strings/internal/str_format/bind.h @@ -1,3 +1,17 @@ +// Copyright 2020 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_STR_FORMAT_BIND_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ diff --git a/absl/strings/internal/str_format/bind_test.cc b/absl/strings/internal/str_format/bind_test.cc index 64790a85..1eef9c43 100644 --- a/absl/strings/internal/str_format/bind_test.cc +++ b/absl/strings/internal/str_format/bind_test.cc @@ -1,3 +1,17 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "absl/strings/internal/str_format/bind.h" #include diff --git a/absl/strings/internal/str_format/checker.h b/absl/strings/internal/str_format/checker.h index 424c51f7..2a2601ec 100644 --- a/absl/strings/internal/str_format/checker.h +++ b/absl/strings/internal/str_format/checker.h @@ -1,3 +1,17 @@ +// Copyright 2020 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_STR_FORMAT_CHECKER_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ diff --git a/absl/strings/internal/str_format/checker_test.cc b/absl/strings/internal/str_format/checker_test.cc index a76d70b0..7c70f47d 100644 --- a/absl/strings/internal/str_format/checker_test.cc +++ b/absl/strings/internal/str_format/checker_test.cc @@ -1,3 +1,17 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include #include "gmock/gmock.h" diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc index 634ee78b..375db0a0 100644 --- a/absl/strings/internal/str_format/convert_test.cc +++ b/absl/strings/internal/str_format/convert_test.cc @@ -1,3 +1,17 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include #include #include diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc index 20aeada5..d3c5f0a7 100644 --- a/absl/strings/internal/str_format/float_conversion.cc +++ b/absl/strings/internal/str_format/float_conversion.cc @@ -1,3 +1,17 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "absl/strings/internal/str_format/float_conversion.h" #include diff --git a/absl/strings/internal/str_format/float_conversion.h b/absl/strings/internal/str_format/float_conversion.h index e78bc191..71100e71 100644 --- a/absl/strings/internal/str_format/float_conversion.h +++ b/absl/strings/internal/str_format/float_conversion.h @@ -1,3 +1,17 @@ +// Copyright 2020 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_STR_FORMAT_FLOAT_CONVERSION_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ diff --git a/absl/strings/internal/str_format/parser.cc b/absl/strings/internal/str_format/parser.cc index cc55dfa9..f308d023 100644 --- a/absl/strings/internal/str_format/parser.cc +++ b/absl/strings/internal/str_format/parser.cc @@ -1,3 +1,17 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "absl/strings/internal/str_format/parser.h" #include diff --git a/absl/strings/internal/str_format/parser.h b/absl/strings/internal/str_format/parser.h index fffed04f..6504dd3d 100644 --- a/absl/strings/internal/str_format/parser.h +++ b/absl/strings/internal/str_format/parser.h @@ -1,3 +1,17 @@ +// Copyright 2020 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_STR_FORMAT_PARSER_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ diff --git a/absl/strings/internal/str_format/parser_test.cc b/absl/strings/internal/str_format/parser_test.cc index 5aced987..a5fa1c79 100644 --- a/absl/strings/internal/str_format/parser_test.cc +++ b/absl/strings/internal/str_format/parser_test.cc @@ -1,3 +1,17 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "absl/strings/internal/str_format/parser.h" #include diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc index d9fb25af..c60027ad 100644 --- a/absl/strings/str_format_test.cc +++ b/absl/strings/str_format_test.cc @@ -1,3 +1,16 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #include "absl/strings/str_format.h" diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel index b2df4131..cd4009a1 100644 --- a/absl/synchronization/BUILD.bazel +++ b/absl/synchronization/BUILD.bazel @@ -80,6 +80,7 @@ cc_library( "barrier.h", "blocking_counter.h", "internal/create_thread_identity.h", + "internal/futex.h", "internal/per_thread_sem.h", "internal/waiter.h", "mutex.h", diff --git a/absl/synchronization/CMakeLists.txt b/absl/synchronization/CMakeLists.txt index c255b03e..e633d0bf 100644 --- a/absl/synchronization/CMakeLists.txt +++ b/absl/synchronization/CMakeLists.txt @@ -52,6 +52,7 @@ absl_cc_library( "barrier.h" "blocking_counter.h" "internal/create_thread_identity.h" + "internal/futex.h" "internal/per_thread_sem.h" "internal/waiter.h" "mutex.h" diff --git a/absl/synchronization/internal/futex.h b/absl/synchronization/internal/futex.h new file mode 100644 index 00000000..3539f491 --- /dev/null +++ b/absl/synchronization/internal/futex.h @@ -0,0 +1,139 @@ +// Copyright 2020 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_SYNCHRONIZATION_INTERNAL_FUTEX_H_ +#define ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_ + +#include "absl/base/config.h" + +#ifdef _WIN32 +#include +#else +#include +#include +#endif + +#ifdef __linux__ +#include +#include +#endif + +#include +#include +#include + +#include +#include + +#include "absl/base/optimization.h" +#include "absl/synchronization/internal/kernel_timeout.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace synchronization_internal { + +// Some Android headers are missing these definitions even though they +// support these futex operations. +#ifdef __BIONIC__ +#ifndef SYS_futex +#define SYS_futex __NR_futex +#endif +#ifndef FUTEX_WAIT_BITSET +#define FUTEX_WAIT_BITSET 9 +#endif +#ifndef FUTEX_PRIVATE_FLAG +#define FUTEX_PRIVATE_FLAG 128 +#endif +#ifndef FUTEX_CLOCK_REALTIME +#define FUTEX_CLOCK_REALTIME 256 +#endif +#ifndef FUTEX_BITSET_MATCH_ANY +#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF +#endif +#endif + +#if defined(__NR_futex_time64) && !defined(SYS_futex_time64) +#define SYS_futex_time64 __NR_futex_time64 +#endif + +#if defined(SYS_futex_time64) && !defined(SYS_futex) +#define SYS_futex SYS_futex_time64 +#endif + +class FutexImpl { + public: + static int WaitUntil(std::atomic *v, int32_t val, + KernelTimeout t) { + int err = 0; + if (t.has_timeout()) { + // https://locklessinc.com/articles/futex_cheat_sheet/ + // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time. + struct timespec abs_timeout = t.MakeAbsTimespec(); + // Atomically check that the futex value is still 0, and if it + // is, sleep until abs_timeout or until woken by FUTEX_WAKE. + err = syscall( + SYS_futex, reinterpret_cast(v), + FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val, + &abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY); + } else { + // Atomically check that the futex value is still 0, and if it + // is, sleep until woken by FUTEX_WAKE. + err = syscall(SYS_futex, reinterpret_cast(v), + FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr); + } + if (ABSL_PREDICT_FALSE(err != 0)) { + err = -errno; + } + return err; + } + + static int WaitBitsetAbsoluteTimeout(std::atomic *v, int32_t val, + int32_t bits, + const struct timespec *abstime) { + int err = syscall(SYS_futex, reinterpret_cast(v), + FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG, val, abstime, + nullptr, bits); + if (ABSL_PREDICT_FALSE(err != 0)) { + err = -errno; + } + return err; + } + + static int Wake(std::atomic *v, int32_t count) { + int err = syscall(SYS_futex, reinterpret_cast(v), + FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count); + if (ABSL_PREDICT_FALSE(err < 0)) { + err = -errno; + } + return err; + } + + // FUTEX_WAKE_BITSET + static int WakeBitset(std::atomic *v, int32_t count, int32_t bits) { + int err = syscall(SYS_futex, reinterpret_cast(v), + FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG, count, nullptr, + nullptr, bits); + if (ABSL_PREDICT_FALSE(err < 0)) { + err = -errno; + } + return err; + } +}; + +class Futex : public FutexImpl {}; + +} // namespace synchronization_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_ diff --git a/absl/synchronization/internal/kernel_timeout.h b/absl/synchronization/internal/kernel_timeout.h index 1084e1e6..bbd4d2d7 100644 --- a/absl/synchronization/internal/kernel_timeout.h +++ b/absl/synchronization/internal/kernel_timeout.h @@ -26,6 +26,7 @@ #define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_ #include + #include #include @@ -142,7 +143,7 @@ inline struct timespec KernelTimeout::MakeAbsTimespec() { struct timespec abstime; int64_t seconds = (std::min)(n / kNanosPerSecond, - int64_t{(std::numeric_limits::max)()}); + int64_t{(std::numeric_limits::max)()}); abstime.tv_sec = static_cast(seconds); abstime.tv_nsec = static_cast(n % kNanosPerSecond); return abstime; diff --git a/absl/synchronization/internal/waiter.cc b/absl/synchronization/internal/waiter.cc index b6150b9b..c51855b0 100644 --- a/absl/synchronization/internal/waiter.cc +++ b/absl/synchronization/internal/waiter.cc @@ -48,6 +48,11 @@ #include "absl/base/optimization.h" #include "absl/synchronization/internal/kernel_timeout.h" +#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX +#include "absl/synchronization/internal/futex.h" +#endif + + namespace absl { ABSL_NAMESPACE_BEGIN namespace synchronization_internal { @@ -66,71 +71,6 @@ static void MaybeBecomeIdle() { #if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX -// Some Android headers are missing these definitions even though they -// support these futex operations. -#ifdef __BIONIC__ -#ifndef SYS_futex -#define SYS_futex __NR_futex -#endif -#ifndef FUTEX_WAIT_BITSET -#define FUTEX_WAIT_BITSET 9 -#endif -#ifndef FUTEX_PRIVATE_FLAG -#define FUTEX_PRIVATE_FLAG 128 -#endif -#ifndef FUTEX_CLOCK_REALTIME -#define FUTEX_CLOCK_REALTIME 256 -#endif -#ifndef FUTEX_BITSET_MATCH_ANY -#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF -#endif -#endif - -#if defined(__NR_futex_time64) && !defined(SYS_futex_time64) -#define SYS_futex_time64 __NR_futex_time64 -#endif - -#if defined(SYS_futex_time64) && !defined(SYS_futex) -#define SYS_futex SYS_futex_time64 -#endif - -class Futex { - public: - static int WaitUntil(std::atomic *v, int32_t val, - KernelTimeout t) { - int err = 0; - if (t.has_timeout()) { - // https://locklessinc.com/articles/futex_cheat_sheet/ - // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time. - struct timespec abs_timeout = t.MakeAbsTimespec(); - // Atomically check that the futex value is still 0, and if it - // is, sleep until abs_timeout or until woken by FUTEX_WAKE. - err = syscall( - SYS_futex, reinterpret_cast(v), - FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val, - &abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY); - } else { - // Atomically check that the futex value is still 0, and if it - // is, sleep until woken by FUTEX_WAKE. - err = syscall(SYS_futex, reinterpret_cast(v), - FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr); - } - if (err != 0) { - err = -errno; - } - return err; - } - - static int Wake(std::atomic *v, int32_t count) { - int err = syscall(SYS_futex, reinterpret_cast(v), - FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count); - if (ABSL_PREDICT_FALSE(err < 0)) { - err = -errno; - } - return err; - } -}; - Waiter::Waiter() { futex_.store(0, std::memory_order_relaxed); } diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc index 9b7f088a..63f09408 100644 --- a/absl/synchronization/mutex.cc +++ b/absl/synchronization/mutex.cc @@ -88,8 +88,8 @@ ABSL_CONST_INIT std::atomic synch_deadlock_detection( ABSL_CONST_INIT std::atomic synch_check_invariants(false); ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES - absl::base_internal::AtomicHook - submit_profile_data; +absl::base_internal::AtomicHook + submit_profile_data; ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook mutex_tracer; @@ -491,7 +491,7 @@ struct SynchWaitParams { std::atomic *cv_word; int64_t contention_start_cycles; // Time (in cycles) when this thread started - // to contend for the mutex. + // to contend for the mutex. }; struct SynchLocksHeld { @@ -2311,7 +2311,8 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { if (!cond_waiter) { // Sample lock contention events only if the (first) waiter was trying to // acquire the lock, not waiting on a condition variable or Condition. - int64_t wait_cycles = base_internal::CycleClock::Now() - enqueue_timestamp; + int64_t wait_cycles = + base_internal::CycleClock::Now() - enqueue_timestamp; mutex_tracer("slow release", this, wait_cycles); ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0); submit_profile_data(enqueue_timestamp); diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h index 6340bd63..f686c4df 100644 --- a/absl/synchronization/mutex.h +++ b/absl/synchronization/mutex.h @@ -667,10 +667,10 @@ class Condition { // }; // mu_.Await(Condition(&reached)); // - // NOTE: never use "mu_.AssertHeld()" instead of "mu_.AssertReadHeld()" in the - // lambda as it may be called when the mutex is being unlocked from a scope - // holding only a reader lock, which will make the assertion not fulfilled and - // crash the binary. + // NOTE: never use "mu_.AssertHeld()" instead of "mu_.AssertReaderHeld()" in + // the lambda as it may be called when the mutex is being unlocked from a + // scope holding only a reader lock, which will make the assertion not + // fulfilled and crash the binary. // See class comment for performance advice. In particular, if there // might be more than one waiter for the same condition, make sure @@ -954,7 +954,7 @@ void RegisterMutexProfiler(void (*fn)(int64_t wait_timestamp)); // // This has the same memory ordering concerns as RegisterMutexProfiler() above. void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj, - int64_t wait_cycles)); + int64_t wait_cycles)); // TODO(gfalcon): Combine RegisterMutexProfiler() and RegisterMutexTracer() // into a single interface, since they are only ever called in pairs. diff --git a/absl/time/clock.cc b/absl/time/clock.cc index e5c423c7..6862e011 100644 --- a/absl/time/clock.cc +++ b/absl/time/clock.cc @@ -74,9 +74,7 @@ ABSL_NAMESPACE_END #if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS namespace absl { ABSL_NAMESPACE_BEGIN -int64_t GetCurrentTimeNanos() { - return GET_CURRENT_TIME_NANOS_FROM_SYSTEM(); -} +int64_t GetCurrentTimeNanos() { return GET_CURRENT_TIME_NANOS_FROM_SYSTEM(); } ABSL_NAMESPACE_END } // namespace absl #else // Use the cyclecounter-based implementation below. diff --git a/absl/time/duration.cc b/absl/time/duration.cc index eca1a6d9..4443109a 100644 --- a/absl/time/duration.cc +++ b/absl/time/duration.cc @@ -356,7 +356,7 @@ namespace time_internal { // the remainder. If it does not saturate, the remainder remain accurate, // but the returned quotient will over/underflow int64_t and should not be used. int64_t IDivDuration(bool satq, const Duration num, const Duration den, - Duration* rem) { + Duration* rem) { int64_t q = 0; if (IDivFastPath(num, den, &q, rem)) { return q; diff --git a/absl/time/time.cc b/absl/time/time.cc index 6bb36cb3..1ec2026e 100644 --- a/absl/time/time.cc +++ b/absl/time/time.cc @@ -60,9 +60,10 @@ inline cctz::time_point unix_epoch() { inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) { absl::Duration rem; int64_t q = absl::IDivDuration(d, unit, &rem); - return (q > 0 || - rem >= ZeroDuration() || - q == std::numeric_limits::min()) ? q : q - 1; + return (q > 0 || rem >= ZeroDuration() || + q == std::numeric_limits::min()) + ? q + : q - 1; } inline absl::Time::Breakdown InfiniteFutureBreakdown() { diff --git a/absl/time/time.h b/absl/time/time.h index 37f6131d..72508031 100644 --- a/absl/time/time.h +++ b/absl/time/time.h @@ -639,7 +639,7 @@ class Time { // Deprecated. Use `absl::TimeZone::CivilInfo`. struct Breakdown { - int64_t year; // year (e.g., 2013) + int64_t year; // year (e.g., 2013) int month; // month of year [1:12] int day; // day of month [1:31] int hour; // hour of day [0:23] @@ -1494,12 +1494,10 @@ constexpr Duration Hours(int64_t n) { constexpr bool operator<(Duration lhs, Duration rhs) { return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs) ? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs) - : time_internal::GetRepHi(lhs) == - (std::numeric_limits::min)() - ? time_internal::GetRepLo(lhs) + 1 < - time_internal::GetRepLo(rhs) + 1 - : time_internal::GetRepLo(lhs) < - time_internal::GetRepLo(rhs); + : time_internal::GetRepHi(lhs) == (std::numeric_limits::min)() + ? time_internal::GetRepLo(lhs) + 1 < + time_internal::GetRepLo(rhs) + 1 + : time_internal::GetRepLo(lhs) < time_internal::GetRepLo(rhs); } constexpr bool operator==(Duration lhs, Duration rhs) { diff --git a/absl/time/time_test.cc b/absl/time/time_test.cc index b28a99fb..cde9423f 100644 --- a/absl/time/time_test.cc +++ b/absl/time/time_test.cc @@ -1070,7 +1070,8 @@ TEST(Time, ConversionSaturation) { EXPECT_EQ("292277026596-12-04T15:30:07+00:00", absl::FormatTime(absl::RFC3339_full, t, utc)); EXPECT_EQ( - absl::UnixEpoch() + absl::Seconds(std::numeric_limits::max()), t); + absl::UnixEpoch() + absl::Seconds(std::numeric_limits::max()), + t); // Checks that we can also get the maximal Time value for a far-east zone. const absl::TimeZone plus14 = absl::FixedTimeZone(14 * 60 * 60); @@ -1078,7 +1079,8 @@ TEST(Time, ConversionSaturation) { EXPECT_EQ("292277026596-12-05T05:30:07+14:00", absl::FormatTime(absl::RFC3339_full, t, plus14)); EXPECT_EQ( - absl::UnixEpoch() + absl::Seconds(std::numeric_limits::max()), t); + absl::UnixEpoch() + absl::Seconds(std::numeric_limits::max()), + t); // One second later should push us to infinity. t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 8), utc); @@ -1092,7 +1094,8 @@ TEST(Time, ConversionSaturation) { EXPECT_EQ("-292277022657-01-27T08:29:52+00:00", absl::FormatTime(absl::RFC3339_full, t, utc)); EXPECT_EQ( - absl::UnixEpoch() + absl::Seconds(std::numeric_limits::min()), t); + absl::UnixEpoch() + absl::Seconds(std::numeric_limits::min()), + t); // Checks that we can also get the minimal Time value for a far-west zone. const absl::TimeZone minus12 = absl::FixedTimeZone(-12 * 60 * 60); @@ -1101,7 +1104,8 @@ TEST(Time, ConversionSaturation) { EXPECT_EQ("-292277022657-01-26T20:29:52-12:00", absl::FormatTime(absl::RFC3339_full, t, minus12)); EXPECT_EQ( - absl::UnixEpoch() + absl::Seconds(std::numeric_limits::min()), t); + absl::UnixEpoch() + absl::Seconds(std::numeric_limits::min()), + t); // One second before should push us to -infinity. t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 51), utc); diff --git a/absl/types/internal/variant.h b/absl/types/internal/variant.h index d404e80c..772008c7 100644 --- a/absl/types/internal/variant.h +++ b/absl/types/internal/variant.h @@ -45,7 +45,7 @@ ABSL_NAMESPACE_BEGIN template class variant; -ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1); +ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, static_cast(-1)); template struct variant_size; diff --git a/absl/types/variant_test.cc b/absl/types/variant_test.cc index cf8f7f33..cf237334 100644 --- a/absl/types/variant_test.cc +++ b/absl/types/variant_test.cc @@ -2311,7 +2311,8 @@ TEST(VariantTest, TestRvalueConversion) { ASSERT_TRUE(absl::holds_alternative(variant2)); EXPECT_EQ(42, absl::get(variant2)); - variant2 = ConvertVariantTo>(variant(42)); + variant2 = + ConvertVariantTo>(variant(42)); ASSERT_TRUE(absl::holds_alternative(variant2)); EXPECT_EQ(42, absl::get(variant2)); #endif // !ABSL_USES_STD_VARIANT @@ -2453,7 +2454,8 @@ TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) { ConvertVariantTo>(variant(42))); EXPECT_THAT(absl::get_if(&variant2), Pointee(42)); - variant2 = ConvertVariantTo>(variant(42)); + variant2 = + ConvertVariantTo>(variant(42)); EXPECT_THAT(absl::get_if(&variant2), Pointee(42)); #endif -- cgit v1.2.3 From 68f1ad93251744f096036e65241493774b4e7ac0 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 14 Dec 2020 21:51:13 -0800 Subject: Export of internal Abseil changes -- f0456157cdc6cef6dbb5d2f99f9dc3ca0e213fab by Abseil Team : Improve flag_benchmark reproducibility, test multiple threads This adds multiple threads to the flags benchmark, and also uses some linker magic to ensure that the defined flags are mapped to a consistent alignment regardless of other code changes in the benchmark binary. The benchmark performance in multiple threads is somewhat sensitive to the alignment of the FlagImpl class, depending on whether the flag value and the absl::Mutex are on the same cacheline or different ones. Making all flags be cacheline-aligned would probably waste too much memory, so this CL instead just makes the memory alignment consistent within the tests. PiperOrigin-RevId: 347536882 -- a019646d306b9497a1eba7efa5e2c4c651d9979d by Derek Mauro : Fix other comments in node_hash_set.h PiperOrigin-RevId: 347462975 -- 66a4b39fe84a3e81935ad08ee76291df13d1d5e6 by Abseil Team : Internal change PiperOrigin-RevId: 347436244 -- 52f4d18c2c4439d26428f64ac4de41e6183919ee by Mark Barolak : container: fix introduction for node_hash_set.h Import of https://github.com/abseil/abseil-cpp/pull/861 PiperOrigin-RevId: 347432772 GitOrigin-RevId: f0456157cdc6cef6dbb5d2f99f9dc3ca0e213fab Change-Id: I629f27e5b9584d92b0a42284c1acf708779bad3f --- absl/container/node_hash_set.h | 30 +++++++++++++++--------------- absl/flags/BUILD.bazel | 4 ++++ absl/flags/flag_benchmark.cc | 13 +++++++++++-- absl/flags/flag_benchmark.lds | 13 +++++++++++++ absl/strings/cord.cc | 1 + 5 files changed, 44 insertions(+), 17 deletions(-) create mode 100644 absl/flags/flag_benchmark.lds (limited to 'absl/flags/flag_benchmark.cc') diff --git a/absl/container/node_hash_set.h b/absl/container/node_hash_set.h index 56ce3b66..93b15f46 100644 --- a/absl/container/node_hash_set.h +++ b/absl/container/node_hash_set.h @@ -18,7 +18,7 @@ // // An `absl::node_hash_set` is an unordered associative container designed to // be a more efficient replacement for `std::unordered_set`. Like -// `unordered_set`, search, insertion, and deletion of map elements can be done +// `unordered_set`, search, insertion, and deletion of set elements can be done // as an `O(1)` operation. However, `node_hash_set` (and other unordered // associative containers known as the collection of Abseil "Swiss tables") // contain other optimizations that result in both memory and computation @@ -60,7 +60,7 @@ struct NodeHashSetPolicy; // following notable differences: // // * Supports heterogeneous lookup, through `find()`, `operator[]()` and -// `insert()`, provided that the map is provided a compatible heterogeneous +// `insert()`, provided that the set is provided a compatible heterogeneous // hashing function and equality operator. // * Contains a `capacity()` member function indicating the number of element // slots (open, deleted, and empty) within the hash set. @@ -76,13 +76,13 @@ struct NodeHashSetPolicy; // Example: // // // Create a node hash set of three strings -// absl::node_hash_map ducks = +// absl::node_hash_set ducks = // {"huey", "dewey", "louie"}; // -// // Insert a new element into the node hash map -// ducks.insert("donald"}; +// // Insert a new element into the node hash set +// ducks.insert("donald"); // -// // Force a rehash of the node hash map +// // Force a rehash of the node hash set // ducks.rehash(0); // // // See if "dewey" is present @@ -100,7 +100,7 @@ class node_hash_set public: // Constructors and Assignment Operators // - // A node_hash_set supports the same overload set as `std::unordered_map` + // A node_hash_set supports the same overload set as `std::unordered_set` // for construction and assignment: // // * Default constructor @@ -167,7 +167,7 @@ class node_hash_set // available within the `node_hash_set`. // // NOTE: this member function is particular to `absl::node_hash_set` and is - // not provided in the `std::unordered_map` API. + // not provided in the `std::unordered_set` API. using Base::capacity; // node_hash_set::empty() @@ -208,7 +208,7 @@ class node_hash_set // `void`. // // NOTE: this return behavior is different than that of STL containers in - // general and `std::unordered_map` in particular. + // general and `std::unordered_set` in particular. // // iterator erase(const_iterator first, const_iterator last): // @@ -314,7 +314,7 @@ class node_hash_set // node_hash_set::merge() // - // Extracts elements from a given `source` flat hash map into this + // Extracts elements from a given `source` node hash set into this // `node_hash_set`. If the destination `node_hash_set` already contains an // element with an equivalent key, that element is not extracted. using Base::merge; @@ -322,15 +322,15 @@ class node_hash_set // node_hash_set::swap(node_hash_set& other) // // Exchanges the contents of this `node_hash_set` with those of the `other` - // flat hash map, avoiding invocation of any move, copy, or swap operations on + // node hash set, avoiding invocation of any move, copy, or swap operations on // individual elements. // // All iterators and references on the `node_hash_set` remain valid, excepting // for the past-the-end iterator, which is invalidated. // - // `swap()` requires that the flat hash set's hashing and key equivalence + // `swap()` requires that the node hash set's hashing and key equivalence // functions be Swappable, and are exchaged using unqualified calls to - // non-member `swap()`. If the map's allocator has + // non-member `swap()`. If the set's allocator has // `std::allocator_traits::propagate_on_container_swap::value` // set to `true`, the allocators are also exchanged using an unqualified call // to non-member `swap()`; otherwise, the allocators are not swapped. @@ -385,14 +385,14 @@ class node_hash_set // node_hash_set::bucket_count() // // Returns the number of "buckets" within the `node_hash_set`. Note that - // because a flat hash map contains all elements within its internal storage, + // because a node hash set contains all elements within its internal storage, // this value simply equals the current capacity of the `node_hash_set`. using Base::bucket_count; // node_hash_set::load_factor() // // Returns the current load factor of the `node_hash_set` (the average number - // of slots occupied with a value within the hash map). + // of slots occupied with a value within the hash set). using Base::load_factor; // node_hash_set::max_load_factor() diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index 78d6da74..6e5c4e87 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -376,9 +376,13 @@ cc_binary( "flag_benchmark.cc", ], copts = ABSL_TEST_COPTS, + linkopts = select({ + "//conditions:default": [], + }) + ABSL_DEFAULT_LINKOPTS, tags = ["benchmark"], visibility = ["//visibility:private"], deps = [ + "flag_benchmark.lds", ":flag", ":marshalling", ":parse", diff --git a/absl/flags/flag_benchmark.cc b/absl/flags/flag_benchmark.cc index 9982b604..57584f85 100644 --- a/absl/flags/flag_benchmark.cc +++ b/absl/flags/flag_benchmark.cc @@ -103,8 +103,17 @@ std::string AbslUnparseFlag(const UDT&) { return ""; } #define FLAG_DEF(T) ABSL_FLAG(T, T##_flag, {}, ""); +#if defined(__clang__) && defined(__linux__) +// Force the flags used for benchmarks into a separate ELF section. +// This ensures that, even when other parts of the code might change size, +// the layout of the flags across cachelines is kept constant. This makes +// benchmark results more reproducible across unrelated code changes. +#pragma clang section data = ".benchmark_flags" +#endif BENCHMARKED_TYPES(FLAG_DEF) - +#if defined(__clang__) && defined(__linux__) +#pragma clang section data = "" +#endif // Register thousands of flags to bloat up the size of the registry. // This mimics real life production binaries. #define DEFINE_FLAG_0(name) ABSL_FLAG(int, name, 0, ""); @@ -130,7 +139,7 @@ namespace { benchmark::DoNotOptimize(absl::GetFlag(FLAGS_##T##_flag)); \ } \ } \ - BENCHMARK(BM_GetFlag_##T); + BENCHMARK(BM_GetFlag_##T)->ThreadRange(1, 16); BENCHMARKED_TYPES(BM_GetFlag) diff --git a/absl/flags/flag_benchmark.lds b/absl/flags/flag_benchmark.lds new file mode 100644 index 00000000..af115dfc --- /dev/null +++ b/absl/flags/flag_benchmark.lds @@ -0,0 +1,13 @@ +/* This linker script forces the flags used by flags_benchmark + * into a separate page-aligned section. This isn't necessary for + * correctness but ensures that the benchmark results are more + * reproducible across unrelated code changes. + */ +SECTIONS { + .benchmark_flags : { + . = ALIGN(0x1000); + * (.benchmark_flags); + } +} + +INSERT AFTER .data diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index 8d51c750..7cadf75d 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc @@ -58,6 +58,7 @@ using ::absl::cord_internal::kMaxFlatLength; using ::absl::cord_internal::CONCAT; using ::absl::cord_internal::EXTERNAL; using ::absl::cord_internal::FLAT; +using ::absl::cord_internal::RING; using ::absl::cord_internal::SUBSTRING; using ::absl::cord_internal::kInlinedVectorSize; -- cgit v1.2.3