From 2b3a53b28515de2001bb58969fbb5b54f0573ee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20K=C3=B6fferlein?= Date: Sun, 5 Apr 2020 15:11:03 +0200 Subject: [PATCH 1/3] Implemented #521 (enhanced API for ObjectInstPath) (#532) --- src/edt/edt/gsiDeclEdt.cc | 34 ++++++++++++++++++++++++++-------- testdata/ruby/edtTest.rb | 4 ++++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/edt/edt/gsiDeclEdt.cc b/src/edt/edt/gsiDeclEdt.cc index b9f73c45b..3e4705043 100644 --- a/src/edt/edt/gsiDeclEdt.cc +++ b/src/edt/edt/gsiDeclEdt.cc @@ -125,6 +125,24 @@ static lay::ObjectInstPath *from_si (const db::RecursiveShapeIterator &si, int c return ip; } +static tl::Variant ip_layer (const lay::ObjectInstPath *ip) +{ + if (ip->is_cell_inst ()) { + return tl::Variant (); + } else { + return tl::Variant (ip->layer ()); + } +} + +static tl::Variant ip_shape (const lay::ObjectInstPath *ip) +{ + if (ip->is_cell_inst ()) { + return tl::Variant (); + } else { + return tl::Variant (ip->shape ()); + } +} + gsi::Class decl_ObjectInstPath ("lay", "ObjectInstPath", gsi::constructor ("new", &from_si, gsi::arg ("si"), gsi::arg ("cv_index"), "@brief Creates a new path object from a \\RecursiveShapeIterator\n" @@ -245,11 +263,11 @@ gsi::Class decl_ObjectInstPath ("lay", "ObjectInstPath", "\n" "The method has been introduced in version 0.25.\n" ) + - gsi::method ("layer", &lay::ObjectInstPath::layer, + gsi::method_ext ("layer", &ip_layer, "@brief Gets the layer index that describes which layer the selected shape is on\n" "\n" - "This method delivers valid results only for object selections that represent shapes, i.e for " - "which \\is_cell_inst? is false." + "Startiong with version 0.27, this method returns nil for this property if \\is_cell_inst? is false - " + "i.e. the selection does not represent a shape." ) + gsi::method ("layer=", &lay::ObjectInstPath::set_layer, gsi::arg ("layer_index"), "@brief Sets to the layer index that describes which layer the selected shape is on\n" @@ -259,15 +277,15 @@ gsi::Class decl_ObjectInstPath ("lay", "ObjectInstPath", "\n" "This method has been introduced in version 0.24." ) + - gsi::method ("shape", (const db::Shape &(lay::ObjectInstPath::*) () const) &lay::ObjectInstPath::shape, + gsi::method_ext ("shape", &ip_shape, "@brief Gets the selected shape\n" "\n" - "This method delivers valid results only for object selections that represent shapes, i.e for " - "which \\is_cell_inst? is false.\n" - "\n" "The shape object may be modified. This does not have an immediate effect on the selection. Instead, " "the selection must be set in the view using \\LayoutView#object_selection= or \\LayoutView#select_object.\n" - ) + + "\n" + "This method delivers valid results only for object selections that represent shapes. " + "Startiong with version 0.27, this method returns nil for this property if \\is_cell_inst? is false." + ) + gsi::method ("shape=", &lay::ObjectInstPath::set_shape, gsi::arg ("shape"), "@brief Sets the shape object that describes the selected shape geometrically\n" "\n" diff --git a/testdata/ruby/edtTest.rb b/testdata/ruby/edtTest.rb index 9bf30f603..dc69ca0ad 100644 --- a/testdata/ruby/edtTest.rb +++ b/testdata/ruby/edtTest.rb @@ -47,8 +47,12 @@ class EDT_TestClass < TestBase assert_equal(p.seq, 2) assert_equal(p.is_cell_inst?, true) + assert_equal(p.layer, nil) + assert_equal(p.shape, nil) p.layer = -1 assert_equal(p.is_cell_inst?, true) + assert_equal(p.layer, nil) + assert_equal(p.shape, nil) p.layer = 42 assert_equal(p.layer, 42) From 865076588bd966c6fcf57f19c0b3e09a8271a7e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20K=C3=B6fferlein?= Date: Sun, 5 Apr 2020 15:11:18 +0200 Subject: [PATCH 2/3] Fixed issue #530 (events are mentioned as getters two times) (#531) --- src/pya/pya/pyaModule.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pya/pya/pyaModule.cc b/src/pya/pya/pyaModule.cc index 1b1d7b6d4..fed005f65 100644 --- a/src/pya/pya/pyaModule.cc +++ b/src/pya/pya/pyaModule.cc @@ -2478,7 +2478,7 @@ PythonModule::make_classes (const char *mod_name) // then add normal methods - on name clash with properties make them a getter for (gsi::ClassBase::method_iterator m = (*c)->begin_methods (); m != (*c)->end_methods (); ++m) { - if (! (*m)->is_callback ()) { + if (! (*m)->is_callback () && ! (*m)->is_signal ()) { for (gsi::MethodBase::synonym_iterator syn = (*m)->begin_synonyms (); syn != (*m)->end_synonyms (); ++syn) { if (! syn->is_getter && ! syn->is_setter) { if ((*m)->end_arguments () - (*m)->begin_arguments () == 0 && mt->find_property ((*m)->is_static (), syn->name).first) { From c93db59e37f02ff27717d5284858c6c843df994b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20K=C3=B6fferlein?= Date: Sun, 5 Apr 2020 15:11:37 +0200 Subject: [PATCH 3/3] Fixed #524 (failed query leaves layout in invalid state) (#528) --- src/db/db/dbLayoutQuery.cc | 72 +++++++++++++++++++------ src/db/db/dbLayoutQuery.h | 25 ++------- src/db/unit_tests/dbLayoutQueryTests.cc | 24 +++++++++ 3 files changed, 85 insertions(+), 36 deletions(-) diff --git a/src/db/db/dbLayoutQuery.cc b/src/db/db/dbLayoutQuery.cc index 05f3aeef7..27ed3d8ad 100644 --- a/src/db/db/dbLayoutQuery.cc +++ b/src/db/db/dbLayoutQuery.cc @@ -2011,7 +2011,7 @@ private: // LayoutQueryIterator implementation LayoutQueryIterator::LayoutQueryIterator (const LayoutQuery &q, db::Layout *layout, tl::Eval *parent_eval, tl::AbsoluteProgress *progress) - : mp_q (const_cast (&q)), mp_layout (layout), m_eval (parent_eval), m_layout_ctx (layout, true /*can modify*/), mp_progress (progress) + : mp_q (const_cast (&q)), mp_layout (layout), m_eval (parent_eval), m_layout_ctx (layout, true /*can modify*/), mp_progress (progress), m_initialized (false) { m_eval.set_ctx_handler (&m_layout_ctx); m_eval.set_var ("layout", tl::Variant::make_variant_ref (layout)); @@ -2022,14 +2022,10 @@ LayoutQueryIterator::LayoutQueryIterator (const LayoutQuery &q, db::Layout *layo // Avoid update() calls while iterating in modifying mode mp_layout->update (); mp_layout->start_changes (); - - // NOTE: Stange - in modifying mode, init() will actually already execute the - // first modification. Hence start_changes() needs to be called before. - init (); } LayoutQueryIterator::LayoutQueryIterator (const LayoutQuery &q, const db::Layout *layout, tl::Eval *parent_eval, tl::AbsoluteProgress *progress) - : mp_q (const_cast (&q)), mp_layout (const_cast (layout)), m_eval (parent_eval), m_layout_ctx (layout), mp_progress (progress) + : mp_q (const_cast (&q)), mp_layout (const_cast (layout)), m_eval (parent_eval), m_layout_ctx (layout), mp_progress (progress), m_initialized (false) { // TODO: check whether the query is a modifying one (with .. do, delete) @@ -2039,8 +2035,6 @@ LayoutQueryIterator::LayoutQueryIterator (const LayoutQuery &q, const db::Layout m_eval.define_function (mp_q->property_name (i), new FilterStateFunction (i, &m_state)); } - init (); - // Avoid update() calls while iterating in modifying mode mp_layout->start_changes (); } @@ -2048,7 +2042,18 @@ LayoutQueryIterator::LayoutQueryIterator (const LayoutQuery &q, const db::Layout LayoutQueryIterator::~LayoutQueryIterator () { mp_layout->end_changes (); - cleanup (); + if (m_initialized) { + cleanup (); + } +} + +void +LayoutQueryIterator::ensure_initialized () +{ + if (! m_initialized) { + init (); + m_initialized = true; + } } void @@ -2080,17 +2085,51 @@ LayoutQueryIterator::cleanup () void LayoutQueryIterator::reset () { - // forces an update if required - mp_layout->end_changes (); - mp_layout->start_changes (); + if (m_initialized) { - cleanup (); - init (); + // forces an update if required + mp_layout->end_changes (); + mp_layout->start_changes (); + + cleanup (); + init (); + + } +} + +bool +LayoutQueryIterator::at_end () const +{ + const_cast (this)->ensure_initialized (); + return m_state.empty (); +} + +bool +LayoutQueryIterator::get (const std::string &name, tl::Variant &v) +{ + ensure_initialized (); + if (m_state.empty () || !m_state.back () || !mp_q->has_property (name)) { + return false; + } else { + return m_state.back ()->get_property (mp_q->property_by_name (name), v); + } +} + +bool +LayoutQueryIterator::get (unsigned int id, tl::Variant &v) +{ + ensure_initialized (); + if (m_state.empty () || !m_state.back ()) { + return false; + } else { + return m_state.back ()->get_property (id, v); + } } void LayoutQueryIterator::dump () const { + const_cast (this)->ensure_initialized (); mp_root_state->dump (); std::cout << std::endl; } @@ -2111,6 +2150,7 @@ LayoutQueryIterator::collect (FilterStateBase *state, std::set b (new FilterBracket (q)); if (ex.test ("instances")) { - ex.test ("of") && (ex.test ("cells") || ex.test ("cell")); + (ex.test ("of") || ex.test ("from")) && (ex.test ("cells") || ex.test ("cell")); // Because an array member cannot be modified we use ArrayInstances in the modification case always parse_cell_name_filter_seq (ex, q, b.get (), reading ? ExplodedInstances : ArrayInstances, reading); } else if (ex.test ("arrays")) { - ex.test ("of") && (ex.test ("cells") || ex.test ("cell")); + (ex.test ("of") || ex.test ("from")) && (ex.test ("cells") || ex.test ("cell")); parse_cell_name_filter_seq (ex, q, b.get (), ArrayInstances, reading); } else { ex.test ("cells") || ex.test ("cell"); diff --git a/src/db/db/dbLayoutQuery.h b/src/db/db/dbLayoutQuery.h index 4c65b004a..96b126914 100644 --- a/src/db/db/dbLayoutQuery.h +++ b/src/db/db/dbLayoutQuery.h @@ -598,10 +598,7 @@ public: /** * @brief Returns true if the iterator is at the end. */ - bool at_end () const - { - return m_state.empty (); - } + bool at_end () const; /** * @brief Increment the iterator: deliver the next state @@ -644,14 +641,7 @@ public: * @param v The value of the property * @return True, if the property could be delivered. */ - bool get (const std::string &name, tl::Variant &v) - { - if (m_state.empty () || !m_state.back () || !mp_q->has_property (name)) { - return false; - } else { - return m_state.back ()->get_property (mp_q->property_by_name (name), v); - } - } + bool get (const std::string &name, tl::Variant &v); /** * @brief Gets a property for the current state (property is given by ID). @@ -660,14 +650,7 @@ public: * @param v The value of the property * @return True, if the property could be delivered. */ - bool get (unsigned int id, tl::Variant &v) - { - if (m_state.empty () || !m_state.back ()) { - return false; - } else { - return m_state.back ()->get_property (id, v); - } - } + bool get (unsigned int id, tl::Variant &v); /** * @brief Get the eval object which provides access to the properties through expressions @@ -690,7 +673,9 @@ private: tl::Eval m_eval; db::LayoutContextHandler m_layout_ctx; tl::AbsoluteProgress *mp_progress; + bool m_initialized; + void ensure_initialized (); void collect (FilterStateBase *state, std::set &states); void next_up (bool skip); bool next_down (); diff --git a/src/db/unit_tests/dbLayoutQueryTests.cc b/src/db/unit_tests/dbLayoutQueryTests.cc index a89d712a4..d6214710f 100644 --- a/src/db/unit_tests/dbLayoutQueryTests.cc +++ b/src/db/unit_tests/dbLayoutQueryTests.cc @@ -1463,4 +1463,28 @@ TEST(62) std::string s = q2s_var (iq, "data"); EXPECT_EQ (s, "T2,T1,T1"); } + + { + // A non-executed query + db::LayoutQuery q ("select inst[\"text\"] from instances of ...* where cell_name ~ \"Basic.*\""); + db::LayoutQueryIterator iq (q, &g); + EXPECT_EQ (true, true); + } +} + +TEST(63) +{ + db::Layout g; + + // A failing query must not leave a layout under construction + try { + db::LayoutQuery q ("!not a valid query"); + db::LayoutQueryIterator iq (q, &g); + std::string s = q2s_var (iq, "data"); + EXPECT_EQ (true, false); + } catch (tl::Exception &ex) { + EXPECT_EQ (ex.msg (), "Expected a word or quoted string here: !not a val .."); + } + + EXPECT_EQ (g.under_construction (), false); }