diff --git a/CMakeLists.txt b/CMakeLists.txt index e09e335..d0c6e60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -41,6 +41,11 @@ cmake_policy(SET CMP0077 NEW) endif (POLICY CMP0077) +# Allow the user to specify the MSVC runtime +if (POLICY CMP0091) + cmake_policy(SET CMP0091 NEW) +endif (POLICY CMP0091) + # Set BUILD_TESTING to OFF by default. # This must come before the project() and include(CTest) lines. OPTION(BUILD_TESTING "Build tests" OFF)
diff --git a/absl/CMakeLists.txt b/absl/CMakeLists.txt index fbfa782..a41e1ee 100644 --- a/absl/CMakeLists.txt +++ b/absl/CMakeLists.txt
@@ -16,6 +16,7 @@ add_subdirectory(base) add_subdirectory(algorithm) +add_subdirectory(cleanup) add_subdirectory(container) add_subdirectory(debugging) add_subdirectory(flags)
diff --git a/absl/base/attributes.h b/absl/base/attributes.h index cf2cb55..325e2f8 100644 --- a/absl/base/attributes.h +++ b/absl/base/attributes.h
@@ -131,14 +131,14 @@ // ABSL_ATTRIBUTE_WEAK // // Tags a function as weak for the purposes of compilation and linking. -// Weak attributes currently do not work properly in LLVM's Windows backend, -// so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598 +// Weak attributes did not work properly in LLVM's Windows backend before +// 9.0.0, so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598 // for further information. // The MinGW compiler doesn't complain about the weak attribute until the link // step, presumably because Windows doesn't use ELF binaries. #if (ABSL_HAVE_ATTRIBUTE(weak) || \ (defined(__GNUC__) && !defined(__clang__))) && \ - !(defined(__llvm__) && defined(_WIN32)) && !defined(__MINGW32__) + (!defined(_WIN32) || __clang_major__ < 9) && !defined(__MINGW32__) #undef ABSL_ATTRIBUTE_WEAK #define ABSL_ATTRIBUTE_WEAK __attribute__((weak)) #define ABSL_HAVE_ATTRIBUTE_WEAK 1 @@ -524,6 +524,13 @@ // ABSL_ATTRIBUTE_UNUSED // // Prevents the compiler from complaining about variables that appear unused. +// +// For code or headers that are assured to only build with C++17 and up, prefer +// just using the standard '[[maybe_unused]]' directly over this macro. +// +// Due to differences in positioning requirements between the old, compiler +// specific __attribute__ syntax and the now standard [[maybe_unused]], this +// macro does not attempt to take advantage of '[[maybe_unused]]'. #if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__)) #undef ABSL_ATTRIBUTE_UNUSED #define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__))
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index e7fd115..5385bcb 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel
@@ -260,6 +260,7 @@ visibility = ["//visibility:private"], deps = [ "//absl/base:config", + "//absl/base:core_headers", ], ) @@ -273,6 +274,7 @@ visibility = ["//visibility:private"], deps = [ "//absl/base:config", + "//absl/base:core_headers", ], )
diff --git a/absl/debugging/leak_check.cc b/absl/debugging/leak_check.cc index db9d5d0..764ca0a 100644 --- a/absl/debugging/leak_check.cc +++ b/absl/debugging/leak_check.cc
@@ -16,6 +16,7 @@ // When lsan is not linked in, these functions are not available, // therefore Abseil code which depends on these functions is conditioned on the // definition of LEAK_SANITIZER. +#include "absl/base/attributes.h" #include "absl/debugging/leak_check.h" #ifndef LEAK_SANITIZER @@ -23,6 +24,7 @@ namespace absl { ABSL_NAMESPACE_BEGIN bool HaveLeakSanitizer() { return false; } +bool LeakCheckerIsActive() { return false; } void DoIgnoreLeak(const void*) { } void RegisterLivePointers(const void*, size_t) { } void UnRegisterLivePointers(const void*, size_t) { } @@ -35,9 +37,22 @@ #include <sanitizer/lsan_interface.h> +#if ABSL_HAVE_ATTRIBUTE_WEAK +extern "C" ABSL_ATTRIBUTE_WEAK int __lsan_is_turned_off(); +#endif + namespace absl { ABSL_NAMESPACE_BEGIN bool HaveLeakSanitizer() { return true; } + +#if ABSL_HAVE_ATTRIBUTE_WEAK +bool LeakCheckerIsActive() { + return !(&__lsan_is_turned_off && __lsan_is_turned_off()); +} +#else +bool LeakCheckerIsActive() { return true; } +#endif + bool FindAndReportLeaks() { return __lsan_do_recoverable_leak_check(); } void DoIgnoreLeak(const void* ptr) { __lsan_ignore_object(ptr); } void RegisterLivePointers(const void* ptr, size_t size) {
diff --git a/absl/debugging/leak_check.h b/absl/debugging/leak_check.h index 61c3216..5fc2b05 100644 --- a/absl/debugging/leak_check.h +++ b/absl/debugging/leak_check.h
@@ -43,6 +43,12 @@ // currently built into this target. bool HaveLeakSanitizer(); +// LeakCheckerIsActive() +// +// Returns true if a leak-checking sanitizer (either ASan or standalone LSan) is +// currently built into this target and is turned on. +bool LeakCheckerIsActive(); + // DoIgnoreLeak() // // Implements `IgnoreLeak()` below. This function should usually
diff --git a/absl/debugging/leak_check_test.cc b/absl/debugging/leak_check_test.cc index b5cc487..9fcfc8e 100644 --- a/absl/debugging/leak_check_test.cc +++ b/absl/debugging/leak_check_test.cc
@@ -23,8 +23,10 @@ TEST(LeakCheckTest, DetectLeakSanitizer) { #ifdef ABSL_EXPECT_LEAK_SANITIZER EXPECT_TRUE(absl::HaveLeakSanitizer()); + EXPECT_TRUE(absl::LeakCheckerIsActive()); #else EXPECT_FALSE(absl::HaveLeakSanitizer()); + EXPECT_FALSE(absl::LeakCheckerIsActive()); #endif }
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index d5cb5f3..b5427a4 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h
@@ -499,6 +499,27 @@ #endif // ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE }; +#if defined(__cpp_lib_remove_cvref) && __cpp_lib_remove_cvref >= 201711L +template <typename T> +using remove_cvref = std::remove_cvref<T>; + +template <typename T> +using remove_cvref_t = typename std::remove_cvref<T>::type; +#else +// remove_cvref() +// +// C++11 compatible implementation of std::remove_cvref which was added in +// C++20. +template <typename T> +struct remove_cvref { + using type = + typename std::remove_cv<typename std::remove_reference<T>::type>::type; +}; + +template <typename T> +using remove_cvref_t = typename remove_cvref<T>::type; +#endif + namespace type_traits_internal { // is_trivially_copyable() //
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc index 1aafd0d..0ef5b66 100644 --- a/absl/meta/type_traits_test.cc +++ b/absl/meta/type_traits_test.cc
@@ -942,6 +942,34 @@ absl::type_traits_internal::is_trivially_copyable<Trivial&>::value); } +TEST(TypeTraitsTest, TestRemoveCVRef) { + EXPECT_TRUE( + (std::is_same<typename absl::remove_cvref<int>::type, int>::value)); + EXPECT_TRUE( + (std::is_same<typename absl::remove_cvref<int&>::type, int>::value)); + EXPECT_TRUE( + (std::is_same<typename absl::remove_cvref<int&&>::type, int>::value)); + EXPECT_TRUE(( + std::is_same<typename absl::remove_cvref<const int&>::type, int>::value)); + EXPECT_TRUE( + (std::is_same<typename absl::remove_cvref<int*>::type, int*>::value)); + // Does not remove const in this case. + EXPECT_TRUE((std::is_same<typename absl::remove_cvref<const int*>::type, + const int*>::value)); + EXPECT_TRUE((std::is_same<typename absl::remove_cvref<int[2]>::type, + int[2]>::value)); + EXPECT_TRUE((std::is_same<typename absl::remove_cvref<int(&)[2]>::type, + int[2]>::value)); + EXPECT_TRUE((std::is_same<typename absl::remove_cvref<int(&&)[2]>::type, + int[2]>::value)); + EXPECT_TRUE((std::is_same<typename absl::remove_cvref<const int[2]>::type, + int[2]>::value)); + EXPECT_TRUE((std::is_same<typename absl::remove_cvref<const int(&)[2]>::type, + int[2]>::value)); + EXPECT_TRUE((std::is_same<typename absl::remove_cvref<const int(&&)[2]>::type, + int[2]>::value)); +} + #define ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(trait_name, ...) \ EXPECT_TRUE((std::is_same<typename std::trait_name<__VA_ARGS__>::type, \ absl::trait_name##_t<__VA_ARGS__>>::value))
diff --git a/absl/status/status_test.cc b/absl/status/status_test.cc index 0e1a43c..1b038f6 100644 --- a/absl/status/status_test.cc +++ b/absl/status/status_test.cc
@@ -36,7 +36,9 @@ // its creator, and its classifier. struct ErrorTest { absl::StatusCode code; - using Creator = absl::Status (*)(absl::string_view); + using Creator = absl::Status (*)( + absl::string_view + ); using Classifier = bool (*)(const absl::Status&); Creator creator; Classifier classifier; @@ -78,7 +80,9 @@ // expected error code and message. std::string message = absl::StrCat("error code ", test.code, " test message"); - absl::Status status = test.creator(message); + absl::Status status = test.creator( + message + ); EXPECT_EQ(test.code, status.code()); EXPECT_EQ(message, status.message());
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index 9353375..1c03a61 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc
@@ -1688,6 +1688,8 @@ } else if (rep->tag == EXTERNAL) { *fragment = absl::string_view(rep->external()->base, rep->length); return true; + } else if (rep->tag == RING) { + return rep->ring()->IsFlat(fragment); } else if (rep->tag == SUBSTRING) { CordRep* child = rep->substring()->child; if (child->tag >= FLAT) { @@ -1698,6 +1700,9 @@ *fragment = absl::string_view( child->external()->base + rep->substring()->start, rep->length); return true; + } else if (child->tag == RING) { + return child->ring()->IsFlat(rep->substring()->start, rep->length, + fragment); } } return false;
diff --git a/absl/strings/cord_ring_test.cc b/absl/strings/cord_ring_test.cc index 7d75e10..2943cf3 100644 --- a/absl/strings/cord_ring_test.cc +++ b/absl/strings/cord_ring_test.cc
@@ -31,9 +31,6 @@ extern thread_local bool cord_ring; -// TOOD(b/177688959): weird things happened with the original test -#define ASAN_BUG_177688959_FIXED false - namespace absl { ABSL_NAMESPACE_BEGIN namespace { @@ -340,19 +337,15 @@ class CordRingTest : public testing::Test { public: ~CordRingTest() override { -#if ASAN_BUG_177688959_FIXED for (CordRep* rep : unrefs_) { CordRep::Unref(rep); } -#endif } template <typename CordRepType> CordRepType* NeedsUnref(CordRepType* rep) { assert(rep); -#if ASAN_BUG_177688959_FIXED unrefs_.push_back(rep); -#endif return rep; } @@ -362,26 +355,16 @@ return NeedsUnref(rep); } - void Unref(CordRep* rep) { -#if !ASAN_BUG_177688959_FIXED - CordRep::Unref(rep); -#endif - } - private: -#if ASAN_BUG_177688959_FIXED std::vector<CordRep*> unrefs_; -#endif }; class CordRingTestWithParam : public testing::TestWithParam<TestParam> { public: ~CordRingTestWithParam() override { -#if ASAN_BUG_177688959_FIXED for (CordRep* rep : unrefs_) { CordRep::Unref(rep); } -#endif } CordRepRing* CreateWithCapacity(CordRep* child, size_t extra_capacity) { @@ -400,9 +383,7 @@ template <typename CordRepType> CordRepType* NeedsUnref(CordRepType* rep) { assert(rep); -#if ASAN_BUG_177688959_FIXED unrefs_.push_back(rep); -#endif return rep; } @@ -412,43 +393,23 @@ return NeedsUnref(rep); } - void Unref(CordRep* rep) { -#if !ASAN_BUG_177688959_FIXED - CordRep::Unref(rep); -#endif - } - template <typename CordRepType> CordRepType* RefIfShared(CordRepType* rep) { return Shared() ? Ref(rep) : rep; } - void UnrefIfShared(CordRep* rep) { - if (Shared()) Unref(rep); - } - template <typename CordRepType> CordRepType* RefIfInputShared(CordRepType* rep) { return InputShared() ? Ref(rep) : rep; } - void UnrefIfInputShared(CordRep* rep) { - if (InputShared()) Unref(rep); - } - template <typename CordRepType> CordRepType* RefIfInputSharedIndirect(CordRepType* rep) { return InputSharedIndirect() ? Ref(rep) : rep; } - void UnrefIfInputSharedIndirect(CordRep* rep) { - if (InputSharedIndirect()) Unref(rep); - } - private: -#if ASAN_BUG_177688959_FIXED std::vector<CordRep*> unrefs_; -#endif }; class CordRingCreateTest : public CordRingTestWithParam { @@ -520,26 +481,26 @@ } }; -INSTANTIATE_TEST_CASE_P(WithParam, CordRingSubTest, - testing::ValuesIn(CordRingSubTest::CreateTestParams()), - TestParamToString); +INSTANTIATE_TEST_SUITE_P(WithParam, CordRingSubTest, + testing::ValuesIn(CordRingSubTest::CreateTestParams()), + TestParamToString); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( WithParam, CordRingCreateTest, testing::ValuesIn(CordRingCreateTest::CreateTestParams()), TestParamToString); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( WithParam, CordRingCreateFromTreeTest, testing::ValuesIn(CordRingCreateFromTreeTest::CreateTestParams()), TestParamToString); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( WithParam, CordRingBuildTest, testing::ValuesIn(CordRingBuildTest::CreateTestParams()), TestParamToString); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( WithParam, CordRingBuildInputTest, testing::ValuesIn(CordRingBuildInputTest::CreateTestParams()), TestParamToString); @@ -550,7 +511,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result->length, Eq(str1.size())); EXPECT_THAT(ToFlats(result), ElementsAre(str1)); - Unref(result); } TEST_P(CordRingCreateTest, CreateFromRing) { @@ -559,8 +519,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivate(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats)); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringRing) { @@ -570,23 +528,20 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfInputPrivate(GetParam(), ring)); EXPECT_THAT(ToString(result), string_view(kFox).substr(2, 11)); - UnrefIfInputSharedIndirect(ring); - UnrefIfInputShared(sub); - Unref(result); } TEST_F(CordRingTest, CreateWithIllegalExtraCapacity) { - CordRep* flat = NeedsUnref(MakeFlat("Hello world")); #if defined(ABSL_HAVE_EXCEPTIONS) + CordRep* flat = NeedsUnref(MakeFlat("Hello world")); try { CordRepRing::Create(flat, CordRepRing::kMaxCapacity); GTEST_FAIL() << "expected std::length_error exception"; } catch (const std::length_error&) { } #elif defined(GTEST_HAS_DEATH_TEST) + CordRep* flat = NeedsUnref(MakeFlat("Hello world")); EXPECT_DEATH(CordRepRing::Create(flat, CordRepRing::kMaxCapacity), ".*"); #endif - Unref(flat); } TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringOfFlat) { @@ -597,9 +552,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result->length, Eq(20)); EXPECT_THAT(ToFlats(result), ElementsAre(str1.substr(4, 20))); - Unref(result); - UnrefIfInputShared(flat); - UnrefIfInputSharedIndirect(child); } TEST_P(CordRingCreateTest, CreateFromExternal) { @@ -609,8 +561,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result->length, Eq(str1.size())); EXPECT_THAT(ToFlats(result), ElementsAre(str1)); - Unref(result); - UnrefIfInputShared(child); } TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringOfExternal) { @@ -621,9 +571,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result->length, Eq(24)); EXPECT_THAT(ToFlats(result), ElementsAre(str1.substr(1, 24))); - Unref(result); - UnrefIfInputShared(external); - UnrefIfInputSharedIndirect(child); } TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringOfLargeExternal) { @@ -637,9 +584,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result->length, Eq(str.size())); EXPECT_THAT(ToRawFlats(result), ElementsAre(str)); - Unref(result); - UnrefIfInputShared(external); - UnrefIfInputSharedIndirect(child); } TEST_P(CordRingBuildInputTest, CreateFromConcat) { @@ -652,10 +596,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result->length, Eq(26)); EXPECT_THAT(ToString(result), Eq(kAlphabet)); - UnrefIfInputSharedIndirect(flats[0]); - UnrefIfInputSharedIndirect(flats[3]); - UnrefIfInputShared(concat); - Unref(result); } TEST_P(CordRingBuildInputTest, CreateFromSubstringConcat) { @@ -671,10 +611,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); ASSERT_THAT(result->length, Eq(len)); ASSERT_THAT(ToString(result), string_view(kAlphabet).substr(off, len)); - UnrefIfInputSharedIndirect(flats[0]); - UnrefIfInputSharedIndirect(flats[3]); - UnrefIfInputShared(child); - Unref(result); } } } @@ -689,7 +625,6 @@ EXPECT_THAT(result->capacity(), Le(2 * 120 + 1)); EXPECT_THAT(result->entries(), Eq(1)); EXPECT_THAT(result->begin_pos(), Eq(0)); - Unref(result); } TEST_P(CordRingCreateTest, EntryForNewFlat) { @@ -700,7 +635,6 @@ EXPECT_THAT(result->entry_child(0), Eq(child)); EXPECT_THAT(result->entry_end_pos(0), Eq(str1.length())); EXPECT_THAT(result->entry_data_offset(0), Eq(0)); - Unref(result); } TEST_P(CordRingCreateTest, EntryForNewFlatSubstring) { @@ -712,7 +646,6 @@ EXPECT_THAT(result->entry_child(0), Eq(child)); EXPECT_THAT(result->entry_end_pos(0), Eq(26)); EXPECT_THAT(result->entry_data_offset(0), Eq(10)); - Unref(result); } TEST_P(CordRingBuildTest, AppendFlat) { @@ -724,8 +657,6 @@ EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(result->length, Eq(str1.size() + str2.size())); EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2)); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildTest, PrependFlat) { @@ -737,8 +668,6 @@ EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(result->length, Eq(str1.size() + str2.size())); EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1)); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildTest, AppendString) { @@ -750,8 +679,6 @@ EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(result->length, Eq(str1.size() + str2.size())); EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2)); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildTest, AppendStringHavingExtra) { @@ -762,8 +689,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result->length, Eq(str1.size() + str2.size())); EXPECT_THAT(result, EqIfPrivate(GetParam(), ring)); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildTest, AppendStringHavingPartialExtra) { @@ -790,8 +715,6 @@ } else { EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2)); } - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildTest, AppendStringHavingExtraInSubstring) { @@ -808,8 +731,6 @@ } else { EXPECT_THAT(ToFlats(result), ElementsAre("1234", str2)); } - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildTest, AppendStringHavingSharedExtra) { @@ -839,8 +760,6 @@ EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(result->length, Eq(4 + str2.size())); EXPECT_THAT(ToFlats(result), ElementsAre("1234", str2)); - UnrefIfShared(ring); - Unref(result); CordRep::Unref(shared_type == 1 ? flat1 : flat); } @@ -857,8 +776,6 @@ EXPECT_THAT(result->length, Eq(str1.size() + str2.size() + str3.size())); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre(str1, StrCat(str2, str3))); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildTest, PrependString) { @@ -875,8 +792,6 @@ } EXPECT_THAT(result->length, Eq(str1.size() + str2.size())); EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1)); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildTest, PrependStringHavingExtra) { @@ -893,8 +808,6 @@ } else { EXPECT_THAT(ToFlats(result), ElementsAre(str2, "1234")); } - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildTest, PrependStringHavingSharedExtra) { @@ -921,8 +834,6 @@ EXPECT_THAT(result->length, Eq(str1a.size() + str2.size())); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1a)); - UnrefIfShared(ring); - Unref(result); CordRep::Unref(shared_type == 1 ? flat1 : flat); } } @@ -938,8 +849,6 @@ EXPECT_THAT(result->length, Eq(str1.size() + str2.size() + str3.size())); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre(StrCat(str3, str2), str1)); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildTest, AppendPrependStringMix) { @@ -950,12 +859,10 @@ result = CordRepRing::Prepend(result, flats[4 - i]); result = CordRepRing::Append(result, flats[4 + i]); } - UnrefIfShared(ring); NeedsUnref(result); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToString(result), kFox); - Unref(result); } TEST_P(CordRingBuildTest, AppendPrependStringMixWithExtra) { @@ -976,8 +883,6 @@ EXPECT_THAT(ToFlats(result), ElementsAre("The quick brown fox ", "jumps ", "over the lazy dog")); } - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildTest, AppendPrependStringMixWithPrependedExtra) { @@ -998,8 +903,6 @@ EXPECT_THAT(ToFlats(result), ElementsAre("The quick brown fox ", "jumps ", "over the lazy dog")); } - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingSubTest, SubRing) { @@ -1011,7 +914,6 @@ CordRepRing* ring = RefIfShared(FromFlats(flats, composition)); CordRepRing* result = CordRepRing::SubRing(ring, offset, 0); EXPECT_THAT(result, nullptr); - UnrefIfShared(ring); for (size_t len = 1; len < all.size() - offset; ++len) { ring = RefIfShared(FromFlats(flats, composition)); @@ -1019,8 +921,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); ASSERT_THAT(result, EqIfPrivate(GetParam(), ring)); ASSERT_THAT(ToString(result), Eq(all.substr(offset, len))); - UnrefIfShared(ring); - Unref(result); } } } @@ -1039,7 +939,6 @@ CordRepRing* ring = RefIfShared(FromFlats(flats, composition)); CordRepRing* result = CordRepRing::SubRing(ring, offset, 0); EXPECT_THAT(result, nullptr); - UnrefIfShared(ring); for (size_t len = all.size() - 30; len < all.size() - offset; ++len) { ring = RefIfShared(FromFlats(flats, composition)); @@ -1049,8 +948,6 @@ auto str = ToString(result); ASSERT_THAT(str, SizeIs(len)); ASSERT_THAT(str, Eq(all.substr(offset, len))); - UnrefIfShared(ring); - Unref(result); } } } @@ -1063,7 +960,6 @@ CordRepRing* ring = RefIfShared(FromFlats(flats, composition)); CordRepRing* result = CordRepRing::RemovePrefix(ring, all.size()); EXPECT_THAT(result, nullptr); - UnrefIfShared(ring); for (size_t len = 1; len < all.size(); ++len) { ring = RefIfShared(FromFlats(flats, composition)); @@ -1071,8 +967,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivate(GetParam(), ring)); EXPECT_THAT(ToString(result), Eq(all.substr(len))); - UnrefIfShared(ring); - Unref(result); } } @@ -1087,7 +981,6 @@ ElementsAre( not_a_string_view(external1->base, 1 << 20).remove_prefix(1 << 16), not_a_string_view(external2->base, 1 << 20))); - Unref(result); } TEST_P(CordRingSubTest, RemoveSuffix) { @@ -1098,7 +991,6 @@ CordRepRing* ring = RefIfShared(FromFlats(flats, composition)); CordRepRing* result = CordRepRing::RemoveSuffix(ring, all.size()); EXPECT_THAT(result, nullptr); - UnrefIfShared(ring); for (size_t len = 1; len < all.size(); ++len) { ring = RefIfShared(FromFlats(flats, composition)); @@ -1106,8 +998,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivate(GetParam(), ring)); EXPECT_THAT(ToString(result), Eq(all.substr(0, all.size() - len))); - UnrefIfShared(ring); - Unref(result); } } @@ -1121,8 +1011,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivate(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats)); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildInputTest, AppendRingWithFlatOffset) { @@ -1137,9 +1025,6 @@ EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("Head", "brown ", "fox ", "jumps ", "over ", "the ", "lazy ", "dog")); - UnrefIfInputSharedIndirect(child); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildInputTest, AppendRingWithBrokenOffset) { @@ -1154,9 +1039,6 @@ EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("Head", "umps ", "over ", "the ", "lazy ", "dog")); - UnrefIfInputSharedIndirect(child); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildInputTest, AppendRingWithFlatLength) { @@ -1171,9 +1053,6 @@ EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("Head", "The ", "quick ", "brown ", "fox ", "jumps ", "over ", "the ")); - UnrefIfInputSharedIndirect(child); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildTest, AppendRingWithBrokenFlatLength) { @@ -1188,9 +1067,6 @@ EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("Head", "The ", "quick ", "brown ", "fox ", "jumps ", "ov")); - UnrefIfInputSharedIndirect(child); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildTest, AppendRingMiddlePiece) { @@ -1205,9 +1081,6 @@ EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("Head", "ck ", "brown ", "fox ", "jum")); - UnrefIfInputSharedIndirect(child); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildTest, AppendRingSinglePiece) { @@ -1221,10 +1094,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("Head", "row")); - UnrefIfInputSharedIndirect(child); - UnrefIfInputShared(stripped); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildInputTest, AppendRingSinglePieceWithPrefix) { @@ -1242,10 +1111,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("Prepend", "Head", "row")); - UnrefIfInputSharedIndirect(child); - UnrefIfInputShared(stripped); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildInputTest, PrependRing) { @@ -1259,9 +1124,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats)); - UnrefIfInputShared(child); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildInputTest, PrependRingWithFlatOffset) { @@ -1276,10 +1138,6 @@ EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("brown ", "fox ", "jumps ", "over ", "the ", "lazy ", "dog", "Tail")); - UnrefIfInputShared(child); - UnrefIfInputSharedIndirect(stripped); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildInputTest, PrependRingWithBrokenOffset) { @@ -1293,10 +1151,6 @@ EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("umps ", "over ", "the ", "lazy ", "dog", "Tail")); - UnrefIfInputShared(child); - UnrefIfInputSharedIndirect(stripped); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildInputTest, PrependRingWithFlatLength) { @@ -1311,10 +1165,6 @@ EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("The ", "quick ", "brown ", "fox ", "jumps ", "over ", "the ", "Tail")); - UnrefIfShared(ring); - UnrefIfInputShared(child); - UnrefIfInputSharedIndirect(stripped); - Unref(result); } TEST_P(CordRingBuildInputTest, PrependRingWithBrokenFlatLength) { @@ -1329,10 +1179,6 @@ EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("The ", "quick ", "brown ", "fox ", "jumps ", "ov", "Tail")); - UnrefIfInputShared(child); - UnrefIfInputSharedIndirect(stripped); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildInputTest, PrependRingMiddlePiece) { @@ -1348,10 +1194,6 @@ EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("ck ", "brown ", "fox ", "jum", "Tail")); - UnrefIfInputShared(child); - UnrefIfInputSharedIndirect(stripped); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildInputTest, PrependRingSinglePiece) { @@ -1365,10 +1207,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("row", "Tail")); - UnrefIfInputShared(child); - UnrefIfInputSharedIndirect(stripped); - UnrefIfShared(ring); - Unref(result); } TEST_P(CordRingBuildInputTest, PrependRingSinglePieceWithPrefix) { @@ -1385,10 +1223,6 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("row", "Prepend", "Tail")); - UnrefIfInputShared(child); - UnrefIfInputSharedIndirect(stripped); - UnrefIfShared(ring); - Unref(result); } TEST_F(CordRingTest, Find) { @@ -1406,7 +1240,6 @@ ASSERT_THAT(found.offset, Lt(data.length())); ASSERT_THAT(data[found.offset], Eq(value[i])); } - Unref(ring); } TEST_F(CordRingTest, FindWithHint) { @@ -1442,7 +1275,6 @@ ++flat_pos; flat_offset += flat.length(); } - Unref(ring); } TEST_F(CordRingTest, FindInLargeRing) { @@ -1464,7 +1296,6 @@ ASSERT_THAT(pos.offset, Lt(data.length())); ASSERT_THAT(data[pos.offset], Eq(value[i])); } - Unref(ring); } TEST_F(CordRingTest, FindTail) { @@ -1483,7 +1314,6 @@ ASSERT_THAT(pos.offset, Lt(data.length())); ASSERT_THAT(data[data.length() - pos.offset - 1], Eq(value[i])); } - Unref(ring); } TEST_F(CordRingTest, FindTailWithHint) { @@ -1510,7 +1340,6 @@ ASSERT_THAT(pos.offset, Lt(data.length())); ASSERT_THAT(data[data.length() - pos.offset - 1], Eq(value[i])); } - Unref(ring); } TEST_F(CordRingTest, FindTailInLargeRing) { @@ -1532,7 +1361,6 @@ ASSERT_THAT(pos.offset, Lt(data.length())); ASSERT_THAT(data[data.length() - pos.offset - 1], Eq(value[i])); } - Unref(ring); } TEST_F(CordRingTest, GetCharacter) { @@ -1544,7 +1372,6 @@ for (int i = 0; i < value.length(); ++i) { ASSERT_THAT(result->GetCharacter(i), Eq(value[i])); } - Unref(result); } TEST_F(CordRingTest, GetCharacterWithSubstring) { @@ -1556,7 +1383,67 @@ for (int i = 0; i < value.length(); ++i) { ASSERT_THAT(result->GetCharacter(i), Eq(value[i])); } - Unref(result); +} + +TEST_F(CordRingTest, IsFlatSingleFlat) { + for (bool external : {false, true}) { + SCOPED_TRACE(external ? "With External" : "With Flat"); + absl::string_view str = "Hello world"; + CordRep* rep = external ? MakeExternal(str) : MakeFlat(str); + CordRepRing* ring = NeedsUnref(CordRepRing::Create(rep)); + + // The ring is a single non-fragmented flat: + absl::string_view fragment; + EXPECT_TRUE(ring->IsFlat(nullptr)); + EXPECT_TRUE(ring->IsFlat(&fragment)); + EXPECT_THAT(fragment, Eq("Hello world")); + fragment = ""; + EXPECT_TRUE(ring->IsFlat(0, 11, nullptr)); + EXPECT_TRUE(ring->IsFlat(0, 11, &fragment)); + EXPECT_THAT(fragment, Eq("Hello world")); + + // Arbitrary ranges must check true as well. + EXPECT_TRUE(ring->IsFlat(1, 4, &fragment)); + EXPECT_THAT(fragment, Eq("ello")); + EXPECT_TRUE(ring->IsFlat(6, 5, &fragment)); + EXPECT_THAT(fragment, Eq("world")); + } +} + +TEST_F(CordRingTest, IsFlatMultiFlat) { + for (bool external : {false, true}) { + SCOPED_TRACE(external ? "With External" : "With Flat"); + absl::string_view str1 = "Hello world"; + absl::string_view str2 = "Halt and catch fire"; + CordRep* rep1 = external ? MakeExternal(str1) : MakeFlat(str1); + CordRep* rep2 = external ? MakeExternal(str2) : MakeFlat(str2); + CordRepRing* ring = CordRepRing::Append(CordRepRing::Create(rep1), rep2); + NeedsUnref(ring); + + // The ring is fragmented, IsFlat() on the entire cord must be false. + EXPECT_FALSE(ring->IsFlat(nullptr)); + absl::string_view fragment = "Don't touch this"; + EXPECT_FALSE(ring->IsFlat(&fragment)); + EXPECT_THAT(fragment, Eq("Don't touch this")); + + // Check for ranges exactly within both flats. + EXPECT_TRUE(ring->IsFlat(0, 11, &fragment)); + EXPECT_THAT(fragment, Eq("Hello world")); + EXPECT_TRUE(ring->IsFlat(11, 19, &fragment)); + EXPECT_THAT(fragment, Eq("Halt and catch fire")); + + // Check for arbitrary partial range inside each flat. + EXPECT_TRUE(ring->IsFlat(1, 4, &fragment)); + EXPECT_THAT(fragment, "ello"); + EXPECT_TRUE(ring->IsFlat(26, 4, &fragment)); + EXPECT_THAT(fragment, "fire"); + + // Check ranges spanning across both flats + fragment = "Don't touch this"; + EXPECT_FALSE(ring->IsFlat(1, 18, &fragment)); + EXPECT_FALSE(ring->IsFlat(10, 2, &fragment)); + EXPECT_THAT(fragment, Eq("Don't touch this")); + } } TEST_F(CordRingTest, Dump) { @@ -1564,7 +1451,6 @@ auto flats = MakeSpan(kFoxFlats); CordRepRing* ring = NeedsUnref(FromFlats(flats, kPrepend)); ss << *ring; - Unref(ring); } } // namespace
diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc index f998242..fb67341 100644 --- a/absl/strings/cord_test.cc +++ b/absl/strings/cord_test.cc
@@ -187,6 +187,18 @@ static cord_internal::CordzInfo* GetCordzInfo(const Cord& c) { return c.contents_.cordz_info(); } + + static Cord MakeSubstring(Cord src, size_t offset, size_t length) { + Cord cord = src; + ABSL_RAW_CHECK(cord.contents_.is_tree(), "Can not be inlined"); + auto* rep = new cord_internal::CordRepSubstring; + rep->tag = cord_internal::SUBSTRING; + rep->child = cord.contents_.tree(); + rep->start = offset; + rep->length = length; + cord.contents_.replace_tree(rep); + return cord; + } }; ABSL_NAMESPACE_END @@ -466,8 +478,8 @@ TEST(TryFlat, SubstrFlat) { absl::Cord c("longer than 15 bytes"); - c.RemovePrefix(1); - EXPECT_EQ(c.TryFlat(), "onger than 15 bytes"); + absl::Cord sub = absl::CordTestPeer::MakeSubstring(c, 1, c.size() - 1); + EXPECT_EQ(sub.TryFlat(), "onger than 15 bytes"); } TEST(TryFlat, Concat) { @@ -482,16 +494,46 @@ TEST(TryFlat, SubstrExternal) { absl::Cord c = absl::MakeCordFromExternal("hell", [](absl::string_view) {}); - c.RemovePrefix(1); - EXPECT_EQ(c.TryFlat(), "ell"); + absl::Cord sub = absl::CordTestPeer::MakeSubstring(c, 1, c.size() - 1); + EXPECT_EQ(sub.TryFlat(), "ell"); } TEST(TryFlat, SubstrConcat) { absl::Cord c = absl::MakeFragmentedCord({"hello", " world"}); + absl::Cord sub = absl::CordTestPeer::MakeSubstring(c, 1, c.size() - 1); + EXPECT_EQ(sub.TryFlat(), absl::nullopt); c.RemovePrefix(1); EXPECT_EQ(c.TryFlat(), absl::nullopt); } +TEST(TryFlat, CommonlyAssumedInvariants) { + // The behavior tested below is not part of the API contract of Cord, but it's + // something we intend to be true in our current implementation. This test + // exists to detect and prevent accidental breakage of the implementation. + absl::string_view fragments[] = {"A fragmented test", + " cord", + " to test subcords", + " of ", + "a", + " cord for", + " each chunk " + "returned by the ", + "iterator"}; + absl::Cord c = absl::MakeFragmentedCord(fragments); + int fragment = 0; + int offset = 0; + absl::Cord::CharIterator itc = c.char_begin(); + for (absl::string_view sv : c.Chunks()) { + absl::string_view expected = fragments[fragment]; + absl::Cord subcord1 = c.Subcord(offset, sv.length()); + absl::Cord subcord2 = absl::Cord::AdvanceAndRead(&itc, sv.size()); + EXPECT_EQ(subcord1.TryFlat(), expected); + EXPECT_EQ(subcord2.TryFlat(), expected); + ++fragment; + offset += sv.length(); + } +} + static bool IsFlat(const absl::Cord& c) { return c.chunk_begin() == c.chunk_end() || ++c.chunk_begin() == c.chunk_end(); }
diff --git a/absl/strings/internal/cord_rep_ring.h b/absl/strings/internal/cord_rep_ring.h index c74d335..830f2b2 100644 --- a/absl/strings/internal/cord_rep_ring.h +++ b/absl/strings/internal/cord_rep_ring.h
@@ -237,6 +237,18 @@ // Returns the character at `offset`. Requires that `offset < length`. char GetCharacter(size_t offset) const; + // Returns true if this instance manages a single contiguous buffer, in which + // case the (optional) output parameter `fragment` is set. Otherwise, the + // function returns false, and `fragment` is left unchanged. + bool IsFlat(absl::string_view* fragment) const; + + // Returns true if the data starting at `offset` with length `length` is + // managed by this instance inside a single contiguous buffer, in which case + // the (optional) output parameter `fragment` is set to the contiguous memory + // starting at offset `offset` with length `length`. Otherwise, the function + // returns false, and `fragment` is left unchanged. + bool IsFlat(size_t offset, size_t length, absl::string_view* fragment) const; + // Testing only: set capacity to requested capacity. void SetCapacityForTesting(size_t capacity); @@ -576,6 +588,25 @@ return static_cast<const CordRepRing*>(this); } +inline bool CordRepRing::IsFlat(absl::string_view* fragment) const { + if (entries() == 1) { + if (fragment) *fragment = entry_data(head()); + return true; + } + return false; +} + +inline bool CordRepRing::IsFlat(size_t offset, size_t length, + absl::string_view* fragment) const { + const Position pos = Find(offset); + const absl::string_view data = entry_data(pos.index); + if (data.length() >= length && data.length() - length >= pos.offset) { + if (fragment) *fragment = data.substr(pos.offset, length); + return true; + } + return false; +} + std::ostream& operator<<(std::ostream& s, const CordRepRing& rep); #ifdef __clang__
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h index 5260b5b..b276bdb 100644 --- a/absl/strings/string_view.h +++ b/absl/strings/string_view.h
@@ -398,12 +398,10 @@ // string_view::compare() // - // Performs a lexicographical comparison between the `string_view` and - // another `absl::string_view`, returning -1 if `this` is less than, 0 if - // `this` is equal to, and 1 if `this` is greater than the passed string - // view. Note that in the case of data equality, a further comparison is made - // on the respective sizes of the two `string_view`s to determine which is - // smaller, equal, or greater. + // Performs a lexicographical comparison between this `string_view` and + // another `string_view` `x`, returning a negative value if `*this` is less + // than `x`, 0 if `*this` is equal to `x`, and a positive value if `*this` + // is greater than `x`. constexpr int compare(string_view x) const noexcept { return CompareImpl(length_, x.length_, Min(length_, x.length_) == 0
diff --git a/absl/time/time.h b/absl/time/time.h index d9ad1ae..2df6858 100644 --- a/absl/time/time.h +++ b/absl/time/time.h
@@ -1180,11 +1180,15 @@ // // Converts the `tm_year`, `tm_mon`, `tm_mday`, `tm_hour`, `tm_min`, and // `tm_sec` fields to an `absl::Time` using the given time zone. See ctime(3) -// for a description of the expected values of the tm fields. If the indicated -// time instant is not unique (see `absl::TimeZone::At(absl::CivilSecond)` -// above), the `tm_isdst` field is consulted to select the desired instant -// (`tm_isdst` > 0 means DST, `tm_isdst` == 0 means no DST, `tm_isdst` < 0 -// means use the post-transition offset). +// for a description of the expected values of the tm fields. If the civil time +// is unique (see `absl::TimeZone::At(absl::CivilSecond)` above), the matching +// time instant is returned. Otherwise, the `tm_isdst` field is consulted to +// choose between the possible results. For a repeated civil time, `tm_isdst != +// 0` returns the matching DST instant, while `tm_isdst == 0` returns the +// matching non-DST instant. For a skipped civil time there is no matching +// instant, so `tm_isdst != 0` returns the DST instant, and `tm_isdst == 0` +// returns the non-DST instant, that would have matched if the transition never +// happened. Time FromTM(const struct tm& tm, TimeZone tz); // ToTM()
diff --git a/ci/macos_xcode_bazel.sh b/ci/macos_xcode_bazel.sh index 738adf9..9e14e66 100755 --- a/ci/macos_xcode_bazel.sh +++ b/ci/macos_xcode_bazel.sh
@@ -24,7 +24,7 @@ fi # If we are running on Kokoro, check for a versioned Bazel binary. -KOKORO_GFILE_BAZEL_BIN="bazel-2.0.0-darwin-x86_64" +KOKORO_GFILE_BAZEL_BIN="bazel-3.7.0-darwin-x86_64" if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f ${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN} ]]; then BAZEL_BIN="${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN}" chmod +x ${BAZEL_BIN}
diff --git a/create_lts.py b/create_lts.py index a98c76b..302812a 100755 --- a/create_lts.py +++ b/create_lts.py
@@ -108,11 +108,16 @@ 'project(absl LANGUAGES CXX)': 'project(absl LANGUAGES CXX VERSION {})'.format(datestamp) }) - # Set the SOVERSION to YYYYMMDD.0.0 - The first 0 means we only have - # ABI compatible changes, and the second 0 means we can increment it - # to mark changes as ABI-compatible, for patch releases. - ReplaceStringsInFile('CMake/AbseilHelpers.cmake', - {'SOVERSION 0': 'SOVERSION "{}.0.0"'.format(datestamp)}) + # Set the SOVERSION to YYMM.0.0 - The first 0 means we only have ABI + # compatible changes, and the second 0 means we can increment it to + # mark changes as ABI-compatible, for patch releases. Note that we + # only use the last two digits of the year and the month because the + # MacOS linker requires the first part of the SOVERSION to fit into + # 16 bits. + # https://www.sicpers.info/2013/03/how-to-version-a-mach-o-library/ + ReplaceStringsInFile( + 'CMake/AbseilHelpers.cmake', + {'SOVERSION 0': 'SOVERSION "{}.0.0"'.format(datestamp[2:6])}) StripContentBetweenTags('CMakeLists.txt', '# absl:lts-remove-begin', '# absl:lts-remove-end')