From b7c515bf917909172ecdf1a6a06fb97064e4b6cf Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 15 Jan 2023 20:23:32 +0100 Subject: [PATCH] WIP: enabling booleans with property constraints --- src/db/db/db.pro | 1 + src/db/db/dbAsIfFlatRegion.cc | 12 +- src/db/db/dbAsIfFlatRegion.h | 6 +- src/db/db/dbDeepRegion.cc | 64 +- src/db/db/dbDeepRegion.h | 10 +- src/db/db/dbEmptyRegion.h | 6 +- src/db/db/dbHierNetworkProcessor.cc | 30 - src/db/db/dbHierProcessor.cc | 41 +- src/db/db/dbLocalOperation.cc | 125 +++- src/db/db/dbLocalOperation.h | 20 + src/db/db/dbNetShape.h | 25 + src/db/db/dbPropertyConstraint.h | 57 ++ src/db/db/dbRegion.h | 52 +- src/db/db/dbRegionDelegate.h | 6 +- src/db/db/dbRegionLocalOperations.h | 1 + src/db/db/dbShapeFlags.h | 621 ++++++++++++++++-- src/db/db/gsiDeclDbRegion.cc | 72 +- src/db/unit_tests/dbHierNetsProcessorTests.cc | 109 +-- 18 files changed, 1008 insertions(+), 250 deletions(-) create mode 100644 src/db/db/dbPropertyConstraint.h diff --git a/src/db/db/db.pro b/src/db/db/db.pro index dc634cd78..441b85bcd 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -288,6 +288,7 @@ HEADERS = \ dbPolygonTools.h \ dbPolygonGenerators.h \ dbPropertiesRepository.h \ + dbPropertyConstraint.h \ dbReader.h \ dbRecursiveInstanceIterator.h \ dbRecursiveShapeIterator.h \ diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index e73a70751..c61252fb4 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -1428,7 +1428,7 @@ AsIfFlatRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const } RegionDelegate * -AsIfFlatRegion::and_with (const Region &other) const +AsIfFlatRegion::and_with (const Region &other, PropertyConstraint property_constraint) const { if (empty () || other.empty ()) { @@ -1479,6 +1479,8 @@ AsIfFlatRegion::and_with (const Region &other) const } else { + // @@@ TODO: implement property constraint + // Generic case db::EdgeProcessor ep (report_progress (), progress_desc ()); ep.set_base_verbosity (base_verbosity ()); @@ -1515,7 +1517,7 @@ AsIfFlatRegion::and_with (const Region &other) const } RegionDelegate * -AsIfFlatRegion::not_with (const Region &other) const +AsIfFlatRegion::not_with (const Region &other, PropertyConstraint property_constraint) const { if (empty ()) { @@ -1534,6 +1536,8 @@ AsIfFlatRegion::not_with (const Region &other) const } else { + // @@@ TODO: implement property constraint + // Generic case db::EdgeProcessor ep (report_progress (), progress_desc ()); ep.set_base_verbosity (base_verbosity ()); @@ -1571,7 +1575,7 @@ AsIfFlatRegion::not_with (const Region &other) const std::pair -AsIfFlatRegion::andnot_with (const Region &other) const +AsIfFlatRegion::andnot_with (const Region &other, PropertyConstraint property_constraint) const { if (empty ()) { @@ -1590,6 +1594,8 @@ AsIfFlatRegion::andnot_with (const Region &other) const } else { + // @@@ TODO: implement property constraint + // Generic case db::EdgeProcessor ep (report_progress (), progress_desc ()); ep.set_base_verbosity (base_verbosity ()); diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index 687e99742..c5ed1dcde 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -122,11 +122,11 @@ public: virtual RegionDelegate *sized (coord_type d, unsigned int mode) const; virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const; - virtual RegionDelegate *and_with (const Region &other) const; - virtual RegionDelegate *not_with (const Region &other) const; + virtual RegionDelegate *and_with (const Region &other, PropertyConstraint property_constraint) const; + virtual RegionDelegate *not_with (const Region &other, PropertyConstraint property_constraint) const; virtual RegionDelegate *xor_with (const Region &other) const; virtual RegionDelegate *or_with (const Region &other) const; - virtual std::pair andnot_with (const Region &) const; + virtual std::pair andnot_with (const Region &other, PropertyConstraint property_constraint) const; virtual RegionDelegate *add_in_place (const Region &other) { diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 928dfa1de..843180d50 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -699,7 +699,7 @@ DeepRegion::insert_into (db::Layout *layout, db::cell_index_type into_cell, unsi } RegionDelegate * -DeepRegion::and_with (const Region &other) const +DeepRegion::and_with (const Region &other, PropertyConstraint property_constraint) const { const DeepRegion *other_deep = dynamic_cast (other.delegate ()); @@ -713,17 +713,17 @@ DeepRegion::and_with (const Region &other) const } else if (! other_deep) { - return AsIfFlatRegion::and_with (other); + return AsIfFlatRegion::and_with (other, property_constraint); } else { - return new DeepRegion (and_or_not_with (other_deep, true)); + return new DeepRegion (and_or_not_with (other_deep, true, property_constraint)); } } RegionDelegate * -DeepRegion::not_with (const Region &other) const +DeepRegion::not_with (const Region &other, PropertyConstraint property_constraint) const { const DeepRegion *other_deep = dynamic_cast (other.delegate ()); @@ -733,11 +733,11 @@ DeepRegion::not_with (const Region &other) const } else if (! other_deep) { - return AsIfFlatRegion::not_with (other); + return AsIfFlatRegion::not_with (other, property_constraint); } else { - return new DeepRegion (and_or_not_with (other_deep, false)); + return new DeepRegion (and_or_not_with (other_deep, false, property_constraint)); } } @@ -750,7 +750,7 @@ DeepRegion::or_with (const Region &other) const } std::pair -DeepRegion::andnot_with (const Region &other) const +DeepRegion::andnot_with (const Region &other, PropertyConstraint property_constraint) const { const DeepRegion *other_deep = dynamic_cast (other.delegate ()); @@ -764,39 +764,59 @@ DeepRegion::andnot_with (const Region &other) const } else if (! other_deep) { - return AsIfFlatRegion::andnot_with (other); + return AsIfFlatRegion::andnot_with (other, property_constraint); } else { - std::pair res = and_and_not_with (other_deep); + std::pair res = and_and_not_with (other_deep, property_constraint); return std::make_pair (new DeepRegion (res.first), new DeepRegion (res.second)); } } DeepLayer -DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op) const +DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op, db::PropertyConstraint property_constraint) const { DeepLayer dl_out (deep_layer ().derived ()); - db::BoolAndOrNotLocalOperation op (and_op); + if (property_constraint == db::NoPropertyConstraint) { - db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ()); - proc.set_base_verbosity (base_verbosity ()); - proc.set_description (progress_desc ()); - proc.set_report_progress (report_progress ()); - proc.set_threads (deep_layer ().store ()->threads ()); - proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ()); - proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ()); + db::BoolAndOrNotLocalOperation op (and_op); - proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ()); + db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); + proc.set_threads (deep_layer ().store ()->threads ()); + proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ()); + proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ()); + + proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ()); + + } else { + + db::BoolAndOrNotLocalOperationWithProperties op (and_op, &deep_layer ().layout (), &other->deep_layer ().layout (), property_constraint); + + db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); + proc.set_threads (deep_layer ().store ()->threads ()); + proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ()); + proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ()); + + proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ()); + + } return dl_out; } std::pair -DeepRegion::and_and_not_with (const DeepRegion *other) const +DeepRegion::and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const { + // @@@ TODO: implement property_constraint + DeepLayer dl_out1 (deep_layer ().derived ()); DeepLayer dl_out2 (deep_layer ().derived ()); @@ -845,8 +865,8 @@ DeepRegion::xor_with (const Region &other) const // Implement XOR as (A-B)+(B-A) - only this implementation // is compatible with the local processor scheme - DeepLayer n1 (and_or_not_with (other_deep, false)); - DeepLayer n2 (other_deep->and_or_not_with (this, false)); + DeepLayer n1 (and_or_not_with (other_deep, false, db::NoPropertyConstraint)); + DeepLayer n2 (other_deep->and_or_not_with (this, false, db::NoPropertyConstraint)); n1.add_from (n2); return new DeepRegion (n1); diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index 26e495763..33948b66b 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -99,11 +99,11 @@ public: virtual RegionDelegate *cop_to_region (db::CompoundRegionOperationNode &node); virtual EdgesDelegate *cop_to_edges (db::CompoundRegionOperationNode &node); - virtual RegionDelegate *and_with (const Region &other) const; - virtual RegionDelegate *not_with (const Region &other) const; + virtual RegionDelegate *and_with (const Region &other, db::PropertyConstraint property_constraint) const; + virtual RegionDelegate *not_with (const Region &other, db::PropertyConstraint property_constraint) const; virtual RegionDelegate *xor_with (const Region &other) const; virtual RegionDelegate *or_with (const Region &other) const; - virtual std::pair andnot_with (const Region &) const; + virtual std::pair andnot_with (const Region &, db::PropertyConstraint property_constraint) const; virtual RegionDelegate *add_in_place (const Region &other); virtual RegionDelegate *add (const Region &other) const; @@ -174,8 +174,8 @@ private: void init (); void ensure_merged_polygons_valid () const; - DeepLayer and_or_not_with(const DeepRegion *other, bool and_op) const; - std::pair and_and_not_with (const DeepRegion *other) const; + DeepLayer and_or_not_with(const DeepRegion *other, bool and_op, PropertyConstraint property_constraint) const; + std::pair and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const; DeepRegion *apply_filter (const PolygonFilterBase &filter) const; template OutputContainer *processed_impl (const polygon_processor &filter) const; diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index 5ccef4e11..50a37cf4f 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -98,9 +98,9 @@ public: virtual RegionDelegate *sized (coord_type, unsigned int) const { return new EmptyRegion (); } virtual RegionDelegate *sized (coord_type, coord_type, unsigned int) const { return new EmptyRegion (); } - virtual RegionDelegate *and_with (const Region &) const { return new EmptyRegion (); } - virtual RegionDelegate *not_with (const Region &) const { return new EmptyRegion (); } - virtual std::pair andnot_with (const Region &) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); } + virtual RegionDelegate *and_with (const Region &, db::PropertyConstraint) const { return new EmptyRegion (); } + virtual RegionDelegate *not_with (const Region &, db::PropertyConstraint) const { return new EmptyRegion (); } + virtual std::pair andnot_with (const Region &, db::PropertyConstraint) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); } virtual RegionDelegate *xor_with (const Region &other) const; virtual RegionDelegate *or_with (const Region &other) const; virtual RegionDelegate *add_in_place (const Region &other); diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 12e226a44..7817fd527 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -1042,36 +1042,6 @@ private: } }; -template -struct addressable_object_from_shape -{ - const T *operator () (const db::Shape &shape) - { - typename T::tag object_tag; - return shape.basic_ptr (object_tag); - } -}; - -template <> -struct addressable_object_from_shape -{ - const NetShape *operator () (const db::Shape &shape) - { - if (shape.type () == db::Shape::TextRef) { - m_heap.push_back (db::NetShape (shape.text_ref ())); - return &m_heap.back (); - } else if (shape.type () == db::Shape::PolygonRef) { - m_heap.push_back (db::NetShape (shape.polygon_ref ())); - return &m_heap.back (); - } else { - tl_assert (false); - } - } - -private: - std::list m_heap; -}; - template struct attr_accessor { diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index 94fa44317..882b81c01 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -197,14 +197,12 @@ public: shape_type operator() (const shape_type &s) const { - // CAUTION: no property ID translation happens here (reasoning: the main use case is fake ID for net tagging) return shape_type (shape_reference_translator::operator () (s), s.properties_id ()); } template shape_type operator() (const shape_type &s, const Trans &tr) const { - // CAUTION: no property ID translation happens here (reasoning: the main use case is fake ID for net tagging) return shape_type (shape_reference_translator::operator () (s, tr), s.properties_id ()); } }; @@ -445,7 +443,7 @@ template class DB_PUBLIC local_processor_cell_context; template class DB_PUBLIC local_processor_cell_context; template class DB_PUBLIC local_processor_cell_context; -template class DB_PUBLIC local_processor_cell_context; +template class DB_PUBLIC local_processor_cell_context; template class DB_PUBLIC local_processor_cell_context; template class DB_PUBLIC local_processor_cell_context; template class DB_PUBLIC local_processor_cell_context; @@ -759,7 +757,7 @@ template class DB_PUBLIC local_processor_cell_contexts; template class DB_PUBLIC local_processor_cell_contexts; template class DB_PUBLIC local_processor_cell_contexts; -template class DB_PUBLIC local_processor_cell_contexts; +template class DB_PUBLIC local_processor_cell_contexts; template class DB_PUBLIC local_processor_cell_contexts; template class DB_PUBLIC local_processor_cell_contexts; template class DB_PUBLIC local_processor_cell_contexts; @@ -1064,6 +1062,7 @@ private: void add_shapes_from_intruder_inst (unsigned int id1, const db::Cell &intruder_cell, const db::ICplxTrans &tn, unsigned int /*inst_id*/, const db::Box ®ion) { db::shape_reference_translator rt (mp_subject_layout); + db::shape_to_object s2o; // Look up all shapes from the intruder instance which interact with the subject shape // (given through region) @@ -1074,7 +1073,7 @@ private: // NOTE: we intentionally rewrite to the *subject* layout - this way polygon refs in the context come from the // subject, not from the intruder. - TI ref2 = rt (*si.shape ().basic_ptr (typename TI::tag ()), tn * si.trans ()); + TI ref2 = rt (s2o (si.shape ()), tn * si.trans ()); // reuse the same id for shapes from the same instance -> this avoid duplicates with different IDs on // the intruder side. @@ -1335,7 +1334,7 @@ template class DB_PUBLIC local_processor_context_computation_task; template class DB_PUBLIC local_processor_context_computation_task; template class DB_PUBLIC local_processor_context_computation_task; -template class DB_PUBLIC local_processor_context_computation_task; +template class DB_PUBLIC local_processor_context_computation_task; template class DB_PUBLIC local_processor_context_computation_task; template class DB_PUBLIC local_processor_context_computation_task; template class DB_PUBLIC local_processor_context_computation_task; @@ -1398,7 +1397,7 @@ template class DB_PUBLIC local_processor_result_computation_task; template class DB_PUBLIC local_processor_result_computation_task; template class DB_PUBLIC local_processor_result_computation_task; -template class DB_PUBLIC local_processor_result_computation_task; +template class DB_PUBLIC local_processor_result_computation_task; template class DB_PUBLIC local_processor_result_computation_task; template class DB_PUBLIC local_processor_result_computation_task; template class DB_PUBLIC local_processor_result_computation_task; @@ -1712,6 +1711,7 @@ void local_processor::compute_contexts (local_processor_contexts scanner; + db::addressable_object_from_shape heap; interaction_registration_inst2shape rec (mp_subject_layout, contexts.subject_layer (), dist, &interactions); for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) { @@ -1728,7 +1728,7 @@ void local_processor::compute_contexts (local_processor_contexts::const_iterator im = intruder_shapes.begin (); im != intruder_shapes.end (); ++im) { for (db::Shapes::shape_iterator i = im->second->begin (shape_flags ()); !i.at_end (); ++i) { - scanner.insert2 (i->basic_ptr (typename TI::tag ()), im->first); + scanner.insert2 (heap (*i), im->first); } } @@ -1880,11 +1880,12 @@ struct scan_shape2shape_same_layer operator () (const db::Shapes *subject_shapes, unsigned int subject_id0, const std::set &intruders, unsigned int intruder_layer_index, shape_interactions &interactions, db::Coord dist) const { db::box_scanner2 scanner; + db::addressable_object_from_shape heap; interaction_registration_shape1 rec (&interactions, intruder_layer_index); unsigned int id = subject_id0; for (db::Shapes::shape_iterator i = subject_shapes->begin (shape_flags ()); !i.at_end (); ++i) { - const TS *ref = i->basic_ptr (typename TS::tag ()); + const TS *ref = heap (*i); scanner.insert1 (ref, id++); } @@ -1904,12 +1905,12 @@ struct scan_shape2shape_same_layer operator () (const db::Shapes *subject_shapes, unsigned int subject_id0, const std::set &intruders, unsigned int intruder_layer, shape_interactions &interactions, db::Coord dist) const { db::box_scanner scanner; + db::addressable_object_from_shape heap; interaction_registration_shape1 rec (&interactions, intruder_layer); unsigned int id = subject_id0; for (db::Shapes::shape_iterator i = subject_shapes->begin (shape_flags ()); !i.at_end (); ++i) { - const T *ref = i->basic_ptr (typename T::tag ()); - scanner.insert (ref, id++); + scanner.insert (heap (*i), id++); } // TODO: can we confine this search to the subject's (sized) bounding box? @@ -1928,12 +1929,13 @@ struct scan_shape2shape_different_layers operator () (db::Layout *layout, const db::Shapes *subject_shapes, const db::Shapes *intruder_shapes, unsigned int subject_id0, const std::set *intruders, unsigned int intruder_layer_index, shape_interactions &interactions, db::Coord dist) const { db::box_scanner2 scanner; + db::addressable_object_from_shape sheap; + db::addressable_object_from_shape iheap; interaction_registration_shape2shape rec (layout, &interactions, intruder_layer_index); unsigned int id = subject_id0; for (db::Shapes::shape_iterator i = subject_shapes->begin (shape_flags ()); !i.at_end (); ++i, ++id) { - const TS *ref = i->basic_ptr (typename TS::tag ()); - scanner.insert1 (ref, id); + scanner.insert1 (sheap (*i), id); } // TODO: can we confine this search to the subject's (sized) bounding box? @@ -1952,7 +1954,7 @@ struct scan_shape2shape_different_layers unsigned int id = subject_id0; for (db::Shapes::shape_iterator i = intruder_shapes->begin (shape_flags ()); !i.at_end (); ++i, ++id) { unsigned int iid = interactions.next_id (); - scanner.insert2 (i->basic_ptr (typename TI::tag ()), iid); + scanner.insert2 (iheap (*i), iid); rec.same (id, iid); } @@ -1960,7 +1962,7 @@ struct scan_shape2shape_different_layers // TODO: can we confine this search to the subject's (sized) bounding box? for (db::Shapes::shape_iterator i = intruder_shapes->begin (shape_flags ()); !i.at_end (); ++i) { - scanner.insert2 (i->basic_ptr (typename TI::tag ()), interactions.next_id ()); + scanner.insert2 (iheap (*i), interactions.next_id ()); } } @@ -1976,6 +1978,7 @@ void local_processor::compute_local_cell (const db::local_processor_contexts &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const local_operation *op, const typename local_processor_cell_contexts::context_key_type &intruders, std::vector > &result) const { const db::Shapes *subject_shapes = &subject_cell->shapes (contexts.subject_layer ()); + db::shape_to_object s2o; shape_interactions interactions; @@ -1990,8 +1993,7 @@ local_processor::compute_local_cell (const db::local_processor_conte } if (op->on_empty_intruder_hint () != OnEmptyIntruderHint::Drop) { - const TS *ref = i->basic_ptr (typename TS::tag ()); - interactions.add_subject (id, *ref); + interactions.add_subject (id, s2o (*i)); } } @@ -2035,11 +2037,12 @@ local_processor::compute_local_cell (const db::local_processor_conte if (! subject_shapes->empty () && ! ((! intruder_cell || intruder_cell->begin ().at_end ()) && intruders.first.empty ())) { db::box_scanner2 scanner; + db::addressable_object_from_shape heap; interaction_registration_shape2inst rec (mp_subject_layout, mp_intruder_layout, ail, il_index, op->dist (), &interactions); unsigned int id = subject_id0; for (db::Shapes::shape_iterator i = subject_shapes->begin (shape_flags ()); !i.at_end (); ++i) { - scanner.insert1 (i->basic_ptr (typename TS::tag ()), id++); + scanner.insert1 (heap (*i), id++); } unsigned int inst_id = 0; @@ -2414,7 +2417,7 @@ template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; -template class DB_PUBLIC local_processor; +template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; diff --git a/src/db/db/dbLocalOperation.cc b/src/db/db/dbLocalOperation.cc index d5c2573f8..5cfbf535d 100644 --- a/src/db/db/dbLocalOperation.cc +++ b/src/db/db/dbLocalOperation.cc @@ -29,10 +29,12 @@ #include "dbPolygonTools.h" #include "dbLocalOperationUtils.h" #include "dbEdgeBoolean.h" +#include "dbLayoutUtils.h" #include "tlLog.h" #include "tlTimer.h" #include "tlInternational.h" #include "tlProgress.h" +#include "tlSList.h" namespace db { @@ -92,7 +94,7 @@ template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; -template class DB_PUBLIC local_operation; +template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; @@ -188,6 +190,127 @@ BoolAndOrNotLocalOperation::do_compute_local (db::Layout *layout, const shape_in } } +// --------------------------------------------------------------------------------------------- +// BoolAndOrNotLocalOperationWithProperties implementation + +BoolAndOrNotLocalOperationWithProperties::BoolAndOrNotLocalOperationWithProperties (bool is_and, const db::Layout *subject_layout, const db::Layout *intruder_layout, db::PropertyConstraint property_constraint) + : m_is_and (is_and), m_property_constraint (property_constraint), mp_subject_layout (subject_layout), mp_intruder_layout (intruder_layout) +{ + // .. nothing yet .. +} + +OnEmptyIntruderHint +BoolAndOrNotLocalOperationWithProperties::on_empty_intruder_hint () const +{ + return m_is_and ? Drop : Copy; +} + +std::string +BoolAndOrNotLocalOperationWithProperties::description () const +{ + return m_is_and ? tl::to_string (tr ("AND operation")) : tl::to_string (tr ("NOT operation")); +} + +void +BoolAndOrNotLocalOperationWithProperties::do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const +{ + db::PropertyMapper pms (*layout, *mp_subject_layout); + db::PropertyMapper pmi (*layout, *mp_intruder_layout); + + // @@@ TODO: implement different property constraint etc. + + tl_assert (results.size () == 1); + std::unordered_set &result = results.front (); + + db::EdgeProcessor ep; + + std::map, std::set > > by_prop_id; + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + const db::PolygonRefWithProperties &subject = interactions.subject_shape (i->first); + + if (i->second.empty ()) { + + if (! m_is_and) { + result.insert (db::PolygonRefWithProperties (subject, pms (subject.properties_id ()))); + } + + } else { + + db::properties_id_type prop_id_s = (m_property_constraint != db::NoPropertyConstraint ? pms (subject.properties_id ()) : 0); + + std::pair, std::set > &shapes_by_prop = by_prop_id [prop_id_s]; + shapes_by_prop.first.push_front (subject); + + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + const db::PolygonRefWithProperties &intruder = interactions.intruder_shape (*j).second; + db::properties_id_type prop_id_i = (m_property_constraint != db::NoPropertyConstraint ? pmi (intruder.properties_id ()) : 0); + if ((prop_id_i != prop_id_s) == (m_property_constraint == db::DifferentPropertiesConstraint)) { + shapes_by_prop.second.insert (intruder); + } + } + + } + + } + + for (auto p2s = by_prop_id.begin (); p2s != by_prop_id.end (); ++p2s) { + + ep.clear (); + size_t p1 = 0, p2 = 1; + + const std::set &others = p2s->second.second; + db::properties_id_type prop_id = p2s->first; + + for (auto s = p2s->second.first.begin (); s != p2s->second.first.end (); ++s) { + + const db::PolygonRef &subject = *s; + if (others.find (subject) != others.end ()) { + if (m_is_and) { + result.insert (db::PolygonRefWithProperties (subject, prop_id)); + } + } else if (others.empty ()) { + // shortcut (not: keep, and: drop) + if (! m_is_and) { + result.insert (db::PolygonRefWithProperties (subject, prop_id)); + } + } else { + for (db::PolygonRef::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end(); ++e) { + ep.insert (*e, p1); + } + p1 += 2; + } + + } + + if (! others.empty () && p1 > 0) { + + for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { + for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end(); ++e) { + ep.insert (*e, p2); + } + p2 += 2; + } + + std::unordered_set result_wo_props; + + db::BooleanOp op (m_is_and ? db::BooleanOp::And : db::BooleanOp::ANotB); + db::PolygonRefGenerator pr (layout, result_wo_props); + db::PolygonSplitter splitter (pr, area_ratio, max_vertex_count); + db::PolygonGenerator pg (splitter, true, true); + ep.set_base_verbosity (50); + ep.process (pg, op); + + for (auto r = result_wo_props.begin (); r != result_wo_props.end (); ++r) { + result.insert (db::PolygonRefWithProperties (*r, prop_id)); + } + + } + + } +} + // --------------------------------------------------------------------------------------------- // TwoBoolAndNotLocalOperation implementation diff --git a/src/db/db/dbLocalOperation.h b/src/db/db/dbLocalOperation.h index 3907fbfc3..4982b6d4d 100644 --- a/src/db/db/dbLocalOperation.h +++ b/src/db/db/dbLocalOperation.h @@ -30,6 +30,7 @@ #include "dbLayout.h" #include "dbEdgeBoolean.h" #include "dbEdgeProcessor.h" +#include "dbPropertyConstraint.h" #include #include @@ -146,6 +147,25 @@ private: bool m_is_and; }; +/** + * @brief Implements a boolean AND or NOT operation + */ +class DB_PUBLIC BoolAndOrNotLocalOperationWithProperties + : public local_operation +{ +public: + BoolAndOrNotLocalOperationWithProperties (bool is_and, const db::Layout *subject_layout, const db::Layout *intruder_layout, db::PropertyConstraint property_constraint); + + virtual void do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &result, size_t max_vertex_count, double area_ratio) const; + virtual OnEmptyIntruderHint on_empty_intruder_hint () const; + virtual std::string description () const; + +private: + bool m_is_and; + db::PropertyConstraint m_property_constraint; + const db::Layout *mp_subject_layout, *mp_intruder_layout; +}; + /** * @brief Implements a boolean AND plus NOT operation * diff --git a/src/db/db/dbNetShape.h b/src/db/db/dbNetShape.h index 05f98c8da..652578c87 100644 --- a/src/db/db/dbNetShape.h +++ b/src/db/db/dbNetShape.h @@ -27,6 +27,9 @@ #include "dbText.h" #include "dbShapeRepository.h" #include "dbBoxConvert.h" +#include "dbShape.h" +#include "dbShapeFlags.h" // for addressable_object_from_shape +#include "tlSList.h" namespace db { @@ -172,6 +175,28 @@ struct box_convert } }; +template <> +struct addressable_object_from_shape +{ + typedef db::NetShape value_type; + + const value_type *operator () (const db::Shape &shape) + { + if (shape.type () == db::Shape::TextRef) { + m_heap.push_back (db::NetShape (shape.text_ref ())); + return &m_heap.back (); + } else if (shape.type () == db::Shape::PolygonRef) { + m_heap.push_back (db::NetShape (shape.polygon_ref ())); + return &m_heap.back (); + } else { + tl_assert (false); + } + } + +private: + tl::slist m_heap; +}; + } #endif diff --git a/src/db/db/dbPropertyConstraint.h b/src/db/db/dbPropertyConstraint.h new file mode 100644 index 000000000..c461ba08b --- /dev/null +++ b/src/db/db/dbPropertyConstraint.h @@ -0,0 +1,57 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2023 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 + +*/ + + + +#ifndef HDR_dbPropertyConstraint +#define HDR_dbPropertyConstraint + +#include "dbCommon.h" + +namespace db +{ + +/** + * @brief Specifies a property constraint for some operations + */ +enum PropertyConstraint +{ + /** + * @brief No constraint, shapes are processed regardless of their properties + */ + NoPropertyConstraint = 0, + + /** + * @brief Shapes are processed if their properties are the same + */ + SamePropertiesConstraint = 1, + + /** + * @brief Shapes are processed if their properties are different + */ + DifferentPropertiesConstraint = 2 +}; + +} + +#endif + diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index a2d40ae01..0594930a3 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -1036,7 +1036,15 @@ public: */ Region operator& (const Region &other) const { - return Region (mp_delegate->and_with (other)); + return Region (mp_delegate->and_with (other, db::NoPropertyConstraint)); + } + + /** + * @brief Boolean AND operator with options + */ + Region bool_and (const Region &other, PropertyConstraint prop_constraint = db::NoPropertyConstraint) const + { + return Region (mp_delegate->and_with (other, prop_constraint)); } /** @@ -1047,7 +1055,19 @@ public: */ Region &operator&= (const Region &other) { - set_delegate (mp_delegate->and_with (other)); + set_delegate (mp_delegate->and_with (other, db::NoPropertyConstraint)); + return *this; + } + + /** + * @brief In-place boolean AND operator with options + * + * This method does not necessarily merge the region. To ensure the region + * is merged, call merge afterwards. + */ + Region &bool_and_with (const Region &other, PropertyConstraint prop_constraint = db::NoPropertyConstraint) + { + set_delegate (mp_delegate->and_with (other, prop_constraint)); return *this; } @@ -1056,7 +1076,15 @@ public: */ Region operator- (const Region &other) const { - return Region (mp_delegate->not_with (other)); + return Region (mp_delegate->not_with (other, db::NoPropertyConstraint)); + } + + /** + * @brief Boolean NOT operator with options + */ + Region bool_not (const Region &other, PropertyConstraint prop_constraint = db::NoPropertyConstraint) const + { + return Region (mp_delegate->not_with (other, prop_constraint)); } /** @@ -1067,7 +1095,19 @@ public: */ Region &operator-= (const Region &other) { - set_delegate (mp_delegate->not_with (other)); + set_delegate (mp_delegate->not_with (other, db::NoPropertyConstraint)); + return *this; + } + + /** + * @brief In-place boolean NOT operator with options + * + * This method does not necessarily merge the region. To ensure the region + * is merged, call merge afterwards. + */ + Region bool_not_with (const Region &other, PropertyConstraint prop_constraint = db::NoPropertyConstraint) + { + set_delegate (mp_delegate->not_with (other, prop_constraint)); return *this; } @@ -1134,9 +1174,9 @@ public: * * The first region delivered will be the AND result, the second one the NOT result. */ - std::pair andnot (const Region &other) const + std::pair andnot (const Region &other, PropertyConstraint prop_constraint = db::NoPropertyConstraint) const { - std::pair res = mp_delegate->andnot_with (other); + std::pair res = mp_delegate->andnot_with (other, prop_constraint); return std::make_pair (Region (res.first), Region (res.second)); } diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index a04add0d9..bb34426b1 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -273,13 +273,13 @@ public: virtual RegionDelegate *sized (coord_type d, unsigned int mode) const = 0; virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const = 0; - virtual RegionDelegate *and_with (const Region &other) const = 0; - virtual RegionDelegate *not_with (const Region &other) const = 0; + virtual RegionDelegate *and_with (const Region &other, PropertyConstraint prop_constraint) const = 0; + virtual RegionDelegate *not_with (const Region &other, PropertyConstraint prop_constraint) const = 0; virtual RegionDelegate *xor_with (const Region &other) const = 0; virtual RegionDelegate *or_with (const Region &other) const = 0; virtual RegionDelegate *add_in_place (const Region &other) = 0; virtual RegionDelegate *add (const Region &other) const = 0; - virtual std::pair andnot_with (const Region &other) const = 0; + virtual std::pair andnot_with (const Region &other, PropertyConstraint prop_constraint) const = 0; virtual RegionDelegate *selected_outside (const Region &other) const = 0; virtual RegionDelegate *selected_not_outside (const Region &other) const = 0; diff --git a/src/db/db/dbRegionLocalOperations.h b/src/db/db/dbRegionLocalOperations.h index e2b9a1f59..60289d003 100644 --- a/src/db/db/dbRegionLocalOperations.h +++ b/src/db/db/dbRegionLocalOperations.h @@ -29,6 +29,7 @@ #include "dbLocalOperation.h" #include "dbEdgeProcessor.h" #include "dbRegionCheckUtils.h" +#include "dbPropertyConstraint.h" #include #include diff --git a/src/db/db/dbShapeFlags.h b/src/db/db/dbShapeFlags.h index 5c2b46e03..e97faf416 100644 --- a/src/db/db/dbShapeFlags.h +++ b/src/db/db/dbShapeFlags.h @@ -26,71 +26,134 @@ #include "dbCommon.h" #include "dbShapes.h" +#include "tlSList.h" namespace db { -template unsigned int shape_flags (); -template unsigned int shape_flags_pure (); - -template <> inline unsigned int shape_flags () { return 1 << db::ShapeIterator::PolygonRef; } -template <> inline unsigned int shape_flags_pure () { return 1 << db::ShapeIterator::PolygonRef; } - -template <> inline unsigned int shape_flags () { return 1 << db::ShapeIterator::TextRef; } -template <> inline unsigned int shape_flags_pure () { return 1 << db::ShapeIterator::TextRef; } - -template <> inline unsigned int shape_flags () { return db::ShapeIterator::Boxes; } -template <> inline unsigned int shape_flags_pure () { return 1 << db::ShapeIterator::Box; } - -template <> inline unsigned int shape_flags () { return db::ShapeIterator::Paths; } -template <> inline unsigned int shape_flags_pure () { return 1 << db::ShapeIterator::Path; } - -template <> inline unsigned int shape_flags () { return db::ShapeIterator::Polygons; } -template <> inline unsigned int shape_flags_pure () { return 1 << db::ShapeIterator::Polygon; } - -template <> inline unsigned int shape_flags () { return db::ShapeIterator::Edges; } -template <> inline unsigned int shape_flags_pure () { return 1 << db::ShapeIterator::Edge; } - -template <> inline unsigned int shape_flags () { return db::ShapeIterator::EdgePairs; } -template <> inline unsigned int shape_flags_pure () { return 1 << db::ShapeIterator::EdgePair; } - -template <> inline unsigned int shape_flags () { return db::ShapeIterator::Texts; } -template <> inline unsigned int shape_flags_pure () { return 1 << db::ShapeIterator::Text; } - -template <> inline unsigned int shape_flags () { return db::ShapeIterator::Properties | shape_flags_pure (); } -template <> inline unsigned int shape_flags_pure () { return db::ShapeIterator::Properties | shape_flags_pure (); } - -template <> inline unsigned int shape_flags () { return db::ShapeIterator::Properties | shape_flags_pure (); } -template <> inline unsigned int shape_flags_pure () { return db::ShapeIterator::Properties | shape_flags_pure (); } - -template <> inline unsigned int shape_flags () { return db::ShapeIterator::Properties | shape_flags_pure (); } -template <> inline unsigned int shape_flags_pure () { return db::ShapeIterator::Properties | shape_flags_pure (); } - -template <> inline unsigned int shape_flags () { return db::ShapeIterator::Properties | shape_flags_pure (); } -template <> inline unsigned int shape_flags_pure () { return db::ShapeIterator::Properties | shape_flags_pure (); } - -template <> inline unsigned int shape_flags () { return db::ShapeIterator::Properties | shape_flags_pure (); } -template <> inline unsigned int shape_flags_pure () { return db::ShapeIterator::Properties | shape_flags_pure (); } - -template <> inline unsigned int shape_flags () { return db::ShapeIterator::Properties | shape_flags_pure (); } -template <> inline unsigned int shape_flags_pure () { return db::ShapeIterator::Properties | shape_flags_pure (); } - -template <> inline unsigned int shape_flags () { return db::ShapeIterator::Properties | shape_flags_pure (); } -template <> inline unsigned int shape_flags_pure () { return db::ShapeIterator::Properties | shape_flags_pure (); } - -template <> inline unsigned int shape_flags () { return db::ShapeIterator::Properties | shape_flags_pure (); } -template <> inline unsigned int shape_flags_pure () { return db::ShapeIterator::Properties | shape_flags_pure (); } - template -struct DB_PUBLIC shape_to_object +struct shape_flags_traits { - void set (const db::Shape &) { } - const T *get (const db::Shape &s) const { return s.basic_ptr (typename T::tag ()); } + static unsigned int generic () { return 0; } + static unsigned int pure () { return 0; } }; +template <> +struct shape_flags_traits +{ + static unsigned int generic () { return 1 << db::ShapeIterator::PolygonRef; } + static unsigned int pure () { return 1 << db::ShapeIterator::PolygonRef; } +}; template <> -struct DB_PUBLIC shape_to_object +struct shape_flags_traits +{ + static unsigned int generic () { return 1 << db::ShapeIterator::TextRef; } + static unsigned int pure () { return 1 << db::ShapeIterator::TextRef; } +}; + +template <> +struct shape_flags_traits +{ + static unsigned int generic () { return db::ShapeIterator::Boxes; } + static unsigned int pure () { return 1 << db::ShapeIterator::Box; } +}; + +template <> +struct shape_flags_traits +{ + static unsigned int generic () { return db::ShapeIterator::Paths; } + static unsigned int pure () { return 1 << db::ShapeIterator::Path; } +}; + +template <> +struct shape_flags_traits +{ + static unsigned int generic () { return db::ShapeIterator::Polygons; } + static unsigned int pure () { return 1 << db::ShapeIterator::Polygon; } +}; + +template <> +struct shape_flags_traits +{ + static unsigned int generic () { return db::ShapeIterator::Polygons; } + static unsigned int pure () { return 1 << db::ShapeIterator::SimplePolygon; } +}; + +template <> +struct shape_flags_traits +{ + static unsigned int generic () { return db::ShapeIterator::Edges; } + static unsigned int pure () { return 1 << db::ShapeIterator::Edge; } +}; + +template <> +struct shape_flags_traits +{ + static unsigned int generic () { return db::ShapeIterator::EdgePairs; } + static unsigned int pure () { return 1 << db::ShapeIterator::EdgePair; } +}; + +template <> +struct shape_flags_traits +{ + static unsigned int generic () { return db::ShapeIterator::Texts; } + static unsigned int pure () { return 1 << db::ShapeIterator::Text; } +}; + +template +struct shape_flags_traits > +{ + static unsigned int generic () { return shape_flags_traits::generic (); } + static unsigned int pure () { return shape_flags_traits::pure (); } +}; + +template unsigned int shape_flags () { return shape_flags_traits::generic (); } +template unsigned int shape_flags_pure () { return shape_flags_traits::pure (); } + +/** + * @brief Converter helpers for changing a shape to an object of a specific type + * + * These converters a volatile. The pointer delivered is not valid after the next object has + * been retrieved. + */ + +template +struct DB_PUBLIC shape_to_object_impl +{ + typedef T value_type; + + void set (const db::Shape &) { } + const value_type *get (const db::Shape &s) const { return s.basic_ptr (typename T::tag ()); } +}; + +template +struct DB_PUBLIC shape_to_object_impl > +{ + typedef db::object_with_properties value_type; + + void set (const db::Shape &s) + { + if (! s.has_prop_id ()) { + m_shape = value_type (*s.basic_ptr (typename T::tag ()), 0); + } + } + + const value_type *get (const db::Shape &s) const + { + if (! s.has_prop_id ()) { + return &m_shape; + } else { + return s.basic_ptr (typename value_type::tag ()); + } + } + +private: + value_type m_shape; +}; + +template <> +struct DB_PUBLIC shape_to_object_impl { typedef db::Polygon value_type; @@ -102,7 +165,27 @@ private: }; template <> -struct DB_PUBLIC shape_to_object +struct DB_PUBLIC shape_to_object_impl +{ + typedef db::PolygonWithProperties value_type; + + void set (const db::Shape &s) + { + s.polygon (m_shape); + m_shape.properties_id (s.prop_id ()); + } + + const value_type *get (const db::Shape &) const + { + return &m_shape; + } + +private: + value_type m_shape; +}; + +template <> +struct DB_PUBLIC shape_to_object_impl { typedef db::SimplePolygon value_type; @@ -114,7 +197,27 @@ private: }; template <> -struct DB_PUBLIC shape_to_object +struct DB_PUBLIC shape_to_object_impl +{ + typedef db::SimplePolygonWithProperties value_type; + + void set (const db::Shape &s) + { + s.simple_polygon (m_shape); + m_shape.properties_id (s.prop_id ()); + } + + const value_type *get (const db::Shape &) const + { + return &m_shape; + } + +private: + value_type m_shape; +}; + +template <> +struct DB_PUBLIC shape_to_object_impl { typedef db::Path value_type; @@ -126,7 +229,27 @@ private: }; template <> -struct DB_PUBLIC shape_to_object +struct DB_PUBLIC shape_to_object_impl +{ + typedef db::PathWithProperties value_type; + + void set (const db::Shape &s) + { + s.path (m_shape); + m_shape.properties_id (s.prop_id ()); + } + + const value_type *get (const db::Shape &) const + { + return &m_shape; + } + +private: + value_type m_shape; +}; + +template <> +struct DB_PUBLIC shape_to_object_impl { typedef db::Text value_type; @@ -138,17 +261,395 @@ private: }; template <> -struct DB_PUBLIC shape_to_object +struct DB_PUBLIC shape_to_object_impl +{ + typedef db::TextWithProperties value_type; + + void set (const db::Shape &s) + { + s.text (m_shape); + m_shape.properties_id (s.prop_id ()); + } + + const value_type *get (const db::Shape &) const + { + return &m_shape; + } + +private: + value_type m_shape; +}; + +template <> +struct DB_PUBLIC shape_to_object_impl { typedef db::Box value_type; - void set (const db::Shape *s) { s->box (m_shape); } + void set (const db::Shape &s) { s.box (m_shape); } const value_type *get (const db::Shape *) const { return &m_shape; } private: value_type m_shape; }; +template <> +struct DB_PUBLIC shape_to_object_impl +{ + typedef db::BoxWithProperties value_type; + + void set (const db::Shape &s) + { + s.box (m_shape); + m_shape.properties_id (s.prop_id ()); + } + + const value_type *get (const db::Shape &) const + { + return &m_shape; + } + +private: + value_type m_shape; +}; + +template +struct DB_PUBLIC shape_to_object + : public shape_to_object_impl +{ + const typename shape_to_object_impl::value_type &operator() (const db::Shape &s) + { + shape_to_object_impl::set (s); + return *shape_to_object_impl::get (s); + } +}; + +/** + * @brief Implements an addressable object heap + * + * This object can deliver addressable objects from shapes. It will keep temporary objects + * internally if required. + */ + +template +struct addressable_object_from_shape +{ + typedef T value_type; + + const T *operator () (const db::Shape &shape) + { + typename T::tag object_tag; + return shape.basic_ptr (object_tag); + } +}; + +template +struct addressable_object_from_shape > +{ + typedef db::object_with_properties value_type; + + const db::object_with_properties *operator () (const db::Shape &shape) + { + if (shape.has_prop_id ()) { + typename db::object_with_properties::tag object_tag; + return shape.basic_ptr (object_tag); + } else { + typename T::tag object_tag; + m_heap.push_back (db::object_with_properties (*shape.basic_ptr (object_tag), 0)); + return &m_heap.back (); + } + } + +private: + tl::slist > m_heap; +}; + +template <> +struct addressable_object_from_shape +{ + typedef db::Box value_type; + + const value_type *operator () (const db::Shape &shape) + { + if (shape.type () == db::Shape::Box) { + return shape.basic_ptr (value_type::tag ()); + } else { + m_heap.push_front (value_type ()); + shape.box (m_heap.front ()); + return &m_heap.front (); + } + } + +private: + tl::slist m_heap; +}; + +template <> +struct addressable_object_from_shape +{ + typedef db::BoxWithProperties value_type; + + const value_type *operator () (const db::Shape &shape) + { + if (shape.has_prop_id () && shape.type () == db::Shape::Box) { + return shape.basic_ptr (value_type::tag ()); + } else { + m_heap.push_front (value_type ()); + shape.box (m_heap.front ()); + m_heap.front ().properties_id (shape.prop_id ()); + return &m_heap.front (); + } + } + +private: + tl::slist m_heap; +}; + +template <> +struct addressable_object_from_shape +{ + typedef db::Polygon value_type; + + const value_type *operator () (const db::Shape &shape) + { + if (shape.type () == db::Shape::Polygon) { + return shape.basic_ptr (value_type::tag ()); + } else { + m_heap.push_front (value_type ()); + shape.polygon (m_heap.front ()); + return &m_heap.front (); + } + } + +private: + tl::slist m_heap; +}; + +template <> +struct addressable_object_from_shape +{ + typedef db::PolygonWithProperties value_type; + + const value_type *operator () (const db::Shape &shape) + { + if (shape.has_prop_id () && shape.type () == db::Shape::Polygon) { + return shape.basic_ptr (value_type::tag ()); + } else { + m_heap.push_front (value_type ()); + shape.polygon (m_heap.front ()); + m_heap.front ().properties_id (shape.prop_id ()); + return &m_heap.front (); + } + } + +private: + tl::slist m_heap; +}; + +template <> +struct addressable_object_from_shape +{ + typedef db::SimplePolygon value_type; + + const value_type *operator () (const db::Shape &shape) + { + if (shape.type () == db::Shape::SimplePolygon) { + return shape.basic_ptr (value_type::tag ()); + } else { + m_heap.push_front (value_type ()); + shape.simple_polygon (m_heap.front ()); + return &m_heap.front (); + } + } + +private: + tl::slist m_heap; +}; + +template <> +struct addressable_object_from_shape +{ + typedef db::SimplePolygonWithProperties value_type; + + const value_type *operator () (const db::Shape &shape) + { + if (shape.has_prop_id () && shape.type () == db::Shape::SimplePolygon) { + return shape.basic_ptr (value_type::tag ()); + } else { + m_heap.push_front (value_type ()); + shape.simple_polygon (m_heap.front ()); + m_heap.front ().properties_id (shape.prop_id ()); + return &m_heap.front (); + } + } + +private: + tl::slist m_heap; +}; + +template <> +struct addressable_object_from_shape +{ + typedef db::Path value_type; + + const value_type *operator () (const db::Shape &shape) + { + if (shape.type () == db::Shape::Path) { + return shape.basic_ptr (value_type::tag ()); + } else { + m_heap.push_front (value_type ()); + shape.path (m_heap.front ()); + return &m_heap.front (); + } + } + +private: + tl::slist m_heap; +}; + +template <> +struct addressable_object_from_shape +{ + typedef db::PathWithProperties value_type; + + const value_type *operator () (const db::Shape &shape) + { + if (shape.has_prop_id () && shape.type () == db::Shape::Path) { + return shape.basic_ptr (value_type::tag ()); + } else { + m_heap.push_front (value_type ()); + shape.path (m_heap.front ()); + m_heap.front ().properties_id (shape.prop_id ()); + return &m_heap.front (); + } + } + +private: + tl::slist m_heap; +}; + +template <> +struct addressable_object_from_shape +{ + typedef db::Edge value_type; + + const value_type *operator () (const db::Shape &shape) + { + if (shape.type () == db::Shape::Edge) { + return shape.basic_ptr (value_type::tag ()); + } else { + m_heap.push_front (value_type ()); + shape.edge (m_heap.front ()); + return &m_heap.front (); + } + } + +private: + tl::slist m_heap; +}; + +template <> +struct addressable_object_from_shape +{ + typedef db::EdgeWithProperties value_type; + + const value_type *operator () (const db::Shape &shape) + { + if (shape.has_prop_id () && shape.type () == db::Shape::Edge) { + return shape.basic_ptr (value_type::tag ()); + } else { + m_heap.push_front (value_type ()); + shape.edge (m_heap.front ()); + m_heap.front ().properties_id (shape.prop_id ()); + return &m_heap.front (); + } + } + +private: + tl::slist m_heap; +}; + +template <> +struct addressable_object_from_shape +{ + typedef db::EdgePair value_type; + + const value_type *operator () (const db::Shape &shape) + { + if (shape.type () == db::Shape::EdgePair) { + return shape.basic_ptr (value_type::tag ()); + } else { + m_heap.push_front (value_type ()); + shape.edge_pair (m_heap.front ()); + return &m_heap.front (); + } + } + +private: + tl::slist m_heap; +}; + +template <> +struct addressable_object_from_shape +{ + typedef db::EdgePairWithProperties value_type; + + const value_type *operator () (const db::Shape &shape) + { + if (shape.has_prop_id () && shape.type () == db::Shape::EdgePair) { + return shape.basic_ptr (value_type::tag ()); + } else { + m_heap.push_front (value_type ()); + shape.edge_pair (m_heap.front ()); + m_heap.front ().properties_id (shape.prop_id ()); + return &m_heap.front (); + } + } + +private: + tl::slist m_heap; +}; + +template <> +struct addressable_object_from_shape +{ + typedef db::Text value_type; + + const value_type *operator () (const db::Shape &shape) + { + if (shape.type () == db::Shape::Text) { + return shape.basic_ptr (value_type::tag ()); + } else { + m_heap.push_front (value_type ()); + shape.text (m_heap.front ()); + return &m_heap.front (); + } + } + +private: + tl::slist m_heap; +}; + +template <> +struct addressable_object_from_shape +{ + typedef db::TextWithProperties value_type; + + const value_type *operator () (const db::Shape &shape) + { + if (shape.has_prop_id () && shape.type () == db::Shape::Text) { + return shape.basic_ptr (value_type::tag ()); + } else { + m_heap.push_front (value_type ()); + shape.text (m_heap.front ()); + m_heap.front ().properties_id (shape.prop_id ()); + return &m_heap.front (); + } + } + +private: + tl::slist m_heap; +}; + } #endif diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 757e8d175..64dc161e6 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -619,9 +619,9 @@ static db::EdgePairs separation2 (const db::Region *r, const db::Region &other, ); } -static std::vector andnot (const db::Region *r, const db::Region &other) +static std::vector andnot (const db::Region *r, const db::Region &other, db::PropertyConstraint prop_constraint) { - return as_2region_vector (r->andnot (other)); + return as_2region_vector (r->andnot (other, prop_constraint)); } static std::vector split_inside (const db::Region *r, const db::Region &other) @@ -1595,7 +1595,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + - method_ext ("andnot", &andnot, gsi::arg ("other"), + method_ext ("andnot", &andnot, gsi::arg ("other"), gsi::arg ("property_constraint", db::NoPropertyConstraint), "@brief Returns the boolean AND and NOT between self and the other region\n" "\n" "@return A two-element array of regions with the first one being the AND result and the second one being the NOT result\n" @@ -1613,6 +1613,18 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "This method will compute the boolean AND (intersection) between two regions. " "The result is often but not necessarily always merged.\n" ) + + method ("and", &db::Region::bool_and, gsi::arg ("other"), gsi::arg ("property_constraint", db::NoPropertyConstraint), + "@brief Returns the boolean AND between self and the other region\n" + "\n" + "@return The result of the boolean AND operation\n" + "\n" + "This method will compute the boolean AND (intersection) between two regions. " + "The result is often but not necessarily always merged.\n" + "It allows specification of a property constaint - e.g. only performing the boolean operation between " + "shapes with the same user properties.\n" + "\n" + "This variant has been introduced in version 0.28.4." + ) + method ("&=", &db::Region::operator&=, gsi::arg ("other"), "@brief Performs the boolean AND between self and the other region\n" "\n" @@ -1621,6 +1633,18 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "This method will compute the boolean AND (intersection) between two regions. " "The result is often but not necessarily always merged.\n" ) + + method ("and_with", &db::Region::bool_and_with, gsi::arg ("other"), gsi::arg ("property_constraint", db::NoPropertyConstraint), + "@brief Performs the boolean AND between self and the other region\n" + "\n" + "@return The region after modification (self)\n" + "\n" + "This method will compute the boolean AND (intersection) between two regions. " + "The result is often but not necessarily always merged.\n" + "It allows specification of a property constaint - e.g. only performing the boolean operation between " + "shapes with the same user properties.\n" + "\n" + "This variant has been introduced in version 0.28.4." + ) + method ("-", &db::Region::operator-, gsi::arg ("other"), "@brief Returns the boolean NOT between self and the other region\n" "\n" @@ -1629,6 +1653,14 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "This method will compute the boolean NOT (intersection) between two regions. " "The result is often but not necessarily always merged.\n" ) + + method ("not", &db::Region::bool_not, gsi::arg ("other"), gsi::arg ("property_constraint", db::NoPropertyConstraint), + "@brief Returns the boolean NOT between self and the other region\n" + "\n" + "@return The result of the boolean NOT operation\n" + "\n" + "This method will compute the boolean NOT (intersection) between two regions. " + "The result is often but not necessarily always merged.\n" + ) + method ("-=", &db::Region::operator-=, gsi::arg ("other"), "@brief Performs the boolean NOT between self and the other region\n" "\n" @@ -1637,6 +1669,14 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "This method will compute the boolean NOT (intersection) between two regions. " "The result is often but not necessarily always merged.\n" ) + + method ("not_with", &db::Region::bool_not_with, gsi::arg ("other"), gsi::arg ("property_constraint", db::NoPropertyConstraint), + "@brief Performs the boolean NOT between self and the other region\n" + "\n" + "@return The region after modification (self)\n" + "\n" + "This method will compute the boolean NOT (intersection) between two regions. " + "The result is often but not necessarily always merged.\n" + ) + method ("^", &db::Region::operator^, gsi::arg ("other"), "@brief Returns the boolean XOR between self and the other region\n" "\n" @@ -3055,6 +3095,32 @@ gsi::EnumIn decl_Region_Metrics ("db", "Metrics", gsi::ClassExt inject_Metrics_in_parent (decl_Region_Metrics.defs ()); gsi::ClassExt inject_Metrics_in_Edges (decl_Region_Metrics.defs ()); +gsi::EnumIn decl_Region_PropertyConstraint ("db", "PropertyConstraint", + gsi::enum_const ("NoPropertyConstraint", db::NoPropertyConstraint, + "@brief Specifies not to apply any property constraint\n" + "When using this constraint - for example on a boolean operation - shapes are considered " + "regardless of their user properties." + ) + + gsi::enum_const ("SamePropertiesConstraint", db::SamePropertiesConstraint, + "@brief Specifies to consider shapes only if their user properties are the same\n" + "When using this constraint - for example on a boolean operation - shapes are considered " + "only if their user properties are the same." + ) + + gsi::enum_const ("DifferentPropertiesConstraint", db::DifferentPropertiesConstraint, + "@brief Specifies to consider shapes only if their user properties are different\n" + "When using this constraint - for example on a boolean operation - shapes are considered " + "only if their user properties are different." + ), + "@brief This class represents the property constraint for boolean and check functions.\n" + "\n" + "This enum has been introduced in version 0.28.4." +); + +// Inject the Region::PropertyConstraint declarations into Region and Edges: +// (Edges injection has to be done here because only here defs() is available) +gsi::ClassExt inject_PropertyConstraint_in_parent (decl_Region_PropertyConstraint.defs ()); +gsi::ClassExt inject_PropertyConstraint_in_Edges (decl_Region_PropertyConstraint.defs ()); + gsi::EnumIn decl_Region_RectFilter ("db", "RectFilter", gsi::enum_const ("NoRectFilter", db::RectFilter::NoRectFilter, "@brief Specifies no filtering" diff --git a/src/db/unit_tests/dbHierNetsProcessorTests.cc b/src/db/unit_tests/dbHierNetsProcessorTests.cc index 91b4d4441..a3faa6048 100644 --- a/src/db/unit_tests/dbHierNetsProcessorTests.cc +++ b/src/db/unit_tests/dbHierNetsProcessorTests.cc @@ -40,92 +40,6 @@ static unsigned int define_layer (db::Layout &ly, db::LayerMap &lmap, int gds_la return lid; } -class BoolBetweenNets - : public db::local_operation -{ -public: - BoolBetweenNets (bool is_and, bool connected) - : m_is_and (is_and), m_connected (connected) - { - // .. nothing yet .. - } - - db::OnEmptyIntruderHint - on_empty_intruder_hint () const - { - return m_is_and ? db::Drop : db::Copy; - } - - std::string - description () const - { - return m_is_and ? tl::to_string (tr ("AND operation")) : tl::to_string (tr ("NOT operation")); - } - - void - do_compute_local (db::Layout *layout, const db::shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const - { - tl_assert (results.size () == 1); - std::unordered_set &result = results.front (); - - db::EdgeProcessor ep; - - // NOTE: is guess we do not need to handle subject/subject interactions ... - for (auto i = interactions.begin (); i != interactions.end (); ++i) { - - const db::PolygonRefWithProperties &subject = interactions.subject_shape (i->first); - - bool any_intruder = false; - for (auto j = i->second.begin (); j != i->second.end () && ! any_intruder; ++j) { - const db::PolygonRefWithProperties &other = interactions.intruder_shape (*j).second; - any_intruder = ((other.properties_id () == subject.properties_id ()) == m_connected); - } - - if (! any_intruder) { - - // shortcut (not: keep, and: drop) - if (! m_is_and) { - result.insert (subject); - } - - } else { - - ep.clear (); - - for (db::PolygonRef::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end(); ++e) { - ep.insert (*e, 0); - } - - for (auto j = i->second.begin (); j != i->second.end (); ++j) { - - const db::PolygonRefWithProperties &other = interactions.intruder_shape (*j).second; - if ((other.properties_id () == subject.properties_id ()) == m_connected) { - for (db::PolygonRef::polygon_edge_iterator e = other.begin_edge (); ! e.at_end(); ++e) { - ep.insert (*e, 1); - } - } - - } - - db::BooleanOp op (m_is_and ? db::BooleanOp::And : db::BooleanOp::ANotB); - db::PolygonRefGenerator pr (layout, result); - db::PolygonSplitter splitter (pr, area_ratio, max_vertex_count); - db::PolygonGenerator pg (splitter, true, true); - ep.set_base_verbosity (50); - ep.process (pg, op); - - } - - } - - } - -private: - bool m_is_and; - bool m_connected; -}; - - TEST(0_Develop) { db::Layout ly; @@ -210,15 +124,26 @@ TEST(0_Develop) lmap_write [wvia1 = ly2.insert_layer (db::LayerProperties (16, 0))] = l2n.layer_by_name ("via1"); lmap_write [wmetal2 = ly2.insert_layer (db::LayerProperties (17, 0))] = l2n.layer_by_name ("metal2"); - l2n.build_all_nets (cm, ly2, lmap_write, "NET_", db::LayoutToNetlist::NetIDOnly, tl::Variant (), db::LayoutToNetlist::BNH_SubcircuitCells, "SC_", 0 /*don't produce devices*/); + l2n.build_all_nets (cm, ly2, lmap_write, "NET_", db::LayoutToNetlist::NetNameAndIDOnly, tl::Variant (1), db::LayoutToNetlist::BNH_SubcircuitCells, "SC_", 0 /*don't produce devices*/); - unsigned int out = ly2.insert_layer (db::LayerProperties (1000, 0)); + unsigned int out1 = ly2.insert_layer (db::LayerProperties (1000, 0)); + unsigned int out2 = ly2.insert_layer (db::LayerProperties (1001, 0)); + unsigned int out3 = ly2.insert_layer (db::LayerProperties (1002, 0)); - db::local_processor proc (&ly2, &top2); - BoolBetweenNets n2n (true, true); - proc.run (&n2n, wmetal1, wmetal2, out); + db::local_processor proc (&ly2, &top2); + { + db::BoolAndOrNotLocalOperationWithProperties n2n (true, &ly2, &ly2, db::SamePropertiesConstraint); + proc.run (&n2n, wmetal1, wmetal2, out1); + } + { + db::BoolAndOrNotLocalOperationWithProperties n2n (true, &ly2, &ly2, db::DifferentPropertiesConstraint); + proc.run (&n2n, wmetal1, wmetal2, out2); + } + { + db::BoolAndOrNotLocalOperationWithProperties n2n (true, &ly2, &ly2, db::NoPropertyConstraint); + proc.run (&n2n, wmetal1, wmetal2, out3); + } - // @@@ may no work correctly as we have used fake prop ids { db::SaveLayoutOptions options;