mirror of https://github.com/KLayout/klayout.git
WIP: performance improvement: copy-on-write for flat edge pairs
This commit is contained in:
parent
4ec00fb129
commit
cc58d7d8ee
|
|
@ -32,7 +32,7 @@ namespace db
|
|||
// FlatEdgePairs implementation
|
||||
|
||||
FlatEdgePairs::FlatEdgePairs ()
|
||||
: AsIfFlatEdgePairs (), m_edge_pairs (false)
|
||||
: AsIfFlatEdgePairs (), mp_edge_pairs (new db::Shapes (false))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -43,13 +43,13 @@ FlatEdgePairs::~FlatEdgePairs ()
|
|||
}
|
||||
|
||||
FlatEdgePairs::FlatEdgePairs (const FlatEdgePairs &other)
|
||||
: AsIfFlatEdgePairs (other), m_edge_pairs (false)
|
||||
: AsIfFlatEdgePairs (other), mp_edge_pairs (other.mp_edge_pairs)
|
||||
{
|
||||
m_edge_pairs = other.m_edge_pairs;
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
FlatEdgePairs::FlatEdgePairs (const db::Shapes &edge_pairs)
|
||||
: AsIfFlatEdgePairs (), m_edge_pairs (edge_pairs)
|
||||
: AsIfFlatEdgePairs (), mp_edge_pairs (new db::Shapes (edge_pairs))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -61,56 +61,58 @@ void FlatEdgePairs::invalidate_cache ()
|
|||
|
||||
void FlatEdgePairs::reserve (size_t n)
|
||||
{
|
||||
m_edge_pairs.reserve (db::EdgePair::tag (), n);
|
||||
mp_edge_pairs->reserve (db::EdgePair::tag (), n);
|
||||
}
|
||||
|
||||
EdgePairsIteratorDelegate *FlatEdgePairs::begin () const
|
||||
{
|
||||
return new FlatEdgePairsIterator (&m_edge_pairs);
|
||||
return new FlatEdgePairsIterator (mp_edge_pairs.get_const ());
|
||||
}
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> FlatEdgePairs::begin_iter () const
|
||||
{
|
||||
return std::make_pair (db::RecursiveShapeIterator (m_edge_pairs), db::ICplxTrans ());
|
||||
return std::make_pair (db::RecursiveShapeIterator (*mp_edge_pairs), db::ICplxTrans ());
|
||||
}
|
||||
|
||||
bool FlatEdgePairs::empty () const
|
||||
{
|
||||
return m_edge_pairs.empty ();
|
||||
return mp_edge_pairs->empty ();
|
||||
}
|
||||
|
||||
size_t FlatEdgePairs::count () const
|
||||
{
|
||||
return m_edge_pairs.size ();
|
||||
return mp_edge_pairs->size ();
|
||||
}
|
||||
|
||||
size_t FlatEdgePairs::hier_count () const
|
||||
{
|
||||
return m_edge_pairs.size ();
|
||||
return mp_edge_pairs->size ();
|
||||
}
|
||||
|
||||
Box FlatEdgePairs::compute_bbox () const
|
||||
{
|
||||
m_edge_pairs.update_bbox ();
|
||||
return m_edge_pairs.bbox ();
|
||||
mp_edge_pairs->update_bbox ();
|
||||
return mp_edge_pairs->bbox ();
|
||||
}
|
||||
|
||||
EdgePairsDelegate *
|
||||
FlatEdgePairs::filter_in_place (const EdgePairFilterBase &filter)
|
||||
{
|
||||
edge_pair_iterator_type pw = m_edge_pairs.get_layer<db::EdgePair, db::unstable_layer_tag> ().begin ();
|
||||
db::Shapes &ep = *mp_edge_pairs;
|
||||
|
||||
edge_pair_iterator_type pw = ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().begin ();
|
||||
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
if (filter.selected (*p)) {
|
||||
if (pw == m_edge_pairs.get_layer<db::EdgePair, db::unstable_layer_tag> ().end ()) {
|
||||
m_edge_pairs.get_layer<db::EdgePair, db::unstable_layer_tag> ().insert (*p);
|
||||
pw = m_edge_pairs.get_layer<db::EdgePair, db::unstable_layer_tag> ().end ();
|
||||
if (pw == ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().end ()) {
|
||||
ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().insert (*p);
|
||||
pw = ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().end ();
|
||||
} else {
|
||||
m_edge_pairs.get_layer<db::EdgePair, db::unstable_layer_tag> ().replace (pw++, *p);
|
||||
ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().replace (pw++, *p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_edge_pairs.get_layer<db::EdgePair, db::unstable_layer_tag> ().erase (pw, m_edge_pairs.get_layer<db::EdgePair, db::unstable_layer_tag> ().end ());
|
||||
ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().erase (pw, ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().end ());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
|
@ -147,22 +149,24 @@ EdgePairsDelegate *FlatEdgePairs::add_in_place (const EdgePairs &other)
|
|||
{
|
||||
invalidate_cache ();
|
||||
|
||||
db::Shapes &ep = *mp_edge_pairs;
|
||||
|
||||
FlatEdgePairs *other_flat = dynamic_cast<FlatEdgePairs *> (other.delegate ());
|
||||
if (other_flat) {
|
||||
|
||||
m_edge_pairs.insert (other_flat->raw_edge_pairs ().get_layer<db::EdgePair, db::unstable_layer_tag> ().begin (), other_flat->raw_edge_pairs ().get_layer<db::EdgePair, db::unstable_layer_tag> ().end ());
|
||||
ep.insert (other_flat->raw_edge_pairs ().get_layer<db::EdgePair, db::unstable_layer_tag> ().begin (), other_flat->raw_edge_pairs ().get_layer<db::EdgePair, db::unstable_layer_tag> ().end ());
|
||||
|
||||
} else {
|
||||
|
||||
size_t n = m_edge_pairs.size ();
|
||||
size_t n = ep.size ();
|
||||
for (EdgePairsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
++n;
|
||||
}
|
||||
|
||||
m_edge_pairs.reserve (db::EdgePair::tag (), n);
|
||||
ep.reserve (db::EdgePair::tag (), n);
|
||||
|
||||
for (EdgePairsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
m_edge_pairs.insert (*p);
|
||||
ep.insert (*p);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -172,7 +176,7 @@ EdgePairsDelegate *FlatEdgePairs::add_in_place (const EdgePairs &other)
|
|||
|
||||
const db::EdgePair *FlatEdgePairs::nth (size_t n) const
|
||||
{
|
||||
return n < m_edge_pairs.size () ? &m_edge_pairs.get_layer<db::EdgePair, db::unstable_layer_tag> ().begin () [n] : 0;
|
||||
return n < mp_edge_pairs->size () ? &mp_edge_pairs->get_layer<db::EdgePair, db::unstable_layer_tag> ().begin () [n] : 0;
|
||||
}
|
||||
|
||||
bool FlatEdgePairs::has_valid_edge_pairs () const
|
||||
|
|
@ -197,13 +201,13 @@ FlatEdgePairs::insert_into_as_polygons (Layout *layout, db::cell_index_type into
|
|||
void
|
||||
FlatEdgePairs::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
layout->cell (into_cell).shapes (into_layer).insert (m_edge_pairs);
|
||||
layout->cell (into_cell).shapes (into_layer).insert (*mp_edge_pairs);
|
||||
}
|
||||
|
||||
void
|
||||
FlatEdgePairs::insert (const db::EdgePair &ep)
|
||||
{
|
||||
m_edge_pairs.insert (ep);
|
||||
mp_edge_pairs->insert (ep);
|
||||
invalidate_cache ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "dbAsIfFlatEdgePairs.h"
|
||||
#include "dbShapes.h"
|
||||
#include "dbGenericShapeIterator.h"
|
||||
#include "tlCopyOnWrite.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
|
|
@ -109,14 +110,16 @@ public:
|
|||
void transform (const Trans &trans)
|
||||
{
|
||||
if (! trans.is_unity ()) {
|
||||
for (edge_pair_iterator_type p = m_edge_pairs.template get_layer<db::EdgePair, db::unstable_layer_tag> ().begin (); p != m_edge_pairs.template get_layer<db::EdgePair, db::unstable_layer_tag> ().end (); ++p) {
|
||||
m_edge_pairs.get_layer<db::EdgePair, db::unstable_layer_tag> ().replace (p, p->transformed (trans));
|
||||
db::Shapes &ep = *mp_edge_pairs;
|
||||
for (edge_pair_iterator_type p = ep.template get_layer<db::EdgePair, db::unstable_layer_tag> ().begin (); p != ep.template get_layer<db::EdgePair, db::unstable_layer_tag> ().end (); ++p) {
|
||||
ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().replace (p, p->transformed (trans));
|
||||
}
|
||||
invalidate_cache ();
|
||||
}
|
||||
}
|
||||
|
||||
db::Shapes &raw_edge_pairs () { return m_edge_pairs; }
|
||||
db::Shapes &raw_edge_pairs () { return *mp_edge_pairs; }
|
||||
const db::Shapes &raw_edge_pairs () const { return *mp_edge_pairs; }
|
||||
|
||||
protected:
|
||||
virtual Box compute_bbox () const;
|
||||
|
|
@ -127,7 +130,7 @@ private:
|
|||
|
||||
FlatEdgePairs &operator= (const FlatEdgePairs &other);
|
||||
|
||||
mutable db::Shapes m_edge_pairs;
|
||||
mutable tl::copy_on_write_ptr<db::Shapes> mp_edge_pairs;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ FORMS =
|
|||
SOURCES = \
|
||||
tlAssert.cc \
|
||||
tlClassRegistry.cc \
|
||||
tlCopyOnWrite.cc \
|
||||
tlDataMapping.cc \
|
||||
tlDeflate.cc \
|
||||
tlException.cc \
|
||||
|
|
@ -54,6 +55,7 @@ HEADERS = \
|
|||
tlAlgorithm.h \
|
||||
tlAssert.h \
|
||||
tlClassRegistry.h \
|
||||
tlCopyOnWrite.h \
|
||||
tlDataMapping.h \
|
||||
tlDeflate.h \
|
||||
tlException.h \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "tlCopyOnWrite.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
tl::Mutex tl::CopyOnWritePtrBase::ms_lock;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,264 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_tlCopyOnWrite
|
||||
#define HDR_tlCopyOnWrite
|
||||
|
||||
#include "tlCommon.h"
|
||||
#include "tlThreads.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A copy duplicator (see copy_on_write_ptr below)
|
||||
*/
|
||||
template <class X>
|
||||
struct copy_duplicator
|
||||
{
|
||||
X *operator() (const X &o)
|
||||
{
|
||||
return new X (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A clone duplicator (see copy_on_write_ptr below)
|
||||
*/
|
||||
template <class X>
|
||||
struct clone_duplicator
|
||||
{
|
||||
X *operator() (const X &o)
|
||||
{
|
||||
return o.clone ();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A base class for the copy-on-write shared pointers
|
||||
*/
|
||||
class TL_PUBLIC CopyOnWritePtrBase
|
||||
{
|
||||
protected:
|
||||
static tl::Mutex ms_lock;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The holder object: keeps the actual reference of the object
|
||||
*/
|
||||
template <class X>
|
||||
class copy_on_write_holder
|
||||
{
|
||||
public:
|
||||
copy_on_write_holder (X *x)
|
||||
: m_ref_count (1), mp_x (x)
|
||||
{ }
|
||||
|
||||
~copy_on_write_holder ()
|
||||
{
|
||||
delete mp_x;
|
||||
mp_x = 0;
|
||||
}
|
||||
|
||||
X *x ()
|
||||
{
|
||||
return mp_x;
|
||||
}
|
||||
|
||||
int ref_count () const { return m_ref_count; };
|
||||
int dec_ref () { return --m_ref_count; }
|
||||
void inc_ref () { ++m_ref_count; }
|
||||
|
||||
private:
|
||||
int m_ref_count;
|
||||
X *mp_x;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Supplies a copy-on-write shared pointer scheme
|
||||
*
|
||||
* The idea is to provide a smart, "unique" pointer providing a copy constructor and assignment, but
|
||||
* sharing the object as long as the object is not written.
|
||||
*
|
||||
* Write access is assumed as soon as the non-const pointer is retrieved.
|
||||
*
|
||||
* In order to duplicate the object, a "duplicator" needs to be defined. By default, the
|
||||
* object is duplicated using the copy constructor ("copy_duplicator"). An alternative implementation
|
||||
* is provided through the "clone_duplicator", which assumes a "clone" method to supply the duplicated
|
||||
* object.
|
||||
*/
|
||||
template <class X, class Dup = copy_duplicator<X> >
|
||||
class copy_on_write_ptr
|
||||
: public CopyOnWritePtrBase
|
||||
{
|
||||
public:
|
||||
typedef X value_type;
|
||||
|
||||
copy_on_write_ptr ()
|
||||
: mp_holder (0)
|
||||
{ }
|
||||
|
||||
copy_on_write_ptr (X *x)
|
||||
: mp_holder (x ? new copy_on_write_holder<X> (x) : 0)
|
||||
{ }
|
||||
|
||||
explicit copy_on_write_ptr (const copy_on_write_ptr<X, Dup> &other)
|
||||
: mp_holder (other.mp_holder)
|
||||
{
|
||||
aquire ();
|
||||
}
|
||||
|
||||
copy_on_write_ptr &operator= (const copy_on_write_ptr<X, Dup> &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
release ();
|
||||
mp_holder = other.mp_holder;
|
||||
aquire ();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~copy_on_write_ptr ()
|
||||
{
|
||||
release ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a writable object
|
||||
* This is when we will create a new copy if the object is shared.
|
||||
*/
|
||||
X *get_non_const ()
|
||||
{
|
||||
if (mp_holder) {
|
||||
tl::MutexLocker locker (&ms_lock);
|
||||
if (mp_holder->ref_count () > 1) {
|
||||
X *x = mp_holder->x ();
|
||||
mp_holder->dec_ref ();
|
||||
mp_holder = new copy_on_write_holder<X> (Dup () (*x));
|
||||
}
|
||||
return mp_holder->x ();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the const pointer
|
||||
* No copy will be created.
|
||||
*/
|
||||
const X *get_const () const
|
||||
{
|
||||
if (mp_holder) {
|
||||
return mp_holder->x ();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the pointer
|
||||
*/
|
||||
void reset (X *x)
|
||||
{
|
||||
release ();
|
||||
if (x) {
|
||||
mp_holder = new copy_on_write_holder<X> (x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the non-const pointer
|
||||
* This is when we will create a new copy if the object is shared.
|
||||
*/
|
||||
X *operator-> ()
|
||||
{
|
||||
return get_non_const ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the const pointer
|
||||
* No copy will be created.
|
||||
*/
|
||||
const X *operator-> () const
|
||||
{
|
||||
return get_const ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the non-const reference
|
||||
* This is when we will create a new copy if the object is shared.
|
||||
*/
|
||||
X &operator* ()
|
||||
{
|
||||
return *get_non_const ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the const reference
|
||||
* No copy will be created.
|
||||
*/
|
||||
const X &operator* () const
|
||||
{
|
||||
return *get_const ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Debugging and testing: gets the reference count
|
||||
*/
|
||||
int ref_count () const
|
||||
{
|
||||
int rc = 0;
|
||||
if (mp_holder) {
|
||||
tl::MutexLocker locker (&ms_lock);
|
||||
rc = mp_holder->ref_count ();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
private:
|
||||
X *mp_x;
|
||||
copy_on_write_holder<X> *mp_holder;
|
||||
|
||||
void release ()
|
||||
{
|
||||
if (mp_holder) {
|
||||
tl::MutexLocker locker (&ms_lock);
|
||||
if (mp_holder->dec_ref () <= 0) {
|
||||
delete mp_holder;
|
||||
}
|
||||
mp_holder = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void aquire ()
|
||||
{
|
||||
if (mp_holder) {
|
||||
tl::MutexLocker locker (&ms_lock);
|
||||
mp_holder->inc_ref ();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "tlCopyOnWrite.h"
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
// This namespace separates the test structs from other objects
|
||||
namespace copy_on_write_tests
|
||||
{
|
||||
|
||||
static int x_instances = 0;
|
||||
|
||||
class X
|
||||
{
|
||||
public:
|
||||
X () { ++x_instances; }
|
||||
virtual ~X () { --x_instances; }
|
||||
virtual const char *name () const = 0;
|
||||
virtual X *clone () const = 0;
|
||||
};
|
||||
|
||||
class Y : public X
|
||||
{
|
||||
public:
|
||||
virtual const char *name () const { return "Y"; }
|
||||
virtual X *clone () const { return new Y (); }
|
||||
};
|
||||
|
||||
class Z : public X
|
||||
{
|
||||
public:
|
||||
virtual const char *name () const { return "Z"; }
|
||||
virtual X *clone () const { return new Z (); }
|
||||
};
|
||||
|
||||
static int a_instances = 0;
|
||||
|
||||
class A
|
||||
{
|
||||
public:
|
||||
A () { ++a_instances; }
|
||||
A (const A &) { ++a_instances; }
|
||||
~A () { --a_instances; }
|
||||
const char *name () const { return "A"; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
TEST(1)
|
||||
{
|
||||
tl::copy_on_write_ptr<copy_on_write_tests::A> ptr1, ptr2;
|
||||
|
||||
EXPECT_EQ (copy_on_write_tests::a_instances, 0);
|
||||
|
||||
ptr1.reset (new copy_on_write_tests::A ());
|
||||
EXPECT_EQ (copy_on_write_tests::a_instances, 1);
|
||||
|
||||
EXPECT_EQ (ptr1.ref_count (), 1);
|
||||
EXPECT_EQ (ptr1.get_const ()->name (), "A");
|
||||
EXPECT_EQ (ptr1.get_non_const ()->name (), "A");
|
||||
EXPECT_EQ (ptr1.ref_count (), 1);
|
||||
|
||||
ptr2 = ptr1;
|
||||
|
||||
EXPECT_EQ (ptr1.ref_count (), 2);
|
||||
EXPECT_EQ (ptr2.ref_count (), 2);
|
||||
EXPECT_EQ (ptr1.get_const () == ptr2.get_const (), true);
|
||||
EXPECT_EQ (ptr1.get_const ()->name (), "A");
|
||||
|
||||
EXPECT_EQ (ptr1.get_non_const ()->name (), "A");
|
||||
EXPECT_EQ (copy_on_write_tests::a_instances, 2);
|
||||
|
||||
EXPECT_EQ (ptr1.ref_count (), 1);
|
||||
EXPECT_EQ (ptr2.ref_count (), 1);
|
||||
|
||||
EXPECT_EQ (ptr1.get_const () == ptr2.get_const (), false);
|
||||
EXPECT_EQ (ptr1.get_const ()->name (), "A");
|
||||
EXPECT_EQ (ptr2.get_const ()->name (), "A");
|
||||
|
||||
ptr1.reset (0);
|
||||
EXPECT_EQ (copy_on_write_tests::a_instances, 1);
|
||||
ptr2.reset (0);
|
||||
EXPECT_EQ (copy_on_write_tests::a_instances, 0);
|
||||
}
|
||||
|
||||
TEST(2)
|
||||
{
|
||||
tl::copy_on_write_ptr<copy_on_write_tests::A> ptr1;
|
||||
|
||||
EXPECT_EQ (copy_on_write_tests::a_instances, 0);
|
||||
|
||||
ptr1.reset (new copy_on_write_tests::A ());
|
||||
EXPECT_EQ (copy_on_write_tests::a_instances, 1);
|
||||
|
||||
EXPECT_EQ (ptr1.ref_count (), 1);
|
||||
EXPECT_EQ (ptr1.get_const ()->name (), "A");
|
||||
EXPECT_EQ (ptr1.get_non_const ()->name (), "A");
|
||||
EXPECT_EQ (ptr1.ref_count (), 1);
|
||||
|
||||
tl::copy_on_write_ptr<copy_on_write_tests::A> ptr2 (ptr1);
|
||||
|
||||
EXPECT_EQ (ptr1.ref_count (), 2);
|
||||
EXPECT_EQ (ptr2.ref_count (), 2);
|
||||
EXPECT_EQ (ptr1.get_const () == ptr2.get_const (), true);
|
||||
EXPECT_EQ (ptr1.get_const ()->name (), "A");
|
||||
|
||||
EXPECT_EQ (ptr1.get_non_const ()->name (), "A");
|
||||
|
||||
EXPECT_EQ (ptr1.ref_count (), 1);
|
||||
EXPECT_EQ (ptr2.ref_count (), 1);
|
||||
|
||||
EXPECT_EQ (ptr1.get_const () == ptr2.get_const (), false);
|
||||
EXPECT_EQ (ptr1.get_const ()->name (), "A");
|
||||
EXPECT_EQ (ptr2.get_const ()->name (), "A");
|
||||
}
|
||||
|
||||
TEST(3)
|
||||
{
|
||||
tl::copy_on_write_ptr<copy_on_write_tests::A> ptr1;
|
||||
|
||||
EXPECT_EQ (copy_on_write_tests::a_instances, 0);
|
||||
|
||||
ptr1.reset (new copy_on_write_tests::A ());
|
||||
EXPECT_EQ (copy_on_write_tests::a_instances, 1);
|
||||
EXPECT_EQ (ptr1.ref_count (), 1);
|
||||
EXPECT_EQ (ptr1.get_const ()->name (), "A");
|
||||
EXPECT_EQ (ptr1.get_non_const ()->name (), "A");
|
||||
EXPECT_EQ (ptr1.ref_count (), 1);
|
||||
|
||||
tl::copy_on_write_ptr<copy_on_write_tests::A> ptr2 (ptr1);
|
||||
|
||||
EXPECT_EQ (ptr1.ref_count (), 2);
|
||||
EXPECT_EQ (ptr2.ref_count (), 2);
|
||||
EXPECT_EQ (ptr1.get_const () == ptr2.get_const (), true);
|
||||
EXPECT_EQ (ptr1.get_const ()->name (), "A");
|
||||
|
||||
ptr2.reset (0);
|
||||
EXPECT_EQ (copy_on_write_tests::a_instances, 1);
|
||||
|
||||
EXPECT_EQ (ptr1.get_non_const ()->name (), "A");
|
||||
|
||||
EXPECT_EQ (ptr1.ref_count (), 1);
|
||||
EXPECT_EQ (ptr2.ref_count (), 0);
|
||||
|
||||
EXPECT_EQ (ptr1.get_const () == 0, false);
|
||||
EXPECT_EQ (ptr2.get_const () == 0, true);
|
||||
EXPECT_EQ (ptr1.get_const () == ptr2.get_const (), false);
|
||||
|
||||
ptr1.reset (0);
|
||||
EXPECT_EQ (ptr1.ref_count (), 0);
|
||||
EXPECT_EQ (copy_on_write_tests::a_instances, 0);
|
||||
}
|
||||
|
||||
TEST(4)
|
||||
{
|
||||
tl::copy_on_write_ptr<copy_on_write_tests::X, tl::clone_duplicator<copy_on_write_tests::X> > ptr1, ptr2;
|
||||
|
||||
EXPECT_EQ (copy_on_write_tests::x_instances, 0);
|
||||
|
||||
ptr1.reset (new copy_on_write_tests::Y ());
|
||||
EXPECT_EQ (copy_on_write_tests::x_instances, 1);
|
||||
|
||||
EXPECT_EQ (ptr1.ref_count (), 1);
|
||||
EXPECT_EQ (ptr1.get_const ()->name (), "Y");
|
||||
EXPECT_EQ (ptr1.get_non_const ()->name (), "Y");
|
||||
EXPECT_EQ (ptr1.ref_count (), 1);
|
||||
|
||||
ptr2 = ptr1;
|
||||
|
||||
EXPECT_EQ (ptr1.ref_count (), 2);
|
||||
EXPECT_EQ (ptr2.ref_count (), 2);
|
||||
EXPECT_EQ (ptr1.get_const () == ptr2.get_const (), true);
|
||||
EXPECT_EQ (ptr1.get_const ()->name (), "Y");
|
||||
|
||||
EXPECT_EQ (ptr1.get_non_const ()->name (), "Y");
|
||||
EXPECT_EQ (copy_on_write_tests::x_instances, 2);
|
||||
|
||||
EXPECT_EQ (ptr1.ref_count (), 1);
|
||||
EXPECT_EQ (ptr2.ref_count (), 1);
|
||||
|
||||
EXPECT_EQ (ptr1.get_const () == ptr2.get_const (), false);
|
||||
EXPECT_EQ (ptr1.get_const ()->name (), "Y");
|
||||
EXPECT_EQ (ptr2.get_const ()->name (), "Y");
|
||||
|
||||
ptr1.reset (0);
|
||||
EXPECT_EQ (copy_on_write_tests::x_instances, 1);
|
||||
ptr2.reset (new copy_on_write_tests::Z ());
|
||||
EXPECT_EQ (copy_on_write_tests::x_instances, 1);
|
||||
EXPECT_EQ (ptr2.get_const ()->name (), "Z");
|
||||
|
||||
ptr2.reset (0);
|
||||
EXPECT_EQ (copy_on_write_tests::x_instances, 0);
|
||||
}
|
||||
|
||||
|
|
@ -10,6 +10,7 @@ SOURCES = \
|
|||
tlAlgorithm.cc \
|
||||
tlClassRegistry.cc \
|
||||
tlCommandLineParser.cc \
|
||||
tlCopyOnWriteTests.cc \
|
||||
tlDataMapping.cc \
|
||||
tlDeflate.cc \
|
||||
tlEvents.cc \
|
||||
|
|
|
|||
Loading…
Reference in New Issue