Merge pull request #1910 from KLayout/bugfix/issue-1907

Bugfix/issue 1907
This commit is contained in:
Matthias Köfferlein 2024-11-26 21:06:04 +01:00 committed by GitHub
commit 926dac96c6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 598 additions and 176 deletions

View File

@ -280,12 +280,18 @@ void
instance_iterator<Traits>::release_iter ()
{
if (m_type == TInstance) {
if (m_stable) {
if (m_stable && ! m_unsorted) {
if (m_with_props) {
basic_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()).~stable_iter_wp_type ();
} else {
basic_iter (cell_inst_array_type::tag (), InstancesEditableTag ()).~stable_iter_type ();
}
} else if (m_stable) {
if (m_with_props) {
basic_unsorted_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()).~stable_unsorted_iter_wp_type ();
} else {
basic_unsorted_iter (cell_inst_array_type::tag (), InstancesEditableTag ()).~stable_unsorted_iter_type ();
}
} else {
if (m_with_props) {
basic_iter (cell_inst_wp_array_type::tag (), InstancesNonEditableTag ()).~iter_wp_type ();
@ -301,12 +307,18 @@ void
instance_iterator<Traits>::make_iter ()
{
if (m_type == TInstance) {
if (m_stable) {
if (m_stable && ! m_unsorted) {
if (m_with_props) {
new (&basic_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ())) stable_iter_wp_type ();
} else {
new (&basic_iter (cell_inst_array_type::tag (), InstancesEditableTag ())) stable_iter_type ();
}
} else if (m_stable) {
if (m_with_props) {
new (&basic_unsorted_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ())) stable_unsorted_iter_wp_type ();
} else {
new (&basic_unsorted_iter (cell_inst_array_type::tag (), InstancesEditableTag ())) stable_unsorted_iter_type ();
}
} else {
if (m_with_props) {
new (&basic_iter (cell_inst_wp_array_type::tag (), InstancesNonEditableTag ())) iter_wp_type ();
@ -322,18 +334,24 @@ template <class Traits>
bool
instance_iterator<Traits>::operator== (const instance_iterator<Traits> &d) const
{
if (! (m_type == d.m_type && m_stable == d.m_stable && m_with_props == d.m_with_props)) {
if (! (m_type == d.m_type && m_stable == d.m_stable && m_with_props == d.m_with_props && m_unsorted == d.m_unsorted)) {
return false;
}
if (m_type == TNull) {
return true;
} else {
if (m_stable) {
if (m_with_props) {
if (m_with_props && ! m_unsorted) {
return (basic_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()) == d.basic_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()));
} else {
return (basic_iter (cell_inst_array_type::tag (), InstancesEditableTag ()) == d.basic_iter (cell_inst_array_type::tag (), InstancesEditableTag ()));
}
} else if (m_stable) {
if (m_with_props) {
return (basic_unsorted_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()) == d.basic_unsorted_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()));
} else {
return (basic_unsorted_iter (cell_inst_array_type::tag (), InstancesEditableTag ()) == d.basic_unsorted_iter (cell_inst_array_type::tag (), InstancesEditableTag ()));
}
} else {
if (m_with_props) {
return (basic_iter (cell_inst_wp_array_type::tag (), InstancesNonEditableTag ()) == d.basic_iter (cell_inst_wp_array_type::tag (), InstancesNonEditableTag ()));
@ -355,16 +373,23 @@ instance_iterator<Traits>::operator= (const instance_iterator<Traits> &iter)
m_type = iter.m_type;
m_stable = iter.m_stable;
m_with_props = iter.m_with_props;
m_unsorted = iter.m_unsorted;
m_traits = iter.m_traits;
if (m_type == TInstance) {
if (m_stable) {
if (m_stable && ! m_unsorted) {
if (m_with_props) {
new (&basic_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ())) stable_iter_wp_type (iter.basic_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()));
} else {
new (&basic_iter (cell_inst_array_type::tag (), InstancesEditableTag ())) stable_iter_type (iter.basic_iter (cell_inst_array_type::tag (), InstancesEditableTag ()));
}
} else if (m_stable) {
if (m_with_props) {
new (&basic_unsorted_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ())) stable_unsorted_iter_wp_type (iter.basic_unsorted_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()));
} else {
new (&basic_unsorted_iter (cell_inst_array_type::tag (), InstancesEditableTag ())) stable_unsorted_iter_type (iter.basic_unsorted_iter (cell_inst_array_type::tag (), InstancesEditableTag ()));
}
} else {
if (m_with_props) {
new (&basic_iter (cell_inst_wp_array_type::tag (), InstancesNonEditableTag ())) iter_wp_type (iter.basic_iter (cell_inst_wp_array_type::tag (), InstancesNonEditableTag ()));
@ -387,12 +412,18 @@ db::Box
instance_iterator<Traits>::quad_box () const
{
if (m_type == TInstance) {
if (m_stable) {
if (m_stable && ! m_unsorted) {
if (m_with_props) {
return m_traits.quad_box (basic_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()));
} else {
return m_traits.quad_box (basic_iter (cell_inst_array_type::tag (), InstancesEditableTag ()));
}
} else if (m_stable) {
if (m_with_props) {
return m_traits.quad_box (basic_unsorted_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()));
} else {
return m_traits.quad_box (basic_unsorted_iter (cell_inst_array_type::tag (), InstancesEditableTag ()));
}
} else {
if (m_with_props) {
return m_traits.quad_box (basic_iter (cell_inst_wp_array_type::tag (), InstancesNonEditableTag ()));
@ -409,12 +440,18 @@ size_t
instance_iterator<Traits>::quad_id () const
{
if (m_type == TInstance) {
if (m_stable) {
if (m_stable && ! m_unsorted) {
if (m_with_props) {
return m_traits.quad_id (basic_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()));
} else {
return m_traits.quad_id (basic_iter (cell_inst_array_type::tag (), InstancesEditableTag ()));
}
} else if (m_stable) {
if (m_with_props) {
return m_traits.quad_id (basic_unsorted_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()));
} else {
return m_traits.quad_id (basic_unsorted_iter (cell_inst_array_type::tag (), InstancesEditableTag ()));
}
} else {
if (m_with_props) {
return m_traits.quad_id (basic_iter (cell_inst_wp_array_type::tag (), InstancesNonEditableTag ()));
@ -431,12 +468,18 @@ void
instance_iterator<Traits>::skip_quad ()
{
if (m_type == TInstance) {
if (m_stable) {
if (m_stable && ! m_unsorted) {
if (m_with_props) {
m_traits.skip_quad (basic_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()));
} else {
m_traits.skip_quad (basic_iter (cell_inst_array_type::tag (), InstancesEditableTag ()));
}
} else if (m_stable) {
if (m_with_props) {
m_traits.skip_quad (basic_unsorted_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()));
} else {
m_traits.skip_quad (basic_unsorted_iter (cell_inst_array_type::tag (), InstancesEditableTag ()));
}
} else {
if (m_with_props) {
m_traits.skip_quad (basic_iter (cell_inst_wp_array_type::tag (), InstancesNonEditableTag ()));
@ -454,12 +497,18 @@ instance_iterator<Traits> &
instance_iterator<Traits>::operator++()
{
if (m_type == TInstance) {
if (m_stable) {
if (m_stable && ! m_unsorted) {
if (m_with_props) {
++basic_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ());
} else {
++basic_iter (cell_inst_array_type::tag (), InstancesEditableTag ());
}
} else if (m_stable) {
if (m_with_props) {
++basic_unsorted_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ());
} else {
++basic_unsorted_iter (cell_inst_array_type::tag (), InstancesEditableTag ());
}
} else {
if (m_with_props) {
++basic_iter (cell_inst_wp_array_type::tag (), InstancesNonEditableTag ());
@ -478,7 +527,7 @@ void
instance_iterator<Traits>::make_next ()
{
while (true) {
if (m_stable) {
if (m_stable && ! m_unsorted) {
if (m_with_props) {
if (! basic_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()).at_end ()) {
return;
@ -488,6 +537,16 @@ instance_iterator<Traits>::make_next ()
return;
}
}
} else if (m_stable) {
if (m_with_props) {
if (! basic_unsorted_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()).at_end ()) {
return;
}
} else {
if (! basic_unsorted_iter (cell_inst_array_type::tag (), InstancesEditableTag ()).at_end ()) {
return;
}
}
} else {
if (m_with_props) {
if (! basic_iter (cell_inst_wp_array_type::tag (), InstancesNonEditableTag ()).at_end ()) {
@ -514,12 +573,18 @@ void
instance_iterator<Traits>::update_ref ()
{
if (m_type == TInstance) {
if (m_stable) {
if (m_stable && ! m_unsorted) {
if (m_with_props) {
m_ref = m_traits.instance_from_stable_iter (basic_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()));
} else {
m_ref = m_traits.instance_from_stable_iter (basic_iter (cell_inst_array_type::tag (), InstancesEditableTag ()));
}
} else if (m_stable) {
if (m_with_props) {
m_ref = m_traits.instance_from_stable_iter (basic_unsorted_iter (cell_inst_wp_array_type::tag (), InstancesEditableTag ()));
} else {
m_ref = m_traits.instance_from_stable_iter (basic_unsorted_iter (cell_inst_array_type::tag (), InstancesEditableTag ()));
}
} else {
if (m_with_props) {
m_ref = value_type (m_traits.instances (), *basic_iter (cell_inst_wp_array_type::tag (), InstancesNonEditableTag ()));
@ -551,7 +616,7 @@ void
NormalInstanceIteratorTraits::init (instance_iterator<NormalInstanceIteratorTraits> *iter) const
{
tl_assert (mp_insts != 0);
if (iter->m_stable) {
if (iter->m_stable && ! iter->m_unsorted) {
if (iter->m_with_props) {
cell_inst_wp_array_type::tag tag = cell_inst_wp_array_type::tag ();
iter->basic_iter (tag, InstancesEditableTag ()) = mp_insts->inst_tree (tag, InstancesEditableTag ()).begin_flat ();
@ -559,6 +624,14 @@ NormalInstanceIteratorTraits::init (instance_iterator<NormalInstanceIteratorTrai
cell_inst_array_type::tag tag = cell_inst_array_type::tag ();
iter->basic_iter (tag, InstancesEditableTag ()) = mp_insts->inst_tree (tag, InstancesEditableTag ()).begin_flat ();
}
} else if (iter->m_stable) {
if (iter->m_with_props) {
cell_inst_wp_array_type::tag tag = cell_inst_wp_array_type::tag ();
iter->basic_unsorted_iter (tag, InstancesEditableTag ()) = stable_unsorted_iter_wp_type (mp_insts->inst_tree (tag, InstancesEditableTag ()).begin (), mp_insts->inst_tree (tag, InstancesEditableTag ()).end ());
} else {
cell_inst_array_type::tag tag = cell_inst_array_type::tag ();
iter->basic_unsorted_iter (tag, InstancesEditableTag ()) = stable_unsorted_iter_type (mp_insts->inst_tree (tag, InstancesEditableTag ()).begin (), mp_insts->inst_tree (tag, InstancesEditableTag ()).end ());
}
} else {
if (iter->m_with_props) {
cell_inst_wp_array_type::tag tag = cell_inst_wp_array_type::tag ();

View File

@ -527,7 +527,9 @@ public:
typedef typename IterTraits::iter_wp_type iter_wp_type;
typedef typename IterTraits::stable_iter_type stable_iter_type;
typedef typename IterTraits::stable_iter_wp_type stable_iter_wp_type;
typedef const value_type *pointer;
typedef typename IterTraits::stable_unsorted_iter_type stable_unsorted_iter_type;
typedef typename IterTraits::stable_unsorted_iter_wp_type stable_unsorted_iter_wp_type;
typedef const value_type *pointer;
typedef value_type reference; // operator* returns a value
typedef std::forward_iterator_tag iterator_category;
typedef void difference_type;
@ -541,7 +543,7 @@ public:
* @brief Default ctor
*/
instance_iterator ()
: m_with_props (false), m_stable (false), m_type (TNull), m_traits ()
: m_type (TNull), m_with_props (false), m_stable (false), m_unsorted (false), m_traits ()
{ }
/**
@ -556,7 +558,7 @@ public:
* @brief Constructor
*/
instance_iterator (const IterTraits &traits)
: m_with_props (false), m_stable (traits.instances ()->is_editable ()), m_type (TInstance), m_traits (traits)
: m_type (TInstance), m_with_props (false), m_stable (traits.instances ()->is_editable ()), m_unsorted (traits.instances ()->instance_tree_needs_sort ()), m_traits (traits)
{
make_iter ();
make_next ();
@ -567,7 +569,7 @@ public:
* @brief Copy constructor
*/
instance_iterator (const instance_iterator &iter)
: m_with_props (false), m_stable (false), m_type (TNull), m_traits ()
: m_type (TNull), m_with_props (false), m_stable (false), m_unsorted (false), m_traits ()
{
operator= (iter);
}
@ -661,7 +663,7 @@ public:
*/
stable_iter_type &basic_iter (cell_inst_array_type::tag, InstancesEditableTag)
{
tl_assert (m_type == TInstance && m_stable == true && m_with_props == false);
tl_assert (m_type == TInstance && m_stable == true && m_with_props == false && m_unsorted == false);
return *((stable_iter_type *) m_generic.stable_iter);
}
@ -670,10 +672,28 @@ public:
*/
const stable_iter_type &basic_iter (cell_inst_array_type::tag, InstancesEditableTag) const
{
tl_assert (m_type == TInstance && m_stable == true && m_with_props == false);
tl_assert (m_type == TInstance && m_stable == true && m_with_props == false && m_unsorted == false);
return *((stable_iter_type *) m_generic.stable_iter);
}
/**
* @brief Gets the basic iterator in the editable case without properties and in the unsorted case
*/
stable_unsorted_iter_type &basic_unsorted_iter (cell_inst_array_type::tag, InstancesEditableTag)
{
tl_assert (m_type == TInstance && m_stable == true && m_with_props == false && m_unsorted == true);
return *((stable_unsorted_iter_type *) m_generic.stable_unsorted_iter);
}
/**
* @brief Gets the basic iterator in the editable case without properties and in the unsorted case (const version)
*/
const stable_unsorted_iter_type &basic_unsorted_iter (cell_inst_array_type::tag, InstancesEditableTag) const
{
tl_assert (m_type == TInstance && m_stable == true && m_with_props == false && m_unsorted == true);
return *((stable_unsorted_iter_type *) m_generic.stable_unsorted_iter);
}
/**
* @brief Gets the basic iterator in the non-editable case with properties
*/
@ -697,7 +717,7 @@ public:
*/
stable_iter_wp_type &basic_iter (cell_inst_wp_array_type::tag, InstancesEditableTag)
{
tl_assert (m_type == TInstance && m_stable == true && m_with_props == true);
tl_assert (m_type == TInstance && m_stable == true && m_with_props == true && m_unsorted == false);
return *((stable_iter_wp_type *) m_generic.pstable_iter);
}
@ -706,10 +726,28 @@ public:
*/
const stable_iter_wp_type &basic_iter (cell_inst_wp_array_type::tag, InstancesEditableTag) const
{
tl_assert (m_type == TInstance && m_stable == true && m_with_props == true);
tl_assert (m_type == TInstance && m_stable == true && m_with_props == true && m_unsorted == false);
return *((stable_iter_wp_type *) m_generic.pstable_iter);
}
/**
* @brief Gets the basic iterator in the editable case with properties and in the unsorted case
*/
stable_unsorted_iter_wp_type &basic_unsorted_iter (cell_inst_wp_array_type::tag, InstancesEditableTag)
{
tl_assert (m_type == TInstance && m_stable == true && m_with_props == true && m_unsorted == true);
return *((stable_unsorted_iter_wp_type *) m_generic.pstable_unsorted_iter);
}
/**
* @brief Gets the basic iterator in the editable case with properties and in the unsorted case (const version)
*/
const stable_unsorted_iter_wp_type &basic_unsorted_iter (cell_inst_wp_array_type::tag, InstancesEditableTag) const
{
tl_assert (m_type == TInstance && m_stable == true && m_with_props == true && m_unsorted == true);
return *((stable_unsorted_iter_wp_type *) m_generic.pstable_unsorted_iter);
}
private:
friend struct NormalInstanceIteratorTraits;
friend struct OverlappingInstanceIteratorTraits;
@ -720,11 +758,14 @@ private:
char piter[sizeof (iter_wp_type)];
char stable_iter[sizeof (stable_iter_type)];
char pstable_iter[sizeof (stable_iter_wp_type)];
char stable_unsorted_iter[sizeof (stable_unsorted_iter_type)];
char pstable_unsorted_iter[sizeof (stable_unsorted_iter_wp_type)];
} m_generic;
bool m_with_props : 8;
bool m_stable : 8;
object_type m_type : 16;
bool m_with_props : 1;
bool m_stable : 1;
bool m_unsorted : 1;
value_type m_ref;
IterTraits m_traits;
@ -759,6 +800,8 @@ struct DB_PUBLIC NormalInstanceIteratorTraits
typedef tl::iterator_pair<cell_inst_wp_tree_type::const_iterator> iter_wp_type;
typedef stable_cell_inst_tree_type::flat_iterator stable_iter_type;
typedef stable_cell_inst_wp_tree_type::flat_iterator stable_iter_wp_type;
typedef tl::iterator_pair<stable_cell_inst_tree_type::const_iterator> stable_unsorted_iter_type;
typedef tl::iterator_pair<stable_cell_inst_wp_tree_type::const_iterator> stable_unsorted_iter_wp_type;
NormalInstanceIteratorTraits ();
NormalInstanceIteratorTraits (const instances_type *insts);
@ -804,6 +847,8 @@ struct DB_PUBLIC TouchingInstanceIteratorTraits
typedef cell_inst_wp_tree_type::touching_iterator iter_wp_type;
typedef stable_cell_inst_tree_type::touching_iterator stable_iter_type;
typedef stable_cell_inst_wp_tree_type::touching_iterator stable_iter_wp_type;
typedef stable_iter_type stable_unsorted_iter_type;
typedef stable_iter_wp_type stable_unsorted_iter_wp_type;
TouchingInstanceIteratorTraits ();
TouchingInstanceIteratorTraits (const instances_type *insts, const box_type &box, const layout_type *layout);
@ -855,6 +900,8 @@ struct DB_PUBLIC OverlappingInstanceIteratorTraits
typedef cell_inst_wp_tree_type::overlapping_iterator iter_wp_type;
typedef stable_cell_inst_tree_type::overlapping_iterator stable_iter_type;
typedef stable_cell_inst_wp_tree_type::overlapping_iterator stable_iter_wp_type;
typedef stable_iter_type stable_unsorted_iter_type;
typedef stable_iter_wp_type stable_unsorted_iter_wp_type;
OverlappingInstanceIteratorTraits ();
OverlappingInstanceIteratorTraits (const instances_type *insts, const box_type &box, const layout_type *layout);
@ -1741,6 +1788,7 @@ private:
friend struct NormalInstanceIteratorTraits;
friend struct TouchingInstanceIteratorTraits;
friend struct OverlappingInstanceIteratorTraits;
template <class Traits> friend class instance_iterator;
template <class Inst, class ET> friend class InstOp;
union {
@ -1773,7 +1821,7 @@ private:
}
/**
* @brief Sets a flag indicating that the instance tree needs sorting
* @brief Gets a flag indicating that the instance tree needs sorting
*/
bool instance_tree_needs_sort () const
{

View File

@ -1749,8 +1749,49 @@ Layout::end_top_cells () const
return m_top_down_list.begin () + m_top_cells;
}
void
Layout::start_changes ()
{
tl::MutexLocker locker (&lock ());
++m_invalid;
}
void
Layout::end_changes ()
{
tl::MutexLocker locker (&lock ());
if (m_invalid > 0) {
if (--m_invalid == 0) {
force_update_no_lock ();
}
}
}
void
Layout::end_changes_no_update ()
{
tl::MutexLocker locker (&lock ());
if (m_invalid > 0) {
--m_invalid;
}
}
void
Layout::force_update ()
{
// NOTE: the assumption is that either one thread is writing or
// multiple threads are reading. Hence, we do not need to lock hier_dirty() or bboxes_dirty().
// We still do double checking as another thread might do the update as well.
if (! hier_dirty () && ! bboxes_dirty ()) {
return;
}
tl::MutexLocker locker (&lock ());
force_update_no_lock ();
}
void
Layout::force_update_no_lock () const
{
if (hier_dirty () || bboxes_dirty ()) {
@ -1776,22 +1817,17 @@ Layout::force_update ()
void
Layout::update () const
{
if (! under_construction () && (hier_dirty () || bboxes_dirty ())) {
// NOTE: the assumption is that either one thread is writing or
// multiple threads are reading. Hence, we do not need to lock hier_dirty() or bboxes_dirty().
// We still do double checking as another thread might do the update as well.
if (under_construction () || (! hier_dirty () && ! bboxes_dirty ())) {
return;
}
try {
m_invalid = std::numeric_limits<unsigned int>::max (); // prevent recursion
db::LayoutStateModel *state_model = const_cast<db::LayoutStateModel *> ((const db::LayoutStateModel *) this);
state_model->update ();
m_invalid = 0;
} catch (...) {
m_invalid = 0;
throw;
}
tl::MutexLocker locker (&lock ());
if (! under_construction ()) {
force_update_no_lock ();
}
}

View File

@ -624,7 +624,7 @@ public:
* @brief Gets the lock for the layout object
* This is a generic lock that can be used to lock modifications against multiple threads.
*/
tl::Mutex &lock ()
tl::Mutex &lock () const
{
return m_lock;
}
@ -1791,34 +1791,18 @@ public:
* an operation, the start/end_changes method pair does not
* need to be called.
*/
void start_changes ()
{
++m_invalid;
}
void start_changes ();
/**
* @brief Cancel the "in changes" state (see "start_changes")
*/
void end_changes ()
{
if (m_invalid > 0) {
--m_invalid;
if (! m_invalid) {
update ();
}
}
}
void end_changes ();
/**
* @brief Cancel the "in changes" state (see "start_changes")
* This version does not force an update
*/
void end_changes_no_update ()
{
if (m_invalid > 0) {
--m_invalid;
}
}
void end_changes_no_update ();
/**
* @brief Tell if the layout object is under construction
@ -2168,7 +2152,7 @@ private:
std::map<db::cell_index_type, meta_info_map> m_meta_info_by_cell;
std::string m_tech_name;
tl::Mutex m_lock;
mutable tl::Mutex m_lock;
/**
* @brief Sort the cells topologically
@ -2211,6 +2195,11 @@ private:
* @brief Recovers a proxy without considering the library from context_info
*/
db::Cell *recover_proxy_no_lib (const LayoutOrCellContextInfo &context_info);
/**
* @brief Does an update without checking under_construction() and no Mutex
*/
void force_update_no_lock () const;
};
/**

View File

@ -29,13 +29,14 @@ namespace db
{
LayoutStateModel::LayoutStateModel (bool busy)
: m_hier_dirty (false), m_hier_generation_id (0), m_all_bboxes_dirty (false), m_busy (busy)
: m_hier_dirty (false), m_hier_generation_id (0), m_all_bboxes_dirty (false), m_some_bboxes_dirty (false), m_busy (busy)
{
// .. nothing yet ..
}
LayoutStateModel::LayoutStateModel (const LayoutStateModel &d)
: m_hier_dirty (d.m_hier_dirty), m_hier_generation_id (d.m_hier_generation_id), m_bboxes_dirty (d.m_bboxes_dirty), m_all_bboxes_dirty (d.m_all_bboxes_dirty), m_busy (d.m_busy)
: m_hier_dirty (d.m_hier_dirty), m_hier_generation_id (d.m_hier_generation_id), m_bboxes_dirty (d.m_bboxes_dirty),
m_all_bboxes_dirty (d.m_all_bboxes_dirty), m_some_bboxes_dirty (d.m_some_bboxes_dirty), m_busy (d.m_busy)
{
// .. nothing yet ..
}
@ -47,6 +48,7 @@ LayoutStateModel::operator= (const LayoutStateModel &d)
m_hier_generation_id = d.m_hier_generation_id;
m_bboxes_dirty = d.m_bboxes_dirty;
m_all_bboxes_dirty = d.m_all_bboxes_dirty;
m_some_bboxes_dirty = d.m_some_bboxes_dirty;
m_busy = d.m_busy;
return *this;
}
@ -84,6 +86,7 @@ LayoutStateModel::invalidate_bboxes (unsigned int index)
m_bboxes_dirty.resize (index + 1, false);
}
m_bboxes_dirty [index] = true;
m_some_bboxes_dirty = true;
}
}
}
@ -91,7 +94,7 @@ LayoutStateModel::invalidate_bboxes (unsigned int index)
bool
LayoutStateModel::bboxes_dirty () const
{
return ! m_bboxes_dirty.empty () || m_all_bboxes_dirty;
return m_some_bboxes_dirty || m_all_bboxes_dirty;
}
void
@ -100,6 +103,7 @@ LayoutStateModel::update ()
if (bboxes_dirty () || m_hier_dirty) {
do_update ();
m_bboxes_dirty.clear ();
m_some_bboxes_dirty = false;
m_all_bboxes_dirty = false;
m_hier_dirty = false;
}

View File

@ -209,7 +209,7 @@ private:
bool m_hier_dirty;
size_t m_hier_generation_id;
std::vector<bool> m_bboxes_dirty;
bool m_all_bboxes_dirty;
bool m_all_bboxes_dirty, m_some_bboxes_dirty;
bool m_busy;
void do_invalidate_hier ();

View File

@ -330,7 +330,11 @@ OriginalLayerRegion::begin_merged_iter () const
bool
OriginalLayerRegion::empty () const
{
return m_iter.at_end ();
// NOTE: we should to make sure the iterator isn't validated as this would spoil the usability or OriginalLayerRegion upon
// layout changes
db::RecursiveShapeIterator iter = m_iter;
return iter.at_end ();
}
bool

View File

@ -61,6 +61,7 @@ RecursiveInstanceIterator &RecursiveInstanceIterator::operator= (const Recursive
m_box_convert = d.m_box_convert;
m_locker = d.m_locker;
m_inst = d.m_inst;
m_inst_array = d.m_inst_array;
m_empty_cells_cache = d.m_empty_cells_cache;
@ -175,7 +176,7 @@ RecursiveInstanceIterator::set_region (const box_type &region)
{
if (m_region != region || mp_complex_region.get () != 0) {
init_region (region);
m_needs_reinit = true;
reset ();
}
}
@ -183,7 +184,7 @@ void
RecursiveInstanceIterator::set_region (const region_type &region)
{
init_region (region);
m_needs_reinit = true;
reset ();
}
void
@ -196,7 +197,7 @@ RecursiveInstanceIterator::confine_region (const box_type &region)
} else {
init_region (m_region & region);
}
m_needs_reinit = true;
reset ();
}
void
@ -209,7 +210,7 @@ RecursiveInstanceIterator::confine_region (const region_type &region)
} else {
init_region (region & region_type (m_region));
}
m_needs_reinit = true;
reset ();
}
void
@ -218,7 +219,7 @@ RecursiveInstanceIterator::enable_all_targets ()
if (! m_all_targets) {
m_all_targets = true;
m_targets.clear ();
m_needs_reinit = true;
reset ();
}
}
@ -228,7 +229,7 @@ RecursiveInstanceIterator::set_targets (const std::set<db::cell_index_type> &tgt
if (m_all_targets || m_targets != tgt) {
m_targets = tgt;
m_all_targets = false;
m_needs_reinit = true;
reset ();
}
}
@ -264,6 +265,8 @@ RecursiveInstanceIterator::validate (RecursiveInstanceReceiver *receiver) const
m_needs_reinit = false;
// re-initialize
m_locker = db::LayoutLocker ();
mp_cell = mp_top_cell;
m_trans_stack.clear ();
m_inst_iterators.clear ();
@ -310,6 +313,17 @@ RecursiveInstanceIterator::validate (RecursiveInstanceReceiver *receiver) const
next_instance (receiver);
}
if (mp_layout && ! at_end ()) {
m_locker = db::LayoutLocker (const_cast <db::Layout *> (mp_layout.get ()), true);
}
}
void
RecursiveInstanceIterator::reset ()
{
m_needs_reinit = true;
m_locker = db::LayoutLocker ();
}
void
@ -320,7 +334,7 @@ RecursiveInstanceIterator::reset_selection ()
m_start.clear ();
m_stop.clear ();
m_needs_reinit = true;
reset ();
}
}
@ -335,7 +349,7 @@ RecursiveInstanceIterator::unselect_cells (const std::set<db::cell_index_type> &
m_start.erase (*c);
}
m_needs_reinit = true;
reset ();
}
}
@ -350,7 +364,7 @@ RecursiveInstanceIterator::unselect_all_cells ()
m_stop.insert (c->cell_index ());
}
m_needs_reinit = true;
reset ();
}
}
@ -365,7 +379,7 @@ RecursiveInstanceIterator::select_cells (const std::set<db::cell_index_type> &ce
m_stop.erase (*c);
}
m_needs_reinit = true;
reset ();
}
}
@ -380,7 +394,7 @@ RecursiveInstanceIterator::select_all_cells ()
m_start.insert (c->cell_index ());
}
m_needs_reinit = true;
reset ();
}
}
@ -441,6 +455,7 @@ void
RecursiveInstanceIterator::next (RecursiveInstanceReceiver *receiver)
{
if (! at_end ()) {
++m_inst_array;
if (! m_inst_array.at_end ()) {
new_inst_member (receiver);
@ -449,6 +464,12 @@ RecursiveInstanceIterator::next (RecursiveInstanceReceiver *receiver)
new_inst (receiver);
}
next_instance (receiver);
if (at_end ()) {
// Take this opportunity the release the layout lock.
// This way, the shape iterator can be held further, without blocking the layout.
m_locker = db::LayoutLocker ();
}
}
}

View File

@ -141,7 +141,7 @@ public:
{
if (m_max_depth != depth) {
m_max_depth = depth;
m_needs_reinit = true;
reset ();
}
}
@ -164,7 +164,7 @@ public:
{
if (m_min_depth != depth) {
m_min_depth = depth;
m_needs_reinit = true;
reset ();
}
}
@ -262,17 +262,14 @@ public:
{
if (m_overlapping != f) {
m_overlapping = f;
m_needs_reinit = true;
reset ();
}
}
/**
* @brief Reset the iterator
*/
void reset ()
{
m_needs_reinit = true;
}
void reset ();
/**
* @brief Gets the selected target cells
@ -552,6 +549,7 @@ private:
std::unique_ptr<region_type> mp_complex_region;
db::box_convert<db::CellInst> m_box_convert;
mutable db::LayoutLocker m_locker;
mutable inst_iterator m_inst;
mutable inst_array_iterator m_inst_array;
mutable instance_element_type m_combined_instance;

View File

@ -67,6 +67,7 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
m_box_convert = d.m_box_convert;
m_locker = d.m_locker;
m_inst = d.m_inst;
m_inst_array = d.m_inst_array;
m_empty_cells_cache = d.m_empty_cells_cache;
@ -340,7 +341,7 @@ RecursiveShapeIterator::set_global_trans (const cplx_trans_type &tr)
{
if (m_global_trans != tr) {
m_global_trans = tr;
m_needs_reinit = true;
reset ();
}
}
@ -360,7 +361,7 @@ RecursiveShapeIterator::set_region (const box_type &region)
{
if (m_region != region || mp_complex_region.get () != 0) {
init_region (region);
m_needs_reinit = true;
reset ();
}
}
@ -368,7 +369,7 @@ void
RecursiveShapeIterator::set_region (const region_type &region)
{
init_region (region);
m_needs_reinit = true;
reset ();
}
void
@ -381,7 +382,7 @@ RecursiveShapeIterator::confine_region (const box_type &region)
} else {
init_region (m_region & region);
}
m_needs_reinit = true;
reset ();
}
void
@ -394,7 +395,7 @@ RecursiveShapeIterator::confine_region (const region_type &region)
} else {
init_region (region & region_type (m_region));
}
m_needs_reinit = true;
reset ();
}
void
@ -404,7 +405,7 @@ RecursiveShapeIterator::set_layer (unsigned int layer)
m_has_layers = false;
m_layers.clear ();
m_layer = layer;
m_needs_reinit = true;
reset ();
}
}
@ -415,7 +416,7 @@ RecursiveShapeIterator::set_layers (const std::vector<unsigned int> &layers)
m_has_layers = true;
m_layers = layers;
m_layer = 0;
m_needs_reinit = true;
reset ();
}
}
@ -451,6 +452,8 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
m_needs_reinit = false;
// re-initialize
m_locker = db::LayoutLocker ();
mp_cell = mp_top_cell;
m_trans_stack.clear ();
m_inst_iterators.clear ();
@ -502,9 +505,20 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
new_cell (receiver);
next_shape (receiver);
}
if (mp_layout && ! at_end ()) {
m_locker = db::LayoutLocker (const_cast<db::Layout *> (mp_layout.get ()), true);
}
}
void
void
RecursiveShapeIterator::reset ()
{
m_needs_reinit = true;
m_locker = db::LayoutLocker ();
}
void
RecursiveShapeIterator::reset_selection ()
{
if (mp_layout) {
@ -512,7 +526,7 @@ RecursiveShapeIterator::reset_selection ()
m_start.clear ();
m_stop.clear ();
m_needs_reinit = true;
reset ();
}
}
@ -527,7 +541,7 @@ RecursiveShapeIterator::unselect_cells (const std::set<db::cell_index_type> &cel
m_start.erase (*c);
}
m_needs_reinit = true;
reset ();
}
}
@ -542,7 +556,7 @@ RecursiveShapeIterator::unselect_all_cells ()
m_stop.insert (c->cell_index ());
}
m_needs_reinit = true;
reset ();
}
}
@ -557,7 +571,7 @@ RecursiveShapeIterator::select_cells (const std::set<db::cell_index_type> &cells
m_stop.erase (*c);
}
m_needs_reinit = true;
reset ();
}
}
@ -572,7 +586,7 @@ RecursiveShapeIterator::select_all_cells ()
m_start.insert (c->cell_index ());
}
m_needs_reinit = true;
reset ();
}
}
@ -688,6 +702,12 @@ RecursiveShapeIterator::next (RecursiveShapeReceiver *receiver)
next_shape (receiver);
}
if (at_end ()) {
// Take this opportunity the release the layout lock.
// This way, the shape iterator can be held further, without blocking the layout.
m_locker = db::LayoutLocker ();
}
}
}

View File

@ -265,7 +265,7 @@ public:
{
if (m_max_depth != depth) {
m_max_depth = depth;
m_needs_reinit = true;
reset ();
}
}
@ -288,7 +288,7 @@ public:
{
if (m_min_depth != depth) {
m_min_depth = depth;
m_needs_reinit = true;
reset ();
}
}
@ -433,7 +433,7 @@ public:
{
if (m_overlapping != f) {
m_overlapping = f;
m_needs_reinit = true;
reset ();
}
}
@ -452,7 +452,7 @@ public:
{
if (m_for_merged_input != f) {
m_for_merged_input = f;
m_needs_reinit = true;
reset ();
}
}
@ -483,10 +483,7 @@ public:
/**
* @brief Reset the iterator
*/
void reset ()
{
m_needs_reinit = true;
}
void reset ();
/**
* @brief Select cells
@ -559,7 +556,7 @@ public:
{
if (m_shape_flags != flags) {
m_shape_flags = flags;
m_needs_reinit = true;
reset ();
}
}
@ -596,7 +593,7 @@ public:
{
if (mp_shape_prop_sel != prop_sel) {
mp_shape_prop_sel = prop_sel;
m_needs_reinit = true;
reset ();
}
}
@ -610,7 +607,7 @@ public:
{
if (m_shape_inv_prop_sel != inv) {
m_shape_inv_prop_sel = inv;
m_needs_reinit = true;
reset ();
}
}
@ -854,6 +851,7 @@ private:
std::unique_ptr<region_type> mp_complex_region;
db::box_convert<db::CellInst> m_box_convert;
mutable db::LayoutLocker m_locker;
mutable inst_iterator m_inst;
mutable inst_array_iterator m_inst_array;
mutable std::map<db::cell_index_type, bool> m_empty_cells_cache;

View File

@ -58,6 +58,11 @@ Writer::write (db::Layout &layout, tl::OutputStream &stream)
{
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Writing file: ")) + stream.path ());
if (layout.under_construction ()) {
tl::warn << tl::to_string (tr ("Cannot properly write a layout that is under construction - forcing update."));
layout.force_update ();
}
tl_assert (mp_writer != 0);
mp_writer->write (layout, stream, m_options);
}

View File

@ -603,6 +603,11 @@ Class<db::RecursiveInstanceIterator> decl_RecursiveInstanceIterator ("db", "Recu
"and the target cell of the current instance.\n"
"\n"
"The RecursiveInstanceIterator class has been introduced in version 0.27.\n"
"Starting with version 0.29.9, the recursive instance iterator will lock the layout it acts on while in iterating mode. "
"While the iterator is active, the Layout object is maintained in 'under construction mode' (see \\Layout#under_construction). "
"This is to prevent layout modifications to interfere with the iterator's operation. Specifically when coding in Ruby, "
"pending iterators may block the Layout until the garbage collector cleans up these objects. To avoid this, call \\_destroy "
"on the iterator when you no longer need it. The Layout is automatically unlocked when the iterator reaches the end."
);
}

View File

@ -804,6 +804,11 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"all cells not starting with one of that letters.\n"
"\n"
"The RecursiveShapeIterator class has been introduced in version 0.18 and has been extended substantially in 0.23.\n"
"Starting with version 0.29.9, the recursive shape iterator will lock the layout it acts on while in iterating mode. "
"While the iterator is active, the Layout object is maintained in 'under construction mode' (see \\Layout#under_construction). "
"This is to prevent layout modifications to interfere with the iterator's operation. Specifically when coding in Ruby, "
"pending iterators may block the Layout until the garbage collector cleans up these objects. To avoid this, call \\_destroy "
"on the iterator when you no longer need it. The Layout is automatically unlocked when the iterator reaches the end."
);
}

View File

@ -28,6 +28,7 @@
#include "dbTextWriter.h"
#include "dbCellMapping.h"
#include "dbInstElement.h"
#include "dbWriter.h"
#include "tlString.h"
#include "tlUnitTest.h"
@ -872,6 +873,68 @@ TEST(11_FindPath)
EXPECT_EQ (d, "cell_index=1 r90 *1 0,0;cell_index=2 r0 *1 100,200");
}
// Shapes can be flat-iterated even in locked layout
TEST(12_ShapesInLockedLayout)
{
db::Layout l;
db::Cell &top = l.cell (l.add_cell ("TOP"));
unsigned int l1 = l.insert_layer (db::LayerProperties (1, 0));
{
db::LayoutLocker locker (&l);
EXPECT_EQ (l.under_construction (), true);
top.shapes (l1).insert (db::Box (1, 2, 3, 4));
top.shapes (l1).insert (db::Box (10, 20, 30, 40));
top.shapes (l1).insert (db::Box (100, 200, 300, 400));
double a = 0;
for (auto s = top.shapes (l1).begin (db::ShapeIterator::All); ! s.at_end (); ++s) {
a += s->area ();
}
EXPECT_EQ (a, 40404.0);
}
EXPECT_EQ (l.under_construction (), false);
double a = 0;
for (auto s = top.shapes (l1).begin (db::ShapeIterator::All); ! s.at_end (); ++s) {
a += s->area ();
}
EXPECT_EQ (a, 40404.0);
}
// Instances can be flat-iterated even in locked layout
TEST(13_InstancesInLockedLayout)
{
db::Layout l;
db::Cell &top = l.cell (l.add_cell ("TOP"));
db::Cell &c = l.cell (l.add_cell ("C"));
{
db::LayoutLocker locker (&l);
EXPECT_EQ (l.under_construction (), true);
top.insert (db::CellInstArray (c.cell_index (), db::Trans (db::Vector (10, 20))));
top.insert (db::CellInstArray (c.cell_index (), db::Trans (db::Vector (100, 200))));
top.insert (db::CellInstArray (c.cell_index (), db::Trans (db::Vector (1, 2))));
db::Vector a;
for (auto i = top.begin (); ! i.at_end (); ++i) {
a += i->cell_inst ().front ().disp ();
}
EXPECT_EQ (a.to_string (), "111,222");
}
EXPECT_EQ (l.under_construction (), false);
db::Vector a;
for (auto i = top.begin (); ! i.at_end (); ++i) {
a += i->cell_inst ().front ().disp ();
}
EXPECT_EQ (a.to_string (), "111,222");
}
// issue #1860
TEST(100_UndoOfDeleteLayer)
{

View File

@ -789,3 +789,70 @@ TEST(6)
"CHILD_CELL_3_1_1@r0 *1 120000,0"
);
}
// layout locking
TEST(7_LayoutLocking)
{
db::Layout layout;
layout.insert_layer (0);
db::Cell &c0 (layout.cell (layout.add_cell ()));
db::Cell &c1 (layout.cell (layout.add_cell ()));
db::Box b (0, 100, 1000, 1200);
c1.shapes (0).insert (b);
db::Trans tt;
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt));
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (2000, -2000))));
EXPECT_EQ (layout.under_construction (), false);
db::RecursiveInstanceIterator iter (layout, c0);
EXPECT_EQ (layout.under_construction (), false);
EXPECT_EQ (iter.at_end (), false);
EXPECT_EQ (layout.under_construction (), true);
EXPECT_EQ (iter.instance ().to_string (), "cell_index=1 r0 *1 0,0");
EXPECT_EQ (layout.under_construction (), true);
++iter;
EXPECT_EQ (iter.at_end (), false);
EXPECT_EQ (iter.instance ().to_string (), "cell_index=1 r0 *1 2000,-2000");
EXPECT_EQ (layout.under_construction (), true);
++iter;
EXPECT_EQ (layout.under_construction (), false);
EXPECT_EQ (iter.at_end (), true);
// reset will restart
iter.reset ();
EXPECT_EQ (layout.under_construction (), false);
EXPECT_EQ (iter.at_end (), false);
EXPECT_EQ (layout.under_construction (), true);
// a copy will hold the lock
iter.reset ();
EXPECT_EQ (layout.under_construction (), false);
EXPECT_EQ (iter.at_end (), false);
EXPECT_EQ (layout.under_construction (), true);
db::RecursiveInstanceIterator iter_copy = iter;
while (! iter.at_end ()) {
++iter;
}
EXPECT_EQ (layout.under_construction (), true);
iter_copy = db::RecursiveInstanceIterator ();
EXPECT_EQ (layout.under_construction (), false);
}

View File

@ -1780,3 +1780,69 @@ TEST(13_ForMergedPerformance)
}
}
// layout locking
TEST(14_LayoutLocking)
{
db::Layout layout;
layout.insert_layer (0);
db::Cell &c0 (layout.cell (layout.add_cell ()));
db::Cell &c1 (layout.cell (layout.add_cell ()));
db::Box b (0, 100, 1000, 1200);
c1.shapes (0).insert (b);
db::Trans tt;
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt));
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (2000, -2000))));
EXPECT_EQ (layout.under_construction (), false);
db::RecursiveShapeIterator iter (layout, c0, 0);
EXPECT_EQ (layout.under_construction (), false);
EXPECT_EQ (iter.at_end (), false);
EXPECT_EQ (layout.under_construction (), true);
EXPECT_EQ (iter.shape ().to_string (), "box (0,100;1000,1200)");
EXPECT_EQ (layout.under_construction (), true);
++iter;
EXPECT_EQ (iter.at_end (), false);
EXPECT_EQ (iter.shape ().to_string (), "box (0,100;1000,1200)");
EXPECT_EQ (layout.under_construction (), true);
++iter;
EXPECT_EQ (layout.under_construction (), false);
EXPECT_EQ (iter.at_end (), true);
// reset will restart
iter.reset ();
EXPECT_EQ (layout.under_construction (), false);
EXPECT_EQ (iter.at_end (), false);
EXPECT_EQ (layout.under_construction (), true);
// a copy will hold the lock
iter.reset ();
EXPECT_EQ (layout.under_construction (), false);
EXPECT_EQ (iter.at_end (), false);
EXPECT_EQ (layout.under_construction (), true);
db::RecursiveShapeIterator iter_copy = iter;
while (! iter.at_end ()) {
++iter;
}
EXPECT_EQ (layout.under_construction (), true);
iter_copy = db::RecursiveShapeIterator ();
EXPECT_EQ (layout.under_construction (), false);
}

View File

@ -232,6 +232,16 @@ class DBLayoutTests1_TestClass < TestBase
end
def first_shape(s)
sdup = s.dup
shape = sdup.shape
sdup._destroy
return shape
end
def collect(s, l)
res = []
@ -1042,18 +1052,18 @@ class DBLayoutTests1_TestClass < TestBase
c0c = l.cell(l.add_cell("c0"))
c0c.copy_shapes(c0)
assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)")
assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil)
assert_equal(first_shape(c0c.begin_shapes_rec(0)).property("p"), nil)
assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)")
assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(1)).property("p"), 17)
c0c.clear
lm = RBA::LayerMapping::new
lm.map(1, 0)
c0c.copy_shapes(c0, lm)
assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](1,101;1001,1201)")
assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(0)).property("p"), 17)
assert_equal(collect(c0c.begin_shapes_rec(1), l), "")
assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), nil)
assert_equal(first_shape(c0c.begin_shapes_rec(1)).property("p"), nil)
l2 = RBA::Layout::new
l2.dbu = 0.0005
@ -1063,9 +1073,9 @@ class DBLayoutTests1_TestClass < TestBase
layer1 = l2.find_layer(1, 0)
layer2 = l2.find_layer(2, 0)
assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)")
assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil)
assert_equal(first_shape(c0c.begin_shapes_rec(layer1)).property("p"), nil)
assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)")
assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(layer2)).property("p"), 17)
l2 = RBA::Layout::new
l2.dbu = 0.0005
@ -1084,9 +1094,9 @@ class DBLayoutTests1_TestClass < TestBase
layer1 = l2.find_layer(1, 0)
layer2 = l2.find_layer(2, 0)
assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)")
assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil)
assert_equal(first_shape(c0c.begin_shapes_rec(layer1)).property("p"), nil)
assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)")
assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(layer2)).property("p"), 17)
end
@ -1127,9 +1137,9 @@ class DBLayoutTests1_TestClass < TestBase
assert_equal(collect(c0.begin_shapes_rec(0), l), "[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)")
assert_equal(collect(c0.begin_shapes_rec(1), l), "")
assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)")
assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil)
assert_equal(first_shape(c0c.begin_shapes_rec(0)).property("p"), nil)
assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)")
assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(1)).property("p"), 17)
c0.move_shapes(c0c)
assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)")
assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)")
@ -1142,9 +1152,9 @@ class DBLayoutTests1_TestClass < TestBase
assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)")
assert_equal(collect(c0.begin_shapes_rec(1), l), "")
assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](1,101;1001,1201)")
assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(0)).property("p"), 17)
assert_equal(collect(c0c.begin_shapes_rec(1), l), "")
assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), nil)
assert_equal(first_shape(c0c.begin_shapes_rec(1)).property("p"), nil)
l = ll.dup
c0 = l.cell("c0")
@ -1159,9 +1169,9 @@ class DBLayoutTests1_TestClass < TestBase
assert_equal(collect(c0.begin_shapes_rec(0), l), "[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)")
assert_equal(collect(c0.begin_shapes_rec(1), l), "")
assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)")
assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil)
assert_equal(first_shape(c0c.begin_shapes_rec(layer1)).property("p"), nil)
assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)")
assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(layer2)).property("p"), 17)
l = ll.dup
c0 = l.cell("c0")
@ -1185,9 +1195,9 @@ class DBLayoutTests1_TestClass < TestBase
assert_equal(collect(c0.begin_shapes_rec(0), l), "[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)")
assert_equal(collect(c0.begin_shapes_rec(1), l), "")
assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)")
assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil)
assert_equal(first_shape(c0c.begin_shapes_rec(layer1)).property("p"), nil)
assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)")
assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(layer2)).property("p"), 17)
end
@ -1351,7 +1361,7 @@ class DBLayoutTests1_TestClass < TestBase
layer1 = l2.find_layer(1, 0)
layer2 = l2.find_layer(2, 0)
assert_equal(l2.cell("c1").begin_shapes_rec(layer1).shape.property("p"), 17)
assert_equal(first_shape(l2.cell("c1").begin_shapes_rec(layer1)).property("p"), 17)
assert_equal(collect(c0c.begin_shapes_rec(layer1), l2), "[c0](0,200;2000,2400)/[c2](200,0;2200,2200)/[c3](2400,0;4400,2200)/[c3](-2400,0;-200,2000)/[c1](0,200;2000,2400)")
assert_equal(collect(c0c.begin_shapes_rec(layer2), l2), "[c0](2,202;2002,2402)")
@ -1401,7 +1411,7 @@ class DBLayoutTests1_TestClass < TestBase
i0 = nil
c0c.each_inst { |i| i.cell_index == l.cell("c1$1").cell_index && i0 = i }
assert_equal(i0.property("p"), 18)
assert_equal(l.cell("c1$1").begin_shapes_rec(0).shape.property("p"), 17)
assert_equal(first_shape(l.cell("c1$1").begin_shapes_rec(0)).property("p"), 17)
assert_equal(collect(c0.begin_shapes_rec(0), l), "")
assert_equal(collect(c0.begin_shapes_rec(1), l), "")
@ -1429,7 +1439,7 @@ class DBLayoutTests1_TestClass < TestBase
layer1 = l2.find_layer(1, 0)
layer2 = l2.find_layer(2, 0)
assert_equal(l2.cell("c1").begin_shapes_rec(layer1).shape.property("p"), 17)
assert_equal(first_shape(l2.cell("c1").begin_shapes_rec(layer1)).property("p"), 17)
assert_equal(collect(c0c.begin_shapes_rec(layer1), l2), "[c0](0,200;2000,2400)/[c2](200,0;2200,2200)/[c3](2400,0;4400,2200)/[c3](-2400,0;-200,2000)/[c1](0,200;2000,2400)")
assert_equal(collect(c0c.begin_shapes_rec(layer2), l2), "[c0](2,202;2002,2402)")
@ -1471,16 +1481,16 @@ class DBLayoutTests1_TestClass < TestBase
cm.for_single_cell(l, c0c.cell_index, l, c0.cell_index)
c0c.copy_tree_shapes(c0, cm)
assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c0$1](0,100;1000,1200)/[c0$1](100,0;1100,1100)/[c0$1](-1200,0;-100,1000)/[c0$1](1200,0;2200,1100)")
assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil)
assert_equal(first_shape(c0c.begin_shapes_rec(0)).property("p"), nil)
assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)")
assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(1)).property("p"), 17)
c0c.clear
lm = RBA::LayerMapping::new
lm.map(1, 0)
c0c.copy_tree_shapes(c0, cm, lm)
assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](1,101;1001,1201)")
assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(0)).property("p"), 17)
assert_equal(collect(c0c.begin_shapes_rec(1), l), "")
assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), nil)
@ -1488,9 +1498,9 @@ class DBLayoutTests1_TestClass < TestBase
cm.for_single_cell_full(l, c0c.cell_index, l, c0.cell_index)
c0c.copy_tree_shapes(c0, cm)
assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c2$1](100,0;1100,1100)/[c3$1](1200,0;2200,1100)/[c3$1](-1200,0;-100,1000)/[c1$1](0,100;1000,1200)")
assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil)
assert_equal(first_shape(c0c.begin_shapes_rec(0)).property("p"), nil)
assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)")
assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(1)).property("p"), 17)
i0 = nil
c0c.each_inst { |i| i.cell_index == l.cell("c1$1").cell_index && i0 = i }
@ -1505,9 +1515,9 @@ class DBLayoutTests1_TestClass < TestBase
layer1 = l2.find_layer(1, 0)
layer2 = l2.find_layer(2, 0)
assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)/[c2](200,0;2200,2200)/[c3](2400,0;4400,2200)/[c3](-2400,0;-200,2000)/[c1](0,200;2000,2400)")
assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil)
assert_equal(first_shape(c0c.begin_shapes_rec(layer1)).property("p"), nil)
assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)")
assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(layer2)).property("p"), 17)
i0 = nil
c0c.each_inst { |i| i.cell_index == l2.cell("c1").cell_index && i0 = i }
@ -1559,9 +1569,9 @@ class DBLayoutTests1_TestClass < TestBase
assert_equal(collect(c0.begin_shapes_rec(0), l), "")
assert_equal(collect(c0.begin_shapes_rec(1), l), "")
assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c0$1](0,100;1000,1200)/[c0$1](100,0;1100,1100)/[c0$1](-1200,0;-100,1000)/[c0$1](1200,0;2200,1100)")
assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil)
assert_equal(first_shape(c0c.begin_shapes_rec(0)).property("p"), nil)
assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)")
assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(1)).property("p"), 17)
l = ll.dup
c0 = l.cell("c0")
@ -1573,9 +1583,9 @@ class DBLayoutTests1_TestClass < TestBase
assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)")
assert_equal(collect(c0.begin_shapes_rec(1), l), "")
assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](1,101;1001,1201)")
assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(0)).property("p"), 17)
assert_equal(collect(c0c.begin_shapes_rec(1), l), "")
assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), nil)
assert_equal(first_shape(c0c.begin_shapes_rec(1)).property("p"), nil)
l = ll.dup
c0 = l.cell("c0")
@ -1586,9 +1596,9 @@ class DBLayoutTests1_TestClass < TestBase
assert_equal(collect(c0.begin_shapes_rec(0), l), "")
assert_equal(collect(c0.begin_shapes_rec(1), l), "")
assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c2$1](100,0;1100,1100)/[c3$1](1200,0;2200,1100)/[c3$1](-1200,0;-100,1000)/[c1$1](0,100;1000,1200)")
assert_equal(c0c.begin_shapes_rec(0).shape.property("p"), nil)
assert_equal(first_shape(c0c.begin_shapes_rec(0)).property("p"), nil)
assert_equal(collect(c0c.begin_shapes_rec(1), l), "[c0$1](1,101;1001,1201)")
assert_equal(c0c.begin_shapes_rec(1).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(1)).property("p"), 17)
i0 = nil
c0c.each_inst { |i| i.cell_index == l.cell("c1$1").cell_index && i0 = i }
@ -1608,9 +1618,9 @@ class DBLayoutTests1_TestClass < TestBase
layer1 = l2.find_layer(1, 0)
layer2 = l2.find_layer(2, 0)
assert_equal(collect(c0c.begin_shapes_rec(layer1), l), "[c0](0,200;2000,2400)/[c2](200,0;2200,2200)/[c3](2400,0;4400,2200)/[c3](-2400,0;-200,2000)/[c1](0,200;2000,2400)")
assert_equal(c0c.begin_shapes_rec(layer1).shape.property("p"), nil)
assert_equal(first_shape(c0c.begin_shapes_rec(layer1)).property("p"), nil)
assert_equal(collect(c0c.begin_shapes_rec(layer2), l), "[c0](2,202;2002,2402)")
assert_equal(c0c.begin_shapes_rec(layer2).shape.property("p"), 17)
assert_equal(first_shape(c0c.begin_shapes_rec(layer2)).property("p"), 17)
i0 = nil
c0c.each_inst { |i| i.cell_index == l2.cell("c1").cell_index && i0 = i }
@ -1833,10 +1843,10 @@ class DBLayoutTests1_TestClass < TestBase
lt.copy_tree_shapes(l, cm)
assert_equal(collect(c0t.begin_shapes_rec(0), lt), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](-1200,0;-100,1000)/[c0](1200,0;2200,1100)")
assert_equal(c0t.begin_shapes_rec(0).shape.property("p"), nil)
assert_equal(first_shape(c0t.begin_shapes_rec(0)).property("p"), nil)
assert_equal(collect(c9t.begin_shapes_rec(0), lt), "[c9](0,100;1000,1200)")
assert_equal(collect(c0t.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)")
assert_equal(c0t.begin_shapes_rec(1).shape.property("p"), 17)
assert_equal(first_shape(c0t.begin_shapes_rec(1)).property("p"), 17)
assert_equal(collect(c9t.begin_shapes_rec(1), l), "")
lt = RBA::Layout::new
@ -1850,10 +1860,10 @@ class DBLayoutTests1_TestClass < TestBase
lt.copy_tree_shapes(l, cm)
assert_equal(collect(c0t.begin_shapes_rec(0), lt), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)")
assert_equal(c0t.begin_shapes_rec(0).shape.property("p"), nil)
assert_equal(first_shape(c0t.begin_shapes_rec(0)).property("p"), nil)
assert_equal(collect(c9t.begin_shapes_rec(0), lt), "[c1](0,100;1000,1200)")
assert_equal(collect(c0t.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)")
assert_equal(c0t.begin_shapes_rec(1).shape.property("p"), 17)
assert_equal(first_shape(c0t.begin_shapes_rec(1)).property("p"), 17)
assert_equal(collect(c9t.begin_shapes_rec(1), l), "")
lt = RBA::Layout::new
@ -1873,7 +1883,7 @@ class DBLayoutTests1_TestClass < TestBase
lt.copy_tree_shapes(l, cm, lm)
assert_equal(collect(c0t.begin_shapes_rec(ll), lt), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)")
assert_equal(c0t.begin_shapes_rec(ll).shape.property("p"), nil)
assert_equal(first_shape(c0t.begin_shapes_rec(ll)).property("p"), nil)
assert_equal(collect(c9t.begin_shapes_rec(ll), lt), "[c1](0,100;1000,1200)")
lt = RBA::Layout::new
@ -1897,10 +1907,10 @@ class DBLayoutTests1_TestClass < TestBase
assert_equal(collect(ls.cell(c9.cell_index).begin_shapes_rec(1), ls), "")
assert_equal(collect(c0t.begin_shapes_rec(0), lt), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](-1200,0;-100,1000)/[c0](1200,0;2200,1100)")
assert_equal(c0t.begin_shapes_rec(0).shape.property("p"), nil)
assert_equal(first_shape(c0t.begin_shapes_rec(0)).property("p"), nil)
assert_equal(collect(c9t.begin_shapes_rec(0), lt), "[c9](0,100;1000,1200)")
assert_equal(collect(c0t.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)")
assert_equal(c0t.begin_shapes_rec(1).shape.property("p"), 17)
assert_equal(first_shape(c0t.begin_shapes_rec(1)).property("p"), 17)
assert_equal(collect(c9t.begin_shapes_rec(1), l), "")
lt = RBA::Layout::new
@ -1931,7 +1941,7 @@ class DBLayoutTests1_TestClass < TestBase
assert_equal(collect(ls.cell(c9.cell_index).begin_shapes_rec(1), ls), "")
assert_equal(collect(c0t.begin_shapes_rec(ll), lt), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](-1200,0;-100,1000)/[c0](1200,0;2200,1100)")
assert_equal(c0t.begin_shapes_rec(ll).shape.property("p"), nil)
assert_equal(first_shape(c0t.begin_shapes_rec(ll)).property("p"), nil)
assert_equal(collect(c9t.begin_shapes_rec(ll), lt), "[c9](0,100;1000,1200)")
end

View File

@ -23,6 +23,16 @@ end
load("test_prologue.rb")
def first_shape(s)
sdup = s.dup
shape = sdup.shape
sdup._destroy
return shape
end
class BoxPCell < RBA::PCellDeclaration
def display_text(parameters)
@ -428,30 +438,30 @@ class DBPCell_TestClass < TestBase
li2 = ly.layer_indices.find { |li| ly.get_info(li).to_s == "10/0" }
assert_equal(li2 != nil, true)
assert_equal(ly.begin_shapes(c1.cell_index, li1).shape.to_s, "box (-250,-500;250,500)")
assert_equal(ly.begin_shapes(lib_proxy.cell_index, li2).shape.to_s, "box (0,0;10,20)")
assert_equal(first_shape(ly.begin_shapes(c1.cell_index, li1)).to_s, "box (-250,-500;250,500)")
assert_equal(first_shape(ly.begin_shapes(lib_proxy.cell_index, li2)).to_s, "box (0,0;10,20)")
param = { "w" => 1, "h" => 2 }
c1.change_pcell_parameters(pcell_inst, param)
assert_equal(ly.begin_shapes(c1.cell_index, li1).shape.to_s, "box (-50,-100;50,100)")
assert_equal(first_shape(ly.begin_shapes(c1.cell_index, li1)).to_s, "box (-50,-100;50,100)")
param = [ RBA::LayerInfo::new(1, 0), 5.0, 5.0 ]
c1.change_pcell_parameters(pcell_inst, param)
assert_equal(ly.begin_shapes(c1.cell_index, li1).shape.to_s, "box (-250,-250;250,250)")
assert_equal(first_shape(ly.begin_shapes(c1.cell_index, li1)).to_s, "box (-250,-250;250,250)")
pcell_inst.change_pcell_parameters({ "w" => 2.0, "h" => 10.0 })
assert_equal(ly.begin_shapes(c1.cell_index, li1).shape.to_s, "box (-100,-500;100,500)")
assert_equal(first_shape(ly.begin_shapes(c1.cell_index, li1)).to_s, "box (-100,-500;100,500)")
pcell_inst.change_pcell_parameters([ RBA::LayerInfo::new(1, 0), 5.0, 5.0 ])
assert_equal(ly.begin_shapes(c1.cell_index, li1).shape.to_s, "box (-250,-250;250,250)")
assert_equal(first_shape(ly.begin_shapes(c1.cell_index, li1)).to_s, "box (-250,-250;250,250)")
pcell_inst.change_pcell_parameter("w", 5.0)
pcell_inst.change_pcell_parameter("h", 1.0)
assert_equal(ly.begin_shapes(c1.cell_index, li1).shape.to_s, "box (-250,-50;250,50)")
assert_equal(first_shape(ly.begin_shapes(c1.cell_index, li1)).to_s, "box (-250,-50;250,50)")
c1.change_pcell_parameter(pcell_inst, "w", 10.0)
c1.change_pcell_parameter(pcell_inst, "h", 2.0)
assert_equal(ly.begin_shapes(c1.cell_index, li1).shape.to_s, "box (-500,-100;500,100)")
assert_equal(first_shape(ly.begin_shapes(c1.cell_index, li1)).to_s, "box (-500,-100;500,100)")
assert_equal(ly.cell(pcell_inst.cell_index).is_pcell_variant?, true)
assert_equal(pcell_inst.is_pcell?, true)
@ -460,18 +470,18 @@ class DBPCell_TestClass < TestBase
assert_equal(ly.cell(new_id).is_pcell_variant?, false)
param = [ RBA::LayerInfo::new(1, 0), 5.0, 5.0 ]
c1.change_pcell_parameters(pcell_inst, param)
assert_equal(ly.begin_shapes(c1.cell_index, li1).shape.to_s, "box (-250,-250;250,250)")
assert_equal(first_shape(ly.begin_shapes(c1.cell_index, li1)).to_s, "box (-250,-250;250,250)")
pcell_inst.cell_index = new_id
assert_equal(ly.begin_shapes(c1.cell_index, li1).shape.to_s, "box (-500,-100;500,100)")
assert_equal(first_shape(ly.begin_shapes(c1.cell_index, li1)).to_s, "box (-500,-100;500,100)")
l10 = ly.layer(10, 0)
c1.shapes(l10).insert(RBA::Box::new(0, 10, 100, 210))
l11 = ly.layer(11, 0)
c1.shapes(l11).insert(RBA::Text::new("hello", RBA::Trans::new))
assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), false)
assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), true)
assert_equal(pcell_decl.parameters_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).inspect, "[<10/0>, 1.0, 2.0]")
assert_equal(pcell_decl.transformation_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).to_s, "r0 50,110")
assert_equal(pcell_decl.can_create_from_shape(ly, first_shape(ly.begin_shapes(c1.cell_index(), l11)), l10), false)
assert_equal(pcell_decl.can_create_from_shape(ly, first_shape(ly.begin_shapes(c1.cell_index(), l10)), l10), true)
assert_equal(pcell_decl.parameters_from_shape(ly, first_shape(ly.begin_shapes(c1.cell_index(), l10)), l10).inspect, "[<10/0>, 1.0, 2.0]")
assert_equal(pcell_decl.transformation_from_shape(ly, first_shape(ly.begin_shapes(c1.cell_index(), l10)), l10).to_s, "r0 50,110")
ly._destroy
tl._destroy
@ -522,21 +532,21 @@ class DBPCell_TestClass < TestBase
pcell_inst.change_pcell_parameter("height", 2.0)
assert_equal(norm_hash(pcell_inst.pcell_parameters_by_name()), "{\"height\"=>2.0, \"layer\"=><1/0>, \"secret\"=>0, \"width\"=>1.0}")
assert_equal(ly.begin_shapes(c1.cell_index(), li1).shape().to_s, "box (-50,-100;50,100)")
assert_equal(first_shape(ly.begin_shapes(c1.cell_index(), li1)).to_s, "box (-50,-100;50,100)")
param = { "layer" => RBA::LayerInfo::new(2, 0), "width" => 2, "height" => 1 }
li2 = ly.layer(2, 0)
c1.change_pcell_parameters(pcell_inst, param)
assert_equal(ly.begin_shapes(c1.cell_index(), li2).shape().to_s, "box (-100,-50;100,50)")
assert_equal(first_shape(ly.begin_shapes(c1.cell_index(), li2)).to_s, "box (-100,-50;100,50)")
l10 = ly.layer(10, 0)
c1.shapes(l10).insert(RBA::Box::new(0, 10, 100, 210))
l11 = ly.layer(11, 0)
c1.shapes(l11).insert(RBA::Text::new("hello", RBA::Trans::new))
assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), false)
assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), true)
assert_equal(pcell_decl.parameters_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).inspect, "[<10/0>, 1.0, 2.0, 0]")
assert_equal(pcell_decl.transformation_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).to_s, "r0 50,110")
assert_equal(pcell_decl.can_create_from_shape(ly, first_shape(ly.begin_shapes(c1.cell_index(), l11)), l10), false)
assert_equal(pcell_decl.can_create_from_shape(ly, first_shape(ly.begin_shapes(c1.cell_index(), l10)), l10), true)
assert_equal(pcell_decl.parameters_from_shape(ly, first_shape(ly.begin_shapes(c1.cell_index(), l10)), l10).inspect, "[<10/0>, 1.0, 2.0, 0]")
assert_equal(pcell_decl.transformation_from_shape(ly, first_shape(ly.begin_shapes(c1.cell_index(), l10)), l10).to_s, "r0 50,110")
param2 = c1.pcell_parameters(pcell_inst)
param2[3] = -2 # "secret"
@ -594,13 +604,13 @@ class DBPCell_TestClass < TestBase
assert_equal(pcell_inst.is_pcell?, true)
assert_equal(ly.begin_shapes(pcell_inst.cell_index, li1).shape.to_s, "box (-500,-100;500,100)")
assert_equal(first_shape(ly.begin_shapes(pcell_inst.cell_index, li1)).to_s, "box (-500,-100;500,100)")
pcell_inst.convert_to_static
assert_equal(pcell_inst.is_pcell?, false)
assert_equal(ly.begin_shapes(pcell_inst.cell_index, li1).shape.to_s, "box (-500,-100;500,100)")
assert_equal(first_shape(ly.begin_shapes(pcell_inst.cell_index, li1)).to_s, "box (-500,-100;500,100)")
pcell_inst.convert_to_static
assert_equal(pcell_inst.is_pcell?, false)
assert_equal(ly.begin_shapes(pcell_inst.cell_index, li1).shape.to_s, "box (-500,-100;500,100)")
assert_equal(first_shape(ly.begin_shapes(pcell_inst.cell_index, li1)).to_s, "box (-500,-100;500,100)")
ly._destroy
tl._destroy
@ -625,7 +635,7 @@ class DBPCell_TestClass < TestBase
pcell_var = ly.cell(pcell_var_id)
pcell_inst = c1.insert(RBA::CellInstArray::new(pcell_var_id, RBA::Trans::new))
assert_equal(ly.begin_shapes(c1.cell_index, ly.layer(1, 0)).shape.to_s, "box (-200,-400;200,400)")
assert_equal(first_shape(ly.begin_shapes(c1.cell_index, ly.layer(1, 0))).to_s, "box (-200,-400;200,400)")
ly._destroy
tl._destroy
@ -643,7 +653,7 @@ class DBPCell_TestClass < TestBase
param = { "w" => 4.0, "h" => 8.0, "l" => RBA::LayerInfo::new(1, 0) }
pcell_var_id = lib.layout.add_pcell_variant(pcell_decl_id, param)
assert_equal(lib.layout.begin_shapes(pcell_var_id, lib.layout.layer(1, 0)).shape.to_s, "box (-2000,-4000;2000,4000)")
assert_equal(first_shape(lib.layout.begin_shapes(pcell_var_id, lib.layout.layer(1, 0))).to_s, "box (-2000,-4000;2000,4000)")
tl._destroy
@ -660,7 +670,7 @@ class DBPCell_TestClass < TestBase
param = { "w" => 3.0, "h" => 7.0, "l" => RBA::LayerInfo::new(2, 0) }
pcell_var_id = lib.layout.add_pcell_variant(pcell_decl_id, param)
assert_equal(lib.layout.begin_shapes(pcell_var_id, lib.layout.layer(2, 0)).shape.to_s, "box (-1500,-3500;1500,3500)")
assert_equal(first_shape(lib.layout.begin_shapes(pcell_var_id, lib.layout.layer(2, 0))).to_s, "box (-1500,-3500;1500,3500)")
tl._destroy
@ -676,7 +686,7 @@ class DBPCell_TestClass < TestBase
param = { "w" => 3.0, "h" => 8.0, "l" => RBA::LayerInfo::new(3, 0) }
pcell_var = lib.layout.create_cell("Box", param)
assert_equal(lib.layout.begin_shapes(pcell_var.cell_index, lib.layout.layer(3, 0)).shape.to_s, "box (-1500,-4000;1500,4000)")
assert_equal(first_shape(lib.layout.begin_shapes(pcell_var.cell_index, lib.layout.layer(3, 0))).to_s, "box (-1500,-4000;1500,4000)")
tl._destroy
@ -693,7 +703,7 @@ class DBPCell_TestClass < TestBase
param = { "w" => 4.0, "h" => 8.0, "l" => RBA::LayerInfo::new(4, 0) }
cell = ly.create_cell("Box", "PCellTestLib", param)
assert_equal(ly.begin_shapes(cell, ly.layer(4, 0)).shape.to_s, "box (-200,-400;200,400)")
assert_equal(first_shape(ly.begin_shapes(cell, ly.layer(4, 0))).to_s, "box (-200,-400;200,400)")
tl._destroy
ly._destroy
@ -715,7 +725,7 @@ class DBPCell_TestClass < TestBase
cell = ly.create_cell("BOXVAR", "PCellTestLib")
assert_equal(cell.begin_shapes_rec(ly.layer(5, 0)).shape.to_s, "box (-100,-300;100,300)")
assert_equal(first_shape(cell.begin_shapes_rec(ly.layer(5, 0))).to_s, "box (-100,-300;100,300)")
tl._destroy
ly._destroy