// Copyright 2016 Google Inc. All rights reserved. // // 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 // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include namespace zc { #if defined(ZCPOINTER_TRACK_REFS) && ZCPOINTER_TRACK_REFS template class ref; namespace internal { template class OwnedPtrDeleter { public: OwnedPtrDeleter() {} ~OwnedPtrDeleter() {} OwnedPtrDeleter(OwnedPtrDeleter&& other) : refs_(std::move(other.refs_)) { } void operator()(T* t) const { for (auto& ref : refs_) { ref->MarkDeleted(); } delete t; } protected: friend class ref; void AddRef(ref* ref) { refs_.push_front(ref); } void RemoveRef(ref* ref) { refs_.remove(ref); } private: std::forward_list*> refs_; }; void RaiseUseAfterFree(const char* error) __attribute__((noreturn)); } // namespace internal template class owned : public std::unique_ptr> { private: using Deleter = internal::OwnedPtrDeleter; public: using std::unique_ptr::unique_ptr; ref get() { return ref(*this); } private: T* get() const { return this->std::unique_ptr::get(); } }; template class ref { public: ref() : ptr_(DeletedSentinel()) {} explicit ref(owned& o) : ptr_(&o) { ptr_->get_deleter().AddRef(this); } ref(const ref& o) { *this = o; } ref& operator=(const ref& o) { ptr_ = o.ptr_; if (!IsDeleted()) { ptr_->get_deleter().AddRef(this); } return *this; } ~ref() { if (!IsDeleted()) { ptr_->get_deleter().RemoveRef(this); MarkDeleted(); } } T* operator->() const { CheckDeleted(); return ptr_->operator->(); } protected: friend class internal::OwnedPtrDeleter; void MarkDeleted() { ptr_ = DeletedSentinel(); } private: void CheckDeleted() const { if (IsDeleted()) { internal::RaiseUseAfterFree("attempt to access deleted pointer"); } } bool IsDeleted() const { return ptr_ == DeletedSentinel(); } inline static owned* DeletedSentinel() { return reinterpret_cast*>(std::numeric_limits::max()); } owned* ptr_; }; #else template using owned = std::unique_ptr; template using ref = T*; #endif } // namespace zc