/** * PANDA 3D SOFTWARE * Copyright (c) Carnegie Mellon University. All rights reserved. * * All use of this software is subject to the terms of the revised BSD * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * * @file copyOnWritePointer.I * @author drose * @date 2007-04-09 */ /** * */ INLINE CopyOnWritePointer:: CopyOnWritePointer(CopyOnWriteObject *object) : _cow_object(object) { if (_cow_object != nullptr) { _cow_object->cache_ref(); } } /** * */ INLINE CopyOnWritePointer:: CopyOnWritePointer(const CopyOnWritePointer ©) : _cow_object(copy._cow_object) { if (_cow_object != nullptr) { _cow_object->cache_ref(); } } /** * */ INLINE void CopyOnWritePointer:: operator = (const CopyOnWritePointer ©) { operator = (copy._cow_object); } /** * */ INLINE void CopyOnWritePointer:: operator = (CopyOnWriteObject *object) { if (_cow_object != object) { if (_cow_object != nullptr) { cache_unref_delete(_cow_object); } _cow_object = object; if (_cow_object != nullptr) { _cow_object->cache_ref(); } } } /** * */ INLINE CopyOnWritePointer:: ~CopyOnWritePointer() { if (_cow_object != nullptr) { cache_unref_delete(_cow_object); } } /** * */ INLINE CopyOnWritePointer:: CopyOnWritePointer(CopyOnWritePointer &&from) noexcept : _cow_object(from._cow_object) { // Steal the other's reference count. from._cow_object = nullptr; } /** * */ INLINE CopyOnWritePointer:: CopyOnWritePointer(PointerTo &&from) noexcept : _cow_object(from.p()) { // Steal the other's reference count, but because it is a regular pointer, // we do need to include the cache reference count. if (_cow_object != nullptr) { _cow_object->cache_ref_only(); } from.cheat() = nullptr; } /** * */ INLINE void CopyOnWritePointer:: operator = (CopyOnWritePointer &&from) noexcept { // Protect against self-move-assignment. if (from._cow_object != _cow_object) { CopyOnWriteObject *old_object = _cow_object; _cow_object = from._cow_object; from._cow_object = nullptr; if (old_object != nullptr) { cache_unref_delete(old_object); } } } /** * */ INLINE void CopyOnWritePointer:: operator = (PointerTo &&from) noexcept { if (from.p() != _cow_object) { CopyOnWriteObject *old_object = _cow_object; // Steal the other's reference count, but because it is a regular pointer, // we do need to include the cache reference count. _cow_object = from.p(); _cow_object->cache_ref_only(); from.cheat() = nullptr; if (old_object != nullptr) { cache_unref_delete(old_object); } } } /** * */ INLINE bool CopyOnWritePointer:: operator == (const CopyOnWritePointer &other) const { return _cow_object == other._cow_object; } /** * */ INLINE bool CopyOnWritePointer:: operator != (const CopyOnWritePointer &other) const { return _cow_object != other._cow_object; } /** * */ INLINE bool CopyOnWritePointer:: operator < (const CopyOnWritePointer &other) const { return _cow_object < other._cow_object; } #ifndef COW_THREADED /** * Returns a pointer locked for read. Until this pointer dereferences, calls * to get_write_pointer() will force a copy. * * This flavor of the method is written for the non-threaded case. */ INLINE const CopyOnWriteObject *CopyOnWritePointer:: get_read_pointer(Thread *current_thread) const { return _cow_object; } #endif // COW_THREADED #ifndef COW_THREADED /** * Returns a pointer locked for write. If another thread or threads already * hold the pointer locked for read, then this will force a copy. * * Until this pointer dereferences, calls to get_read_pointer() or * get_write_pointer() will block. * * This flavor of the method is written for the non-threaded case. */ INLINE CopyOnWriteObject *CopyOnWritePointer:: get_write_pointer() { if (_cow_object == nullptr) { return nullptr; } if (_cow_object->get_cache_ref_count() > 1) { PT(CopyOnWriteObject) new_object = _cow_object->make_cow_copy(); cache_unref_delete(_cow_object); _cow_object = new_object; _cow_object->cache_ref(); } return _cow_object; } #endif // COW_THREADED /** * Returns an unlocked pointer that you can write to. This should only be * used in very narrow circumstances in which you know that no other thread * may be accessing the pointer at the same time. */ INLINE CopyOnWriteObject *CopyOnWritePointer:: get_unsafe_pointer() { return _cow_object; } /** * Returns true if the CopyOnWritePointer contains a NULL pointer, false * otherwise. */ bool CopyOnWritePointer:: is_null() const { return (_cow_object == nullptr); } /** * Sets the pointer to NULL. */ void CopyOnWritePointer:: clear() { if (_cow_object != nullptr) { cache_unref_delete(_cow_object); } _cow_object = nullptr; } /** * Does some easy checks to make sure that the reference count isn't * completely bogus. Returns true if ok, false otherwise. */ INLINE bool CopyOnWritePointer:: test_ref_count_integrity() const { nassertr(_cow_object != nullptr, false); return _cow_object->test_ref_count_integrity(); } /** * Does some easy checks to make sure that the reference count isn't zero, or * completely bogus. Returns true if ok, false otherwise. */ INLINE bool CopyOnWritePointer:: test_ref_count_nonzero() const { nassertr(_cow_object != nullptr, false); return _cow_object->test_ref_count_nonzero(); } #ifndef CPPPARSER /** * */ template INLINE CopyOnWritePointerTo:: CopyOnWritePointerTo(To *object) : CopyOnWritePointer(object) { } #endif // CPPPARSER #ifndef CPPPARSER /** * */ template INLINE CopyOnWritePointerTo:: CopyOnWritePointerTo(const CopyOnWritePointerTo ©) : CopyOnWritePointer(copy) { } #endif // CPPPARSER #ifndef CPPPARSER /** * */ template INLINE void CopyOnWritePointerTo:: operator = (const CopyOnWritePointerTo ©) { CopyOnWritePointer::operator = (copy); } #endif // CPPPARSER #ifndef CPPPARSER /** * */ template INLINE void CopyOnWritePointerTo:: operator = (To *object) { CopyOnWritePointer::operator = (object); } #endif // CPPPARSER #ifndef CPPPARSER /** * */ template INLINE CopyOnWritePointerTo:: CopyOnWritePointerTo(CopyOnWritePointerTo &&from) noexcept : CopyOnWritePointer((CopyOnWritePointer &&)from) { } #endif // CPPPARSER #ifndef CPPPARSER /** * */ template INLINE CopyOnWritePointerTo:: CopyOnWritePointerTo(PointerTo &&from) noexcept { // Steal the other's reference count, but because it is a regular pointer, // we do need to include the cache reference count. _cow_object = from.p(); if (_cow_object != nullptr) { _cow_object->cache_ref_only(); } from.cheat() = nullptr; } #endif // CPPPARSER #ifndef CPPPARSER /** * */ template INLINE void CopyOnWritePointerTo:: operator = (CopyOnWritePointerTo &&from) noexcept { CopyOnWritePointer::operator = ((CopyOnWritePointer &&)from); } #endif // CPPPARSER #ifndef CPPPARSER /** * */ template INLINE void CopyOnWritePointerTo:: operator = (PointerTo &&from) noexcept { if (from.p() != _cow_object) { CopyOnWriteObject *old_object = _cow_object; // Steal the other's reference count, but because it is a regular pointer, // we do need to include the cache reference count. _cow_object = from.p(); _cow_object->cache_ref_only(); from.cheat() = nullptr; if (old_object != nullptr) { cache_unref_delete(old_object); } } } #endif // CPPPARSER #ifndef CPPPARSER #ifdef COW_THREADED /** * See CopyOnWritePointer::get_read_pointer(). */ template INLINE CPT(typename CopyOnWritePointerTo::To) CopyOnWritePointerTo:: get_read_pointer(Thread *current_thread) const { // This is necessary because we don't currently have a way to cast between // two compatible PointerTo types without losing the reference count. CPT(typename CopyOnWritePointerTo::To) to; CPT(CopyOnWriteObject) from = CopyOnWritePointer::get_read_pointer(current_thread); to.cheat() = (const To *)from.p(); from.cheat() = nullptr; return to; } #else // COW_THREADED /** * See CopyOnWritePointer::get_read_pointer(). */ template INLINE const typename CopyOnWritePointerTo::To *CopyOnWritePointerTo:: get_read_pointer(Thread *current_thread) const { return (const To *)CopyOnWritePointer::get_read_pointer(current_thread); } #endif // COW_THREADED #endif // CPPPARSER #ifndef CPPPARSER #ifdef COW_THREADED /** * See CopyOnWritePointer::get_write_pointer(). */ template INLINE PT(typename CopyOnWritePointerTo::To) CopyOnWritePointerTo:: get_write_pointer() { // This is necessary because we don't currently have a way to cast between // two compatible PointerTo types without losing the reference count. PT(typename CopyOnWritePointerTo::To) to; PT(CopyOnWriteObject) from = CopyOnWritePointer::get_write_pointer(); to.cheat() = (To *)from.p(); from.cheat() = nullptr; return to; } #else // COW_THREADED /** * See CopyOnWritePointer::get_write_pointer(). */ template INLINE typename CopyOnWritePointerTo::To *CopyOnWritePointerTo:: get_write_pointer() { return (To *)CopyOnWritePointer::get_write_pointer(); } #endif // COW_THREADED #endif // CPPPARSER #ifndef CPPPARSER /** * See CopyOnWritePointer::get_unsafe_pointer(). */ template INLINE typename CopyOnWritePointerTo::To *CopyOnWritePointerTo:: get_unsafe_pointer() { return (To *)(CopyOnWritePointer::get_unsafe_pointer()); } #endif // CPPPARSER