diff options
Diffstat (limited to 'absl')
-rw-r--r-- | absl/algorithm/BUILD.bazel | 4 | ||||
-rw-r--r-- | absl/base/internal/endian_test.cc | 6 | ||||
-rw-r--r-- | absl/base/optimization.h | 34 | ||||
-rw-r--r-- | absl/container/internal/raw_hash_set.h | 24 | ||||
-rw-r--r-- | absl/flags/BUILD.bazel | 2 | ||||
-rw-r--r-- | absl/flags/CMakeLists.txt | 1 | ||||
-rw-r--r-- | absl/flags/flag.h | 6 | ||||
-rw-r--r-- | absl/flags/flag_test.cc | 173 | ||||
-rw-r--r-- | absl/flags/internal/flag.cc | 73 | ||||
-rw-r--r-- | absl/flags/internal/flag.h | 103 | ||||
-rw-r--r-- | absl/random/internal/iostream_state_saver.h | 4 | ||||
-rw-r--r-- | absl/random/internal/nanobenchmark_test.cc | 2 | ||||
-rw-r--r-- | absl/random/internal/wide_multiply.h | 10 | ||||
-rw-r--r-- | absl/time/duration.cc | 6 |
14 files changed, 313 insertions, 135 deletions
diff --git a/absl/algorithm/BUILD.bazel b/absl/algorithm/BUILD.bazel index 6a96420b96a3..229cd713a206 100644 --- a/absl/algorithm/BUILD.bazel +++ b/absl/algorithm/BUILD.bazel @@ -31,7 +31,9 @@ cc_library( hdrs = ["algorithm.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - deps = ["//absl/base:config"], + deps = [ + "//absl/base:config", + ], ) cc_test( diff --git a/absl/base/internal/endian_test.cc b/absl/base/internal/endian_test.cc index aa6b8496905c..678a0bf78be1 100644 --- a/absl/base/internal/endian_test.cc +++ b/absl/base/internal/endian_test.cc @@ -57,6 +57,7 @@ const uint16_t k16ValueBE{0x2301}; template<typename T> std::vector<T> GenerateAllValuesForType() { std::vector<T> result; + result.reserve(size_t{1} << (sizeof(T) * 8)); T next = std::numeric_limits<T>::min(); while (true) { result.push_back(next); @@ -68,10 +69,11 @@ std::vector<T> GenerateAllValuesForType() { } template<typename T> -std::vector<T> GenerateRandomIntegers(size_t numValuesToTest) { +std::vector<T> GenerateRandomIntegers(size_t num_values_to_test) { std::vector<T> result; + result.reserve(num_values_to_test); std::mt19937_64 rng(kRandomSeed); - for (size_t i = 0; i < numValuesToTest; ++i) { + for (size_t i = 0; i < num_values_to_test; ++i) { result.push_back(rng()); } return result; diff --git a/absl/base/optimization.h b/absl/base/optimization.h index 646523b34612..1541d7a8dc31 100644 --- a/absl/base/optimization.h +++ b/absl/base/optimization.h @@ -178,4 +178,38 @@ #define ABSL_PREDICT_TRUE(x) (x) #endif +// ABSL_INTERNAL_ASSUME(cond) +// Informs the compiler than a condition is always true and that it can assume +// it to be true for optimization purposes. The call has undefined behavior if +// the condition is false. +// In !NDEBUG mode, the condition is checked with an assert(). +// NOTE: The expression must not have side effects, as it will only be evaluated +// in some compilation modes and not others. +// +// Example: +// +// int x = ...; +// ABSL_INTERNAL_ASSUME(x >= 0); +// // The compiler can optimize the division to a simple right shift using the +// // assumption specified above. +// int y = x / 16; +// +#if !defined(NDEBUG) +#define ABSL_INTERNAL_ASSUME(cond) assert(cond) +#elif ABSL_HAVE_BUILTIN(__builtin_assume) +#define ABSL_INTERNAL_ASSUME(cond) __builtin_assume(cond) +#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable) +#define ABSL_INTERNAL_ASSUME(cond) \ + do { \ + if (!(cond)) __builtin_unreachable(); \ + } while (0) +#elif defined(_MSC_VER) +#define ABSL_INTERNAL_ASSUME(cond) __assume(cond) +#else +#define ABSL_INTERNAL_ASSUME(cond) \ + do { \ + static_cast<void>(false && (cond)); \ + } while (0) +#endif + #endif // ABSL_BASE_OPTIMIZATION_H_ diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index e47e1fedf725..df0f2b2b54be 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -104,7 +104,7 @@ #include "absl/base/internal/bits.h" #include "absl/base/internal/endian.h" -#include "absl/base/macros.h" +#include "absl/base/optimization.h" #include "absl/base/port.h" #include "absl/container/internal/common.h" #include "absl/container/internal/compressed_tuple.h" @@ -649,24 +649,26 @@ class raw_hash_set { } private: - iterator(ctrl_t* ctrl) : ctrl_(ctrl) {} // for end() - iterator(ctrl_t* ctrl, slot_type* slot) : ctrl_(ctrl), slot_(slot) {} + iterator(ctrl_t* ctrl, slot_type* slot) : ctrl_(ctrl), slot_(slot) { + // This assumption helps the compiler know that any non-end iterator is + // not equal to any end iterator. + ABSL_INTERNAL_ASSUME(ctrl != nullptr); + } - void assert_is_full() const { ABSL_HARDENING_ASSERT(IsFull(*ctrl_)); } + void assert_is_full() const { + ABSL_HARDENING_ASSERT(ctrl_ != nullptr && IsFull(*ctrl_)); + } void assert_is_valid() const { - ABSL_HARDENING_ASSERT(!ctrl_ || IsFull(*ctrl_) || *ctrl_ == kSentinel); + ABSL_HARDENING_ASSERT(ctrl_ == nullptr || IsFull(*ctrl_)); } void skip_empty_or_deleted() { while (IsEmptyOrDeleted(*ctrl_)) { - // ctrl is not necessarily aligned to Group::kWidth. It is also likely - // to read past the space for ctrl bytes and into slots. This is ok - // because ctrl has sizeof() == 1 and slot has sizeof() >= 1 so there - // is no way to read outside the combined slot array. uint32_t shift = Group{ctrl_}.CountLeadingEmptyOrDeleted(); ctrl_ += shift; slot_ += shift; } + if (ABSL_PREDICT_FALSE(*ctrl_ == kSentinel)) ctrl_ = nullptr; } ctrl_t* ctrl_ = nullptr; @@ -908,12 +910,12 @@ class raw_hash_set { it.skip_empty_or_deleted(); return it; } - iterator end() { return {ctrl_ + capacity_}; } + iterator end() { return {}; } const_iterator begin() const { return const_cast<raw_hash_set*>(this)->begin(); } - const_iterator end() const { return const_cast<raw_hash_set*>(this)->end(); } + const_iterator end() const { return {}; } const_iterator cbegin() const { return begin(); } const_iterator cend() const { return end(); } diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index 4b51d9d45207..685e395419eb 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -326,7 +326,9 @@ cc_test( ":handle", ":registry", "//absl/base:core_headers", + "//absl/base:malloc_internal", "//absl/strings", + "//absl/time", "@com_google_googletest//:gtest_main", ], ) diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt index 2204b0ff2dd8..ec82ee1e36bb 100644 --- a/absl/flags/CMakeLists.txt +++ b/absl/flags/CMakeLists.txt @@ -304,6 +304,7 @@ absl_cc_test( absl::flags_internal absl::flags_registry absl::strings + absl::time gtest_main ) diff --git a/absl/flags/flag.h b/absl/flags/flag.h index 4cc8ae373299..150615929b0f 100644 --- a/absl/flags/flag.h +++ b/absl/flags/flag.h @@ -314,9 +314,9 @@ ABSL_NAMESPACE_END static std::string NonConst() { return ABSL_FLAG_IMPL_FLAGHELP(txt); } \ } -#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ - static void* AbslFlagsInitFlag##name() { \ - return absl::flags_internal::MakeFromDefaultValue<Type>(default_value); \ +#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ + static void AbslFlagsInitFlag##name(void* dst) { \ + absl::flags_internal::MakeFromDefaultValue<Type>(dst, default_value); \ } // ABSL_FLAG_IMPL diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc index 377e3b2b89ad..dbe94a2c3b62 100644 --- a/absl/flags/flag_test.cc +++ b/absl/flags/flag_test.cc @@ -19,6 +19,7 @@ #include <cmath> #include <string> +#include <thread> // NOLINT #include <vector> #include "gtest/gtest.h" @@ -34,6 +35,7 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_split.h" #include "absl/strings/string_view.h" +#include "absl/time/time.h" ABSL_DECLARE_FLAG(int64_t, mistyped_int_flag); ABSL_DECLARE_FLAG(std::vector<std::string>, mistyped_string_flag); @@ -44,8 +46,8 @@ namespace flags = absl::flags_internal; std::string TestHelpMsg() { return "dynamic help"; } template <typename T> -void* TestMakeDflt() { - return new T{}; +void TestMakeDflt(void* dst) { + new (dst) T{}; } void TestCallback() {} @@ -74,6 +76,7 @@ class FlagTest : public testing::Test { #endif return std::string(fname); } + flags::FlagSaver flag_saver_; }; struct S1 { @@ -107,15 +110,15 @@ TEST_F(FlagTest, Traits) { flags::FlagValueStorageKind::kTwoWordsAtomic); #else EXPECT_EQ(flags::StorageKind<S1>(), - flags::FlagValueStorageKind::kHeapAllocated); + flags::FlagValueStorageKind::kAlignedBuffer); EXPECT_EQ(flags::StorageKind<S2>(), - flags::FlagValueStorageKind::kHeapAllocated); + flags::FlagValueStorageKind::kAlignedBuffer); #endif EXPECT_EQ(flags::StorageKind<std::string>(), - flags::FlagValueStorageKind::kHeapAllocated); + flags::FlagValueStorageKind::kAlignedBuffer); EXPECT_EQ(flags::StorageKind<std::vector<std::string>>(), - flags::FlagValueStorageKind::kHeapAllocated); + flags::FlagValueStorageKind::kAlignedBuffer); } // -------------------------------------------------------------------- @@ -190,6 +193,7 @@ ABSL_DECLARE_FLAG(uint64_t, test_flag_08); ABSL_DECLARE_FLAG(double, test_flag_09); ABSL_DECLARE_FLAG(float, test_flag_10); ABSL_DECLARE_FLAG(std::string, test_flag_11); +ABSL_DECLARE_FLAG(absl::Duration, test_flag_12); namespace { @@ -208,6 +212,7 @@ TEST_F(FlagTest, TestFlagDeclaration) { 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"); } #endif // !ABSL_FLAGS_STRIP_NAMES @@ -226,6 +231,7 @@ ABSL_FLAG(uint64_t, test_flag_08, 9876543, "test flag 08"); ABSL_FLAG(double, test_flag_09, -9.876e-50, "test flag 09"); ABSL_FLAG(float, test_flag_10, 1.234e12f, "test flag 10"); ABSL_FLAG(std::string, test_flag_11, "", "test flag 11"); +ABSL_FLAG(absl::Duration, test_flag_12, absl::Minutes(10), "test flag 12"); namespace { @@ -287,6 +293,11 @@ TEST_F(FlagTest, TestFlagDefinition) { 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(); } #endif // !ABSL_FLAGS_STRIP_NAMES @@ -304,6 +315,20 @@ TEST_F(FlagTest, TestDefault) { 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::GetFlag(FLAGS_test_flag_01), true); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234); @@ -316,6 +341,7 @@ TEST_F(FlagTest, TestDefault) { EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55); EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), ""); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10)); } // -------------------------------------------------------------------- @@ -408,6 +434,38 @@ TEST_F(FlagTest, TestGetSet) { absl::SetFlag(&FLAGS_test_flag_11, "asdf"); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "asdf"); + + absl::SetFlag(&FLAGS_test_flag_12, absl::Seconds(110)); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Seconds(110)); +} + +// -------------------------------------------------------------------- + +TEST_F(FlagTest, TestGetViaReflection) { + auto* handle = flags::FindCommandLineFlag("test_flag_01"); + EXPECT_EQ(*handle->Get<bool>(), true); + handle = flags::FindCommandLineFlag("test_flag_02"); + EXPECT_EQ(*handle->Get<int>(), 1234); + handle = flags::FindCommandLineFlag("test_flag_03"); + EXPECT_EQ(*handle->Get<int16_t>(), -34); + handle = flags::FindCommandLineFlag("test_flag_04"); + EXPECT_EQ(*handle->Get<uint16_t>(), 189); + handle = flags::FindCommandLineFlag("test_flag_05"); + EXPECT_EQ(*handle->Get<int32_t>(), 10765); + handle = flags::FindCommandLineFlag("test_flag_06"); + EXPECT_EQ(*handle->Get<uint32_t>(), 40000); + handle = flags::FindCommandLineFlag("test_flag_07"); + EXPECT_EQ(*handle->Get<int64_t>(), -1234567); + handle = flags::FindCommandLineFlag("test_flag_08"); + EXPECT_EQ(*handle->Get<uint64_t>(), 9876543); + handle = flags::FindCommandLineFlag("test_flag_09"); + EXPECT_NEAR(*handle->Get<double>(), -9.876e-50, 1e-55); + handle = flags::FindCommandLineFlag("test_flag_10"); + EXPECT_NEAR(*handle->Get<float>(), 1.234e12f, 1e5f); + handle = flags::FindCommandLineFlag("test_flag_11"); + EXPECT_EQ(*handle->Get<std::string>(), ""); + handle = flags::FindCommandLineFlag("test_flag_12"); + EXPECT_EQ(*handle->Get<absl::Duration>(), absl::Minutes(10)); } // -------------------------------------------------------------------- @@ -416,28 +474,32 @@ int GetDflt1() { return 1; } } // namespace -ABSL_FLAG(int, test_flag_12, GetDflt1(), "test flag 12"); -ABSL_FLAG(std::string, test_flag_13, absl::StrCat("AAA", "BBB"), - "test flag 13"); +ABSL_FLAG(int, test_int_flag_with_non_const_default, GetDflt1(), + "test int flag non const default"); +ABSL_FLAG(std::string, test_string_flag_with_non_const_default, + absl::StrCat("AAA", "BBB"), "test string flag non const default"); namespace { TEST_F(FlagTest, TestNonConstexprDefault) { - EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), 1); - EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), "AAABBB"); + EXPECT_EQ(absl::GetFlag(FLAGS_test_int_flag_with_non_const_default), 1); + EXPECT_EQ(absl::GetFlag(FLAGS_test_string_flag_with_non_const_default), + "AAABBB"); } // -------------------------------------------------------------------- } // namespace -ABSL_FLAG(bool, test_flag_14, true, absl::StrCat("test ", "flag ", "14")); +ABSL_FLAG(bool, test_flag_with_non_const_help, true, + absl::StrCat("test ", "flag ", "non const help")); namespace { #if !ABSL_FLAGS_STRIP_HELP TEST_F(FlagTest, TestNonConstexprHelp) { - EXPECT_EQ(FLAGS_test_flag_14.Help(), "test flag 14"); + EXPECT_EQ(FLAGS_test_flag_with_non_const_help.Help(), + "test flag non const help"); } #endif //! ABSL_FLAGS_STRIP_HELP @@ -503,14 +565,14 @@ std::string AbslUnparseFlag(const CustomUDT& f) { } // namespace -ABSL_FLAG(CustomUDT, test_flag_15, CustomUDT(), "test flag 15"); +ABSL_FLAG(CustomUDT, test_flag_custom_udt, CustomUDT(), "test flag custom UDT"); namespace { TEST_F(FlagTest, TestCustomUDT) { - EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_15), CustomUDT(1, 1)); - absl::SetFlag(&FLAGS_test_flag_15, CustomUDT(2, 3)); - EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_15), CustomUDT(2, 3)); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(1, 1)); + absl::SetFlag(&FLAGS_test_flag_custom_udt, CustomUDT(2, 3)); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(2, 3)); } // MSVC produces link error on the type mismatch. @@ -570,16 +632,17 @@ std::string AbslUnparseFlag(const ConversionTestVal& val) { // Flag default values can be specified with a value that converts to the flag // value type implicitly. -ABSL_FLAG(ConversionTestVal, test_flag_16, - ConversionTestVal::ViaImplicitConv::kTen, "test flag 16"); +ABSL_FLAG(ConversionTestVal, test_flag_implicit_conv, + ConversionTestVal::ViaImplicitConv::kTen, + "test flag init via implicit conversion"); namespace { TEST_F(FlagTest, CanSetViaImplicitConversion) { - EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_16).a, 10); - absl::SetFlag(&FLAGS_test_flag_16, + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_implicit_conv).a, 10); + absl::SetFlag(&FLAGS_test_flag_implicit_conv, ConversionTestVal::ViaImplicitConv::kEleven); - EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_16).a, 11); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_implicit_conv).a, 11); } // -------------------------------------------------------------------- @@ -646,3 +709,69 @@ TEST_F(FlagTest, TestRetiredFlagRegistration) { } } // namespace + +// -------------------------------------------------------------------- + +namespace { + +// User-defined type with small alignment, but size exceeding 16. +struct SmallAlignUDT { + SmallAlignUDT() : c('A'), s(12) {} + char c; + int16_t s; + char bytes[14]; +}; + +bool AbslParseFlag(absl::string_view, SmallAlignUDT*, std::string*) { + return true; +} +std::string AbslUnparseFlag(const SmallAlignUDT&) { return ""; } + +// User-defined type with small size, but not trivially copyable. +struct NonTriviallyCopyableUDT { + NonTriviallyCopyableUDT() : c('A') {} + NonTriviallyCopyableUDT(const NonTriviallyCopyableUDT& rhs) : c(rhs.c) {} + NonTriviallyCopyableUDT& operator=(const NonTriviallyCopyableUDT& rhs) { + c = rhs.c; + return *this; + } + + char c; +}; + +bool AbslParseFlag(absl::string_view, NonTriviallyCopyableUDT*, std::string*) { + return true; +} +std::string AbslUnparseFlag(const NonTriviallyCopyableUDT&) { return ""; } + +} // namespace + +ABSL_FLAG(SmallAlignUDT, test_flag_sa_udt, {}, "help"); +ABSL_FLAG(NonTriviallyCopyableUDT, test_flag_ntc_udt, {}, "help"); + +namespace { + +TEST_F(FlagTest, TestSmallAlignUDT) { + SmallAlignUDT value = absl::GetFlag(FLAGS_test_flag_sa_udt); + EXPECT_EQ(value.c, 'A'); + EXPECT_EQ(value.s, 12); + + value.c = 'B'; + value.s = 45; + absl::SetFlag(&FLAGS_test_flag_sa_udt, value); + value = absl::GetFlag(FLAGS_test_flag_sa_udt); + EXPECT_EQ(value.c, 'B'); + EXPECT_EQ(value.s, 45); +} + +TEST_F(FlagTest, TestNonTriviallyCopyableUDT) { + NonTriviallyCopyableUDT value = absl::GetFlag(FLAGS_test_flag_ntc_udt); + EXPECT_EQ(value.c, 'A'); + + value.c = 'B'; + absl::SetFlag(&FLAGS_test_flag_ntc_udt, value); + value = absl::GetFlag(FLAGS_test_flag_ntc_udt); + EXPECT_EQ(value.c, 'B'); +} + +} // namespace diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc index f3c424ad83d8..089567f7ae50 100644 --- a/absl/flags/internal/flag.cc +++ b/absl/flags/internal/flag.cc @@ -92,9 +92,9 @@ class FlagState : public flags_internal::FlagStateInterface { counter_(counter) {} ~FlagState() override { - if (flag_impl_->ValueStorageKind() != FlagValueStorageKind::kHeapAllocated) + if (flag_impl_->ValueStorageKind() != FlagValueStorageKind::kAlignedBuffer) return; - flags_internal::Delete(flag_impl_->op_, value_.dynamic); + flags_internal::Delete(flag_impl_->op_, value_.heap_allocated); } private: @@ -112,11 +112,11 @@ class FlagState : public flags_internal::FlagStateInterface { // Flag and saved flag data. FlagImpl* flag_impl_; union SavedValue { - explicit SavedValue(void* v) : dynamic(v) {} + explicit SavedValue(void* v) : heap_allocated(v) {} explicit SavedValue(int64_t v) : one_word(v) {} explicit SavedValue(flags_internal::AlignedTwoWords v) : two_words(v) {} - void* dynamic; + void* heap_allocated; int64_t one_word; flags_internal::AlignedTwoWords two_words; } value_; @@ -128,25 +128,33 @@ class FlagState : public flags_internal::FlagStateInterface { /////////////////////////////////////////////////////////////////////////////// // Flag implementation, which does not depend on flag value type. +DynValueDeleter::DynValueDeleter(FlagOpFn op_arg) : op(op_arg) {} + +void DynValueDeleter::operator()(void* ptr) const { + if (op == nullptr) return; + + Delete(op, ptr); +} + void FlagImpl::Init() { new (&data_guard_) absl::Mutex; // At this point the default_value_ always points to gen_func. - std::unique_ptr<void, DynValueDeleter> init_value( - (*default_value_.gen_func)(), DynValueDeleter{op_}); switch (ValueStorageKind()) { - case FlagValueStorageKind::kHeapAllocated: - HeapAllocatedValue() = init_value.release(); + case FlagValueStorageKind::kAlignedBuffer: + (*default_value_.gen_func)(AlignedBufferValue()); break; case FlagValueStorageKind::kOneWordAtomic: { - int64_t atomic_value; - std::memcpy(&atomic_value, init_value.get(), Sizeof(op_)); - OneWordValue().store(atomic_value, std::memory_order_release); + alignas(int64_t) std::array<char, sizeof(int64_t)> buf{}; + (*default_value_.gen_func)(buf.data()); + auto value = absl::bit_cast<int64_t>(buf); + OneWordValue().store(value, std::memory_order_release); break; } case FlagValueStorageKind::kTwoWordsAtomic: { - AlignedTwoWords atomic_value{0, 0}; - std::memcpy(&atomic_value, init_value.get(), Sizeof(op_)); + alignas(AlignedTwoWords) std::array<char, sizeof(AlignedTwoWords)> buf{}; + (*default_value_.gen_func)(buf.data()); + auto atomic_value = absl::bit_cast<AlignedTwoWords>(buf); TwoWordsValue().store(atomic_value, std::memory_order_release); break; } @@ -191,15 +199,16 @@ std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const { if (DefaultKind() == FlagDefaultKind::kDynamicValue) { res = flags_internal::Clone(op_, default_value_.dynamic_value); } else { - res = (*default_value_.gen_func)(); + res = flags_internal::Alloc(op_); + (*default_value_.gen_func)(res); } return {res, DynValueDeleter{op_}}; } void FlagImpl::StoreValue(const void* src) { switch (ValueStorageKind()) { - case FlagValueStorageKind::kHeapAllocated: - Copy(op_, src, HeapAllocatedValue()); + case FlagValueStorageKind::kAlignedBuffer: + Copy(op_, src, AlignedBufferValue()); break; case FlagValueStorageKind::kOneWordAtomic: { int64_t one_word_val = 0; @@ -257,9 +266,9 @@ std::string FlagImpl::DefaultValue() const { std::string FlagImpl::CurrentValue() const { auto* guard = DataGuard(); // Make sure flag initialized switch (ValueStorageKind()) { - case FlagValueStorageKind::kHeapAllocated: { + case FlagValueStorageKind::kAlignedBuffer: { absl::MutexLock l(guard); - return flags_internal::Unparse(op_, HeapAllocatedValue()); + return flags_internal::Unparse(op_, AlignedBufferValue()); } case FlagValueStorageKind::kOneWordAtomic: { const auto one_word_val = @@ -318,9 +327,9 @@ std::unique_ptr<FlagStateInterface> FlagImpl::SaveState() { bool modified = modified_; bool on_command_line = on_command_line_; switch (ValueStorageKind()) { - case FlagValueStorageKind::kHeapAllocated: { + case FlagValueStorageKind::kAlignedBuffer: { return absl::make_unique<FlagState>( - this, flags_internal::Clone(op_, HeapAllocatedValue()), modified, + this, flags_internal::Clone(op_, AlignedBufferValue()), modified, on_command_line, counter_); } case FlagValueStorageKind::kOneWordAtomic: { @@ -345,8 +354,8 @@ bool FlagImpl::RestoreState(const FlagState& flag_state) { } switch (ValueStorageKind()) { - case FlagValueStorageKind::kHeapAllocated: - StoreValue(flag_state.value_.dynamic); + case FlagValueStorageKind::kAlignedBuffer: + StoreValue(flag_state.value_.heap_allocated); break; case FlagValueStorageKind::kOneWordAtomic: StoreValue(&flag_state.value_.one_word); @@ -363,25 +372,27 @@ bool FlagImpl::RestoreState(const FlagState& flag_state) { } template <typename StorageT> -typename StorageT::value_type& FlagImpl::OffsetValue() const { +StorageT* FlagImpl::OffsetValue() const { char* p = reinterpret_cast<char*>(const_cast<FlagImpl*>(this)); // The offset is deduced via Flag value type specific op_. size_t offset = flags_internal::ValueOffset(op_); - return reinterpret_cast<StorageT*>(p + offset)->value; + return reinterpret_cast<StorageT*>(p + offset); } -void*& FlagImpl::HeapAllocatedValue() const { - assert(ValueStorageKind() == FlagValueStorageKind::kHeapAllocated); - return OffsetValue<FlagHeapAllocatedValue>(); +void* FlagImpl::AlignedBufferValue() const { + assert(ValueStorageKind() == FlagValueStorageKind::kAlignedBuffer); + return OffsetValue<void>(); } + std::atomic<int64_t>& FlagImpl::OneWordValue() const { assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic); - return OffsetValue<FlagOneWordValue>(); + return OffsetValue<FlagOneWordValue>()->value; } + std::atomic<AlignedTwoWords>& FlagImpl::TwoWordsValue() const { assert(ValueStorageKind() == FlagValueStorageKind::kTwoWordsAtomic); - return OffsetValue<FlagTwoWordsValue>(); + return OffsetValue<FlagTwoWordsValue>()->value; } // Attempts to parse supplied `value` string using parsing routine in the `flag` @@ -406,9 +417,9 @@ std::unique_ptr<void, DynValueDeleter> FlagImpl::TryParse( void FlagImpl::Read(void* dst) const { auto* guard = DataGuard(); // Make sure flag initialized switch (ValueStorageKind()) { - case FlagValueStorageKind::kHeapAllocated: { + case FlagValueStorageKind::kAlignedBuffer: { absl::MutexLock l(guard); - flags_internal::CopyConstruct(op_, HeapAllocatedValue(), dst); + flags_internal::CopyConstruct(op_, AlignedBufferValue(), dst); break; } case FlagValueStorageKind::kOneWordAtomic: { diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h index ae42dedcd633..2ae3dce3d13d 100644 --- a/absl/flags/internal/flag.h +++ b/absl/flags/internal/flag.h @@ -46,8 +46,8 @@ namespace flags_internal { // by function specific to that type with a signature matching FlagOpFn. enum class FlagOp { + kAlloc, kDelete, - kClone, kCopy, kCopyConstruct, kSizeof, @@ -63,13 +63,13 @@ using FlagOpFn = void* (*)(FlagOp, const void*, void*, void*); template <typename T> void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3); -// Deletes memory interpreting obj as flag value type pointer. -inline void Delete(FlagOpFn op, const void* obj) { - op(FlagOp::kDelete, obj, nullptr, nullptr); +// Allocate aligned memory for a flag value. +inline void* Alloc(FlagOpFn op) { + return op(FlagOp::kAlloc, nullptr, nullptr, nullptr); } -// Makes a copy of flag value pointed by obj. -inline void* Clone(FlagOpFn op, const void* obj) { - return op(FlagOp::kClone, obj, nullptr, nullptr); +// Deletes memory interpreting obj as flag value type pointer. +inline void Delete(FlagOpFn op, void* obj) { + op(FlagOp::kDelete, nullptr, obj, nullptr); } // Copies src to dst interpreting as flag value type pointers. inline void Copy(FlagOpFn op, const void* src, void* dst) { @@ -80,6 +80,12 @@ inline void Copy(FlagOpFn op, const void* src, void* dst) { inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) { op(FlagOp::kCopyConstruct, src, dst, nullptr); } +// Makes a copy of flag value pointed by obj. +inline void* Clone(FlagOpFn op, const void* obj) { + void* res = flags_internal::Alloc(op); + flags_internal::CopyConstruct(op, obj, res); + return res; +} // Returns true if parsing of input text is successfull. inline bool Parse(FlagOpFn op, absl::string_view text, void* dst, std::string* error) { @@ -195,7 +201,7 @@ constexpr FlagHelpArg HelpArg(char) { // Signature for the function generating the initial flag value (usually // based on default value supplied in flag's definition) -using FlagDfltGenFunc = void* (*)(); +using FlagDfltGenFunc = void (*)(void*); union FlagDefaultSrc { constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg) @@ -253,46 +259,36 @@ using FlagUseTwoWordsStorage = #endif template <typename T> -using FlagUseHeapStorage = +using FlagUseBufferStorage = std::integral_constant<bool, !FlagUseOneWordStorage<T>::value && !FlagUseTwoWordsStorage<T>::value>; enum class FlagValueStorageKind : uint8_t { - kHeapAllocated = 0, + kAlignedBuffer = 0, kOneWordAtomic = 1, kTwoWordsAtomic = 2 }; template <typename T> static constexpr FlagValueStorageKind StorageKind() { - return FlagUseHeapStorage<T>::value - ? FlagValueStorageKind::kHeapAllocated + return FlagUseBufferStorage<T>::value + ? FlagValueStorageKind::kAlignedBuffer : FlagUseOneWordStorage<T>::value ? FlagValueStorageKind::kOneWordAtomic - : FlagUseTwoWordsStorage<T>::value - ? FlagValueStorageKind::kTwoWordsAtomic - : FlagValueStorageKind::kHeapAllocated; + : FlagValueStorageKind::kTwoWordsAtomic; } -struct FlagHeapAllocatedValue { - using value_type = void*; - - value_type value; -}; - struct FlagOneWordValue { - using value_type = std::atomic<int64_t>; constexpr FlagOneWordValue() : value(UninitializedFlagValue()) {} - value_type value; + std::atomic<int64_t> value; }; struct FlagTwoWordsValue { - using value_type = std::atomic<AlignedTwoWords>; constexpr FlagTwoWordsValue() : value(AlignedTwoWords{UninitializedFlagValue(), 0}) {} - value_type value; + std::atomic<AlignedTwoWords> value; }; template <typename T, @@ -300,9 +296,10 @@ template <typename T, struct FlagValue; template <typename T> -struct FlagValue<T, FlagValueStorageKind::kHeapAllocated> - : FlagHeapAllocatedValue { +struct FlagValue<T, FlagValueStorageKind::kAlignedBuffer> { bool Get(T*) const { return false; } + + alignas(T) char value[sizeof(T)]; }; template <typename T> @@ -347,10 +344,8 @@ struct FlagCallback { // The class encapsulates the Flag's data and access to it. struct DynValueDeleter { - explicit DynValueDeleter(FlagOpFn op_arg = nullptr) : op(op_arg) {} - void operator()(void* ptr) const { - if (op != nullptr) flags_internal::Delete(op, ptr); - } + explicit DynValueDeleter(FlagOpFn op_arg = nullptr); + void operator()(void* ptr) const; FlagOpFn op; }; @@ -416,10 +411,10 @@ class FlagImpl final : public flags_internal::CommandLineFlag { // it is only used inside the three routines below, which are defined in // flag.cc, we can define it in that file as well. template <typename StorageT> - typename StorageT::value_type& OffsetValue() const; - // This is an accessor for a value stored in heap allocated storage. - // Returns a mutable reference to a pointer to allow vlaue mutation. - void*& HeapAllocatedValue() const; + StorageT* OffsetValue() const; + // This is an accessor for a value stored in an aligned buffer storage. + // Returns a mutable pointer to the start of a buffer. + void* AlignedBufferValue() const; // This is an accessor for a value stored as one word atomic. Returns a // mutable reference to an atomic value. std::atomic<int64_t>& OneWordValue() const; @@ -492,17 +487,8 @@ class FlagImpl final : public flags_internal::CommandLineFlag { // 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 - // containing the mutable bitfields. - // ------------------------------------------------------------------------ - - // Unique tag for absl::call_once call to initialize this flag. - // - // The placement of this variable between the immutable and mutable bitfields - // is important as prevents them from occupying the same byte. If you remove - // this variable, make sure to maintain this property. - absl::once_flag init_control_; + uint8_t : 0; // The bytes containing the const bitfields must not be + // shared with bytes containing the mutable bitfields. // Mutable flag's state (guarded by `data_guard_`). @@ -514,6 +500,9 @@ class FlagImpl final : public flags_internal::CommandLineFlag { // Has this flag been specified on command line. bool on_command_line_ : 1 ABSL_GUARDED_BY(*DataGuard()); + // Unique tag for absl::call_once call to initialize this flag. + absl::once_flag init_control_; + // Mutation counter int64_t counter_ ABSL_GUARDED_BY(*DataGuard()); // Optional flag's callback and absl::Mutex to guard the invocations. @@ -600,11 +589,17 @@ class Flag { template <typename T> void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) { switch (op) { - case FlagOp::kDelete: - delete static_cast<const T*>(v1); + case FlagOp::kAlloc: { + std::allocator<T> alloc; + return std::allocator_traits<std::allocator<T>>::allocate(alloc, 1); + } + case FlagOp::kDelete: { + T* p = static_cast<T*>(v2); + p->~T(); + std::allocator<T> alloc; + std::allocator_traits<std::allocator<T>>::deallocate(alloc, p, 1); return nullptr; - case FlagOp::kClone: - return new T(*static_cast<const T*>(v1)); + } case FlagOp::kCopy: *static_cast<T*>(v2) = *static_cast<const T*>(v1); return nullptr; @@ -675,13 +670,13 @@ class FlagRegistrar { struct EmptyBraces {}; template <typename T> -T* MakeFromDefaultValue(T t) { - return new T(std::move(t)); +void MakeFromDefaultValue(void* dst, T t) { + new (dst) T(std::move(t)); } template <typename T> -T* MakeFromDefaultValue(EmptyBraces) { - return new T{}; +void MakeFromDefaultValue(void* dst, EmptyBraces) { + new (dst) T{}; } } // namespace flags_internal diff --git a/absl/random/internal/iostream_state_saver.h b/absl/random/internal/iostream_state_saver.h index 7378829a423c..e6e242ee1e66 100644 --- a/absl/random/internal/iostream_state_saver.h +++ b/absl/random/internal/iostream_state_saver.h @@ -192,8 +192,8 @@ struct stream_u128_helper<absl::uint128> { template <typename OStream> inline void write(absl::uint128 val, OStream& out) { - uint64_t h = Uint128High64(val); - uint64_t l = Uint128Low64(val); + uint64_t h = absl::Uint128High64(val); + uint64_t l = absl::Uint128Low64(val); out << h << out.fill() << l; } }; diff --git a/absl/random/internal/nanobenchmark_test.cc b/absl/random/internal/nanobenchmark_test.cc index ab824ef55fd9..f1571e269ff5 100644 --- a/absl/random/internal/nanobenchmark_test.cc +++ b/absl/random/internal/nanobenchmark_test.cc @@ -53,7 +53,7 @@ void RunAll(const int argc, char* argv[]) { // Avoid migrating between cores - important on multi-socket systems. int cpu = -1; if (argc == 2) { - if (!SimpleAtoi(argv[1], &cpu)) { + if (!absl::SimpleAtoi(argv[1], &cpu)) { ABSL_RAW_LOG(FATAL, "The optional argument must be a CPU number >= 0.\n"); } } diff --git a/absl/random/internal/wide_multiply.h b/absl/random/internal/wide_multiply.h index 6e4cf1be0af4..0afcbe08e229 100644 --- a/absl/random/internal/wide_multiply.h +++ b/absl/random/internal/wide_multiply.h @@ -38,9 +38,9 @@ namespace random_internal { // MultiplyU64ToU128 multiplies two 64-bit values to a 128-bit value. // If an intrinsic is available, it is used, otherwise use native 32-bit // multiplies to construct the result. -inline uint128 MultiplyU64ToU128(uint64_t a, uint64_t b) { +inline absl::uint128 MultiplyU64ToU128(uint64_t a, uint64_t b) { #if defined(ABSL_HAVE_INTRINSIC_INT128) - return uint128(static_cast<__uint128_t>(a) * b); + return absl::uint128(static_cast<__uint128_t>(a) * b); #elif defined(ABSL_INTERNAL_USE_UMUL128) // uint64_t * uint64_t => uint128 multiply using imul intrinsic on MSVC. uint64_t high = 0; @@ -93,14 +93,14 @@ struct wide_multiply { template <> struct wide_multiply<uint64_t> { using input_type = uint64_t; - using result_type = uint128; + using result_type = absl::uint128; static result_type multiply(uint64_t a, uint64_t b) { return MultiplyU64ToU128(a, b); } - static uint64_t hi(result_type r) { return Uint128High64(r); } - static uint64_t lo(result_type r) { return Uint128Low64(r); } + static uint64_t hi(result_type r) { return absl::Uint128High64(r); } + static uint64_t lo(result_type r) { return absl::Uint128Low64(r); } }; #endif diff --git a/absl/time/duration.cc b/absl/time/duration.cc index 1353fa0aecdc..f01825599de0 100644 --- a/absl/time/duration.cc +++ b/absl/time/duration.cc @@ -732,9 +732,9 @@ void AppendNumberUnit(std::string* out, int64_t n, DisplayUnit unit) { // Note: unit.prec is limited to double's digits10 value (typically 15) so it // always fits in buf[]. void AppendNumberUnit(std::string* out, double n, DisplayUnit unit) { - const int buf_size = std::numeric_limits<double>::digits10; - const int prec = std::min(buf_size, unit.prec); - char buf[buf_size]; // also large enough to hold integer part + constexpr int kBufferSize = std::numeric_limits<double>::digits10; + const int prec = std::min(kBufferSize, unit.prec); + char buf[kBufferSize]; // also large enough to hold integer part char* ep = buf + sizeof(buf); double d = 0; int64_t frac_part = Round(std::modf(n, &d) * unit.pow10); |