// 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 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); } protected: friend class ref; T* GetRawPointer() const { return get(); } private: T* get() const { return this->std::unique_ptr::get(); } }; template class ref { public: ref() : ptr_(nullptr), deleter_(nullptr), deleted_(true) {} explicit ref(owned& o) : ptr_(o.GetRawPointer()), deleter_(&o.get_deleter()) { deleter_->AddRef(this); } ref(const ref& o) { *this = o; } ref& operator=(const ref& o) { ptr_ = o.ptr_; deleter_ = o.deleter_; deleted_ = o.deleted_; if (!deleted_) { deleter_->AddRef(this); } return *this; } ~ref() { MarkDeleted(); deleter_->RemoveRef(this); } T* operator->() const { CheckDeleted(); return ptr_; } protected: friend class internal::OwnedPtrDeleter; void MarkDeleted() { deleted_ = true; } private: void CheckDeleted() const { if (deleted_) { internal::RaiseUseAfterFree("attempt to access deleted pointer"); } } T* ptr_; internal::OwnedPtrDeleter* deleter_; bool deleted_ = false; }; #else template using owned = std::unique_ptr; template using ref = T*; #endif } // namespace zc