mirror of https://github.com/KLayout/klayout.git
Maybe fixing basic issues with strmxor
1. Output of shape countsi in deep mode was hierarchical with output file, flat without 2. Refactoring of XOR (for_merged optimization) needed to create cover cell variants
This commit is contained in:
parent
449a9a968e
commit
41e9cb5893
|
|
@ -572,14 +572,22 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
if (! silent && ! no_summary) {
|
||||
|
||||
if (result) {
|
||||
tl::info << "No differences found";
|
||||
tl::info << tl::to_string (tr ("No differences found"));
|
||||
} else {
|
||||
|
||||
const char *line_format = " %-10s %-12s %s";
|
||||
const char *sep = " -------------------------------------------------------";
|
||||
|
||||
tl::info << "Result summary (layers without differences are not shown):" << tl::endl;
|
||||
tl::info << tl::sprintf (line_format, "Layer", "Output", "Differences (shape count)") << tl::endl << sep;
|
||||
std::string headline;
|
||||
if (deep) {
|
||||
headline = tl::sprintf (line_format, tl::to_string (tr ("Layer")), tl::to_string (tr ("Output")), tl::to_string (tr ("Differences (hierarchical shape count)")));
|
||||
} else {
|
||||
headline = tl::sprintf (line_format, tl::to_string (tr ("Layer")), tl::to_string (tr ("Output")), tl::to_string (tr ("Differences (shape count)")));
|
||||
}
|
||||
|
||||
const char *sep = " ----------------------------------------------------------------";
|
||||
|
||||
tl::info << tl::to_string (tr ("Result summary (layers without differences are not shown):")) << tl::endl;
|
||||
tl::info << headline << tl::endl << sep;
|
||||
|
||||
int ti = -1;
|
||||
for (std::map<std::pair<int, db::LayerProperties>, ResultDescriptor>::const_iterator r = results.begin (); r != results.end (); ++r) {
|
||||
|
|
@ -587,17 +595,17 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
if (r->first.first != ti) {
|
||||
ti = r->first.first;
|
||||
if (tolerances[ti] > db::epsilon) {
|
||||
tl::info << tl::endl << "Tolerance " << tl::micron_to_string (tolerances[ti]) << ":" << tl::endl;
|
||||
tl::info << tl::sprintf (line_format, "Layer", "Output", "Differences (shape count)") << tl::endl << sep;
|
||||
tl::info << tl::endl << tl::to_string (tr ("Tolerance ")) << tl::micron_to_string (tolerances[ti]) << ":" << tl::endl;
|
||||
tl::info << headline << tl::endl << sep;
|
||||
}
|
||||
}
|
||||
|
||||
std::string out ("-");
|
||||
std::string value;
|
||||
if (r->second.layer_a < 0 && ! dont_summarize_missing_layers) {
|
||||
value = "(no such layer in first layout)";
|
||||
value = tl::to_string (tr ("(no such layer in first layout)"));
|
||||
} else if (r->second.layer_b < 0 && ! dont_summarize_missing_layers) {
|
||||
value = "(no such layer in second layout)";
|
||||
value = tl::to_string (tr ("(no such layer in second layout)"));
|
||||
} else if (! r->second.is_empty ()) {
|
||||
if (r->second.layer_output >= 0 && r->second.layout) {
|
||||
out = r->second.layout->get_properties (r->second.layer_output).to_string ();
|
||||
|
|
@ -857,7 +865,7 @@ bool run_deep_xor (const XORData &xor_data)
|
|||
result.layer_output = result.layout->insert_layer (lp);
|
||||
xor_res.insert_into (xor_data.output_layout, xor_data.output_cell, result.layer_output);
|
||||
} else {
|
||||
result.shape_count = xor_res.count ();
|
||||
result.shape_count = xor_res.hier_count ();
|
||||
}
|
||||
|
||||
++tol_index;
|
||||
|
|
|
|||
|
|
@ -1571,6 +1571,17 @@ struct array_iterator
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the iterator is a synthetic one
|
||||
*
|
||||
* "is_singular" is true, if the iterator was default-created or with a single
|
||||
* transformation.
|
||||
*/
|
||||
bool is_singular () const
|
||||
{
|
||||
return mp_base == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
trans_type m_trans;
|
||||
basic_array_iterator <Coord> *mp_base;
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ HierarchyBuilder::begin (const RecursiveShapeIterator *iter)
|
|||
return;
|
||||
}
|
||||
|
||||
CellMapKey key (iter->top_cell ()->cell_index (), false, std::set<db::Box> ());
|
||||
CellMapKey key (iter->top_cell ()->cell_index (), false, std::set<db::Box> (), false);
|
||||
m_cm_entry = m_cell_map.find (key);
|
||||
|
||||
if (m_cm_entry == m_cell_map.end ()) {
|
||||
|
|
@ -351,7 +351,6 @@ HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, co
|
|||
if (! key.clip_region.empty ()) {
|
||||
cn += "$CLIP_VAR";
|
||||
description += "CLIP";
|
||||
|
||||
}
|
||||
if (key.inactive) {
|
||||
cn += "$DIS";
|
||||
|
|
@ -360,6 +359,13 @@ HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, co
|
|||
}
|
||||
description += "DISABLED";
|
||||
}
|
||||
if (key.skip_shapes) {
|
||||
cn += "$SKIP";
|
||||
if (! description.empty ()) {
|
||||
description += "/";
|
||||
}
|
||||
description += "SKIPPED";
|
||||
}
|
||||
|
||||
new_cell = mp_target->add_cell (cn.c_str ());
|
||||
|
||||
|
|
@ -383,11 +389,11 @@ HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, co
|
|||
}
|
||||
|
||||
HierarchyBuilder::new_inst_mode
|
||||
HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
|
||||
HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all, bool skip_shapes)
|
||||
{
|
||||
if (all) {
|
||||
|
||||
CellMapKey key (inst.object ().cell_index (), iter->is_child_inactive (inst.object ().cell_index ()), std::set<db::Box> ());
|
||||
CellMapKey key (inst.object ().cell_index (), iter->is_child_inactive (inst.object ().cell_index ()), std::set<db::Box> (), skip_shapes);
|
||||
db::cell_index_type new_cell = make_cell_variant (key, iter->layout ()->cell_name (inst.object ().cell_index ()));
|
||||
|
||||
// for new cells, create this instance
|
||||
|
|
@ -402,7 +408,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
|
|||
}
|
||||
|
||||
// To see the cell once, use NI_single. If we did see the cell already, skip the whole instance array.
|
||||
return (m_cells_seen.find (key) == m_cells_seen.end ()) ? NI_single : NI_skip;
|
||||
return (! skip_shapes && m_cells_seen.find (key) == m_cells_seen.end ()) ? NI_single : NI_skip;
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -413,7 +419,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
|
|||
}
|
||||
|
||||
bool
|
||||
HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all)
|
||||
HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all, bool skip_shapes)
|
||||
{
|
||||
if (all) {
|
||||
|
||||
|
|
@ -429,7 +435,7 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
|
|||
return false;
|
||||
}
|
||||
|
||||
CellMapKey key (inst.object ().cell_index (), iter->is_child_inactive (inst_cell), clip_variant.second);
|
||||
CellMapKey key (inst.object ().cell_index (), iter->is_child_inactive (inst_cell), clip_variant.second, skip_shapes);
|
||||
db::cell_index_type new_cell = make_cell_variant (key, iter->layout ()->cell_name (inst_cell));
|
||||
|
||||
// for a new cell, create this instance
|
||||
|
|
@ -441,7 +447,7 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
|
|||
}
|
||||
}
|
||||
|
||||
return (m_cells_seen.find (key) == m_cells_seen.end ());
|
||||
return ! skip_shapes && m_cells_seen.find (key) == m_cells_seen.end ();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -249,16 +249,16 @@ public:
|
|||
struct CellMapKey
|
||||
{
|
||||
CellMapKey ()
|
||||
: original_cell (0), inactive (false)
|
||||
: original_cell (0), inactive (false), skip_shapes (false)
|
||||
{ }
|
||||
|
||||
CellMapKey (db::cell_index_type _original_cell, bool _inactive, const std::set<db::Box> &_clip_region)
|
||||
: original_cell (_original_cell), inactive (_inactive), clip_region (_clip_region)
|
||||
CellMapKey (db::cell_index_type _original_cell, bool _inactive, const std::set<db::Box> &_clip_region, bool _skip_shapes)
|
||||
: original_cell (_original_cell), inactive (_inactive), clip_region (_clip_region), skip_shapes (_skip_shapes)
|
||||
{ }
|
||||
|
||||
bool operator== (const CellMapKey &other) const
|
||||
{
|
||||
return original_cell == other.original_cell && inactive == other.inactive && clip_region == other.clip_region;
|
||||
return original_cell == other.original_cell && inactive == other.inactive && clip_region == other.clip_region && skip_shapes == other.skip_shapes;
|
||||
}
|
||||
|
||||
bool operator< (const CellMapKey &other) const
|
||||
|
|
@ -266,12 +266,14 @@ public:
|
|||
if (original_cell != other.original_cell) { return original_cell < other.original_cell; }
|
||||
if (inactive != other.inactive) { return inactive < other.inactive; }
|
||||
if (clip_region != other.clip_region) { return clip_region < other.clip_region; }
|
||||
if (skip_shapes != other.skip_shapes) { return skip_shapes < other.skip_shapes; }
|
||||
return false;
|
||||
}
|
||||
|
||||
db::cell_index_type original_cell;
|
||||
bool inactive;
|
||||
std::set<db::Box> clip_region;
|
||||
bool skip_shapes;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -294,8 +296,8 @@ public:
|
|||
virtual void end (const RecursiveShapeIterator *iter);
|
||||
virtual void enter_cell (const RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box ®ion, const box_tree_type *complex_region);
|
||||
virtual void leave_cell (const RecursiveShapeIterator *iter, const db::Cell *cell);
|
||||
virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::Box ®ion, const box_tree_type *complex_region, bool all);
|
||||
virtual bool new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all);
|
||||
virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::Box ®ion, const box_tree_type *complex_region, bool all, bool skip_shapes);
|
||||
virtual bool new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all, bool skip_shapes);
|
||||
virtual void shape (const RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
|
|||
m_layer = d.m_layer;
|
||||
mp_cell = d.mp_cell;
|
||||
m_current_layer = d.m_current_layer;
|
||||
m_skip_shapes = d.m_skip_shapes;
|
||||
m_skip_shapes_member = d.m_skip_shapes_member;
|
||||
m_shape = d.m_shape;
|
||||
m_trans = d.m_trans;
|
||||
m_global_trans = d.m_global_trans;
|
||||
|
|
@ -85,6 +87,7 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
|
|||
m_local_complex_region_stack = d.m_local_complex_region_stack;
|
||||
m_local_region_stack = d.m_local_region_stack;
|
||||
m_skip_shapes_stack = d.m_skip_shapes_stack;
|
||||
m_skip_shapes_member_stack = d.m_skip_shapes_member_stack;
|
||||
m_needs_reinit = d.m_needs_reinit;
|
||||
m_inst_quad_id = d.m_inst_quad_id;
|
||||
m_inst_quad_id_stack = d.m_inst_quad_id_stack;
|
||||
|
|
@ -469,6 +472,8 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
|
|||
m_local_region_stack.push_back (m_global_trans.inverted () * m_region);
|
||||
m_skip_shapes_stack.clear ();
|
||||
m_skip_shapes_stack.push_back (false);
|
||||
m_skip_shapes_member_stack.clear ();
|
||||
m_skip_shapes_member_stack.push_back (false);
|
||||
|
||||
m_local_complex_region_stack.clear ();
|
||||
if (mp_complex_region.get ()) {
|
||||
|
|
@ -814,39 +819,6 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const
|
|||
bool
|
||||
RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
|
||||
{
|
||||
bool skip_shapes = false;
|
||||
|
||||
if (m_for_merged_input && ! m_skip_shapes_stack.back () && (! m_has_layers || m_layers.size () == 1)) {
|
||||
|
||||
// Try some optimization: if the instance we're looking at is entirely covered
|
||||
// by a rectangle (other objects are too expensive to check), then we skip it
|
||||
//
|
||||
// We check 10 shapes max.
|
||||
|
||||
box_type inst_bx;
|
||||
if (m_inst->size () == 1) {
|
||||
inst_bx = m_inst->bbox (m_box_convert);
|
||||
} else {
|
||||
inst_bx = m_inst->complex_trans (*m_inst_array) * m_box_convert (m_inst->cell_inst ().object ());
|
||||
}
|
||||
|
||||
unsigned int l = m_has_layers ? m_layers.front () : m_layer;
|
||||
auto si = cell ()->shapes (l).begin_overlapping (inst_bx, m_shape_flags, mp_shape_prop_sel, m_shape_inv_prop_sel);
|
||||
size_t nmax = 10;
|
||||
while (! si.at_end () && nmax-- > 0) {
|
||||
if (inst_bx.inside (si->rectangle ())) {
|
||||
skip_shapes = true;
|
||||
break;
|
||||
}
|
||||
++si;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (skip_shapes && (! receiver || ! receiver->wants_all_cells ())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tl_assert (mp_layout);
|
||||
|
||||
m_trans_stack.push_back (m_trans);
|
||||
|
|
@ -874,7 +846,8 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
|
|||
}
|
||||
|
||||
m_local_region_stack.push_back (new_region);
|
||||
m_skip_shapes_stack.push_back (m_skip_shapes_stack.back () || skip_shapes);
|
||||
m_skip_shapes_stack.push_back (m_skip_shapes);
|
||||
m_skip_shapes_member_stack.push_back (m_skip_shapes_member);
|
||||
|
||||
if (! m_local_complex_region_stack.empty ()) {
|
||||
|
||||
|
|
@ -948,6 +921,8 @@ RecursiveShapeIterator::pop () const
|
|||
m_inst = m_inst_iterators.back ();
|
||||
m_inst_array = m_inst_array_iterators.back ();
|
||||
m_inst_quad_id = m_inst_quad_id_stack.back ();
|
||||
m_skip_shapes = m_skip_shapes_stack.back ();
|
||||
m_skip_shapes_member = m_skip_shapes_member_stack.back ();
|
||||
m_inst_iterators.pop_back ();
|
||||
m_inst_array_iterators.pop_back ();
|
||||
m_inst_quad_id_stack.pop_back ();
|
||||
|
|
@ -958,6 +933,7 @@ RecursiveShapeIterator::pop () const
|
|||
m_cells.pop_back ();
|
||||
m_local_region_stack.pop_back ();
|
||||
m_skip_shapes_stack.pop_back ();
|
||||
m_skip_shapes_member_stack.pop_back ();
|
||||
if (! m_local_complex_region_stack.empty ()) {
|
||||
m_local_complex_region_stack.pop_back ();
|
||||
}
|
||||
|
|
@ -982,7 +958,7 @@ RecursiveShapeIterator::start_shapes () const
|
|||
void
|
||||
RecursiveShapeIterator::new_layer () const
|
||||
{
|
||||
if (m_skip_shapes_stack.back () || int (m_trans_stack.size ()) < m_min_depth || int (m_trans_stack.size ()) > m_max_depth) {
|
||||
if (skip_shapes () || int (m_trans_stack.size ()) < m_min_depth || int (m_trans_stack.size ()) > m_max_depth) {
|
||||
m_shape = shape_iterator ();
|
||||
} else if (! m_overlapping) {
|
||||
m_shape = cell ()->shapes (m_layer).begin_touching (m_local_region_stack.back (), m_shape_flags, mp_shape_prop_sel, m_shape_inv_prop_sel);
|
||||
|
|
@ -1029,6 +1005,32 @@ RecursiveShapeIterator::new_cell (RecursiveShapeReceiver *receiver) const
|
|||
new_inst (receiver);
|
||||
}
|
||||
|
||||
bool
|
||||
RecursiveShapeIterator::instance_is_covered (const box_type &inst_bx, unsigned int layer) const
|
||||
{
|
||||
// Try some optimization: if the instance we're looking at is entirely covered
|
||||
// by a rectangle (other objects are too expensive to check), then we skip it
|
||||
//
|
||||
// We check 10 shapes max.
|
||||
|
||||
auto si = cell ()->shapes (layer).begin_overlapping (inst_bx, m_shape_flags, mp_shape_prop_sel, m_shape_inv_prop_sel);
|
||||
size_t nmax = 10;
|
||||
while (! si.at_end () && nmax-- > 0) {
|
||||
if (inst_bx.inside (si->rectangle ())) {
|
||||
return true;
|
||||
}
|
||||
++si;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RecursiveShapeIterator::skip_shapes () const
|
||||
{
|
||||
return m_skip_shapes_stack.back () || m_skip_shapes_member_stack.back ();
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
|
||||
{
|
||||
|
|
@ -1055,9 +1057,19 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
|
|||
all_of_instance = m_local_complex_region_stack.empty ();
|
||||
}
|
||||
|
||||
m_skip_shapes = skip_shapes ();
|
||||
m_skip_shapes_member = false;
|
||||
|
||||
if (m_for_merged_input && ! m_skip_shapes && (! m_has_layers || m_layers.size () == 1)) {
|
||||
box_type inst_bx = m_inst->bbox (m_box_convert);
|
||||
m_skip_shapes = instance_is_covered (inst_bx, m_has_layers ? m_layers.front () : m_layer);
|
||||
}
|
||||
|
||||
RecursiveShapeReceiver::new_inst_mode ni = RecursiveShapeReceiver::NI_all;
|
||||
if (receiver) {
|
||||
ni = receiver->new_inst (this, m_inst->cell_inst (), always_apply (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance);
|
||||
ni = receiver->new_inst (this, m_inst->cell_inst (), always_apply (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance, m_skip_shapes);
|
||||
} else if (m_skip_shapes) {
|
||||
ni = RecursiveShapeReceiver::NI_skip;
|
||||
}
|
||||
|
||||
if (ni == RecursiveShapeReceiver::NI_skip) {
|
||||
|
|
@ -1095,7 +1107,7 @@ RecursiveShapeIterator::new_inst_member (RecursiveShapeReceiver *receiver) const
|
|||
|
||||
// skip instance array members not part of the complex region
|
||||
while (! m_inst_array.at_end ()) {
|
||||
db::Box ia_box = m_inst->complex_trans (*m_inst_array) * cell_bbox (m_inst->cell_index ());
|
||||
box_type ia_box = m_inst->complex_trans (*m_inst_array) * cell_bbox (m_inst->cell_index ());
|
||||
if (! is_outside_complex_region (ia_box)) {
|
||||
break;
|
||||
} else {
|
||||
|
|
@ -1105,12 +1117,31 @@ RecursiveShapeIterator::new_inst_member (RecursiveShapeReceiver *receiver) const
|
|||
|
||||
}
|
||||
|
||||
while (! m_inst_array.at_end () && receiver) {
|
||||
if (receiver->new_inst_member (this, m_inst->cell_inst (), always_apply (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), is_all_of_instance ())) {
|
||||
break;
|
||||
} else {
|
||||
++m_inst_array;
|
||||
m_skip_shapes_member = false;
|
||||
|
||||
while (! m_inst_array.at_end () && (m_for_merged_input || receiver)) {
|
||||
|
||||
m_skip_shapes_member = m_skip_shapes;
|
||||
if (m_for_merged_input && ! m_inst_array.is_singular () && ! m_skip_shapes && (! m_has_layers || m_layers.size () == 1)) {
|
||||
|
||||
box_type ia_box = m_inst->complex_trans (*m_inst_array) * cell_bbox (m_inst->cell_index ());
|
||||
m_skip_shapes_member = instance_is_covered (ia_box, m_has_layers ? m_layers.front () : m_layer);
|
||||
|
||||
}
|
||||
|
||||
bool skip = false;
|
||||
if (receiver) {
|
||||
skip = ! receiver->new_inst_member (this, m_inst->cell_inst (), always_apply (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), is_all_of_instance (), m_skip_shapes_member);
|
||||
} else {
|
||||
skip = m_skip_shapes_member;
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
++m_inst_array;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -868,6 +868,7 @@ private:
|
|||
mutable unsigned int m_layer;
|
||||
mutable const cell_type *mp_cell;
|
||||
mutable size_t m_current_layer;
|
||||
mutable bool m_skip_shapes, m_skip_shapes_member;
|
||||
mutable shape_iterator m_shape;
|
||||
mutable cplx_trans_type m_trans;
|
||||
mutable std::vector<cplx_trans_type> m_trans_stack;
|
||||
|
|
@ -876,7 +877,7 @@ private:
|
|||
mutable std::vector<const cell_type *> m_cells;
|
||||
mutable std::vector<box_tree_type> m_local_complex_region_stack;
|
||||
mutable std::vector<box_type> m_local_region_stack;
|
||||
mutable std::vector<bool> m_skip_shapes_stack;
|
||||
mutable std::vector<bool> m_skip_shapes_stack, m_skip_shapes_member_stack;
|
||||
mutable bool m_needs_reinit;
|
||||
mutable size_t m_inst_quad_id;
|
||||
mutable std::vector<size_t> m_inst_quad_id_stack;
|
||||
|
|
@ -899,6 +900,8 @@ private:
|
|||
bool down (RecursiveShapeReceiver *receiver) const;
|
||||
void pop () const;
|
||||
|
||||
bool instance_is_covered (const box_type &inst_bx, unsigned int layer) const;
|
||||
bool skip_shapes () const;
|
||||
bool is_outside_complex_region (const db::Box &box) const;
|
||||
|
||||
void set_inactive (bool a) const
|
||||
|
|
@ -1013,8 +1016,11 @@ public:
|
|||
* - NI_all: iterate all members through "new_inst_member"
|
||||
* - NI_single: iterate a single member (the first one)
|
||||
* - NI_skip: skips the whole array (not a single instance is iterated)
|
||||
*
|
||||
* The "skip_shapes" parameter indicates that the instance is visited with the
|
||||
* purpose of skipping all shapes. This is used to implement the "for_merged" optimization.
|
||||
*/
|
||||
virtual new_inst_mode new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return NI_all; }
|
||||
virtual new_inst_mode new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/, bool /*skip_shapes*/) { return NI_all; }
|
||||
|
||||
/**
|
||||
* @brief Enters a new array member of the instance
|
||||
|
|
@ -1026,8 +1032,11 @@ public:
|
|||
* "all" is true, if an instance array is iterated in "all" mode (see new_inst).
|
||||
*
|
||||
* If this method returns false, this array instance (but not the whole array) is skipped and the cell is not entered.
|
||||
*
|
||||
* The "skip_shapes" parameter indicates that the instance member is visited with the
|
||||
* purpose of skipping all shapes. This is used to implement the "for_merged" optimization.
|
||||
*/
|
||||
virtual bool new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; }
|
||||
virtual bool new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/, bool /*skip_shapes*/) { return true; }
|
||||
|
||||
/**
|
||||
* @brief Delivers a shape
|
||||
|
|
|
|||
|
|
@ -756,15 +756,25 @@ namespace {
|
|||
: public db::RecursiveShapeReceiver
|
||||
{
|
||||
public:
|
||||
FlatPusher (std::set<db::Box> *boxes) : mp_boxes (boxes) { }
|
||||
FlatPusher (std::set<db::Box> *boxes = 0) : mp_boxes (boxes ? boxes : &m_boxes) { }
|
||||
|
||||
void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
{
|
||||
mp_boxes->insert (trans * shape.bbox ());
|
||||
}
|
||||
|
||||
std::string to_string () const
|
||||
{
|
||||
std::vector<std::string> s;
|
||||
for (auto i = mp_boxes->begin (); i != mp_boxes->end (); ++i) {
|
||||
s.push_back (i->to_string ());
|
||||
}
|
||||
return tl::join (s.begin (), s.end (), ";");
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<db::Box> *mp_boxes;
|
||||
std::set<db::Box> m_boxes;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1038,7 +1048,7 @@ public:
|
|||
m_text += std::string ("leave_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n";
|
||||
}
|
||||
|
||||
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
|
||||
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all, bool /*skip_shapes*/)
|
||||
{
|
||||
m_text += std::string ("new_inst(") + iter->layout ()->cell_name (inst.object ().cell_index ());
|
||||
if (all) {
|
||||
|
|
@ -1048,7 +1058,7 @@ public:
|
|||
return NI_all;
|
||||
}
|
||||
|
||||
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
|
||||
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all, bool /*skip_shapes*/)
|
||||
{
|
||||
m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (always_apply * trans);
|
||||
if (all) {
|
||||
|
|
@ -1073,9 +1083,9 @@ class ReceiverRejectingACellInstanceArray
|
|||
public:
|
||||
ReceiverRejectingACellInstanceArray (db::cell_index_type rejected) : m_rejected (rejected) { }
|
||||
|
||||
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box ®ion, const box_tree_type *complex_region, bool all)
|
||||
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box ®ion, const box_tree_type *complex_region, bool all, bool skip_shapes)
|
||||
{
|
||||
LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all);
|
||||
LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all, skip_shapes);
|
||||
return inst.object ().cell_index () != m_rejected ? NI_all : NI_skip;
|
||||
}
|
||||
|
||||
|
|
@ -1089,9 +1099,9 @@ class ReceiverRejectingACellInstanceArrayExceptOne
|
|||
public:
|
||||
ReceiverRejectingACellInstanceArrayExceptOne (db::cell_index_type rejected) : m_rejected (rejected) { }
|
||||
|
||||
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box ®ion, const box_tree_type *complex_region, bool all)
|
||||
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box ®ion, const box_tree_type *complex_region, bool all, bool skip_shapes)
|
||||
{
|
||||
LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all);
|
||||
LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all, skip_shapes);
|
||||
return inst.object ().cell_index () != m_rejected ? NI_all : NI_single;
|
||||
}
|
||||
|
||||
|
|
@ -1105,9 +1115,9 @@ class ReceiverRejectingACellInstance
|
|||
public:
|
||||
ReceiverRejectingACellInstance (db::cell_index_type rejected, const db::ICplxTrans &trans_rejected) : m_rejected (rejected), m_trans_rejected (trans_rejected) { }
|
||||
|
||||
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all)
|
||||
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all, bool skip_shapes)
|
||||
{
|
||||
LoggingReceiver::new_inst_member (iter, inst, always_apply, trans, region, complex_region, all);
|
||||
LoggingReceiver::new_inst_member (iter, inst, always_apply, trans, region, complex_region, all, skip_shapes);
|
||||
return inst.object ().cell_index () != m_rejected || trans != m_trans_rejected;
|
||||
}
|
||||
|
||||
|
|
@ -1586,49 +1596,174 @@ TEST(12_ForMerged)
|
|||
db::RecursiveShapeIterator i1 (*g, c0, 0);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
|
||||
EXPECT_EQ (collect_with_copy(i1, *g), x);
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
|
||||
EXPECT_EQ (collect_with_copy(i1, *g), x);
|
||||
|
||||
std::vector<unsigned int> lv;
|
||||
lv.push_back (0);
|
||||
i1 = db::RecursiveShapeIterator (*g, c0, lv);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
|
||||
EXPECT_EQ (collect_with_copy(i1, *g), x);
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
|
||||
EXPECT_EQ (collect_with_copy(i1, *g), x);
|
||||
|
||||
lv.push_back (1); // empty, but kills "for merged" optimization
|
||||
i1 = db::RecursiveShapeIterator (*g, c0, lv);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
|
||||
EXPECT_EQ (collect_with_copy(i1, *g), x);
|
||||
|
||||
{
|
||||
FlatPusher f;
|
||||
i1.reset ();
|
||||
i1.push (&f);
|
||||
EXPECT_EQ (f.to_string (), "(-1200,0;-100,1000);(0,0;3000,2000);(100,0;1100,1100);(1200,0;2200,1100);(0,100;1000,1200)");
|
||||
}
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
// no longer optimized
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
|
||||
EXPECT_EQ (collect_with_copy(i1, *g), x);
|
||||
|
||||
{
|
||||
FlatPusher f;
|
||||
i1.reset ();
|
||||
i1.push (&f);
|
||||
EXPECT_EQ (f.to_string (), "(-1200,0;-100,1000);(0,0;3000,2000);(100,0;1100,1100);(1200,0;2200,1100);(0,100;1000,1200)");
|
||||
}
|
||||
|
||||
i1 = db::RecursiveShapeIterator (*g, c0, 0, db::Box (-100, 0, 100, 50));
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
{
|
||||
FlatPusher f;
|
||||
i1.reset ();
|
||||
i1.push (&f);
|
||||
EXPECT_EQ (f.to_string (), "(-1200,0;-100,1000);(0,0;3000,2000);(100,0;1100,1100)");
|
||||
}
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
|
||||
EXPECT_EQ (collect_with_copy(i1, *g), x);
|
||||
|
||||
{
|
||||
FlatPusher f;
|
||||
i1.reset ();
|
||||
i1.push (&f);
|
||||
EXPECT_EQ (f.to_string (), "(-1200,0;-100,1000);(0,0;3000,2000)");
|
||||
}
|
||||
|
||||
i1 = db::RecursiveShapeIterator (*g, c0, 0, db::Box (-101, 0, 100, 50));
|
||||
i1.set_overlapping (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
|
||||
EXPECT_EQ (collect_with_copy(i1, *g), x);
|
||||
|
||||
{
|
||||
FlatPusher f;
|
||||
i1.reset ();
|
||||
i1.push (&f);
|
||||
EXPECT_EQ (f.to_string (), "(-1200,0;-100,1000);(0,0;3000,2000)");
|
||||
}
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
|
||||
EXPECT_EQ (collect_with_copy(i1, *g), x);
|
||||
|
||||
{
|
||||
FlatPusher f;
|
||||
i1.reset ();
|
||||
i1.push (&f);
|
||||
EXPECT_EQ (f.to_string (), "(-1200,0;-100,1000);(0,0;3000,2000)");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(12b_ForMerged)
|
||||
{
|
||||
std::unique_ptr<db::Layout> g (new db::Layout ());
|
||||
g->insert_layer (0);
|
||||
g->insert_layer (1);
|
||||
db::Cell &c0 (g->cell (g->add_cell ()));
|
||||
db::Cell &c1 (g->cell (g->add_cell ()));
|
||||
|
||||
db::Box b (0, 100, 1000, 1200);
|
||||
c0.shapes (0).insert (db::Box (0, 0, 3000, 2200));
|
||||
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, 1000)), db::Vector (0, 2000), db::Vector (2000, 0), 2l, 2l));
|
||||
|
||||
std::string x;
|
||||
|
||||
db::RecursiveShapeIterator i1 (*g, c0, 0);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2200)/[$2](0,100;1000,1200)/[$2](2000,1100;3000,2200)/[$2](2000,3100;3000,4200)/[$2](4000,1100;5000,2200)/[$2](4000,3100;5000,4200)");
|
||||
EXPECT_EQ (collect_with_copy(i1, *g), x);
|
||||
|
||||
{
|
||||
FlatPusher f;
|
||||
i1.reset ();
|
||||
i1.push (&f);
|
||||
EXPECT_EQ (f.to_string (), "(0,0;3000,2200);(0,100;1000,1200);(2000,1100;3000,2200);(4000,1100;5000,2200);(2000,3100;3000,4200);(4000,3100;5000,4200)");
|
||||
}
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2200)/[$2](2000,3100;3000,4200)/[$2](4000,1100;5000,2200)/[$2](4000,3100;5000,4200)");
|
||||
EXPECT_EQ (collect_with_copy(i1, *g), x);
|
||||
|
||||
{
|
||||
FlatPusher f;
|
||||
i1.reset ();
|
||||
i1.push (&f);
|
||||
EXPECT_EQ (f.to_string (), "(0,0;3000,2200);(4000,1100;5000,2200);(2000,3100;3000,4200);(4000,3100;5000,4200)");
|
||||
}
|
||||
|
||||
i1.set_for_merged_input (false);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2200)/[$2](0,100;1000,1200)/[$2](2000,1100;3000,2200)/[$2](2000,3100;3000,4200)/[$2](4000,1100;5000,2200)/[$2](4000,3100;5000,4200)");
|
||||
EXPECT_EQ (collect_with_copy(i1, *g), x);
|
||||
|
||||
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (0, 2000))));
|
||||
|
||||
db::RecursiveShapeIterator i2 (*g, c0, 0);
|
||||
|
||||
x = collect(i2, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2200)/[$2](0,100;1000,1200)/[$2](2000,1100;3000,2200)/[$2](2000,3100;3000,4200)/[$2](4000,1100;5000,2200)/[$2](4000,3100;5000,4200)/[$2](0,2100;1000,3200)");
|
||||
EXPECT_EQ (collect_with_copy(i2, *g), x);
|
||||
|
||||
{
|
||||
FlatPusher f;
|
||||
i2.reset ();
|
||||
i2.push (&f);
|
||||
EXPECT_EQ (f.to_string (), "(0,0;3000,2200);(0,100;1000,1200);(2000,1100;3000,2200);(4000,1100;5000,2200);(0,2100;1000,3200);(2000,3100;3000,4200);(4000,3100;5000,4200)");
|
||||
}
|
||||
|
||||
i2.set_for_merged_input (true);
|
||||
x = collect(i2, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2200)/[$2](2000,3100;3000,4200)/[$2](4000,1100;5000,2200)/[$2](4000,3100;5000,4200)/[$2](0,2100;1000,3200)");
|
||||
EXPECT_EQ (collect_with_copy(i2, *g), x);
|
||||
|
||||
{
|
||||
FlatPusher f;
|
||||
i2.reset ();
|
||||
i2.push (&f);
|
||||
EXPECT_EQ (f.to_string (), "(0,0;3000,2200);(4000,1100;5000,2200);(0,2100;1000,3200);(2000,3100;3000,4200);(4000,3100;5000,4200)");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(13_ForMergedPerformance)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ public:
|
|||
m_cell_stack.pop_back ();
|
||||
}
|
||||
|
||||
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator * /*iter*/, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/)
|
||||
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator * /*iter*/, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/, bool /*skip_shapes*/)
|
||||
{
|
||||
db::cell_index_type ci = inst.object ().cell_index ();
|
||||
if (m_id_to_cell.find (ci) != m_id_to_cell.end ()) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue