mirror of https://github.com/KLayout/klayout.git
274 lines
5.9 KiB
C++
274 lines
5.9 KiB
C++
|
|
/*
|
|
|
|
KLayout Layout Viewer
|
|
Copyright (C) 2006-2017 Matthias Koefferlein
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
#include "tlObject.h"
|
|
|
|
#include <QMutexLocker>
|
|
#include <memory>
|
|
|
|
namespace tl
|
|
{
|
|
|
|
// ---------------------------------------------------------------------
|
|
// Object implementation
|
|
|
|
Object::Object ()
|
|
: mp_ptrs (0)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
Object::~Object ()
|
|
{
|
|
WeakOrSharedPtr *ptrs;
|
|
|
|
// NOTE: basically we'd need to lock the mutex here.
|
|
// But this will easily create deadlocks and the
|
|
// destructor should not be called while other threads
|
|
// are accessing this object anyway.
|
|
while ((ptrs = (WeakOrSharedPtr *)(size_t (mp_ptrs) & ~size_t (1))) != 0) {
|
|
ptrs->reset_object ();
|
|
}
|
|
}
|
|
|
|
Object::Object (const Object & /*other*/)
|
|
: mp_ptrs (0)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
Object &Object::operator= (const Object & /*other*/)
|
|
{
|
|
// .. nothing yet ..
|
|
return *this;
|
|
}
|
|
|
|
void Object::register_ptr (WeakOrSharedPtr *p)
|
|
{
|
|
tl_assert (p->mp_next == 0);
|
|
tl_assert (p->mp_prev == 0);
|
|
|
|
WeakOrSharedPtr *ptrs = (WeakOrSharedPtr *)(size_t (mp_ptrs) & ~size_t (1));
|
|
bool kept = (size_t (mp_ptrs) & size_t(1));
|
|
|
|
p->mp_next = ptrs;
|
|
if (ptrs) {
|
|
ptrs->mp_prev = p;
|
|
}
|
|
|
|
mp_ptrs = (WeakOrSharedPtr *)(size_t (p) | kept);
|
|
}
|
|
|
|
void Object::unregister_ptr (WeakOrSharedPtr *p)
|
|
{
|
|
WeakOrSharedPtr *ptrs = (WeakOrSharedPtr *)(size_t (mp_ptrs) & ~size_t (1));
|
|
bool kept = (size_t (mp_ptrs) & size_t(1));
|
|
|
|
if (p == ptrs) {
|
|
mp_ptrs = (WeakOrSharedPtr *)(size_t (p->mp_next) | kept);
|
|
}
|
|
if (p->mp_prev) {
|
|
p->mp_prev->mp_next = p->mp_next;
|
|
}
|
|
if (p->mp_next) {
|
|
p->mp_next->mp_prev = p->mp_prev;
|
|
}
|
|
p->mp_prev = p->mp_next = 0;
|
|
}
|
|
|
|
void Object::detach_from_all_events ()
|
|
{
|
|
WeakOrSharedPtr *ptrs = (WeakOrSharedPtr *)(size_t (mp_ptrs) & ~size_t (1));
|
|
|
|
for (WeakOrSharedPtr *p = ptrs; p; ) {
|
|
WeakOrSharedPtr *pnext = p->mp_next;
|
|
if (p->is_event ()) {
|
|
p->reset_object ();
|
|
}
|
|
p = pnext;
|
|
}
|
|
}
|
|
|
|
bool Object::has_strong_references () const
|
|
{
|
|
WeakOrSharedPtr *ptrs = (WeakOrSharedPtr *)(size_t (mp_ptrs) & ~size_t (1));
|
|
if (ptrs != mp_ptrs) {
|
|
// Object is kept
|
|
return true;
|
|
}
|
|
|
|
for (WeakOrSharedPtr *p = ptrs; p; p = p->mp_next) {
|
|
if (p->is_shared ()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Object::keep ()
|
|
{
|
|
mp_ptrs = (WeakOrSharedPtr *)(size_t (mp_ptrs) | size_t (1));
|
|
}
|
|
|
|
void Object::release ()
|
|
{
|
|
mp_ptrs = (WeakOrSharedPtr *)(size_t (mp_ptrs) & ~size_t (1));
|
|
|
|
// If no more strong references are left, we have to delete ourselves
|
|
if (! has_strong_references ()) {
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
// WeakOrSharedPtr implementation
|
|
|
|
WeakOrSharedPtr::WeakOrSharedPtr ()
|
|
: mp_next (0), mp_prev (0), mp_t (0), m_is_shared (true), m_is_event (false)
|
|
{
|
|
}
|
|
|
|
WeakOrSharedPtr::WeakOrSharedPtr (const WeakOrSharedPtr &o)
|
|
: mp_next (0), mp_prev (0), mp_t (0), m_is_shared (true), m_is_event (false)
|
|
{
|
|
operator= (o);
|
|
}
|
|
|
|
WeakOrSharedPtr::WeakOrSharedPtr (Object *t, bool shared, bool is_event)
|
|
: mp_next (0), mp_prev (0), mp_t (0), m_is_shared (true), m_is_event (false)
|
|
{
|
|
reset (t, shared, is_event);
|
|
}
|
|
|
|
WeakOrSharedPtr::~WeakOrSharedPtr ()
|
|
{
|
|
reset (0, true, false);
|
|
}
|
|
|
|
WeakOrSharedPtr &WeakOrSharedPtr::operator= (const WeakOrSharedPtr &o)
|
|
{
|
|
reset (o.mp_t, o.m_is_shared, o.m_is_event);
|
|
return *this;
|
|
}
|
|
|
|
namespace {
|
|
|
|
/**
|
|
* @brief Provides the global lock instance
|
|
*/
|
|
struct GlobalLockInitializer
|
|
{
|
|
GlobalLockInitializer ()
|
|
{
|
|
if (! sp_lock) {
|
|
sp_lock = new QMutex ();
|
|
}
|
|
}
|
|
|
|
QMutex &gl ()
|
|
{
|
|
return *sp_lock;
|
|
}
|
|
|
|
private:
|
|
static QMutex *sp_lock;
|
|
};
|
|
|
|
QMutex *GlobalLockInitializer::sp_lock = 0;
|
|
|
|
// This ensures the instance is created in the initialization code
|
|
static GlobalLockInitializer s_gl_init;
|
|
|
|
}
|
|
|
|
QMutex &WeakOrSharedPtr::lock ()
|
|
{
|
|
// NOTE: to ensure proper function in static initialization code we cannot simply use
|
|
// a static QMutex instance - this may not be initialized. This is not entirely thread
|
|
// safe we make sure above that this initialization is guaranteed to happen in the
|
|
// static initialization which is single-threaded.
|
|
return GlobalLockInitializer ().gl ();
|
|
}
|
|
|
|
Object *WeakOrSharedPtr::get ()
|
|
{
|
|
// NOTE: this assumes that the pointer access is an atomic operation. Hence no locking.
|
|
return mp_t;
|
|
}
|
|
|
|
const Object *WeakOrSharedPtr::get () const
|
|
{
|
|
// NOTE: this assumes that the pointer access is an atomic operation. Hence no locking.
|
|
return mp_t;
|
|
}
|
|
|
|
void WeakOrSharedPtr::reset_object ()
|
|
{
|
|
QMutexLocker locker (&lock ());
|
|
|
|
if (mp_t) {
|
|
mp_t->unregister_ptr (this);
|
|
mp_t = 0;
|
|
}
|
|
|
|
tl_assert (mp_prev == 0);
|
|
tl_assert (mp_next == 0);
|
|
|
|
m_is_shared = true;
|
|
}
|
|
|
|
void WeakOrSharedPtr::reset (Object *t, bool is_shared, bool is_event)
|
|
{
|
|
Object *to_delete = 0;
|
|
|
|
{
|
|
QMutexLocker locker (&lock ());
|
|
|
|
if (mp_t) {
|
|
Object *told = mp_t;
|
|
mp_t->unregister_ptr (this);
|
|
mp_t = 0;
|
|
if (m_is_shared && told && !told->has_strong_references ()) {
|
|
to_delete = told;
|
|
}
|
|
}
|
|
|
|
tl_assert (mp_prev == 0);
|
|
tl_assert (mp_next == 0);
|
|
|
|
mp_t = t;
|
|
m_is_shared = is_shared;
|
|
m_is_event = is_event;
|
|
|
|
if (mp_t) {
|
|
mp_t->register_ptr (this);
|
|
}
|
|
}
|
|
|
|
if (to_delete) {
|
|
delete to_delete;
|
|
}
|
|
}
|
|
|
|
}
|