mirror of https://github.com/KLayout/klayout.git
RecursiveShapeIterator now features a push mode
This will eventually enable catching a hierarchy skeleton (with shapes) from a RecursiveShapeIterator.
This commit is contained in:
parent
b192417809
commit
f346e70746
|
|
@ -383,7 +383,7 @@ private:
|
|||
}
|
||||
|
||||
void
|
||||
RecursiveShapeIterator::validate () const
|
||||
RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
|
||||
{
|
||||
if (! m_needs_reinit) {
|
||||
return;
|
||||
|
|
@ -438,8 +438,8 @@ RecursiveShapeIterator::validate () const
|
|||
} else if (mp_layout && (! m_has_layers || m_current_layer < m_layers.size ())) {
|
||||
// Ensures the trees are built properly - this is important in MT contexts (i.e. TilingProcessor)
|
||||
mp_layout->update ();
|
||||
new_cell ();
|
||||
next_shape ();
|
||||
new_cell (receiver);
|
||||
next_shape (receiver);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -519,7 +519,7 @@ RecursiveShapeIterator::select_all_cells ()
|
|||
bool
|
||||
RecursiveShapeIterator::at_end () const
|
||||
{
|
||||
validate ();
|
||||
validate (0);
|
||||
return m_shape.at_end () || is_inactive ();
|
||||
}
|
||||
|
||||
|
|
@ -611,7 +611,7 @@ RecursiveShapeIterator::skip_inst_iter_for_complex_region () const
|
|||
}
|
||||
|
||||
void
|
||||
RecursiveShapeIterator::next ()
|
||||
RecursiveShapeIterator::next (RecursiveShapeReceiver *receiver)
|
||||
{
|
||||
if (! at_end ()) {
|
||||
|
||||
|
|
@ -622,14 +622,14 @@ RecursiveShapeIterator::next ()
|
|||
}
|
||||
|
||||
if (! mp_shapes && m_shape.at_end ()) {
|
||||
next_shape ();
|
||||
next_shape (receiver);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveShapeIterator::next_shape () const
|
||||
RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const
|
||||
{
|
||||
while (at_end ()) {
|
||||
|
||||
|
|
@ -674,10 +674,10 @@ RecursiveShapeIterator::next_shape () const
|
|||
if (is_empty) {
|
||||
|
||||
++m_inst;
|
||||
new_inst ();
|
||||
new_inst (receiver);
|
||||
|
||||
} else {
|
||||
down ();
|
||||
down (receiver);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -688,12 +688,14 @@ RecursiveShapeIterator::next_shape () const
|
|||
}
|
||||
|
||||
// no more instances: up and next instance
|
||||
up ();
|
||||
up (receiver);
|
||||
|
||||
++m_inst_array;
|
||||
new_inst_member (receiver);
|
||||
|
||||
if (m_inst_array.at_end ()) {
|
||||
++m_inst;
|
||||
new_inst ();
|
||||
new_inst (receiver);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -704,7 +706,7 @@ RecursiveShapeIterator::next_shape () const
|
|||
}
|
||||
|
||||
void
|
||||
RecursiveShapeIterator::down () const
|
||||
RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
|
||||
{
|
||||
m_trans_stack.push_back (m_trans);
|
||||
m_cells.push_back (mp_cell);
|
||||
|
|
@ -761,12 +763,24 @@ RecursiveShapeIterator::down () const
|
|||
|
||||
}
|
||||
|
||||
new_cell ();
|
||||
if (receiver && ! receiver->enter_cell (this, cell (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ())) {
|
||||
if (m_has_layers) {
|
||||
m_current_layer = m_layers.size ();
|
||||
}
|
||||
m_shape = shape_iterator ();
|
||||
m_inst = inst_iterator ();
|
||||
} else {
|
||||
new_cell (receiver);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveShapeIterator::up () const
|
||||
RecursiveShapeIterator::up (RecursiveShapeReceiver *receiver) const
|
||||
{
|
||||
if (receiver) {
|
||||
receiver->leave_cell (this, cell ());
|
||||
}
|
||||
|
||||
m_shape = shape_iterator ();
|
||||
m_shape_quad_id = 0;
|
||||
|
||||
|
|
@ -823,7 +837,7 @@ RecursiveShapeIterator::new_layer () const
|
|||
}
|
||||
|
||||
void
|
||||
RecursiveShapeIterator::new_cell () const
|
||||
RecursiveShapeIterator::new_cell (RecursiveShapeReceiver *receiver) const
|
||||
{
|
||||
if (m_has_layers) {
|
||||
m_current_layer = 0;
|
||||
|
|
@ -847,11 +861,11 @@ RecursiveShapeIterator::new_cell () const
|
|||
skip_inst_iter_for_complex_region ();
|
||||
}
|
||||
|
||||
new_inst ();
|
||||
new_inst (receiver);
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveShapeIterator::new_inst () const
|
||||
RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
|
||||
{
|
||||
// look for the next instance with a non-empty array iterator. The latter can be
|
||||
// empty because we use a per-layer box converter for that case what we don't for the
|
||||
|
|
@ -866,12 +880,21 @@ RecursiveShapeIterator::new_inst () const
|
|||
}
|
||||
}
|
||||
|
||||
if (m_local_region_stack.back () != box_type::world ()) {
|
||||
bool all_of_instance = true;
|
||||
if (m_local_region_stack.back () != box_type::world () && ! m_inst->cell_inst ().bbox (m_box_convert).inside (m_local_region_stack.back ())) {
|
||||
m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back (), m_box_convert);
|
||||
all_of_instance = false;
|
||||
} else {
|
||||
m_inst_array = m_inst->cell_inst ().begin ();
|
||||
m_inst_array = m_inst->cell_inst ().begin ();
|
||||
// TODO: optimization potential: only report all_of_instance == false, if not entirely within the complex region
|
||||
all_of_instance = m_local_complex_region_stack.empty ();
|
||||
}
|
||||
|
||||
if (receiver) {
|
||||
receiver->new_inst (this, m_inst->cell_inst (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance);
|
||||
}
|
||||
|
||||
new_inst_member (receiver);
|
||||
if (! m_inst_array.at_end ()) {
|
||||
break;
|
||||
} else {
|
||||
|
|
@ -881,6 +904,28 @@ RecursiveShapeIterator::new_inst () const
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveShapeIterator::new_inst_member (RecursiveShapeReceiver *receiver) const
|
||||
{
|
||||
if (! m_local_complex_region_stack.empty ()) {
|
||||
|
||||
// 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) * m_box_convert (m_inst->cell_inst ().object ());
|
||||
if (! is_outside_complex_region (ia_box)) {
|
||||
break;
|
||||
} else {
|
||||
++m_inst_array;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! m_inst_array.at_end () && receiver) {
|
||||
receiver->new_inst_member (this, m_inst->cell_inst (), 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 ());
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RecursiveShapeIterator::is_outside_complex_region (const db::Box &box) const
|
||||
{
|
||||
|
|
@ -891,5 +936,23 @@ RecursiveShapeIterator::is_outside_complex_region (const db::Box &box) const
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveShapeIterator::push (RecursiveShapeReceiver *receiver)
|
||||
{
|
||||
// force reset so we can validate with a receiver
|
||||
reset ();
|
||||
|
||||
receiver->begin (this);
|
||||
|
||||
validate (receiver);
|
||||
|
||||
while (! at_end ()) {
|
||||
receiver->shape (this, *m_shape, m_trans);
|
||||
next (receiver);
|
||||
}
|
||||
|
||||
receiver->end (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ namespace db
|
|||
{
|
||||
|
||||
class Region;
|
||||
class RecursiveShapeReceiver;
|
||||
|
||||
/**
|
||||
* @brief An iterator delivering shapes that touch or overlap the given region recursively
|
||||
|
|
@ -479,7 +480,7 @@ public:
|
|||
*/
|
||||
unsigned int layer () const
|
||||
{
|
||||
validate ();
|
||||
validate (0);
|
||||
return m_layer;
|
||||
}
|
||||
|
||||
|
|
@ -514,7 +515,7 @@ public:
|
|||
*/
|
||||
const cplx_trans_type &trans () const
|
||||
{
|
||||
validate ();
|
||||
validate (0);
|
||||
return m_trans;
|
||||
}
|
||||
|
||||
|
|
@ -525,7 +526,7 @@ public:
|
|||
*/
|
||||
unsigned int depth () const
|
||||
{
|
||||
validate ();
|
||||
validate (0);
|
||||
return (unsigned int) m_trans_stack.size ();
|
||||
}
|
||||
|
||||
|
|
@ -537,7 +538,7 @@ public:
|
|||
*/
|
||||
shape_type shape () const
|
||||
{
|
||||
validate ();
|
||||
validate (0);
|
||||
return *m_shape;
|
||||
}
|
||||
|
||||
|
|
@ -548,7 +549,7 @@ public:
|
|||
*/
|
||||
shape_type operator* () const
|
||||
{
|
||||
validate ();
|
||||
validate (0);
|
||||
return *m_shape;
|
||||
}
|
||||
|
||||
|
|
@ -559,7 +560,7 @@ public:
|
|||
*/
|
||||
const shape_type *operator-> () const
|
||||
{
|
||||
validate ();
|
||||
validate (0);
|
||||
return m_shape.operator-> ();
|
||||
}
|
||||
|
||||
|
|
@ -575,7 +576,7 @@ public:
|
|||
*/
|
||||
db::cell_index_type cell_index () const
|
||||
{
|
||||
validate ();
|
||||
validate (0);
|
||||
size_t c = reinterpret_cast<size_t> (mp_cell);
|
||||
return reinterpret_cast<const cell_type *> (c - (c & size_t (1)))->cell_index ();
|
||||
}
|
||||
|
|
@ -585,7 +586,7 @@ public:
|
|||
*/
|
||||
const cell_type *cell () const
|
||||
{
|
||||
validate ();
|
||||
validate (0);
|
||||
size_t c = reinterpret_cast<size_t> (mp_cell);
|
||||
return reinterpret_cast<const cell_type *> (c - (c & size_t (1)));
|
||||
}
|
||||
|
|
@ -595,14 +596,17 @@ public:
|
|||
*/
|
||||
RecursiveShapeIterator &operator++()
|
||||
{
|
||||
next ();
|
||||
next (0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Increment the iterator
|
||||
* @brief Increments the iterator
|
||||
*/
|
||||
void next ();
|
||||
void next ()
|
||||
{
|
||||
next (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Comparison of iterators - equality
|
||||
|
|
@ -638,6 +642,20 @@ public:
|
|||
*/
|
||||
std::vector<db::InstElement> path () const;
|
||||
|
||||
/**
|
||||
* @brief Push-mode delivery
|
||||
*
|
||||
* This method will deliver all shapes to the given receiver.
|
||||
* In contrast to pull mode, this method allows tailoring the
|
||||
* traversal of the hierarchy tree during iteration.
|
||||
* For this purpose, the receiver has methods that receive
|
||||
* events and to some extend may modify the traversal (e.g.
|
||||
* return value of enter_cell).
|
||||
*
|
||||
* See RecursiveShapeReceiver class for more details.
|
||||
*/
|
||||
void push (RecursiveShapeReceiver *receiver);
|
||||
|
||||
private:
|
||||
std::vector<unsigned int> m_layers;
|
||||
bool m_has_layers;
|
||||
|
|
@ -681,14 +699,16 @@ private:
|
|||
void init_region (const box_type ®ion);
|
||||
void skip_shape_iter_for_complex_region () const;
|
||||
void skip_inst_iter_for_complex_region () const;
|
||||
void validate () const;
|
||||
void validate (RecursiveShapeReceiver *receiver) const;
|
||||
void start_shapes () const;
|
||||
void next_shape () const;
|
||||
void new_inst () const;
|
||||
void new_cell () const;
|
||||
void next (RecursiveShapeReceiver *receiver);
|
||||
void next_shape (RecursiveShapeReceiver *receiver) const;
|
||||
void new_inst (RecursiveShapeReceiver *receiver) const;
|
||||
void new_inst_member (RecursiveShapeReceiver *receiver) const;
|
||||
void new_cell (RecursiveShapeReceiver *receiver) const;
|
||||
void new_layer () const;
|
||||
void up () const;
|
||||
void down () const;
|
||||
void up (RecursiveShapeReceiver *receiver) const;
|
||||
void down (RecursiveShapeReceiver *receiver) const;
|
||||
|
||||
bool is_outside_complex_region (const db::Box &box) const;
|
||||
|
||||
|
|
@ -705,8 +725,99 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A receiver interface for "push" mode
|
||||
*
|
||||
* In push mode, the iterator will deliver the shapes and hierarchy transitions
|
||||
* to this interface. See "RecursiveShapeIterator::push" for details about this
|
||||
* mode.
|
||||
*
|
||||
* The receiver receives events for the start of the delivery, on each cell
|
||||
* entry and on each instance (followed by a cell entry). It also receives
|
||||
* the shapes.
|
||||
*/
|
||||
class DB_PUBLIC RecursiveShapeReceiver
|
||||
{
|
||||
public:
|
||||
typedef RecursiveShapeIterator::box_tree_type box_tree_type;
|
||||
|
||||
RecursiveShapeReceiver () { }
|
||||
virtual ~RecursiveShapeReceiver () { }
|
||||
|
||||
/**
|
||||
* @brief Called once when the iterator begins pushing
|
||||
*/
|
||||
virtual void begin (const RecursiveShapeIterator * /*iter*/) { }
|
||||
|
||||
/**
|
||||
* @brief Called once after the iterator pushed everything
|
||||
*/
|
||||
virtual void end (const RecursiveShapeIterator * /*iter*/) { }
|
||||
|
||||
/**
|
||||
* @brief Enters a cell
|
||||
*
|
||||
* This method is called when the recursive shape iterator
|
||||
* enters a new cell. This method can return false. In this
|
||||
* case, the cell is skipped together with it's subcells.
|
||||
*
|
||||
* This method is not called for the top cell. When it is called, "iter->trans()"
|
||||
* will already be updated.
|
||||
*
|
||||
* @param iter The iterator
|
||||
* @param cell The cell which is entered
|
||||
* @param region The clip box as seen from "cell" or db::Box::world if there is no clip box
|
||||
* @param complex_region A complex clip region if one is supplied together with "region"
|
||||
*/
|
||||
virtual bool enter_cell (const RecursiveShapeIterator * /*iter*/, const db::Cell * /*cell*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { return true; }
|
||||
|
||||
/**
|
||||
* @brief Leaves the current cell
|
||||
*
|
||||
* This method is the counterpart for "enter_cell". It is called when traversal of "cell" ended.
|
||||
*/
|
||||
virtual void leave_cell (const RecursiveShapeIterator * /*iter*/, const db::Cell * /*cell*/) { }
|
||||
|
||||
/**
|
||||
* @brief Enters a new instance
|
||||
*
|
||||
* This method is called before "enter_cell" and "new_inst_member" is called and will indicate the instance to follow.
|
||||
* The sequence of events is
|
||||
*
|
||||
* new_inst(A)
|
||||
* new_inst_member(A[0,0])
|
||||
* enter_cell(A)
|
||||
* ...
|
||||
* leave_cell(A)
|
||||
* new_inst_member(A[1,0])
|
||||
* enter_cell(A)
|
||||
* ...
|
||||
* leave_cell(A)
|
||||
* ...
|
||||
* new_inst(B)
|
||||
* ...
|
||||
*
|
||||
* The "all" parameter is true, if all instances of the array will be addressed.
|
||||
*/
|
||||
virtual void new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { }
|
||||
|
||||
/**
|
||||
* @brief Enters a new array member of the instance
|
||||
*
|
||||
* See "new_inst" for a description. This method adds the "trans" parameter
|
||||
* which holds the complex transformation for this particular instance of
|
||||
* the array.
|
||||
*/
|
||||
virtual void new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { }
|
||||
|
||||
/**
|
||||
* @brief Delivers a shape
|
||||
*
|
||||
* @param trans The transformation which maps the shape to the top cell.
|
||||
*/
|
||||
virtual void shape (const RecursiveShapeIterator * /*iter*/, const db::Shape & /*shape*/, const db::ICplxTrans & /*trans*/) { }
|
||||
};
|
||||
|
||||
} // namespace db
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -453,7 +453,7 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
|
|||
gsi::method ("cell_index", &db::RecursiveShapeIterator::cell_index,
|
||||
"@brief Gets the current cell's index \n"
|
||||
) +
|
||||
gsi::method ("next", &db::RecursiveShapeIterator::next,
|
||||
gsi::method ("next", (void (db::RecursiveShapeIterator::*) ()) &db::RecursiveShapeIterator::next,
|
||||
"@brief Increment the iterator\n"
|
||||
"This moves the iterator to the next shape inside the search scope."
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -709,6 +709,21 @@ static db::Layout boxes2layout (const std::set<db::Box> &boxes)
|
|||
return l;
|
||||
}
|
||||
|
||||
class FlatPusher
|
||||
: public db::RecursiveShapeReceiver
|
||||
{
|
||||
public:
|
||||
FlatPusher (std::set<db::Box> *boxes) : mp_boxes (boxes) { }
|
||||
|
||||
void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans)
|
||||
{
|
||||
mp_boxes->insert (trans * shape.bbox ());
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<db::Box> *mp_boxes;
|
||||
};
|
||||
|
||||
TEST(4)
|
||||
{
|
||||
// Big fun
|
||||
|
|
@ -751,6 +766,16 @@ TEST(4)
|
|||
EXPECT_EQ (selected_boxes.size () > 100, true);
|
||||
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
|
||||
|
||||
// push mode
|
||||
{
|
||||
selected_boxes.clear ();
|
||||
FlatPusher pusher (&selected_boxes);
|
||||
db::RecursiveShapeIterator (g, c0, 0, search_box, true).push (&pusher);
|
||||
}
|
||||
|
||||
EXPECT_EQ (selected_boxes.size () > 100, true);
|
||||
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
|
||||
|
||||
db::Box search_box2 (500, 500, 1000, 1000);
|
||||
|
||||
selected_boxes.clear ();
|
||||
|
|
@ -772,6 +797,16 @@ TEST(4)
|
|||
|
||||
EXPECT_EQ (selected_boxes.size () > 100, true);
|
||||
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
|
||||
|
||||
// push mode
|
||||
{
|
||||
selected_boxes.clear ();
|
||||
FlatPusher pusher (&selected_boxes);
|
||||
db::RecursiveShapeIterator (g, c0, 0, reg, true).push (&pusher);
|
||||
}
|
||||
|
||||
EXPECT_EQ (selected_boxes.size () > 100, true);
|
||||
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
|
||||
}
|
||||
|
||||
TEST(5)
|
||||
|
|
@ -819,6 +854,16 @@ TEST(5)
|
|||
EXPECT_EQ (selected_boxes.size () > 100, true);
|
||||
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
|
||||
|
||||
// push mode
|
||||
{
|
||||
selected_boxes.clear ();
|
||||
FlatPusher pusher (&selected_boxes);
|
||||
db::RecursiveShapeIterator (g, c0, 0, search_box, true).push (&pusher);
|
||||
}
|
||||
|
||||
EXPECT_EQ (selected_boxes.size () > 100, true);
|
||||
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
|
||||
|
||||
db::Box search_box2 (500, 500, 1000, 1000);
|
||||
|
||||
selected_boxes.clear ();
|
||||
|
|
@ -840,4 +885,310 @@ TEST(5)
|
|||
|
||||
EXPECT_EQ (selected_boxes.size () > 100, true);
|
||||
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
|
||||
|
||||
// push mode
|
||||
{
|
||||
selected_boxes.clear ();
|
||||
FlatPusher pusher (&selected_boxes);
|
||||
db::RecursiveShapeIterator (g, c0, 0, reg, true).push (&pusher);
|
||||
}
|
||||
|
||||
EXPECT_EQ (selected_boxes.size () > 100, true);
|
||||
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
|
||||
}
|
||||
|
||||
class LoggingReceiver
|
||||
: public db::RecursiveShapeReceiver
|
||||
{
|
||||
public:
|
||||
LoggingReceiver () { }
|
||||
|
||||
const std::string &text () const { return m_text; }
|
||||
|
||||
virtual void begin (const db::RecursiveShapeIterator * /*iter*/) { m_text += "begin\n"; }
|
||||
virtual void end (const db::RecursiveShapeIterator * /*iter*/) { m_text += "end\n"; }
|
||||
|
||||
virtual bool enter_cell (const db::RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
{
|
||||
m_text += std::string ("enter_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void leave_cell (const db::RecursiveShapeIterator *iter, const db::Cell *cell)
|
||||
{
|
||||
m_text += std::string ("leave_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n";
|
||||
}
|
||||
|
||||
virtual void new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
|
||||
{
|
||||
m_text += std::string ("new_inst(") + iter->layout ()->cell_name (inst.object ().cell_index ());
|
||||
if (all) {
|
||||
m_text += ",all";
|
||||
}
|
||||
m_text += ")\n";
|
||||
}
|
||||
|
||||
virtual void new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
{
|
||||
m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (trans) + ")\n";
|
||||
}
|
||||
|
||||
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans)
|
||||
{
|
||||
m_text += "shape(" + shape.to_string () + "," + tl::to_string (trans) + ")\n";
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_text;
|
||||
};
|
||||
|
||||
class ReceiverRejectingACell
|
||||
: public LoggingReceiver
|
||||
{
|
||||
public:
|
||||
ReceiverRejectingACell (db::cell_index_type rejected) : m_rejected (rejected) { }
|
||||
|
||||
virtual bool enter_cell (const db::RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box ®ion, const box_tree_type *complex_region)
|
||||
{
|
||||
LoggingReceiver::enter_cell (iter, cell, region, complex_region);
|
||||
return cell->cell_index () != m_rejected;
|
||||
}
|
||||
|
||||
private:
|
||||
db::cell_index_type m_rejected;
|
||||
};
|
||||
|
||||
// Push mode with cells
|
||||
TEST(10)
|
||||
{
|
||||
db::Manager m;
|
||||
db::Layout g (&m);
|
||||
g.insert_layer(0);
|
||||
|
||||
db::Cell &c0 (g.cell (g.add_cell ()));
|
||||
db::Cell &c1 (g.cell (g.add_cell ()));
|
||||
db::Cell &c2 (g.cell (g.add_cell ()));
|
||||
|
||||
db::Box b (1000, -500, 2000, 500);
|
||||
c2.shapes (0).insert (b);
|
||||
|
||||
db::Trans tt;
|
||||
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt, db::Vector (0, 6000), db::Vector (6000, 0), 2, 2));
|
||||
c1.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), tt, db::Vector (0, 2000), db::Vector (3000, 1000), 2, 2));
|
||||
|
||||
LoggingReceiver lr1;
|
||||
db::RecursiveShapeIterator i1 (g, c0, 0);
|
||||
i1.push (&lr1);
|
||||
|
||||
EXPECT_EQ (lr1.text (),
|
||||
"begin\n"
|
||||
"new_inst($2,all)\n"
|
||||
"new_inst_member($2,r0 *1 0,0)\n"
|
||||
"enter_cell($2)\n"
|
||||
"new_inst($3,all)\n"
|
||||
"new_inst_member($3,r0 *1 0,0)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 0,0)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 0,2000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 0,2000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,1000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 3000,1000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,3000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 3000,3000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"leave_cell($2)\n"
|
||||
"new_inst_member($2,r0 *1 0,6000)\n"
|
||||
"enter_cell($2)\n"
|
||||
"new_inst($3,all)\n"
|
||||
"new_inst_member($3,r0 *1 0,0)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 0,6000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 0,2000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 0,8000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,1000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 3000,7000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,3000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 3000,9000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"leave_cell($2)\n"
|
||||
"new_inst_member($2,r0 *1 6000,0)\n"
|
||||
"enter_cell($2)\n"
|
||||
"new_inst($3,all)\n"
|
||||
"new_inst_member($3,r0 *1 0,0)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 6000,0)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 0,2000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 6000,2000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,1000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 9000,1000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,3000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 9000,3000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"leave_cell($2)\n"
|
||||
"new_inst_member($2,r0 *1 6000,6000)\n"
|
||||
"enter_cell($2)\n"
|
||||
"new_inst($3,all)\n"
|
||||
"new_inst_member($3,r0 *1 0,0)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 6000,6000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 0,2000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 6000,8000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,1000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 9000,7000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,3000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 9000,9000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"leave_cell($2)\n"
|
||||
"end\n"
|
||||
);
|
||||
|
||||
ReceiverRejectingACell rr1 (c2.cell_index ());
|
||||
db::RecursiveShapeIterator ir1 (g, c0, 0);
|
||||
ir1.push (&rr1);
|
||||
|
||||
EXPECT_EQ (rr1.text (),
|
||||
"begin\n"
|
||||
"new_inst($2,all)\n"
|
||||
"new_inst_member($2,r0 *1 0,0)\n"
|
||||
"enter_cell($2)\n"
|
||||
"new_inst($3,all)\n"
|
||||
"new_inst_member($3,r0 *1 0,0)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 0,2000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,1000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,3000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"leave_cell($2)\n"
|
||||
"new_inst_member($2,r0 *1 0,6000)\n"
|
||||
"enter_cell($2)\n"
|
||||
"new_inst($3,all)\n"
|
||||
"new_inst_member($3,r0 *1 0,0)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 0,2000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,1000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,3000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"leave_cell($2)\n"
|
||||
"new_inst_member($2,r0 *1 6000,0)\n"
|
||||
"enter_cell($2)\n"
|
||||
"new_inst($3,all)\n"
|
||||
"new_inst_member($3,r0 *1 0,0)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 0,2000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,1000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,3000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"leave_cell($2)\n"
|
||||
"new_inst_member($2,r0 *1 6000,6000)\n"
|
||||
"enter_cell($2)\n"
|
||||
"new_inst($3,all)\n"
|
||||
"new_inst_member($3,r0 *1 0,0)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 0,2000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,1000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,3000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"leave_cell($3)\n"
|
||||
"leave_cell($2)\n"
|
||||
"end\n"
|
||||
);
|
||||
|
||||
ReceiverRejectingACell rr2 (c1.cell_index ());
|
||||
db::RecursiveShapeIterator ir2 (g, c0, 0);
|
||||
ir2.push (&rr2);
|
||||
|
||||
EXPECT_EQ (rr2.text (),
|
||||
"begin\n"
|
||||
"new_inst($2,all)\n"
|
||||
"new_inst_member($2,r0 *1 0,0)\n"
|
||||
"enter_cell($2)\n"
|
||||
"leave_cell($2)\n"
|
||||
"new_inst_member($2,r0 *1 0,6000)\n"
|
||||
"enter_cell($2)\n"
|
||||
"leave_cell($2)\n"
|
||||
"new_inst_member($2,r0 *1 6000,0)\n"
|
||||
"enter_cell($2)\n"
|
||||
"leave_cell($2)\n"
|
||||
"new_inst_member($2,r0 *1 6000,6000)\n"
|
||||
"enter_cell($2)\n"
|
||||
"leave_cell($2)\n"
|
||||
"end\n"
|
||||
);
|
||||
|
||||
LoggingReceiver lr2;
|
||||
db::RecursiveShapeIterator i2 (g, c0, 0, db::Box (0, 0, 5000, 5000));
|
||||
i2.push (&lr2);
|
||||
|
||||
EXPECT_EQ (lr2.text (),
|
||||
"begin\n"
|
||||
"new_inst($2)\n"
|
||||
"new_inst_member($2,r0 *1 0,0)\n"
|
||||
"enter_cell($2)\n"
|
||||
"new_inst($3)\n"
|
||||
"new_inst_member($3,r0 *1 0,0)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 0,0)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 0,2000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 0,2000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,1000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 3000,1000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,3000)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 3000,3000)\n"
|
||||
"leave_cell($3)\n"
|
||||
"leave_cell($2)\n"
|
||||
"end\n"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue