diff --git a/common/BUILD b/common/BUILD index a41f0cb1a..14e3b6c0d 100644 --- a/common/BUILD +++ b/common/BUILD @@ -894,18 +894,11 @@ cc_library( ], ) -cc_library( - name = "reference_count", - hdrs = ["reference_count.h"], - deps = ["//common/internal:reference_count"], -) - cc_library( name = "allocator", hdrs = ["allocator.h"], deps = [ ":arena", - ":data", "//internal:new", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/base:nullability", @@ -927,29 +920,6 @@ cc_test( ], ) -cc_library( - name = "data", - hdrs = ["data.h"], - deps = [ - "//common/internal:metadata", - "@com_google_absl//absl/base:nullability", - "@com_google_absl//absl/log:absl_check", - "@com_google_protobuf//:protobuf", - ], -) - -cc_test( - name = "data_test", - srcs = ["data_test.cc"], - deps = [ - ":data", - "//common/internal:reference_count", - "//internal:testing", - "@com_google_absl//absl/base:nullability", - "@com_google_protobuf//:protobuf", - ], -) - cc_library( name = "optional_ref", hdrs = ["optional_ref.h"], diff --git a/common/allocator.h b/common/allocator.h index 81d56b096..a6453d3f9 100644 --- a/common/allocator.h +++ b/common/allocator.h @@ -27,7 +27,6 @@ #include "absl/log/die_if_null.h" #include "absl/numeric/bits.h" #include "common/arena.h" -#include "common/data.h" #include "internal/new.h" #include "google/protobuf/arena.h" @@ -291,9 +290,6 @@ class ArenaAllocator { using U = std::remove_const_t; U* object; if constexpr (google::protobuf::Arena::is_arena_constructable::value) { - // Classes derived from `cel::Data` are manually allocated and constructed - // as those class support determining whether the destructor is skippable - // at runtime. object = google::protobuf::Arena::Create(arena(), std::forward(args)...); } else { if constexpr (ArenaTraits<>::constructible()) { @@ -309,8 +305,7 @@ class ArenaAllocator { } } } - if constexpr (google::protobuf::Arena::is_arena_constructable::value || - std::is_base_of_v) { + if constexpr (google::protobuf::Arena::is_arena_constructable::value) { ABSL_DCHECK_EQ(object->GetArena(), arena()); } return object; @@ -322,8 +317,7 @@ class ArenaAllocator { void delete_object(T* p) noexcept { using U = std::remove_const_t; ABSL_DCHECK(p != nullptr); - if constexpr (google::protobuf::Arena::is_arena_constructable::value || - std::is_base_of_v) { + if constexpr (google::protobuf::Arena::is_arena_constructable::value) { ABSL_DCHECK_EQ(p->GetArena(), arena()); } } diff --git a/common/data.h b/common/data.h deleted file mode 100644 index cefc21fa4..000000000 --- a/common/data.h +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2024 Google LLC -// -// 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 THIRD_PARTY_CEL_CPP_COMMON_DATA_H_ -#define THIRD_PARTY_CEL_CPP_COMMON_DATA_H_ - -#include -#include - -#include "absl/base/nullability.h" -#include "absl/log/absl_check.h" -#include "common/internal/metadata.h" -#include "google/protobuf/arena.h" - -namespace cel { - -class Data; -template -struct Ownable; -template -struct Borrowable; - -namespace common_internal { - -class ReferenceCount; - -void SetDataReferenceCount(const Data* absl_nonnull data, - const ReferenceCount* absl_nonnull refcount); - -const ReferenceCount* absl_nullable GetDataReferenceCount( - const Data* absl_nonnull data); - -} // namespace common_internal - -// `Data` is one of the base classes of objects that can be managed by -// `MemoryManager`, the other is `google::protobuf::MessageLite`. -class Data { - public: - Data(const Data&) = default; - Data(Data&&) = default; - ~Data() = default; - Data& operator=(const Data&) = default; - Data& operator=(Data&&) = default; - - google::protobuf::Arena* absl_nullable GetArena() const { - return (owner_ & kOwnerBits) == kOwnerArenaBit - ? reinterpret_cast(owner_ & kOwnerPointerMask) - : nullptr; - } - - protected: - // At this point, the reference count has not been created. So we create it - // unowned and set the reference count after. In theory we could create the - // reference count ahead of time and then update it with the data it has to - // delete, but that is a bit counter intuitive. Doing it this way is also - // similar to how std::enable_shared_from_this works. - Data() = default; - - Data(std::nullptr_t) = delete; - - explicit Data(google::protobuf::Arena* absl_nullable arena) - : owner_(reinterpret_cast(arena) | - (arena != nullptr ? kOwnerArenaBit : kOwnerNone)) {} - - private: - static constexpr uintptr_t kOwnerNone = common_internal::kMetadataOwnerNone; - static constexpr uintptr_t kOwnerReferenceCountBit = - common_internal::kMetadataOwnerReferenceCountBit; - static constexpr uintptr_t kOwnerArenaBit = - common_internal::kMetadataOwnerArenaBit; - static constexpr uintptr_t kOwnerBits = common_internal::kMetadataOwnerBits; - static constexpr uintptr_t kOwnerPointerMask = - common_internal::kMetadataOwnerPointerMask; - - friend void common_internal::SetDataReferenceCount( - const Data* absl_nonnull data, - const common_internal::ReferenceCount* absl_nonnull refcount); - friend const common_internal::ReferenceCount* absl_nullable - common_internal::GetDataReferenceCount(const Data* absl_nonnull data); - template - friend struct Ownable; - template - friend struct Borrowable; - - mutable uintptr_t owner_ = kOwnerNone; -}; - -namespace common_internal { - -inline void SetDataReferenceCount(const Data* absl_nonnull data, - const ReferenceCount* absl_nonnull refcount) { - ABSL_DCHECK_EQ(data->owner_, Data::kOwnerNone); - data->owner_ = - reinterpret_cast(refcount) | Data::kOwnerReferenceCountBit; -} - -inline const ReferenceCount* absl_nullable GetDataReferenceCount( - const Data* absl_nonnull data) { - return (data->owner_ & Data::kOwnerBits) == Data::kOwnerReferenceCountBit - ? reinterpret_cast(data->owner_ & - Data::kOwnerPointerMask) - : nullptr; -} - -} // namespace common_internal - -} // namespace cel - -#endif // THIRD_PARTY_CEL_CPP_COMMON_DATA_H_ diff --git a/common/data_test.cc b/common/data_test.cc deleted file mode 100644 index a6b2a788f..000000000 --- a/common/data_test.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2024 Google LLC -// -// 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 header contains primitives for reference counting, roughly equivalent to -// the primitives used to implement `std::shared_ptr`. These primitives should -// not be used directly in most cases, instead `cel::ManagedMemory` should be -// used instead. - -#include "common/data.h" - -#include "absl/base/nullability.h" -#include "common/internal/reference_count.h" -#include "internal/testing.h" -#include "google/protobuf/arena.h" - -namespace cel { -namespace { - -using ::testing::IsNull; - -class DataTest final : public Data { - public: - DataTest() noexcept : Data() {} - - explicit DataTest(google::protobuf::Arena* absl_nullable arena) noexcept - : Data(arena) {} -}; - -class DataReferenceCount final : public common_internal::ReferenceCounted { - public: - explicit DataReferenceCount(const Data* data) : data_(data) {} - - private: - void Finalize() noexcept override { delete data_; } - - const Data* data_; -}; - -TEST(Data, Arena) { - google::protobuf::Arena arena; - DataTest data(&arena); - EXPECT_EQ(data.GetArena(), &arena); - EXPECT_THAT(common_internal::GetDataReferenceCount(&data), IsNull()); -} - -TEST(Data, ReferenceCount) { - auto* data = new DataTest(); - EXPECT_THAT(data->GetArena(), IsNull()); - auto* refcount = new DataReferenceCount(data); - common_internal::SetDataReferenceCount(data, refcount); - EXPECT_EQ(common_internal::GetDataReferenceCount(data), refcount); - common_internal::StrongUnref(refcount); -} - -} // namespace -} // namespace cel diff --git a/common/internal/BUILD b/common/internal/BUILD index eebf66219..0b6f6238c 100644 --- a/common/internal/BUILD +++ b/common/internal/BUILD @@ -28,40 +28,6 @@ cc_library( ], ) -cc_library( - name = "reference_count", - srcs = ["reference_count.cc"], - hdrs = ["reference_count.h"], - deps = [ - "//common:data", - "//internal:new", - "@com_google_absl//absl/base:core_headers", - "@com_google_absl//absl/base:nullability", - "@com_google_absl//absl/log:absl_check", - "@com_google_absl//absl/strings:string_view", - "@com_google_protobuf//:protobuf", - ], -) - -cc_test( - name = "reference_count_test", - srcs = ["reference_count_test.cc"], - deps = [ - ":reference_count", - "//common:data", - "//internal:testing", - "@com_google_absl//absl/base:nullability", - "@com_google_protobuf//:protobuf", - "@com_google_protobuf//:struct_cc_proto", - ], -) - -cc_library( - name = "metadata", - hdrs = ["metadata.h"], - deps = ["@com_google_protobuf//:protobuf"], -) - cc_library( name = "byte_string", srcs = ["byte_string.cc"], diff --git a/common/internal/metadata.h b/common/internal/metadata.h deleted file mode 100644 index 5d2fa8322..000000000 --- a/common/internal/metadata.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 THIRD_PARTY_CEL_CPP_COMMON_INTERNAL_METADATA_H_ -#define THIRD_PARTY_CEL_CPP_COMMON_INTERNAL_METADATA_H_ - -#include - -#include "google/protobuf/arena.h" - -namespace cel::common_internal { - -// `google::protobuf::Arena` has a minimum alignment of 8. `ReferenceCount` has a minimum -// alignment that is guaranteed to be greater than or equal to `google::protobuf::Arena`. -inline constexpr uintptr_t kMetadataOwnerNone = 0; -inline constexpr uintptr_t kMetadataOwnerReferenceCountBit = uintptr_t{1} << 0; -inline constexpr uintptr_t kMetadataOwnerArenaBit = uintptr_t{1} << 1; -inline constexpr uintptr_t kMetadataOwnerBits = alignof(google::protobuf::Arena) - 1; -inline constexpr uintptr_t kMetadataOwnerPointerMask = ~kMetadataOwnerBits; - -// Ensure kMetadataOwnerBits encompasses kMetadataOwnerReferenceCountBit and -// kMetadataOwnerArenaBit. -static_assert((kMetadataOwnerBits | kMetadataOwnerReferenceCountBit) == - kMetadataOwnerBits); -static_assert((kMetadataOwnerBits | kMetadataOwnerArenaBit) == - kMetadataOwnerBits); - -} // namespace cel::common_internal - -#endif // THIRD_PARTY_CEL_CPP_COMMON_INTERNAL_METADATA_H_ diff --git a/common/internal/reference_count.cc b/common/internal/reference_count.cc deleted file mode 100644 index c954c685e..000000000 --- a/common/internal/reference_count.cc +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2024 Google LLC -// -// 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 "common/internal/reference_count.h" - -#include -#include -#include -#include -#include -#include - -#include "absl/base/nullability.h" -#include "absl/log/absl_check.h" -#include "absl/strings/string_view.h" -#include "common/data.h" -#include "internal/new.h" -#include "google/protobuf/message_lite.h" - -namespace cel::common_internal { - -template class DeletingReferenceCount; - -namespace { - -class ReferenceCountedStdString final : public ReferenceCounted { - public: - static std::pair New( - std::string&& string) { - const auto* const refcount = - new ReferenceCountedStdString(std::move(string)); - const auto* const refcount_string = std::launder( - reinterpret_cast(&refcount->string_[0])); - return std::pair{static_cast(refcount), - absl::string_view(*refcount_string)}; - } - - explicit ReferenceCountedStdString(std::string&& string) { - (::new (static_cast(&string_[0])) std::string(std::move(string))) - ->shrink_to_fit(); - } - - private: - void Finalize() noexcept override { - std::destroy_at(std::launder(reinterpret_cast(&string_[0]))); - } - - alignas(std::string) char string_[sizeof(std::string)]; -}; - -class ReferenceCountedString final : public ReferenceCounted { - public: - static std::pair New( - absl::string_view string) { - const auto* const refcount = - ::new (internal::New(Overhead() + string.size())) - ReferenceCountedString(string); - return std::pair{static_cast(refcount), - absl::string_view(refcount->data_, refcount->size_)}; - } - - private: -// ReferenceCountedString is non-standard-layout due to having virtual functions -// from a base class. This causes compilers to warn about the use of offsetof(), -// but it still works here, so silence the warning and proceed. -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Winvalid-offsetof" -#endif - - static size_t Overhead() { return offsetof(ReferenceCountedString, data_); } - -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic pop -#endif - - explicit ReferenceCountedString(absl::string_view string) - : size_(string.size()) { - std::memcpy(data_, string.data(), size_); - } - - void Delete() noexcept override { - void* const that = this; - const auto size = size_; - std::destroy_at(this); - internal::SizedDelete(that, Overhead() + size); - } - - const size_t size_; - char data_[]; -}; - -} // namespace - -std::pair -MakeReferenceCountedString(absl::string_view value) { - ABSL_DCHECK(!value.empty()); - return ReferenceCountedString::New(value); -} - -std::pair -MakeReferenceCountedString(std::string&& value) { - ABSL_DCHECK(!value.empty()); - return ReferenceCountedStdString::New(std::move(value)); -} - -} // namespace cel::common_internal diff --git a/common/internal/reference_count.h b/common/internal/reference_count.h deleted file mode 100644 index 9c7fb5371..000000000 --- a/common/internal/reference_count.h +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 header contains primitives for reference counting, roughly equivalent to -// the primitives used to implement `std::shared_ptr`. These primitives should -// not be used directly in most cases, instead `cel::Shared` should be -// used instead. - -#ifndef THIRD_PARTY_CEL_CPP_COMMON_INTERNAL_REFERENCE_COUNT_H_ -#define THIRD_PARTY_CEL_CPP_COMMON_INTERNAL_REFERENCE_COUNT_H_ - -#include -#include -#include -#include -#include -#include - -#include "absl/base/attributes.h" -#include "absl/base/nullability.h" -#include "absl/base/optimization.h" -#include "absl/log/absl_check.h" -#include "absl/strings/string_view.h" -#include "common/data.h" -#include "google/protobuf/arena.h" -#include "google/protobuf/message_lite.h" - -namespace cel::common_internal { - -struct AdoptRef final { - explicit AdoptRef() = default; -}; - -inline constexpr AdoptRef kAdoptRef{}; - -class ReferenceCount; -struct ReferenceCountFromThis; - -void SetReferenceCountForThat(ReferenceCountFromThis& that, - ReferenceCount* absl_nullable refcount); - -ReferenceCount* absl_nullable GetReferenceCountForThat( - const ReferenceCountFromThis& that); - -// `ReferenceCountFromThis` is similar to `std::enable_shared_from_this`. It -// allows the derived object to inspect its own reference count. It should not -// be used directly, but should be used through -// `cel::EnableManagedMemoryFromThis`. -struct ReferenceCountFromThis { - private: - friend void SetReferenceCountForThat(ReferenceCountFromThis& that, - ReferenceCount* absl_nullable refcount); - friend ReferenceCount* absl_nullable GetReferenceCountForThat( - const ReferenceCountFromThis& that); - - static constexpr uintptr_t kNullPtr = uintptr_t{0}; - static constexpr uintptr_t kSentinelPtr = ~kNullPtr; - - void* absl_nullable refcount = reinterpret_cast(kSentinelPtr); -}; - -inline void SetReferenceCountForThat(ReferenceCountFromThis& that, - ReferenceCount* absl_nullable refcount) { - ABSL_DCHECK_EQ(that.refcount, - reinterpret_cast(ReferenceCountFromThis::kSentinelPtr)); - that.refcount = static_cast(refcount); -} - -inline ReferenceCount* absl_nullable GetReferenceCountForThat( - const ReferenceCountFromThis& that) { - ABSL_DCHECK_NE(that.refcount, - reinterpret_cast(ReferenceCountFromThis::kSentinelPtr)); - return static_cast(that.refcount); -} - -void StrongRef(const ReferenceCount& refcount) noexcept; - -void StrongRef(const ReferenceCount* absl_nullable refcount) noexcept; - -void StrongUnref(const ReferenceCount& refcount) noexcept; - -void StrongUnref(const ReferenceCount* absl_nullable refcount) noexcept; - -ABSL_MUST_USE_RESULT -bool StrengthenRef(const ReferenceCount& refcount) noexcept; - -ABSL_MUST_USE_RESULT -bool StrengthenRef(const ReferenceCount* absl_nullable refcount) noexcept; - -void WeakRef(const ReferenceCount& refcount) noexcept; - -void WeakRef(const ReferenceCount* absl_nullable refcount) noexcept; - -void WeakUnref(const ReferenceCount& refcount) noexcept; - -void WeakUnref(const ReferenceCount* absl_nullable refcount) noexcept; - -ABSL_MUST_USE_RESULT -bool IsUniqueRef(const ReferenceCount& refcount) noexcept; - -ABSL_MUST_USE_RESULT -bool IsUniqueRef(const ReferenceCount* absl_nullable refcount) noexcept; - -ABSL_MUST_USE_RESULT -bool IsExpiredRef(const ReferenceCount& refcount) noexcept; - -ABSL_MUST_USE_RESULT -bool IsExpiredRef(const ReferenceCount* absl_nullable refcount) noexcept; - -// `ReferenceCount` is similar to the control block used by `std::shared_ptr`. -// It is not meant to be interacted with directly in most cases, instead -// `cel::Shared` should be used. -class alignas(8) ReferenceCount { - public: - ReferenceCount() = default; - - ReferenceCount(const ReferenceCount&) = delete; - ReferenceCount(ReferenceCount&&) = delete; - ReferenceCount& operator=(const ReferenceCount&) = delete; - ReferenceCount& operator=(ReferenceCount&&) = delete; - - virtual ~ReferenceCount() = default; - - private: - friend void StrongRef(const ReferenceCount& refcount) noexcept; - friend void StrongUnref(const ReferenceCount& refcount) noexcept; - friend bool StrengthenRef(const ReferenceCount& refcount) noexcept; - friend void WeakRef(const ReferenceCount& refcount) noexcept; - friend void WeakUnref(const ReferenceCount& refcount) noexcept; - friend bool IsUniqueRef(const ReferenceCount& refcount) noexcept; - friend bool IsExpiredRef(const ReferenceCount& refcount) noexcept; - - virtual void Finalize() noexcept = 0; - - virtual void Delete() noexcept = 0; - - mutable std::atomic strong_refcount_ = 1; - mutable std::atomic weak_refcount_ = 1; -}; - -// ReferenceCount and its derivations must be at least as aligned as -// google::protobuf::Arena. This is a requirement for the pointer tagging defined in -// common/internal/metadata.h. -static_assert(alignof(ReferenceCount) >= alignof(google::protobuf::Arena)); - -// `ReferenceCounted` is a base class for classes which should be reference -// counted. It provides default implementations for `Finalize()` and `Delete()`. -class ReferenceCounted : public ReferenceCount { - private: - void Finalize() noexcept override {} - - void Delete() noexcept override { delete this; } -}; - -// `EmplacedReferenceCount` adapts `T` to make it reference countable, by -// storing `T` inside the reference count. This only works when `T` has not yet -// been allocated. -template -class EmplacedReferenceCount final : public ReferenceCounted { - public: - static_assert(std::is_destructible_v, "T must be destructible"); - static_assert(!std::is_reference_v, "T must not be a reference"); - static_assert(!std::is_volatile_v, "T must not be volatile qualified"); - static_assert(!std::is_const_v, "T must not be const qualified"); - static_assert(!std::is_array_v, "T must not be an array"); - - template - explicit EmplacedReferenceCount(T*& value, Args&&... args) noexcept( - std::is_nothrow_constructible_v) { - value = - ::new (static_cast(&value_[0])) T(std::forward(args)...); - } - - private: - void Finalize() noexcept override { - std::destroy_at(std::launder(reinterpret_cast(&value_[0]))); - } - - // We store the instance of `T` in a char buffer and use placement new and - // direct calls to the destructor. The reason for this is `Finalize()` is - // called when the strong reference count hits 0. This allows us to destroy - // our instance of `T` once we are no longer strongly reachable and deallocate - // the memory once we are no longer weakly reachable. - alignas(T) char value_[sizeof(T)]; -}; - -// `DeletingReferenceCount` adapts `T` to make it reference countable, by taking -// ownership of `T` and deleting it. This only works when `T` has already been -// allocated and is to expensive to move or copy. -template -class DeletingReferenceCount final : public ReferenceCounted { - public: - explicit DeletingReferenceCount(const T* absl_nonnull to_delete) noexcept - : to_delete_(to_delete) {} - - private: - void Finalize() noexcept override { delete to_delete_; } - - const T* absl_nonnull const to_delete_; -}; - -extern template class DeletingReferenceCount; - -template -const ReferenceCount* absl_nonnull MakeDeletingReferenceCount( - const T* absl_nonnull to_delete) { - if constexpr (google::protobuf::Arena::is_arena_constructable::value) { - ABSL_DCHECK_EQ(to_delete->GetArena(), nullptr); - } - if constexpr (std::is_base_of_v) { - return new DeletingReferenceCount(to_delete); - } else { - auto* refcount = new DeletingReferenceCount(to_delete); - if constexpr (std::is_base_of_v) { - common_internal::SetDataReferenceCount(to_delete, refcount); - } - return refcount; - } -} - -template -std::pair -MakeEmplacedReferenceCount(Args&&... args) { - using U = std::remove_const_t; - U* pointer; - auto* const refcount = - new EmplacedReferenceCount(pointer, std::forward(args)...); - if constexpr (google::protobuf::Arena::is_arena_constructable::value) { - ABSL_DCHECK_EQ(pointer->GetArena(), nullptr); - } - if constexpr (std::is_base_of_v) { - common_internal::SetDataReferenceCount(pointer, refcount); - } - return std::pair{static_cast(pointer), - static_cast(refcount)}; -} - -template -class InlinedReferenceCount final : public ReferenceCounted { - public: - template - explicit InlinedReferenceCount(std::in_place_t, Args&&... args) - : ReferenceCounted() { - ::new (static_cast(value())) T(std::forward(args)...); - } - - ABSL_ATTRIBUTE_ALWAYS_INLINE T* absl_nonnull value() { - return reinterpret_cast(&value_[0]); - } - - ABSL_ATTRIBUTE_ALWAYS_INLINE const T* absl_nonnull value() const { - return reinterpret_cast(&value_[0]); - } - - private: - void Finalize() noexcept override { value()->~T(); } - - // We store the instance of `T` in a char buffer and use placement new and - // direct calls to the destructor. The reason for this is `Finalize()` is - // called when the strong reference count hits 0. This allows us to destroy - // our instance of `T` once we are no longer strongly reachable and deallocate - // the memory once we are no longer weakly reachable. - alignas(T) char value_[sizeof(T)]; -}; - -template -std::pair MakeReferenceCount( - Args&&... args) { - using U = std::remove_const_t; - auto* const refcount = - new InlinedReferenceCount(std::in_place, std::forward(args)...); - auto* const pointer = refcount->value(); - if constexpr (std::is_base_of_v) { - SetReferenceCountForThat(*pointer, refcount); - } - return std::make_pair(static_cast(pointer), - static_cast(refcount)); -} - -inline void StrongRef(const ReferenceCount& refcount) noexcept { - const auto count = - refcount.strong_refcount_.fetch_add(1, std::memory_order_relaxed); - ABSL_DCHECK_GT(count, 0); -} - -inline void StrongRef(const ReferenceCount* absl_nullable refcount) noexcept { - if (refcount != nullptr) { - StrongRef(*refcount); - } -} - -inline void StrongUnref(const ReferenceCount& refcount) noexcept { - const auto count = - refcount.strong_refcount_.fetch_sub(1, std::memory_order_acq_rel); - ABSL_DCHECK_GT(count, 0); - ABSL_ASSUME(count > 0); - if (ABSL_PREDICT_FALSE(count == 1)) { - const_cast(refcount).Finalize(); - WeakUnref(refcount); - } -} - -inline void StrongUnref(const ReferenceCount* absl_nullable refcount) noexcept { - if (refcount != nullptr) { - StrongUnref(*refcount); - } -} - -ABSL_MUST_USE_RESULT -inline bool StrengthenRef(const ReferenceCount& refcount) noexcept { - auto count = refcount.strong_refcount_.load(std::memory_order_relaxed); - while (true) { - ABSL_DCHECK_GE(count, 0); - ABSL_ASSUME(count >= 0); - if (count == 0) { - return false; - } - if (refcount.strong_refcount_.compare_exchange_weak( - count, count + 1, std::memory_order_release, - std::memory_order_relaxed)) { - return true; - } - } -} - -ABSL_MUST_USE_RESULT -inline bool StrengthenRef( - const ReferenceCount* absl_nullable refcount) noexcept { - return refcount != nullptr ? StrengthenRef(*refcount) : false; -} - -inline void WeakRef(const ReferenceCount& refcount) noexcept { - const auto count = - refcount.weak_refcount_.fetch_add(1, std::memory_order_relaxed); - ABSL_DCHECK_GT(count, 0); -} - -inline void WeakRef(const ReferenceCount* absl_nullable refcount) noexcept { - if (refcount != nullptr) { - WeakRef(*refcount); - } -} - -inline void WeakUnref(const ReferenceCount& refcount) noexcept { - const auto count = - refcount.weak_refcount_.fetch_sub(1, std::memory_order_acq_rel); - ABSL_DCHECK_GT(count, 0); - ABSL_ASSUME(count > 0); - if (ABSL_PREDICT_FALSE(count == 1)) { - const_cast(refcount).Delete(); - } -} - -inline void WeakUnref(const ReferenceCount* absl_nullable refcount) noexcept { - if (refcount != nullptr) { - WeakUnref(*refcount); - } -} - -ABSL_MUST_USE_RESULT -inline bool IsUniqueRef(const ReferenceCount& refcount) noexcept { - const auto count = refcount.strong_refcount_.load(std::memory_order_acquire); - ABSL_DCHECK_GT(count, 0); - ABSL_ASSUME(count > 0); - return count == 1; -} - -ABSL_MUST_USE_RESULT -inline bool IsUniqueRef(const ReferenceCount* absl_nullable refcount) noexcept { - return refcount != nullptr ? IsUniqueRef(*refcount) : false; -} - -ABSL_MUST_USE_RESULT -inline bool IsExpiredRef(const ReferenceCount& refcount) noexcept { - const auto count = refcount.strong_refcount_.load(std::memory_order_acquire); - ABSL_DCHECK_GE(count, 0); - ABSL_ASSUME(count >= 0); - return count == 0; -} - -ABSL_MUST_USE_RESULT -inline bool IsExpiredRef( - const ReferenceCount* absl_nullable refcount) noexcept { - return refcount != nullptr ? IsExpiredRef(*refcount) : false; -} - -std::pair -MakeReferenceCountedString(absl::string_view value); - -std::pair -MakeReferenceCountedString(std::string&& value); - -} // namespace cel::common_internal - -#endif // THIRD_PARTY_CEL_CPP_COMMON_INTERNAL_REFERENCE_COUNT_H_ diff --git a/common/internal/reference_count_test.cc b/common/internal/reference_count_test.cc deleted file mode 100644 index af36fa9a5..000000000 --- a/common/internal/reference_count_test.cc +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 "common/internal/reference_count.h" - -#include - -#include "google/protobuf/struct.pb.h" -#include "absl/base/nullability.h" -#include "common/data.h" -#include "internal/testing.h" -#include "google/protobuf/arena.h" -#include "google/protobuf/message_lite.h" - -namespace cel::common_internal { -namespace { - -using ::testing::NotNull; -using ::testing::WhenDynamicCastTo; - -class Object : public virtual ReferenceCountFromThis { - public: - explicit Object(bool& destructed) : destructed_(destructed) {} - - ~Object() { destructed_ = true; } - - private: - bool& destructed_; -}; - -class Subobject : public Object, public virtual ReferenceCountFromThis { - public: - using Object::Object; -}; - -TEST(ReferenceCount, Strong) { - bool destructed = false; - Object* object; - ReferenceCount* refcount; - std::tie(object, refcount) = MakeReferenceCount(destructed); - EXPECT_EQ(GetReferenceCountForThat(*object), refcount); - EXPECT_EQ(GetReferenceCountForThat(*static_cast(object)), - refcount); - StrongRef(refcount); - StrongUnref(refcount); - EXPECT_TRUE(IsUniqueRef(refcount)); - EXPECT_FALSE(IsExpiredRef(refcount)); - EXPECT_FALSE(destructed); - StrongUnref(refcount); - EXPECT_TRUE(destructed); -} - -TEST(ReferenceCount, Weak) { - bool destructed = false; - Object* object; - ReferenceCount* refcount; - std::tie(object, refcount) = MakeReferenceCount(destructed); - EXPECT_EQ(GetReferenceCountForThat(*object), refcount); - EXPECT_EQ(GetReferenceCountForThat(*static_cast(object)), - refcount); - WeakRef(refcount); - ASSERT_TRUE(StrengthenRef(refcount)); - StrongUnref(refcount); - EXPECT_TRUE(IsUniqueRef(refcount)); - EXPECT_FALSE(IsExpiredRef(refcount)); - EXPECT_FALSE(destructed); - StrongUnref(refcount); - EXPECT_TRUE(destructed); - EXPECT_TRUE(IsExpiredRef(refcount)); - ASSERT_FALSE(StrengthenRef(refcount)); - WeakUnref(refcount); -} - -class DataObject final : public Data { - public: - DataObject() noexcept : Data() {} - - explicit DataObject(google::protobuf::Arena* absl_nullable arena) noexcept - : Data(arena) {} - - char member_[17]; -}; - -struct OtherObject final { - char data[17]; -}; - -TEST(DeletingReferenceCount, Data) { - auto* data = new DataObject(); - const auto* refcount = MakeDeletingReferenceCount(data); - EXPECT_THAT( - refcount, - WhenDynamicCastTo*>(NotNull())); - EXPECT_EQ(common_internal::GetDataReferenceCount(data), refcount); - StrongUnref(refcount); -} - -TEST(DeletingReferenceCount, MessageLite) { - auto* message_lite = new google::protobuf::Value(); - const auto* refcount = MakeDeletingReferenceCount(message_lite); - EXPECT_THAT( - refcount, - WhenDynamicCastTo*>( - NotNull())); - StrongUnref(refcount); -} - -TEST(DeletingReferenceCount, Other) { - auto* other = new OtherObject(); - const auto* refcount = MakeDeletingReferenceCount(other); - EXPECT_THAT( - refcount, - WhenDynamicCastTo*>(NotNull())); - StrongUnref(refcount); -} - -TEST(EmplacedReferenceCount, Data) { - Data* data; - const ReferenceCount* refcount; - std::tie(data, refcount) = MakeEmplacedReferenceCount(); - EXPECT_THAT( - refcount, - WhenDynamicCastTo*>(NotNull())); - EXPECT_EQ(common_internal::GetDataReferenceCount(data), refcount); - StrongUnref(refcount); -} - -TEST(EmplacedReferenceCount, MessageLite) { - google::protobuf::Value* message_lite; - const ReferenceCount* refcount; - std::tie(message_lite, refcount) = - MakeEmplacedReferenceCount(); - EXPECT_THAT( - refcount, - WhenDynamicCastTo*>( - NotNull())); - StrongUnref(refcount); -} - -TEST(EmplacedReferenceCount, Other) { - OtherObject* other; - const ReferenceCount* refcount; - std::tie(other, refcount) = MakeEmplacedReferenceCount(); - EXPECT_THAT( - refcount, - WhenDynamicCastTo*>(NotNull())); - StrongUnref(refcount); -} - -} // namespace -} // namespace cel::common_internal diff --git a/common/memory.h b/common/memory.h index a9ae46023..684e708f8 100644 --- a/common/memory.h +++ b/common/memory.h @@ -49,12 +49,10 @@ enum class MemoryManagement { std::ostream& operator<<(std::ostream& out, MemoryManagement memory_management); class MemoryManager; -class ReferenceCountingMemoryManager; -class PoolingMemoryManager; // `ReferenceCountingMemoryManager` is a `MemoryManager` which employs automatic // memory management through reference counting. -class ReferenceCountingMemoryManager final { +class ABSL_DEPRECATED("Do not use") ReferenceCountingMemoryManager final { public: ReferenceCountingMemoryManager(const ReferenceCountingMemoryManager&) = delete; @@ -76,7 +74,7 @@ class ReferenceCountingMemoryManager final { // `PoolingMemoryManager` is a `MemoryManager` which employs automatic // memory management through memory pooling. -class PoolingMemoryManager final { +class ABSL_DEPRECATED("Do not use") PoolingMemoryManager final { public: PoolingMemoryManager(const PoolingMemoryManager&) = delete; PoolingMemoryManager(PoolingMemoryManager&&) = delete; diff --git a/common/memory_testing.h b/common/memory_testing.h index 37244dd8f..7c06de298 100644 --- a/common/memory_testing.h +++ b/common/memory_testing.h @@ -39,8 +39,6 @@ class ThreadCompatibleMemoryTest MemoryManagerRef memory_manager() { switch (memory_management()) { case MemoryManagement::kReferenceCounting: - return MemoryManager::ReferenceCounting(); - break; case MemoryManagement::kPooling: if (!arena_) { arena_.emplace(); diff --git a/common/reference_count.h b/common/reference_count.h deleted file mode 100644 index 0a07670bd..000000000 --- a/common/reference_count.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2024 Google LLC -// -// 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 THIRD_PARTY_CEL_CPP_COMMON_REFERENCE_COUNT_H_ -#define THIRD_PARTY_CEL_CPP_COMMON_REFERENCE_COUNT_H_ - -#include "common/internal/reference_count.h" - -namespace cel { - -using ReferenceCount = common_internal::ReferenceCount; - -} // namespace cel - -#endif // THIRD_PARTY_CEL_CPP_COMMON_REFERENCE_COUNT_H_