diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index c33724a66..2793eb707 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -156,6 +156,16 @@ local_cluster::clear () m_shapes.clear (); m_needs_update = false; m_bbox = box_type (); + m_attrs.clear (); +} + +template +void +local_cluster::add_attr (attr_id a) +{ + if (a > 0) { + m_attrs.insert (a); + } } template @@ -175,6 +185,8 @@ local_cluster::join_with (const local_cluster &other) other_tree.insert (s->second.begin (), s->second.end ()); } + m_attrs.insert (other.m_attrs.begin (), other.m_attrs.end ()); + m_needs_update = true; } @@ -427,7 +439,7 @@ namespace template struct cluster_building_receiver - : public db::box_scanner_receiver + : public db::box_scanner_receiver > { typedef typename local_cluster::id_type id_type; @@ -437,9 +449,9 @@ struct cluster_building_receiver // .. nothing yet.. } - void add (const T *s1, unsigned int l1, const T *s2, unsigned int l2) + void add (const T *s1, std::pair p1, const T *s2, std::pair p2) { - if (! mp_conn->interacts (*s1, l1, *s2, l2)) { + if (! mp_conn->interacts (*s1, p1.first, *s2, p2.first)) { return; } @@ -451,8 +463,10 @@ struct cluster_building_receiver if (id2 == m_shape_to_cluster_id.end ()) { local_cluster *cluster = mp_clusters->insert (); - cluster->add (*s1, l1); - cluster->add (*s2, l2); + cluster->add (*s1, p1.first); + cluster->add (*s2, p2.first); + cluster->add_attr (p1.second); + cluster->add_attr (p2.second); m_shape_to_cluster_id.insert (std::make_pair (s1, cluster->id ())); m_shape_to_cluster_id.insert (std::make_pair (s2, cluster->id ())); @@ -460,7 +474,9 @@ struct cluster_building_receiver } else { // NOTE: const_cast is in order - we know what we're doing. - const_cast &> (mp_clusters->cluster_by_id (id2->second)).add (*s1, l1); + local_cluster &c2 = const_cast &> (mp_clusters->cluster_by_id (id2->second)); + c2.add (*s1, p1.first); + c2.add_attr (p1.second); m_shape_to_cluster_id.insert (std::make_pair (s1, id2->second)); } @@ -468,7 +484,9 @@ struct cluster_building_receiver } else if (id2 == m_shape_to_cluster_id.end ()) { // NOTE: const_cast is in order - we know what we're doing. - const_cast &> (mp_clusters->cluster_by_id (id1->second)).add (*s2, l2); + local_cluster &c1 = const_cast &> (mp_clusters->cluster_by_id (id1->second)); + c1.add (*s2, p2.first); + c1.add_attr (p2.second); m_shape_to_cluster_id.insert (std::make_pair (s2, id1->second)); } else if (id1->second != id2->second) { @@ -481,13 +499,14 @@ struct cluster_building_receiver } } - void finish (const T *s, unsigned int l) + void finish (const T *s, std::pair p) { // if the shape has not been handled yet, insert a single cluster with only this shape typename std::map::const_iterator id = m_shape_to_cluster_id.find (s); if (id == m_shape_to_cluster_id.end ()) { local_cluster *cluster = mp_clusters->insert (); - cluster->add (*s, l); + cluster->add (*s, p.first); + cluster->add_attr (p.second); } } @@ -503,14 +522,14 @@ template void local_clusters::build_clusters (const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn) { - db::box_scanner bs; + db::box_scanner > bs; typename T::tag object_tag; db::box_convert bc; for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { const db::Shapes &shapes = cell.shapes (*l); for (db::Shapes::shape_iterator s = shapes.begin (shape_flags); ! s.at_end (); ++s) { - bs.insert (s->basic_ptr (object_tag), *l); + bs.insert (s->basic_ptr (object_tag), std::make_pair (*l, (attr_id) s->prop_id ())); } } @@ -1361,6 +1380,19 @@ recursive_cluster_shape_iterator::recursive_cluster_shape_iterator (const hie } } +template +std::vector recursive_cluster_shape_iterator::inst_path () const +{ + std::vector p; + if (!m_conn_iter_stack.empty ()) { + p.reserve (m_conn_iter_stack.size ()); + for (size_t i = 0; i < m_conn_iter_stack.size () - 1; ++i) { + p.push_back (*m_conn_iter_stack [i].first); + } + } + return p; +} + template recursive_cluster_shape_iterator &recursive_cluster_shape_iterator::operator++ () { @@ -1427,6 +1459,78 @@ void recursive_cluster_shape_iterator::down (db::cell_index_type ci, typename // explicit instantiations template class DB_PUBLIC recursive_cluster_shape_iterator; +// ------------------------------------------------------------------------------ +// recursive_cluster_iterator implementation + +template +recursive_cluster_iterator::recursive_cluster_iterator (const hier_clusters &hc, db::cell_index_type ci, typename local_cluster::id_type id) + : mp_hc (&hc), m_id (id) +{ + down (ci, id); +} + +template +std::vector recursive_cluster_iterator::inst_path () const +{ + std::vector p; + if (!m_conn_iter_stack.empty ()) { + p.reserve (m_conn_iter_stack.size ()); + for (size_t i = 0; i < m_conn_iter_stack.size () - 1; ++i) { + p.push_back (*m_conn_iter_stack [i].first); + } + } + return p; +} + +template +recursive_cluster_iterator &recursive_cluster_iterator::operator++ () +{ + next_conn (); + return *this; +} + +template +void recursive_cluster_iterator::next_conn () +{ + while (m_conn_iter_stack.back ().first == m_conn_iter_stack.back ().second) { + + up (); + if (m_conn_iter_stack.empty ()) { + return; + } + + ++m_conn_iter_stack.back ().first; + + } + + if (m_conn_iter_stack.back ().first != m_conn_iter_stack.back ().second) { + + const ClusterInstance &cli = *m_conn_iter_stack.back ().first; + down (cli.inst ().inst_ptr.cell_index (), cli.id ()); + + } +} + +template +void recursive_cluster_iterator::up () +{ + m_conn_iter_stack.pop_back (); + m_cell_index_stack.pop_back (); +} + +template +void recursive_cluster_iterator::down (db::cell_index_type ci, typename db::local_cluster::id_type id) +{ + const connected_clusters &clusters = mp_hc->clusters_per_cell (ci); + const typename connected_clusters::connections_type &conn = clusters.connections_for_cluster (id); + + m_cell_index_stack.push_back (ci); + m_conn_iter_stack.push_back (std::make_pair (conn.begin (), conn.end ())); +} + +// explicit instantiations +template class DB_PUBLIC recursive_cluster_iterator; + // ------------------------------------------------------------------------------ // incoming_cluster_connections implementation diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index 2442298cb..d3afe5412 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -123,6 +123,9 @@ public: typedef typename T::box_type box_type; typedef db::unstable_box_tree > tree_type; typedef typename tree_type::flat_iterator shape_iterator; + typedef unsigned int attr_id; + typedef std::set attr_set; + typedef attr_set::const_iterator attr_iterator; /** * @brief Creates an empty cluster @@ -179,6 +182,31 @@ public: */ shape_iterator begin (unsigned int l) const; + /** + * @brief Adds the given attribute to the attribute set + * + * Attributes are arbitary IDs attached to clusters. + * The attribute value 0 is reserved for "no attribute" and is not + * put into the set. + */ + void add_attr (attr_id a); + + /** + * @brief Gets the attribute iterator (begin) + */ + attr_iterator begin_attr () const + { + return m_attrs.begin (); + } + + /** + * @brief Gets the attribute iterator (end) + */ + attr_iterator end_attr () const + { + return m_attrs.end (); + } + private: template friend class local_clusters; template friend class interaction_receiver; @@ -201,6 +229,7 @@ private: bool m_needs_update; std::map m_shapes; box_type m_bbox; + attr_set m_attrs; }; /** @@ -231,6 +260,7 @@ class DB_PUBLIC local_clusters public: typedef typename local_cluster::id_type id_type; typedef typename local_cluster::box_type box_type; + typedef typename local_cluster::attr_id attr_id; typedef db::box_tree, local_cluster_box_convert > tree_type; typedef typename tree_type::touching_iterator touching_iterator; typedef typename tree_type::const_iterator const_iterator; @@ -669,6 +699,13 @@ public: return m_shape_iter.operator-> (); } + /** + * @brief Returns the instantiation path of the current cluster + * + * The call path's root is the initial cell + */ + std::vector inst_path () const; + /** * @brief Returns the transformation applicable for transforming the shape to the root cluster */ @@ -718,6 +755,73 @@ private: void down (db::cell_index_type ci, typename db::local_cluster::id_type id, const db::ICplxTrans &t); }; +/** + * @brief A recursive cluster iterator for the clusters itself + * + * This iterator will deliver the child clusters of a specific cluster. + */ +template +class DB_PUBLIC recursive_cluster_iterator +{ +public: + /** + * @brief Constructor + */ + recursive_cluster_iterator (const hier_clusters &hc, db::cell_index_type ci, typename local_cluster::id_type id); + + /** + * @brief Returns a value indicating whether there are any more shapes + */ + bool at_end () const + { + return m_cell_index_stack.empty (); + } + + /** + * @brief Returns the cell index the shape lives in + */ + db::cell_index_type cell_index () const + { + return m_cell_index_stack.back (); + } + + /** + * @brief Returns the id of the current cluster + */ + typename db::local_cluster::id_type cluster_id () const + { + if (m_conn_iter_stack.size () <= 1) { + return m_id; + } else { + return m_conn_iter_stack [m_conn_iter_stack.size () - 2].first->id (); + } + } + + /** + * @brief Returns the instantiation path of the current cluster + * + * The call path's root is the initial cell + */ + std::vector inst_path () const; + + /** + * @brief Increment operator + */ + recursive_cluster_iterator &operator++ (); + +private: + typedef typename db::connected_clusters::connections_type connections_type; + + const hier_clusters *mp_hc; + std::vector m_cell_index_stack; + std::vector > m_conn_iter_stack; + typename db::local_cluster::id_type m_id; + + void next_conn (); + void up (); + void down (db::cell_index_type ci, typename db::local_cluster::id_type id); +}; + /** * @brief A connection to a cluster from a parent cluster */ diff --git a/src/db/unit_tests/dbHierNetworkProcessorTests.cc b/src/db/unit_tests/dbHierNetworkProcessorTests.cc index 90bc2701d..0fba6ec8e 100644 --- a/src/db/unit_tests/dbHierNetworkProcessorTests.cc +++ b/src/db/unit_tests/dbHierNetworkProcessorTests.cc @@ -149,13 +149,21 @@ TEST(10_LocalClusterBasic) EXPECT_EQ (cluster.id (), size_t (0)); cluster.add (db::PolygonRef (poly, repo), 0); + cluster.add_attr (1); EXPECT_EQ (cluster.bbox ().to_string (), "(0,0;1000,1000)"); db::local_cluster cluster2; - cluster.add (db::PolygonRef (poly, repo).transformed (db::Trans (db::Vector (10, 20))), 1); + cluster2.add (db::PolygonRef (poly, repo).transformed (db::Trans (db::Vector (10, 20))), 1); + cluster2.add_attr (2); cluster.join_with (cluster2); EXPECT_EQ (cluster.bbox ().to_string (), "(0,0;1010,1020)"); + + EXPECT_EQ (cluster.begin_attr () == cluster.end_attr (), false); + db::local_cluster::attr_iterator a = cluster.begin_attr (); + EXPECT_EQ (*a++, 1u); + EXPECT_EQ (*a++, 2u); + EXPECT_EQ (a == cluster.end_attr (), true); } TEST(11_LocalClusterInteractBasic) @@ -248,6 +256,9 @@ static std::string local_cluster_to_string (const db::local_cluster &cluster, res += "[" + tl::to_string (*l) + "]" + obj2string (*s); } } + for (typename db::local_cluster::attr_iterator a = cluster.begin_attr (); a != cluster.end_attr (); ++a) { + res += "%" + tl::to_string (*a); + } return res; } @@ -325,6 +336,67 @@ TEST(20_LocalClustersBasic) ); } +TEST(21_LocalClustersBasicWithAttributes) +{ + db::Layout layout; + db::Cell &cell = layout.cell (layout.add_cell ("TOP")); + db::GenericRepository &repo = layout.shape_repository (); + + db::Connectivity conn; + conn.connect (0); + conn.connect (1); + conn.connect (2); + conn.connect (0, 1); + conn.connect (0, 2); + + db::Polygon poly; + tl::from_string ("(0,0;0,1000;1000,1000;1000,0)", poly); + + cell.shapes (0).insert (db::PolygonRef (poly, repo)); + + db::local_clusters clusters; + EXPECT_EQ (local_clusters_to_string (clusters, conn), ""); + + clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0)"); + + // one more shape + cell.shapes (0).insert (db::PolygonRefWithProperties (db::PolygonRef (poly.transformed (db::Trans (db::Vector (10, 20))), repo), 1)); + + clusters.clear (); + clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20)%1"); + + // one more shape creating a new cluster + cell.shapes (2).insert (db::PolygonRefWithProperties (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1100))), repo), 2)); + + clusters.clear (); + clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + EXPECT_EQ (local_clusters_to_string (clusters, conn), + "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20)%1\n" + "#2:[2](0,1100;0,2100;1000,2100;1000,1100)%2" + ); + + // one more shape connecting these + cell.shapes (2).insert (db::PolygonRefWithProperties (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1000))), repo), 3)); + + clusters.clear (); + clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + EXPECT_EQ (local_clusters_to_string (clusters, conn), + "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20);[2](0,1000;0,2000;1000,2000;1000,1000);[2](0,1100;0,2100;1000,2100;1000,1100)%1%2%3" + ); + + // one more shape opening a new cluster + cell.shapes (1).insert (db::PolygonRefWithProperties (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1100))), repo), 4)); + + clusters.clear (); + clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + EXPECT_EQ (local_clusters_to_string (clusters, conn), + "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20);[2](0,1000;0,2000;1000,2000;1000,1000);[2](0,1100;0,2100;1000,2100;1000,1100)%1%2%3\n" + "#2:[1](0,1100;0,2100;1000,2100;1000,1100)%4" + ); +} + TEST(30_LocalConnectedClusters) { db::Layout layout; @@ -408,28 +480,234 @@ TEST(30_LocalConnectedClusters) EXPECT_EQ (x.size (), size_t (0)); } -static void normalize_layer (db::Layout &layout, unsigned int layer) +static db::PolygonRef make_box (db::Layout &ly, const db::Box &box) { - for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { - db::Shapes s (layout.is_editable ()); - s.swap (c->shapes (layer)); - for (db::Shapes::shape_iterator i = s.begin (db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes); !i.at_end (); ++i) { - db::Polygon poly; - i->polygon (poly); - c->shapes (layer).insert (db::PolygonRef (poly, layout.shape_repository ())); - } - } + return db::PolygonRef (db::Polygon (box), ly.shape_repository ()); } -static void copy_cluster_shapes (db::Shapes &out, db::cell_index_type ci, const db::hier_clusters &hc, db::local_cluster::id_type cluster_id, const db::ICplxTrans &trans, const db::Connectivity &conn) +TEST(40_HierClustersBasic) +{ + db::hier_clusters hc; + + db::Layout ly; + unsigned int l1 = ly.insert_layer (db::LayerProperties (1, 0)); + + db::Cell &top = ly.cell (ly.add_cell ("TOP")); + top.shapes (l1).insert (make_box (ly, db::Box (0, 0, 1000, 1000))); + + db::Cell &c1 = ly.cell (ly.add_cell ("C1")); + c1.shapes (l1).insert (make_box (ly, db::Box (0, 0, 2000, 500))); + top.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans ())); + + db::Cell &c2 = ly.cell (ly.add_cell ("C2")); + c2.shapes (l1).insert (make_box (ly, db::Box (0, 0, 500, 2000))); + c2.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans ())); + top.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans ())); + + db::Connectivity conn; + conn.connect (l1, l1); + + hc.build (ly, top, db::ShapeIterator::Polygons, conn); + + int n, nc; + const db::connected_clusters *cluster; + + // 1 cluster in TOP with 2 connections + n = 0; + cluster = &hc.clusters_per_cell (top.cell_index ()); + for (db::connected_clusters::const_iterator i = cluster->begin (); i != cluster->end (); ++i) { + ++n; + } + EXPECT_EQ (n, 1); + EXPECT_EQ (cluster->bbox ().to_string (), "(0,0;1000,1000)") + nc = 0; + for (db::connected_clusters::connections_iterator i = cluster->begin_connections (); i != cluster->end_connections (); ++i) { + nc += i->second.size (); + } + EXPECT_EQ (nc, 2); + + // 1 cluster in C1 without connection + n = 0; + cluster = &hc.clusters_per_cell (c1.cell_index ()); + for (db::connected_clusters::const_iterator i = cluster->begin (); i != cluster->end (); ++i) { + ++n; + } + EXPECT_EQ (n, 1); + EXPECT_EQ (cluster->bbox ().to_string (), "(0,0;2000,500)") + nc = 0; + for (db::connected_clusters::connections_iterator i = cluster->begin_connections (); i != cluster->end_connections (); ++i) { + nc += i->second.size (); + } + EXPECT_EQ (nc, 0); + + // 1 cluster in C2 with one connection + n = 0; + cluster = &hc.clusters_per_cell (c2.cell_index ()); + for (db::connected_clusters::const_iterator i = cluster->begin (); i != cluster->end (); ++i) { + ++n; + } + EXPECT_EQ (n, 1); + EXPECT_EQ (cluster->bbox ().to_string (), "(0,0;500,2000)") + nc = 0; + for (db::connected_clusters::connections_iterator i = cluster->begin_connections (); i != cluster->end_connections (); ++i) { + nc += i->second.size (); + } + EXPECT_EQ (nc, 1); +} + +static std::string path2string (const db::Layout &ly, db::cell_index_type ci, const std::vector &path) +{ + std::string res = ly.cell_name (ci); + for (std::vector::const_iterator p = path.begin (); p != path.end (); ++p) { + res += "/"; + res += ly.cell_name (p->inst ().inst_ptr.cell_index ()); + } + return res; +} + +static std::string rcsiter2string (const db::Layout &ly, db::cell_index_type ci, db::recursive_cluster_shape_iterator si) +{ + std::string res; + while (! si.at_end ()) { + db::Polygon poly = si->obj (); + poly.transform (si->trans ()); + poly.transform (si.trans ()); + if (! res.empty ()) { + res += ";"; + } + res += path2string (ly, ci, si.inst_path ()); + res += ":"; + res += poly.to_string (); + ++si; + } + return res; +} + +static std::string rciter2string (const db::Layout &ly, db::cell_index_type ci, db::recursive_cluster_iterator si) +{ + std::string res; + while (! si.at_end ()) { + if (! res.empty ()) { + res += ";"; + } + res += path2string (ly, ci, si.inst_path ()); + ++si; + } + return res; +} + +TEST(41_HierClustersRecursiveClusterShapeIterator) +{ + db::hier_clusters hc; + + db::Layout ly; + unsigned int l1 = ly.insert_layer (db::LayerProperties (1, 0)); + + db::Cell &top = ly.cell (ly.add_cell ("TOP")); + top.shapes (l1).insert (make_box (ly, db::Box (0, 0, 1000, 1000))); + + db::Cell &c1 = ly.cell (ly.add_cell ("C1")); + c1.shapes (l1).insert (make_box (ly, db::Box (0, 0, 2000, 500))); + top.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (0, 10)))); + + db::Cell &c2 = ly.cell (ly.add_cell ("C2")); + c2.shapes (l1).insert (make_box (ly, db::Box (0, 0, 500, 2000))); + c2.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (0, 20)))); + top.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans (db::Vector (0, 30)))); + + db::Connectivity conn; + conn.connect (l1, l1); + + hc.build (ly, top, db::ShapeIterator::Polygons, conn); + + std::string res; + int n = 0; + db::connected_clusters *cluster = &hc.clusters_per_cell (top.cell_index ()); + for (db::connected_clusters::const_iterator i = cluster->begin (); i != cluster->end (); ++i) { + res = rcsiter2string (ly, top.cell_index (), db::recursive_cluster_shape_iterator (hc, l1, top.cell_index (), i->id ())); + ++n; + } + EXPECT_EQ (n, 1); + EXPECT_EQ (res, "TOP:(0,0;0,1000;1000,1000;1000,0);TOP/C1:(0,10;0,510;2000,510;2000,10);TOP/C2:(0,30;0,2030;500,2030;500,30);TOP/C2/C1:(0,50;0,550;2000,550;2000,50)"); +} + +TEST(41_HierClustersRecursiveClusterIterator) +{ + db::hier_clusters hc; + + db::Layout ly; + unsigned int l1 = ly.insert_layer (db::LayerProperties (1, 0)); + + db::Cell &top = ly.cell (ly.add_cell ("TOP")); + top.shapes (l1).insert (make_box (ly, db::Box (0, 0, 1000, 1000))); + + db::Cell &c1 = ly.cell (ly.add_cell ("C1")); + c1.shapes (l1).insert (make_box (ly, db::Box (0, 0, 2000, 500))); + top.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (0, 10)))); + + db::Cell &c2 = ly.cell (ly.add_cell ("C2")); + c2.shapes (l1).insert (make_box (ly, db::Box (0, 0, 500, 2000))); + c2.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (0, 20)))); + top.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans (db::Vector (0, 30)))); + + db::Connectivity conn; + conn.connect (l1, l1); + + hc.build (ly, top, db::ShapeIterator::Polygons, conn); + + std::string res; + int n = 0; + db::connected_clusters *cluster = &hc.clusters_per_cell (top.cell_index ()); + for (db::connected_clusters::const_iterator i = cluster->begin (); i != cluster->end (); ++i) { + res = rciter2string (ly, top.cell_index (), db::recursive_cluster_iterator (hc, top.cell_index (), i->id ())); + ++n; + } + EXPECT_EQ (n, 1); + EXPECT_EQ (res, "TOP;TOP/C1;TOP/C2;TOP/C2/C1"); +} + +static void normalize_layer (db::Layout &layout, std::vector &strings, unsigned int &layer) +{ + unsigned int new_layer = layout.insert_layer (); + + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + const db::Shapes &s = c->shapes (layer); + for (db::Shapes::shape_iterator i = s.begin (db::ShapeIterator::Texts | db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes); !i.at_end (); ++i) { + if (! i->is_text ()) { + db::Polygon poly; + i->polygon (poly); + c->shapes (new_layer).insert (db::PolygonRef (poly, layout.shape_repository ())); + } else { + db::Polygon poly (i->bbox ()); + unsigned int attr_id = (unsigned int) strings.size () + 1; + strings.push_back (i->text_string ()); + c->shapes (new_layer).insert (db::PolygonRefWithProperties (db::PolygonRef (poly, layout.shape_repository ()), attr_id)); + } + } + } + + layer = new_layer; +} + +static void copy_cluster_shapes (const std::string *&attrs, db::Shapes &out, db::cell_index_type ci, const db::hier_clusters &hc, db::local_cluster::id_type cluster_id, const db::ICplxTrans &trans, const db::Connectivity &conn) { // use property #1 to code the cell name + // use property #2 to code the attrs string for the first shape db::PropertiesRepository &pr = out.layout ()->properties_repository (); + + db::properties_id_type cell_pid = 0, cell_and_attr_pid = 0; + db::property_names_id_type pn_id = pr.prop_name_id (tl::Variant (1)); db::PropertiesRepository::properties_set pm; pm.insert (std::make_pair (pn_id, tl::Variant (out.layout ()->cell_name (ci)))); - db::properties_id_type cell_pid = pr.properties_id (pm); + cell_pid = pr.properties_id (pm); + + if (attrs && ! attrs->empty ()) { + db::property_names_id_type pn2_id = pr.prop_name_id (tl::Variant (2)); + pm.insert (std::make_pair (pn2_id, tl::Variant (*attrs))); + cell_and_attr_pid = pr.properties_id (pm); + } const db::connected_clusters &clusters = hc.clusters_per_cell (ci); const db::local_cluster &lc = clusters.cluster_by_id (cluster_id); @@ -438,7 +716,9 @@ static void copy_cluster_shapes (db::Shapes &out, db::cell_index_type ci, const for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { for (db::local_cluster::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) { db::Polygon poly = s->obj ().transformed (trans * db::ICplxTrans (s->trans ())); - out.insert (db::PolygonWithProperties (poly, cell_pid)); + out.insert (db::PolygonWithProperties (poly, cell_and_attr_pid > 0 ? cell_and_attr_pid : cell_pid)); + cell_and_attr_pid = 0; + attrs = 0; // used } } @@ -452,7 +732,7 @@ static void copy_cluster_shapes (db::Shapes &out, db::cell_index_type ci, const db::ICplxTrans t = trans * i->inst ().complex_trans (); db::cell_index_type cci = i->inst ().inst_ptr.cell_index (); - copy_cluster_shapes (out, cci, hc, i->id (), t, conn); + copy_cluster_shapes (attrs, out, cci, hc, i->id (), t, conn); } } @@ -460,12 +740,17 @@ static void copy_cluster_shapes (db::Shapes &out, db::cell_index_type ci, const static void run_hc_test (tl::TestBase *_this, const std::string &file, const std::string &au_file) { db::Layout ly; - unsigned int l1 = 0, l2 = 0, l3 = 0; + unsigned int l0 = 0, l1 = 0, l2 = 0, l3 = 0; { db::LayerProperties p; db::LayerMap lmap; + p.layer = 0; + p.datatype = 0; + lmap.map (db::LDPair (p.layer, p.datatype), l0 = ly.insert_layer ()); + ly.set_properties (l0, p); + p.layer = 1; p.datatype = 0; lmap.map (db::LDPair (p.layer, p.datatype), l1 = ly.insert_layer ()); @@ -493,9 +778,10 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std reader.read (ly, options); } - normalize_layer (ly, l1); - normalize_layer (ly, l2); - normalize_layer (ly, l3); + std::vector strings; + normalize_layer (ly, strings, l1); + normalize_layer (ly, strings, l2); + normalize_layer (ly, strings, l3); // connect 1 to 1, 1 to 2 and 1 to 3, but *not* 2 to 3 db::Connectivity conn; @@ -519,12 +805,25 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std continue; } + // collect strings + std::string attrs; + for (db::recursive_cluster_iterator rc (hc, *td, *c); ! rc.at_end (); ++rc) { + const db::local_cluster &rcc = hc.clusters_per_cell (rc.cell_index ()).cluster_by_id (rc.cluster_id ()); + for (db::local_cluster::attr_iterator a = rcc.begin_attr (); a != rcc.end_attr (); ++a) { + if (! attrs.empty ()) { + attrs += "/"; + } + attrs += std::string (ly.cell_name (rc.cell_index ())) + ":" + strings[*a - 1]; + } + } + net_layers.push_back (std::make_pair (0, ly.insert_layer ())); unsigned int lout = net_layers.back ().second; db::Shapes &out = ly.cell (*td).shapes (lout); - copy_cluster_shapes (out, *td, hc, *c, db::ICplxTrans (), conn); + const std::string *attrs_str = &attrs; + copy_cluster_shapes (attrs_str, out, *td, hc, *c, db::ICplxTrans (), conn); db::Polygon::area_type area = 0; for (db::Shapes::shape_iterator s = out.begin (db::ShapeIterator::All); ! s.at_end (); ++s) { @@ -586,9 +885,10 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str reader.read (ly, options); } - normalize_layer (ly, l1); - normalize_layer (ly, l2); - normalize_layer (ly, l3); + std::vector strings; + normalize_layer (ly, strings, l1); + normalize_layer (ly, strings, l2); + normalize_layer (ly, strings, l3); // connect 1 to 1, 1 to 2 and 1 to 3, but *not* 2 to 3 db::Connectivity conn; @@ -611,68 +911,69 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/" + au_file); } -TEST(41_HierClusters) +TEST(101_HierClusters) { run_hc_test (_this, "hc_test_l1.gds", "hc_test_au1.gds"); run_hc_test_with_backannotation (_this, "hc_test_l1.gds", "hc_test_au1b.gds"); } -TEST(42_HierClusters) +TEST(102_HierClusters) { run_hc_test (_this, "hc_test_l2.gds", "hc_test_au2.gds"); run_hc_test_with_backannotation (_this, "hc_test_l2.gds", "hc_test_au2b.gds"); } -TEST(43_HierClusters) +TEST(103_HierClusters) { run_hc_test (_this, "hc_test_l3.gds", "hc_test_au3.gds"); run_hc_test_with_backannotation (_this, "hc_test_l3.gds", "hc_test_au3b.gds"); } -TEST(44_HierClusters) +TEST(104_HierClusters) { run_hc_test (_this, "hc_test_l4.gds", "hc_test_au4.gds"); run_hc_test_with_backannotation (_this, "hc_test_l4.gds", "hc_test_au4b.gds"); } -TEST(45_HierClusters) +TEST(105_HierClusters) { run_hc_test (_this, "hc_test_l5.gds", "hc_test_au5.gds"); run_hc_test_with_backannotation (_this, "hc_test_l5.gds", "hc_test_au5b.gds"); } -TEST(46_HierClusters) +TEST(106_HierClusters) { run_hc_test (_this, "hc_test_l6.gds", "hc_test_au6.gds"); run_hc_test_with_backannotation (_this, "hc_test_l6.gds", "hc_test_au6b.gds"); } -TEST(47_HierClusters) +TEST(107_HierClusters) { run_hc_test (_this, "hc_test_l7.gds", "hc_test_au7.gds"); run_hc_test_with_backannotation (_this, "hc_test_l7.gds", "hc_test_au7b.gds"); } -TEST(48_HierClusters) +TEST(108_HierClusters) { run_hc_test (_this, "hc_test_l8.gds", "hc_test_au8.gds"); run_hc_test_with_backannotation (_this, "hc_test_l8.gds", "hc_test_au8b.gds"); } -TEST(49_HierClusters) +TEST(109_HierClusters) { run_hc_test (_this, "hc_test_l9.gds", "hc_test_au9.gds"); run_hc_test_with_backannotation (_this, "hc_test_l9.gds", "hc_test_au9b.gds"); } -TEST(50_HierClusters) +TEST(110_HierClusters) { run_hc_test (_this, "hc_test_l10.gds", "hc_test_au10.gds"); run_hc_test_with_backannotation (_this, "hc_test_l10.gds", "hc_test_au10b.gds"); } -TEST(51_HierClusters) +TEST(111_HierClusters) { run_hc_test (_this, "hc_test_l11.gds", "hc_test_au11.gds"); run_hc_test_with_backannotation (_this, "hc_test_l4.gds", "hc_test_au4b.gds"); } + diff --git a/testdata/algo/hc_test_au1.gds b/testdata/algo/hc_test_au1.gds index 21209e2b3..09622935b 100644 Binary files a/testdata/algo/hc_test_au1.gds and b/testdata/algo/hc_test_au1.gds differ diff --git a/testdata/algo/hc_test_au1b.gds b/testdata/algo/hc_test_au1b.gds index e1f2615cf..65406edd5 100644 Binary files a/testdata/algo/hc_test_au1b.gds and b/testdata/algo/hc_test_au1b.gds differ diff --git a/testdata/algo/hc_test_au9.gds b/testdata/algo/hc_test_au9.gds index 3bf9b01e0..d5306c761 100644 Binary files a/testdata/algo/hc_test_au9.gds and b/testdata/algo/hc_test_au9.gds differ diff --git a/testdata/algo/hc_test_au9b.gds b/testdata/algo/hc_test_au9b.gds index 3e89d8674..fce2779a8 100644 Binary files a/testdata/algo/hc_test_au9b.gds and b/testdata/algo/hc_test_au9b.gds differ diff --git a/testdata/algo/hc_test_l1.gds b/testdata/algo/hc_test_l1.gds index 49f6575ad..e428b70b0 100644 Binary files a/testdata/algo/hc_test_l1.gds and b/testdata/algo/hc_test_l1.gds differ diff --git a/testdata/algo/hc_test_l9.gds b/testdata/algo/hc_test_l9.gds index ebbf2798e..2bc98a30e 100644 Binary files a/testdata/algo/hc_test_l9.gds and b/testdata/algo/hc_test_l9.gds differ