From a438dfd6f087c6a99bc2d627020f997f87d30590 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 17 Nov 2018 00:16:13 +0100 Subject: [PATCH] WIP: deep region debugged, GSI binding, tests. --- src/db/db/dbAsIfFlatRegion.cc | 9 ++ src/db/db/dbAsIfFlatRegion.h | 2 + src/db/db/dbCellMapping.h | 13 +- src/db/db/dbDeepRegion.cc | 66 ++++++++- src/db/db/dbDeepRegion.h | 54 +------- src/db/db/dbDeepShapeStore.cc | 133 ++++++++++++++++++- src/db/db/dbDeepShapeStore.h | 73 +++++++++- src/db/db/dbEmptyRegion.h | 2 + src/db/db/dbFlatRegion.cc | 5 + src/db/db/dbFlatRegion.h | 2 + src/db/db/dbHierarchyBuilder.cc | 11 +- src/db/db/dbHierarchyBuilder.h | 38 +++++- src/db/db/dbLayout.cc | 7 + src/db/db/dbLayout.h | 10 ++ src/db/db/dbRegion.h | 8 ++ src/db/db/dbRegionDelegate.h | 2 + src/db/db/gsiDeclDbCell.cc | 3 - src/db/db/gsiDeclDbLayout.cc | 13 ++ src/db/db/gsiDeclDbRegion.cc | 42 ++++++ src/db/unit_tests/dbDeepRegionTests.cc | 113 ++++++++++++++++ src/db/unit_tests/dbHierarchyBuilderTests.cc | 132 ++++++++++++++++++ src/db/unit_tests/unit_tests.pro | 3 +- testdata/algo/deep_region_au1.gds | Bin 0 -> 9250 bytes testdata/algo/deep_region_l1.gds | Bin 0 -> 2762 bytes testdata/ruby/dbRegionTest.rb | 29 ++++ 25 files changed, 699 insertions(+), 71 deletions(-) create mode 100644 src/db/unit_tests/dbDeepRegionTests.cc create mode 100644 testdata/algo/deep_region_au1.gds create mode 100644 testdata/algo/deep_region_l1.gds diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 50bb03d83..46af6c33b 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -1447,6 +1447,15 @@ AsIfFlatRegion::add (const Region &other) const } } +void +AsIfFlatRegion::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const +{ + db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer); + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + shapes.insert (*p); + } +} + bool AsIfFlatRegion::equals (const Region &other) const { diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index e9cedaaa8..b932903e4 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -201,6 +201,8 @@ public: virtual bool equals (const Region &other) const; virtual bool less (const Region &other) const; + virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; + protected: void update_bbox (const db::Box &box); void invalidate_bbox (); diff --git a/src/db/db/dbCellMapping.h b/src/db/db/dbCellMapping.h index 66cb0a01c..c50001a0c 100644 --- a/src/db/db/dbCellMapping.h +++ b/src/db/db/dbCellMapping.h @@ -179,6 +179,17 @@ public: return m_b2a_mapping; } + /** + * @brief Creates mappings for all cells not mapped yet + * + * When constructing a cell mapping by explicit mapping (map (a, b)), some cells may be + * left unmapped. This method allows creating mappings for these missing cells by adding + * new cells and the corresponding instances into the target layout_a. + * + * The returned vector lists the new cells. + */ + std::vector create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b); + private: void extract_unique (std::map >::const_iterator cand, std::map &unique_mapping, @@ -187,8 +198,6 @@ private: void dump_mapping (const std::map > &candidates, const db::Layout &layout_a, const db::Layout &layout_b); - std::vector create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b); - std::map m_b2a_mapping; }; diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 78fa48d95..d5c1cbbfa 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -31,17 +31,73 @@ namespace db { +namespace +{ + /** + * @brief An iterator delegate for the deep region + * TODO: this is kind of redundant with OriginalLayerIterator .. + */ + class DB_PUBLIC DeepRegionIterator + : public RegionIteratorDelegate + { + public: + typedef db::Polygon value_type; + + DeepRegionIterator (const db::RecursiveShapeIterator &iter) + : m_iter (iter) + { + set (); + } + + virtual bool at_end () const + { + return m_iter.at_end (); + } + + virtual void increment () + { + ++m_iter; + set (); + } + + virtual const value_type *get () const + { + return &m_polygon; + } + + virtual RegionIteratorDelegate *clone () const + { + return new DeepRegionIterator (*this); + } + + private: + friend class Region; + + db::RecursiveShapeIterator m_iter; + mutable value_type m_polygon; + + void set () const + { + if (! m_iter.at_end ()) { + m_iter.shape ().polygon (m_polygon); + m_polygon.transform (m_iter.trans (), false); + } + } + }; + +} + // ------------------------------------------------------------------------------------------------------------- // DeepRegion implementation DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio, size_t max_vertex_count) - : AsIfFlatRegion (), m_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count)) + : AsIfFlatRegion (), m_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count)), m_merged_polygons (false) { init (); } DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool merged_semantics, double area_ratio, size_t max_vertex_count) - : AsIfFlatRegion (), m_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count)) + : AsIfFlatRegion (), m_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count)), m_merged_polygons (false) { init (); @@ -223,5 +279,11 @@ DeepRegion::ensure_merged_polygons_valid () const } } +void +DeepRegion::insert_into (db::Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const +{ + m_deep_layer.insert_into (layout, into_cell, into_layer); +} + } diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index 415973bf8..147162aa0 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -32,57 +32,7 @@ namespace db { /** - * @brief An iterator delegate for the deep region - */ -class DB_PUBLIC DeepRegionIterator - : public RegionIteratorDelegate -{ -public: - typedef db::Polygon value_type; - - DeepRegionIterator (const db::RecursiveShapeIterator &iter) - : m_iter (iter) - { - set (); - } - - virtual bool at_end () const - { - return m_iter.at_end (); - } - - virtual void increment () - { - ++m_iter; - set (); - } - - virtual const value_type *get () const - { - return &m_tmp; - } - - virtual RegionIteratorDelegate *clone () const - { - return new DeepRegionIterator (*this); - } - -private: - friend class Region; - - db::RecursiveShapeIterator m_iter; - mutable value_type m_tmp; - - void set () const - { - if (! m_iter.at_end ()) { - m_iter->polygon (m_tmp); - } - } -}; - -/** - * @brief A flat, polygon-set delegate + * @brief A deep, polygon-set delegate */ class DB_PUBLIC DeepRegion : public AsIfFlatRegion @@ -120,6 +70,8 @@ public: virtual bool equals (const Region &other) const; virtual bool less (const Region &other) const; + virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; + protected: virtual void merged_semantics_changed (); diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index e9a317ae9..b17a15b39 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -22,6 +22,9 @@ #include "dbDeepShapeStore.h" +#include "dbCellMapping.h" +#include "dbLayoutUtils.h" + #include "tlTimer.h" namespace db @@ -47,16 +50,57 @@ DeepLayer::DeepLayer (DeepShapeStore *store, unsigned int layout, unsigned int l // .. nothing yet .. } -// ---------------------------------------------------------------------------------- - -DeepShapeStore::DeepShapeStore () +DeepLayer::~DeepLayer () { // .. nothing yet .. } +void +DeepLayer::insert_into (db::Layout *into_layout, db::cell_index_type into_cell, unsigned int into_layer) const +{ + check_dss (); + const_cast (mp_store.get ())->insert (*this, into_layout, into_cell, into_layer); +} + +db::Layout * +DeepLayer::layout () +{ + check_dss (); + return mp_store->layout (m_layout); +} + +const db::Layout * +DeepLayer::layout () const +{ + check_dss (); + return const_cast (mp_store.get ())->layout (m_layout); +} + +void +DeepLayer::check_dss () const +{ + if (mp_store.get () == 0) { + throw tl::Exception (tl::to_string (tr ("Heap lost: the DeepShapeStore container no longer exists"))); + } +} + +// ---------------------------------------------------------------------------------- + +static size_t s_instance_count = 0; + +DeepShapeStore::DeepShapeStore () +{ + ++s_instance_count; +} + DeepShapeStore::~DeepShapeStore () { - // .. nothing yet .. + --s_instance_count; +} + +size_t DeepShapeStore::instance_count () +{ + return s_instance_count; } DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio, size_t max_vertex_count) @@ -108,5 +152,86 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator return DeepLayer (this, layout_index, layer_index); } +void +DeepShapeStore::insert (const DeepLayer &deep_layer, db::Layout *into_layout, db::cell_index_type into_cell, unsigned int into_layer) +{ + const db::Layout *source_layout = deep_layer.layout (); + if (source_layout->begin_top_down () == source_layout->end_top_cells ()) { + // empty source - nothing to do. + return; + } + + db::cell_index_type source_top = *source_layout->begin_top_down(); + + db::HierarchyBuilder &original_builder = m_builders [deep_layer.layout_index ()]; + + // derive a cell mapping for source to target. We employ a + + DeliveryMappingCacheKey key (deep_layer.layout_index (), into_layout, into_cell); + + std::map::iterator cm = m_delivery_mapping_cache.find (key); + if (cm == m_delivery_mapping_cache.end ()) { + + cm = m_delivery_mapping_cache.insert (std::make_pair (key, db::CellMapping ())).first; + + if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell ()) { + + // This is the case of mapping back to the original. In this case we can use the information + // provided inside the original hierarchy builders. They list the source cells and the target cells + // create from them. We need to consider however, that the hierarchy builder is allowed to create + // variants which we cannot map. + + bool any_skipped = false; + + for (HierarchyBuilder::cell_map_type::const_iterator m = original_builder.begin_cell_map (); m != original_builder.end_cell_map (); ++m) { + + HierarchyBuilder::cell_map_type::const_iterator mm = m; + ++mm; + bool skip = false; + while (mm != original_builder.end_cell_map () && mm->first.first == m->first.first) { + // we have cell variants and cannot simply map + ++mm; + ++m; + skip = true; + } + + if (! skip) { + cm->second.map (m->first.first, m->second); + } else { + any_skipped = true; + } + + } + + if (any_skipped) { + // Add new cells for the variants + cm->second.create_missing_mapping (*into_layout, into_cell, *source_layout, source_top); + } + + } else if (into_layout->cells () == 1) { + + // Another simple case is mapping into an empty (or single-top-cell-only) layout, where we can use "create_from_single_full". + cm->second.create_single_mapping_full (*into_layout, into_cell, *source_layout, source_top); + + } else { + + cm->second.create_from_geometry_full (*into_layout, into_cell, *source_layout, source_top); + + } + + } + + // Actually copy the shapes + + db::ICplxTrans trans (source_layout->dbu () / into_layout->dbu ()); + + std::map lm; + lm.insert (std::make_pair (deep_layer.layer (), into_layer)); + + std::vector source_cells; + source_cells.push_back (source_top); + db::copy_shapes (*into_layout, *source_layout, trans, source_cells, cm->second.table (), lm); +} + } diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index c08bfb44d..227213d36 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -31,6 +31,7 @@ #include "dbLayout.h" #include "dbRecursiveShapeIterator.h" #include "dbHierarchyBuilder.h" +#include "gsiObject.h" #include #include @@ -87,6 +88,19 @@ public: return m_layer; } + /** + * @brief Gets the layout index + */ + unsigned int layout_index () const + { + return m_layout; + } + + /** + * @brief Inserts the layer into the given layout, starting from the given cell and into the given layer + */ + void insert_into (Layout *into_layout, db::cell_index_type into_cell, unsigned int into_layer) const; + private: friend class DeepShapeStore; @@ -95,6 +109,8 @@ private: */ DeepLayer (DeepShapeStore *store, unsigned int layout, unsigned int layer); + void check_dss () const; + tl::weak_ptr mp_store; unsigned int m_layout; unsigned int m_layer; @@ -121,7 +137,7 @@ struct DB_PUBLIC RecursiveShapeIteratorCompareForTargetHierarchy * algorithms for doing the preparation and transfer. */ class DB_PUBLIC DeepShapeStore - : public tl::Object + : public tl::Object, public gsi::ObjectBase { public: /** @@ -146,7 +162,24 @@ public: */ DeepLayer create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio = 3.0, size_t max_vertex_count = 16); + /** + * @brief Inserts the deep layer's into some target layout + */ + void insert (const DeepLayer &layer, db::Layout *into_layout, db::cell_index_type into_cell, unsigned int into_layer); + + /** + * @brief For testing + */ + static size_t instance_count (); + private: + friend class DeepLayer; + + db::Layout *layout (unsigned int n) + { + return &m_layouts [n]; + } + typedef std::map layout_map_type; // no copying @@ -156,9 +189,47 @@ private: tl::stable_vector m_layouts; tl::stable_vector m_builders; layout_map_type m_layout_map; + + struct DeliveryMappingCacheKey + { + // NOTE: we shouldn't keep pointers here as the layouts may get deleted and recreated with the same address. + // But as we don't access these objects that's fairly safe. + DeliveryMappingCacheKey (unsigned int _from_index, db::Layout *_into_layout, db::cell_index_type _into_cell) + : from_index (_from_index), into_layout (_into_layout), into_cell (_into_cell) + { + // .. nothing yet .. + } + + bool operator< (const DeliveryMappingCacheKey &other) const + { + if (from_index != other.from_index) { + return from_index < other.from_index; + } + if (into_layout != other.into_layout) { + return into_layout < other.into_layout; + } + return into_cell m_delivery_mapping_cache; }; } +namespace tl +{ + + // disable copying of the deep shape store object + template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; + }; + +} + #endif diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index 696853af1..da0327ba0 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -120,6 +120,8 @@ public: virtual bool equals (const Region &other) const; virtual bool less (const Region &other) const; + virtual void insert_into (Layout *, db::cell_index_type, unsigned int) const { } + private: EmptyRegion &operator= (const EmptyRegion &other); }; diff --git a/src/db/db/dbFlatRegion.cc b/src/db/db/dbFlatRegion.cc index 411dff8e5..ae1868c23 100644 --- a/src/db/db/dbFlatRegion.cc +++ b/src/db/db/dbFlatRegion.cc @@ -362,6 +362,11 @@ const db::RecursiveShapeIterator *FlatRegion::iter () const return 0; } +void FlatRegion::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const +{ + layout->cell (into_cell).shapes (into_layer).insert (m_polygons); +} + void FlatRegion::insert (const db::Box &box) { diff --git a/src/db/db/dbFlatRegion.h b/src/db/db/dbFlatRegion.h index 72e712a6d..cbae0ba71 100644 --- a/src/db/db/dbFlatRegion.h +++ b/src/db/db/dbFlatRegion.h @@ -109,6 +109,8 @@ public: virtual size_t size () const; virtual bool is_merged () const; + virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; + virtual RegionDelegate *merged_in_place (); virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc); virtual RegionDelegate *merged () const; diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index 383f2b685..c07523fb4 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -62,16 +62,19 @@ compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIter if (iter1.has_complex_region () && iter1.complex_region () != iter2.complex_region ()) { return iter1.complex_region () < iter2.complex_region () ? -1 : 1; } + if (iter1.region () != iter2.region ()) { + return iter1.region () < iter2.region () ? -1 : 1; + } if (iter1.multiple_layers () != iter2.multiple_layers ()) { return iter1.multiple_layers () < iter2.multiple_layers () ? -1 : 1; } if (iter1.multiple_layers ()) { if (iter1.layers () != iter2.layers ()) { - return iter1.layers () < iter2.layers (); + return iter1.layers () < iter2.layers () ? -1 : 1; } } else { if (iter1.layer () != iter2.layer ()) { - return iter1.layer () < iter2.layer (); + return iter1.layer () < iter2.layer () ? -1 : 1; } } } @@ -161,9 +164,9 @@ void HierarchyBuilder::begin (const RecursiveShapeIterator *iter) { if (m_initial_pass) { - m_ref_iter = *iter; + m_source = *iter; } else { - tl_assert (compare_iterators_with_respect_to_target_hierarchy (m_ref_iter, *iter) == 0); + tl_assert (compare_iterators_with_respect_to_target_hierarchy (m_source, *iter) == 0); } m_cell_stack.clear (); diff --git a/src/db/db/dbHierarchyBuilder.h b/src/db/db/dbHierarchyBuilder.h index c982ec384..37176b340 100644 --- a/src/db/db/dbHierarchyBuilder.h +++ b/src/db/db/dbHierarchyBuilder.h @@ -41,7 +41,7 @@ namespace db * This function will return -1, 0 or 1 depending on whether the two iterators * can be used with the same builder (0) or whether they are less (-1) or greater (1). */ -int compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIterator &iter1, const db::RecursiveShapeIterator &iter2); +int DB_PUBLIC compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIterator &iter1, const db::RecursiveShapeIterator &iter2); /** * @brief A class to receive shapes from the hierarchy builder @@ -199,18 +199,50 @@ public: void reset (); /** - * @brief Gets the initial cell the builder produced + * @brief Gets the initial cell the builder produced in the target layout */ db::Cell *initial_cell () { return mp_initial_cell; } + /** + * @brief Gets the target layout + */ + db::Layout *target () + { + return mp_target.get (); + } + + /** + * @brief Gets the recursive shape iterator the data was taken from + */ + const db::RecursiveShapeIterator &source () const + { + return m_source; + } + + /** + * @brief Gets the iterator for the cell map + */ + cell_map_type::const_iterator begin_cell_map () const + { + return m_cell_map.begin (); + } + + /** + * @brief Gets the iterator for the cell map (end) + */ + cell_map_type::const_iterator end_cell_map () const + { + return m_cell_map.end (); + } + private: tl::weak_ptr mp_target; HierarchyBuilderShapeReceiver *mp_pipe; bool m_initial_pass; - db::RecursiveShapeIterator m_ref_iter; + db::RecursiveShapeIterator m_source; cell_map_type m_cell_map; std::set m_cells_seen; cell_map_type::const_iterator m_cm_entry; diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 0380deb12..91fd9f995 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -31,6 +31,7 @@ #include "dbLibraryProxy.h" #include "dbLibraryManager.h" #include "dbLibrary.h" +#include "dbRegion.h" #include "tlTimer.h" #include "tlLog.h" #include "tlInternational.h" @@ -638,6 +639,12 @@ Layout::delete_cell (cell_index_type id) } } +void +Layout::insert (db::cell_index_type cell, int layer, const db::Region ®ion) +{ + region.insert_into (this, cell, layer); +} + void Layout::flatten (const db::Cell &source_cell, db::Cell &target_cell, const db::ICplxTrans &t, int levels) { diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 8ebaf1fbc..eb48b7727 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -61,6 +61,7 @@ class Library; class LibraryProxy; class CellMapping; class LayerMapping; +class Region; template class generic_repository; typedef generic_repository GenericRepository; @@ -1090,6 +1091,15 @@ public: */ void flatten (db::Cell &cell, int levels, bool prune = false); + /** + * @brief Inserts a region (potentially hierarchical) into the given cell and layer + * + * If the region is flat (conceptionally), it will be put into the cell. + * If the region is hierarchical, a cell hierarchy will be built below the + * given cell. + */ + void insert (db::cell_index_type cell, int layer, const db::Region ®ion); + /** * @brief Delete a cell plus all subcells * diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 4a4cc4e9e..c2969f45e 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -1685,6 +1685,14 @@ public: return mp_delegate->less (other); } + /** + * @brief Less operator + */ + void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const + { + return mp_delegate->insert_into (layout, into_cell, into_layer); + } + private: friend class Edges; friend class EdgePairs; diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index ecf10d292..626317f50 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -179,6 +179,8 @@ public: virtual bool equals (const Region &other) const = 0; virtual bool less (const Region &other) const = 0; + virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const = 0; + protected: const std::string &progress_desc () const { diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index 9784a56af..220fd40f8 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -1356,7 +1356,6 @@ static std::vector copy_tree (db::Cell *cell, const db::Cel throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout"))); } - db::PropertyMapper pm (*target_layout, *source_layout); db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ()); db::CellMapping cm; @@ -1387,7 +1386,6 @@ static void copy_tree_shapes2 (db::Cell *cell, const db::Cell &source_cell, cons throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout"))); } - db::PropertyMapper pm (*target_layout, *source_layout); db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ()); db::LayerMapping lm; @@ -1413,7 +1411,6 @@ static void copy_tree_shapes3 (db::Cell *cell, const db::Cell &source_cell, cons throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout"))); } - db::PropertyMapper pm (*target_layout, *source_layout); db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ()); std::vector source_cells; diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index 48c60db98..537cd5ada 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -32,6 +32,7 @@ #include "dbLibraryManager.h" #include "dbPCellDeclaration.h" #include "dbHash.h" +#include "dbRegion.h" #include "tlStream.h" namespace gsi @@ -1179,6 +1180,18 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduced in version 0.20.\n" ) + + gsi::method ("insert", (void (db::Layout::*) (db::cell_index_type, unsigned int, const db::Region &)) &db::Layout::insert, + gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"), + "@brief Inserts a region into the given cell and layer\n" + "If the region is (conceptionally) a flat region, it will be inserted into the cell's shapes " + "list as a flat sequence of polygons.\n" + "If the region is a deep (hierarchical) region, it will create a subhierarchy below the given " + "cell and it's shapes will be put into the respective cells. Suitable subcells will be picked " + "for inserting the shapes. If a hierarchy already exists below the given cell, the algorithm will " + "try to reuse this hierarchy.\n" + "\n" + "This method has been introduced in version 0.26.\n" + ) + gsi::method_ext ("flatten", &flatten, "@brief Flattens the given cell\n" "@args cell_index, levels, prune\n" diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 7cb106fa8..12df8eeee 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -26,6 +26,8 @@ #include "dbPolygonTools.h" #include "dbLayoutUtils.h" #include "dbShapes.h" +#include "dbDeepShapeStore.h" +#include "dbRegion.h" #include "tlGlobPattern.h" #include @@ -213,6 +215,11 @@ static db::Region *new_si (const db::RecursiveShapeIterator &si) return new db::Region (si); } +static db::Region *new_sid (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, double area_ratio, size_t max_vertex_count) +{ + return new db::Region (si, dss, area_ratio, max_vertex_count); +} + static db::Region *new_si2 (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans) { return new db::Region (si, trans); @@ -712,6 +719,25 @@ static Container *decompose_trapezoids (const db::Region *r, int mode) int td_simple (); int po_any (); +Class decl_DeepShapeStore ("db", "DeepShapeStore", + method ("instance_count", db::DeepShapeStore::instance_count, "@hide"), + "@brief An opaque layout heap for the deep region processor\n" + "\n" + "This class is used for keeping intermediate, hierarchical data for the " + "deep region processor. It is used in conjunction with the region " + "constructor to create a deep (hierarchical) region." + "\n" + "@code\n" + "layout = ... # a layout\n" + "layer = ... # a layer\n" + "cell = ... # a cell (initial cell for the deep region)\n" + "dss = RBA::DeepShapeStore::new\n" + "region = RBA::Region::new(cell.begin(layer), dss)\n" + "@/code\n" + "\n" + "This class has been introduced in version 0.26.\n" +); + Class decl_Region ("db", "Region", constructor ("new", &new_v, "@brief Default constructor\n" @@ -789,6 +815,22 @@ Class decl_Region ("db", "Region", "r = RBA::Region::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n" "@/code\n" ) + + constructor ("new", &new_sid, gsi::arg ("shape_iterator"), gsi::arg ("deep_shape_store"), gsi::arg ("area_ratio", 3.0), gsi::arg ("max_vertex_count", size_t (16)), + "@brief Constructor for a deep region from a hierarchical shape set\n" + "\n" + "This constructor creates a hierarchical region. Use a \\DeepShapeStore object to " + "supply the hierarchical heap. See \\DeepShapeStore for more details.\n" + "\n" + "'area_ratio' and 'max_vertex' supply two optimization parameters which control how " + "big polygons are split to reduce the region's polygon complexity.\n" + "\n" + "@param shape_iterator The recursive shape iterator which delivers the hierarchy to take\n" + "@param deep_shape_store The hierarchical heap (see there)\n" + "@param area_ratio The maximum ratio of bounding box to polygon area before polygons are split\n" + "@param" + "\n" + "This method has been introduced in version 0.26.\n" + ) + constructor ("new", &new_texts, gsi::arg("shape_iterator"), gsi::arg ("expr"), gsi::arg ("as_pattern", true), "@brief Constructor from a text set\n" "\n" diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc new file mode 100644 index 000000000..a5e582579 --- /dev/null +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -0,0 +1,113 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbHierarchyBuilder.h" +#include "dbReader.h" +#include "dbTestSupport.h" +#include "dbRegion.h" +#include "dbDeepShapeStore.h" +#include "tlUnitTest.h" +#include "tlStream.h" + +TEST(1) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/deep_region_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + + db::DeepShapeStore dss; + db::Layout target; + + // deliberately using vector to force reallocation ... + std::vector regions; + std::vector target_layers; + + for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) { + + unsigned int li1 = (*li).first; + db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1); + target_layers.push_back (target.insert_layer (*(*li).second)); + + regions.push_back (db::Region (iter, dss)); + + } + + unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); + + for (std::vector::const_iterator r = regions.begin (); r != regions.end (); ++r) { + target.insert (target_top_cell_index, target_layers [r - regions.begin ()], *r); + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au1.gds"); +} + +TEST(2) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/deep_region_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + + db::DeepShapeStore dss; + db::Layout target; + + // deliberately using vector to force reallocation ... + std::vector > regions; + + for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) { + + unsigned int li1 = (*li).first; + unsigned int tl = target.insert_layer (*(*li).second); + + db::RecursiveShapeIterator iter1 (ly, ly.cell (top_cell_index), li1, db::Box (2000, -1000, 6000, 4000)); + regions.push_back (std::make_pair (db::Region (iter1, dss), tl)); + + db::RecursiveShapeIterator iter2 (ly, ly.cell (top_cell_index), li1, db::Box (14000, 0, 20000, 3000)); + regions.push_back (std::make_pair (db::Region (iter2, dss), tl)); + + } + + unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); + + for (std::vector >::const_iterator r = regions.begin (); r != regions.end (); ++r) { + target.insert (target_top_cell_index, r->second, r->first); + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au1.gds"); +} + diff --git a/src/db/unit_tests/dbHierarchyBuilderTests.cc b/src/db/unit_tests/dbHierarchyBuilderTests.cc index 1dffa2d9d..84a7394f5 100644 --- a/src/db/unit_tests/dbHierarchyBuilderTests.cc +++ b/src/db/unit_tests/dbHierarchyBuilderTests.cc @@ -335,3 +335,135 @@ TEST(4_ComplexRegionAndLayoutWithClip) db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au4a.gds"); } +TEST(5_CompareRecursiveShapeIterators) +{ + db::Layout ly; + db::cell_index_type ci = ly.add_cell ("TOP"); + db::cell_index_type ci1 = ly.add_cell ("TOPA"); + + db::Layout ly2; + db::cell_index_type ci2 = ly2.add_cell ("TOP"); + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0); + db::RecursiveShapeIterator iter2 (ly2, ly2.cell (ci2), 0); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci1), 0); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 1); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2), 0); + } + + { + std::vector ll1; + ll1.push_back (100); + ll1.push_back (101); + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), ll1); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 1); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2), 0); + } + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0); + iter1.max_depth (1); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0); + iter2.max_depth (1); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2), 0); + + iter2.max_depth (2); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2), 0); + } + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 1, db::Box (0, 1000, 2000, 3000)); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + std::vector ll1; + ll1.push_back (100); + ll1.push_back (101); + + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), ll1, db::Box (0, 1000, 2000, 3000)); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3001)); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + db::Region r1; + r1.insert (db::Box (0, 1000, 2000, 3000)); + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, r1); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2), 0); + } + + { + db::Region r1; + r1.insert (db::Box (0, 1000, 2000, 3000)); + r1.insert (db::Box (0, 4000, 2000, 6000)); + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, r1); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + db::Region r1; + r1.insert (db::Box (0, 1000, 2000, 3000)); + r1.insert (db::Box (0, 4000, 2000, 6000)); + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, r1); + db::Region r2; + r2.insert (db::Box (0, 1000, 2000, 3000)); + r2.insert (db::Box (0, 4000, 2000, 6000)); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0, r2); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2), 0); + } + + { + db::Region r1; + r1.insert (db::Box (0, 1000, 2000, 3000)); + r1.insert (db::Box (0, 4000, 2000, 6000)); + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, r1); + db::Region r2; + r2.insert (db::Box (0, 1000, 2000, 3000)); + r2.insert (db::Box (0, 4000, 2000, 6001)); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0, r2); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } +} + diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index e6b19cd84..5c0d7a9a4 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -55,7 +55,8 @@ SOURCES = \ dbSaveLayoutOptionsTests.cc \ dbHierarchyBuilderTests.cc \ dbRecursiveShapeIteratorTests.cc \ - dbHierProcessorTests.cc + dbHierProcessorTests.cc \ + dbDeepRegionTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC diff --git a/testdata/algo/deep_region_au1.gds b/testdata/algo/deep_region_au1.gds new file mode 100644 index 0000000000000000000000000000000000000000..bfa6b5bde37c2c7396658552e9a72212db726a82 GIT binary patch literal 9250 zcmdT|&x@5+7(VyT%)NJhD3cBb;X-8EiRq}5A&HhzgEGl9NQlrs(87gCgvLNEs+EgY z)UWzq z&*Sx8ulomn3$d<^*XiS&XE_i1&Qm`}$=%s1eazkM?K8ZN-(BvX;o<(czq6wK9OwRq zjd|+fKSRlr{afMr*KXVS*KR}a5}s#;k`p8Q1AXlMyB`Nq5BGmUD0xA@5Hs{&Ss^f47a!?^buHR&@$$qV`gpDEA1BJ$ku3FP^Kb@=RV z<};75^g4Dh5KiSb2HDKQ1W>Hz~@QKz%kdOi z9o#xj7I=MQ)g7yEsyb(O7OHbDPwWr8juBL4{|Ah#b1uhIc>cs|oQG&BFnTVR{($OS z^xFP%ufftQ*pb|K1^)$3?~jL82VU!s+dAS>p#jmhg1nlOvi-p+yfeRV z!YN!=^=0TYS7tZQlxKJ281_fJG>%D5jG{Y;6O4hs#n;30IQ4PTP4<2fC%|rh_q0Fj z50X0%?8i9+PVjNc^D|z7syfwi8goM0`whzpjBkJc9$`OXA?q`I%nk7QL{`&Li#qmZ zk<@Xl7jK zWMRi<_C3-L-xT?F-@OIPfxRD*-RRtel6P-KCrb38bCUWv(HqpyQF3>(UVr?C=}&xP z`a;RaZ`A8g9x?r?L#8j3eDa9t54b1vGX6&UA1C(D&gGRW>YyH;LpfXS^@we}xBY!B zN6A~uk=32>)*pQeOVNQ58+S}!C^;sCm7}0PzSs08Z<@YP^6|Zqek0w#-6_|XyxocP z$3p#wU*r5&aeiPM-)bIxl%wRWtENBvt@BINgmXK#WnZTH4q>!U@tailJnzre$IO|+ z%mewniTgG44!YJ0jTOh)@Pu_a{?G-;5L3kQ3+MyB$Wd}ksMcSF4F~z& zhDl$+F7$dr$w%<*h2QzI^F}$b_5iD6e`1HhrA#_W8FX*)5d3&i*u~8Dq?C;_x{QzkPtS+%e?&E$1WqYjWE3CT|)JpVP7a;GBl7 zyK#RX8jhX;f*XaB1H=2@a81bK=b2>^-aDDBj~TUr4>aHj@iZf z$9L2^Qv8BUC5D0#j9(`Po^?@?ng<}>|fC^<1Ye~{OvCkC7P!SscaSLe0qi@~=3YWhOS zmDgGP1B|;5|8F2IGZo%3gK4r8!(POWB9Ik=LLkLxVi7oD-}Q z=K8Z#QJzX~y|%&%g9@;c_te&7OHPb3AgW;0V+A6rClyLw*PE_AV1@YqRv@06Jv320 zwNUbe0ip`x?;jP2`syeQS$QZYM)#lS!*6(BramhVdvl@Wbrs0ljrV0DD-ZRBtUxv% z?Z4p)G@yduyU)_X;+t>xD@RgKkgF&Hryc)1qgpQ!%|aV#Z@e?t>gSRF-{O~ rh;cAv>zE;*pFeNUM9G0+#}nz#e{b`M)L-0{BlWX!ua9^c9d-WzeKT?l literal 0 HcmV?d00001 diff --git a/testdata/algo/deep_region_l1.gds b/testdata/algo/deep_region_l1.gds new file mode 100644 index 0000000000000000000000000000000000000000..fa837f4e2a317771de909276f480b397e7cf8199 GIT binary patch literal 2762 zcma);(MuFj6vofa&fb|_S2L5skSHmrP>VDpBvIQ+F*MvwY7z9Ymmo+YqCzOak|3xj z>p_C-!M7j~^eH03ryheM_8$lqd~(U1zB6}@Gb7HJpugpu^WAgrJ?Ea46dA@1YEBqd zi89no2k0cV1wWH*sH=nhM2*Q*Pv5h1Ltj6X&*zp;Exaifs5up_%P3VC?HkS$nKqHC zHOL@UXAn_qebR9@?>SEO7?UXRlgM~36g!j5y}sTI>Z=C)Yxo77Mew&zu~*mP^w>#} z^~l@BdY@vaVw4`SEzqoKI*VYH^J|JdIzQ_;zhzDNMt0P=RdruO7E7VxeB**z%ViF|}>#P>V z_J^(1;PBWPGBZS(2I-Y7_eS-OyO3M^oxPc|&JpsegNbP(tbmiej96h?jI86GP;Mx2 z!o)4^SNBvz-_VScSlOe6#>Qz$n4XHdZ`@8R&Na>?N>8C~uZ3b~#^_7P)v0gUe5>mv z6nnBWq?dZ>_qL86QOLWF(($|bBNRI`N{<`e=lVg`A%Cq~Z_w z7)KKp9EWLf@1sYAVpoOG{_Wsb_9y%s4&j)voo~k6JGjd%8WO zPlWSxpJ;vE53Lu99eos>cPU?wy|&=~9%!0lAm)Wo>|lf*_x29=H?L`7_EsKaKOV)d z=0keR&yU(Z!TqdgI-gL-NBHbf?A4VxJv2kC$KEfo-ly1UC|;jl()!GMtrvDKz}S*;g}y{231vs?3Szd;F}DEi%@KB@^*D-?y9AyHe?z;03_*9#~Re|zmR2k|{Q zIyih~1d*6#c7vXZ?i9l=`A6np$d|bm?Q2|!_8lrm`%d&m`#QoCHMExtrD)y2>1f~R zbhK~$yYIu8<^LaKI=l01`#h+8(er@$Kl5N?0CBx|51@ryMa%=C*j2B-doO=ro)AqO zXT2utCYQCIDfVsp(0kf=g}6E72dx>r#}_`uuI57d1A3yH9jw>1X0ZP@)@zDAPCs#1 z>zS;ZyzP_qp5N^~?>*rBey2~A5pNTBdj6uI} literal 0 HcmV?d00001 diff --git a/testdata/ruby/dbRegionTest.rb b/testdata/ruby/dbRegionTest.rb index 01d4ea556..3bce9e803 100644 --- a/testdata/ruby/dbRegionTest.rb +++ b/testdata/ruby/dbRegionTest.rb @@ -769,6 +769,35 @@ class DBRegion_TestClass < TestBase end + # deep region tests + def test_deep1 + + # construction/destruction magic ... + GC.start + assert_equal(RBA::DeepShapeStore::instance_count, 0) + dss = RBA::DeepShapeStore::new + dss._create + assert_equal(RBA::DeepShapeStore::instance_count, 1) + dss = nil + GC.start + assert_equal(RBA::DeepShapeStore::instance_count, 0) + + dss = RBA::DeepShapeStore::new + ly = RBA::Layout::new + ly.read(File.join($ut_testsrc, "testdata", "algo", "deep_region_l1.gds")) + l1 = ly.layer(1, 0) + r = RBA::Region::new(ly.top_cell.begin_shapes_rec(l1), dss) + rf = RBA::Region::new(ly.top_cell.begin_shapes_rec(l1)) + + assert_equal(r.area, 53120000) + assert_equal(rf.area, 53120000) + + # force destroy, so the unit tests pass on the next iteration + dss._destroy + assert_equal(RBA::DeepShapeStore::instance_count, 0) + + end + end load("test_epilogue.rb")