From 2369c69f69b7f8c7be1fe15ece857aed043782d9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 26 Jul 2025 15:26:47 +0200 Subject: [PATCH] Implemented feature request: a method to clear properties on shapes, instances, cells and layout --- src/db/db/dbInstances.cc | 30 +++++++-- src/db/db/dbInstances.h | 7 +++ src/db/db/dbPropertiesRepository.cc | 11 ++++ src/db/db/dbPropertiesRepository.h | 5 ++ src/db/db/dbShape.h | 12 ---- src/db/db/dbShapes.cc | 94 ++++++++++++++++++++++++++++- src/db/db/dbShapes.h | 15 ++++- src/db/db/gsiDeclDbCell.cc | 57 +++++++++++++++++ src/db/db/gsiDeclDbLayout.cc | 52 +++++++++++----- src/db/db/gsiDeclDbShape.cc | 30 +++++++++ src/db/unit_tests/dbShapesTests.cc | 12 ++-- testdata/ruby/dbInstanceTest.rb | 35 +++++++++++ testdata/ruby/dbLayoutTests2.rb | 13 ++++ testdata/ruby/dbShapesTest.rb | 7 +++ 14 files changed, 337 insertions(+), 43 deletions(-) diff --git a/src/db/db/dbInstances.cc b/src/db/db/dbInstances.cc index 697e42c33..02ca1e743 100644 --- a/src/db/db/dbInstances.cc +++ b/src/db/db/dbInstances.cc @@ -1611,10 +1611,8 @@ Instances::replace_prop_id (const instance_type &ref, db::properties_id_type pro throw tl::Exception (tl::to_string (tr ("Trying to replace an object in a list that it does not belong to"))); } - if (! ref.is_null ()) { - if (ref.prop_id () != prop_id) { - invalidate_prop_ids (); - } + if (! ref.is_null () && (!ref.has_prop_id () || ref.prop_id () != prop_id)) { + invalidate_prop_ids (); cell_inst_wp_array_type new_inst (ref.cell_inst (), prop_id); return replace (ref, new_inst); } else { @@ -1622,7 +1620,29 @@ Instances::replace_prop_id (const instance_type &ref, db::properties_id_type pro } } -void +Instances::instance_type +Instances::clear_properties (const instance_type &ref) +{ + if (ref.instances () != this) { + throw tl::Exception (tl::to_string (tr ("Trying to replace an object in a list that it does not belong to"))); + } + + if (! ref.is_null () && ref.has_prop_id ()) { + + invalidate_prop_ids (); + + cell_inst_array_type new_inst (ref.cell_inst ()); + erase (ref); + return insert (new_inst); + + } else { + + return ref; + + } +} + +void Instances::do_clear_insts () { if (m_generic.any) { diff --git a/src/db/db/dbInstances.h b/src/db/db/dbInstances.h index b472604bc..17d71ab28 100644 --- a/src/db/db/dbInstances.h +++ b/src/db/db/dbInstances.h @@ -1497,6 +1497,13 @@ public: */ instance_type replace_prop_id (const instance_type &ref, db::properties_id_type prop_id); + /** + * @brief Clears the properties + * + * @return The reference to the new instance + */ + instance_type clear_properties (const instance_type &ref); + /** * @brief Replace the instance pointed to by the iterator with the given instance * diff --git a/src/db/db/dbPropertiesRepository.cc b/src/db/db/dbPropertiesRepository.cc index bba686627..7a526113b 100644 --- a/src/db/db/dbPropertiesRepository.cc +++ b/src/db/db/dbPropertiesRepository.cc @@ -79,6 +79,17 @@ db::properties_id_type properties_id (const PropertiesSet &ps) return PropertiesRepository::instance ().properties_id (ps); } +db::properties_id_type properties_id (const std::map &dict) +{ + db::PropertiesSet props; + + for (std::map::const_iterator v = dict.begin (); v != dict.end (); ++v) { + props.insert (v->first, v->second); + } + + return db::properties_id (props); +} + size_t hash_for_properties_id (properties_id_type id) { return id == 0 ? 0 : db::properties (id).hash (); diff --git a/src/db/db/dbPropertiesRepository.h b/src/db/db/dbPropertiesRepository.h index 99388e326..5596460b3 100644 --- a/src/db/db/dbPropertiesRepository.h +++ b/src/db/db/dbPropertiesRepository.h @@ -310,6 +310,11 @@ DB_PUBLIC const PropertiesSet &properties (db::properties_id_type id); */ DB_PUBLIC db::properties_id_type properties_id (const PropertiesSet &ps); +/** + * @brief Gets the properties ID from a raw properties set + */ +DB_PUBLIC db::properties_id_type properties_id (const std::map &dict); + /** * @brief The properties repository * diff --git a/src/db/db/dbShape.h b/src/db/db/dbShape.h index 86eb16d32..a3d34cbef 100644 --- a/src/db/db/dbShape.h +++ b/src/db/db/dbShape.h @@ -1098,18 +1098,6 @@ public: m_type = UserObject; } - /** - * @brief Determine, if the shape is of "object_with_properties" type. - * - * Usually, the properties id (see prop_id()) should be used. - * - * @return true, if the shape is of "object_with_properties type". - */ - bool with_props () const - { - return m_with_props; - } - /** * @brief Get the properties Id associated with the shape */ diff --git a/src/db/db/dbShapes.cc b/src/db/db/dbShapes.cc index 5774973b9..ff2c1bfff 100644 --- a/src/db/db/dbShapes.cc +++ b/src/db/db/dbShapes.cc @@ -738,16 +738,87 @@ Shapes::find (const Shapes::shape_type &shape) const } Shapes::shape_type -Shapes::replace_prop_id (const Shapes::shape_type &ref, db::properties_id_type prop_id) +Shapes::clear_properties (const Shapes::shape_type &ref) { tl_assert (! ref.is_array_member ()); if (ref.has_prop_id ()) { - if (ref.prop_id () != prop_id) { - invalidate_prop_ids (); + if (! is_editable ()) { + throw tl::Exception (tl::to_string (tr ("Function 'clear_properties' is permitted only in editable mode when going to property-less shapes from some with properties"))); } + switch (ref.m_type) { + case shape_type::Null: + return ref; + case shape_type::Polygon: + return clear_properties_iter (shape_type::polygon_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::PolygonRef: + return clear_properties_iter (shape_type::polygon_ref_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::PolygonPtrArray: + return clear_properties_iter (shape_type::polygon_ptr_array_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::SimplePolygon: + return clear_properties_iter (shape_type::simple_polygon_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::SimplePolygonRef: + return clear_properties_iter (shape_type::simple_polygon_ref_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::SimplePolygonPtrArray: + // HINT: since we are in editing mode, this type should not appear .. + return clear_properties_iter (shape_type::simple_polygon_ptr_array_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::Edge: + return clear_properties_iter (shape_type::edge_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::Point: + return clear_properties_iter (shape_type::point_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::EdgePair: + return clear_properties_iter (shape_type::edge_pair_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::Path: + return clear_properties_iter (shape_type::path_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::PathRef: + return clear_properties_iter (shape_type::path_ref_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::PathPtrArray: + // HINT: since we are in editing mode, this type should not appear .. + return clear_properties_iter (shape_type::path_ptr_array_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::Box: + return clear_properties_iter (shape_type::box_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::BoxArray: + // HINT: since we are in editing mode, this type should not appear .. + return clear_properties_iter (shape_type::box_array_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::ShortBox: + return clear_properties_iter (shape_type::short_box_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::ShortBoxArray: + // HINT: since we are in editing mode, this type should not appear .. + return clear_properties_iter (shape_type::short_box_array_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::Text: + return clear_properties_iter (shape_type::text_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::TextRef: + return clear_properties_iter (shape_type::text_ref_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::TextPtrArray: + // HINT: since we are in editing mode, this type should not appear .. + return clear_properties_iter (shape_type::text_ptr_array_type::tag (), ref.basic_iter (object_with_properties::tag ())); + case shape_type::UserObject: + return clear_properties_iter (shape_type::user_object_type::tag (), ref.basic_iter (object_with_properties::tag ())); + default: + return ref; + }; + + } + + return ref; +} + +Shapes::shape_type +Shapes::replace_prop_id (const Shapes::shape_type &ref, db::properties_id_type prop_id) +{ + tl_assert (! ref.is_array_member ()); + + // nothing to do? + if (ref.has_prop_id () && ref.prop_id () == prop_id) { + return ref; + } + + if (ref.has_prop_id ()) { + + invalidate_prop_ids (); + // this assumes we can simply patch the properties ID .. switch (ref.m_type) { case shape_type::Null: @@ -1311,6 +1382,23 @@ Shapes::replace_prop_id_iter (typename db::object_tag, const Iter &iter, db: return shape_type (this, get_layer , db::stable_layer_tag> ().insert (wp)); } +template +Shapes::shape_type +Shapes::clear_properties_iter (typename db::object_tag, const Iter &iter) +{ + if (manager () && manager ()->transacting ()) { + check_is_editable_for_undo_redo (); + db::layer_op, db::stable_layer_tag>::queue_or_append (manager (), this, false /*not insert*/, *iter); + } + Sh wop (*iter); + invalidate_state (); // HINT: must come before the change is done! + get_layer, db::stable_layer_tag> ().erase (iter); + if (manager () && manager ()->transacting ()) { + db::layer_op::queue_or_append (manager (), this, true /*insert*/, wop); + } + return shape_type (this, get_layer ().insert (wop)); +} + template Shapes::shape_type Shapes::reinsert_member_with_props (typename db::object_tag, const shape_type &ref, const Sh2 &sh) diff --git a/src/db/db/dbShapes.h b/src/db/db/dbShapes.h index 84bd1c062..b2fcfdc72 100644 --- a/src/db/db/dbShapes.h +++ b/src/db/db/dbShapes.h @@ -1149,12 +1149,22 @@ public: * of type object_with_properties. * This method is only allowed in editable mode. * - * @param ref The shape reference which to replace the properties ID with + * @param ref The shape reference for which to replace the properties ID with * @param prop_id The properties Id to replace. * @return The reference to the new object */ shape_type replace_prop_id (const shape_type &ref, db::properties_id_type prop_id); + /** + * @brief Clears the user properties + * + * This method is only allowed in editable mode. + * + * @param ref The shape reference for which to clear the properties + * @return The reference to the new object + */ + shape_type clear_properties (const shape_type &ref); + /** * @brief Replace an element by a given shape * @@ -1638,6 +1648,9 @@ private: template shape_type replace_prop_id_iter (typename db::object_tag, const Iter &iter, db::properties_id_type prop_id); + template + shape_type clear_properties_iter (typename db::object_tag, const Iter &iter); + // A helper function to replace a shape given by a generic reference by doing an erase & insert // Sh2 must not be a shape with properties template diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index 0e2f6f119..31b693cd8 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -1076,6 +1076,16 @@ static void set_cell_property (db::Cell *c, const tl::Variant &key, const tl::Va c->prop_id (db::properties_id (props)); } +static void set_cell_properties (db::Cell *c, const std::map &dict) +{ + c->prop_id (db::properties_id (dict)); +} + +static void clear_cell_properties (db::Cell *c) +{ + c->prop_id (0); +} + static tl::Variant get_cell_property (const db::Cell *c, const tl::Variant &key) { db::properties_id_type id = c->prop_id (); @@ -1831,6 +1841,22 @@ Class decl_Cell ("db", "Cell", "\n" "This method has been introduced in version 0.23." ) + + gsi::method_ext ("set_properties", &set_cell_properties, gsi::arg ("dict"), + "@brief Sets all user properties from the given dict\n" + "This method is a convenience method that replaces all user properties of the cell. Using that method is more " + "convenient than creating a new property set with a new ID and assigning that properties ID.\n" + "This method may change the properties ID. " + "Note: GDS only supports integer keys. OASIS supports numeric and string keys. " + "\n" + "This method has been introduced in version 0.30.3." + ) + + gsi::method_ext ("clear_properties", &clear_cell_properties, + "@brief Clears all user properties\n" + "This method will remove all user properties. After it has been called, \\has_prop_id? will return false.\n" + "It is equivalent to setting the properties ID to zero.\n" + "\n" + "This method has been introduced in version 0.30.3." + ) + gsi::method_ext ("property", &get_cell_property, gsi::arg ("key"), "@brief Gets the user property with the given key\n" "This method is a convenience method that gets the property with the given key. " @@ -3539,6 +3565,18 @@ static void set_property (db::Instance *i, const tl::Variant &key, const tl::Var set_prop_id (i, db::properties_id (props)); } +static void set_properties (db::Instance *inst, const std::map &dict) +{ + set_prop_id (inst, db::properties_id (dict)); +} + +static void clear_properties (db::Instance *inst) +{ + tl_assert (inst->instances () != 0); + check_is_editable (inst->instances ()); + *inst = inst->instances ()->clear_properties (*inst); +} + static tl::Variant get_property (const db::Instance *i, const tl::Variant &key) { db::properties_id_type id = i->prop_id (); @@ -4019,6 +4057,25 @@ Class decl_Instance ("db", "Instance", "\n" "This method has been introduced in version 0.22." ) + + gsi::method_ext ("set_properties", &set_properties, gsi::arg ("dict"), + "@brief Sets all user properties from the given dict\n" + "This method is a convenience method that replaces all user properties of the instance. Using that method is more " + "convenient than creating a new property set with a new ID and assigning that properties ID.\n" + "This method may change the properties ID. " + "Note: GDS only supports integer keys. OASIS supports numeric and string keys. " + "Calling this method may invalidate any iterators. It should not be called inside a " + "loop iterating over instances.\n" + "\n" + "This method has been introduced in version 0.30.3." + ) + + gsi::method_ext ("clear_properties", &clear_properties, + "@brief Clears all user properties\n" + "This method will remove all user properties. After it has been called, \\has_prop_id? will return false.\n" + "Calling this method may invalidate any iterators. It should not be called inside a " + "loop iterating over instances.\n" + "\n" + "This method has been introduced in version 0.30.3." + ) + gsi::method_ext ("property", &get_property, gsi::arg ("key"), "@brief Gets the user property with the given key\n" "This method is a convenience method that gets the property with the given key. " diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index 19ab98411..647dbd921 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -323,6 +323,16 @@ static void set_layout_property (db::Layout *l, const tl::Variant &key, const tl l->prop_id (db::properties_id (props)); } +static void set_layout_properties (db::Layout *l, const std::map &dict) +{ + l->prop_id (db::properties_id (dict)); +} + +static void clear_layout_properties (db::Layout *l) +{ + l->prop_id (0); +} + static tl::Variant get_layout_property (const db::Layout *l, const tl::Variant &key) { db::properties_id_type id = l->prop_id (); @@ -579,21 +589,15 @@ static db::properties_id_type properties_id_from_list_meth (const db::Layout *, return properties_id_from_list (properties); } -static db::properties_id_type properties_id_from_hash (const std::map &properties) +static db::properties_id_type properties_id_from_dict (const std::map &properties) { - db::PropertiesSet props; - - for (std::map::const_iterator v = properties.begin (); v != properties.end (); ++v) { - props.insert (v->first, v->second); - } - - return db::properties_id (props); + return db::properties_id (properties); } // for backward compatibility -static db::properties_id_type properties_id_from_hash_meth (const db::Layout *, const std::map &properties) +static db::properties_id_type properties_id_from_dict_meth (const db::Layout *, const std::map &properties) { - return properties_id_from_hash (properties); + return properties_id_from_dict (properties); } static tl::Variant get_properties_list (db::properties_id_type id) @@ -607,13 +611,13 @@ static tl::Variant get_properties_list_meth (const db::Layout *, db::properties_ return db::properties (id).to_list_var (); } -static tl::Variant get_properties_hash (db::properties_id_type id) +static tl::Variant get_properties_dict (db::properties_id_type id) { return db::properties (id).to_dict_var (); } // for backward compatibility -static tl::Variant get_properties_hash_meth (const db::Layout *, db::properties_id_type id) +static tl::Variant get_properties_dict_meth (const db::Layout *, db::properties_id_type id) { return db::properties (id).to_dict_var (); } @@ -1320,6 +1324,22 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduced in version 0.24." ) + + gsi::method_ext ("set_properties", &set_layout_properties, gsi::arg ("dict"), + "@brief Sets all user properties from the given dict\n" + "This method is a convenience method that replaces all user properties of the layout object. Using that method is more " + "convenient than creating a new property set with a new ID and assigning that properties ID.\n" + "This method may change the properties ID. " + "Note: GDS only supports integer keys. OASIS supports numeric and string keys. " + "\n" + "This method has been introduced in version 0.30.3." + ) + + gsi::method_ext ("clear_properties", &clear_layout_properties, + "@brief Clears all user properties\n" + "This method will remove all user properties. After it has been called, \\has_prop_id? will return false.\n" + "It is equivalent to setting the properties ID to zero.\n" + "\n" + "This method has been introduced in version 0.30.3." + ) + gsi::method_ext ("property", &get_layout_property, gsi::arg ("key"), "@brief Gets the Layout's user property with the given key\n" "This method is a convenience method that gets the property with the given key. " @@ -1364,10 +1384,10 @@ Class decl_Layout ("db", "Layout", "@return The unique properties ID for that set" ) + // backward-compatible version as method - gsi::method_ext ("properties_id", &properties_id_from_hash_meth, gsi::arg ("properties"), + gsi::method_ext ("properties_id", &properties_id_from_dict_meth, gsi::arg ("properties"), "@hide" ) + - gsi::method ("properties_id", &properties_id_from_hash, gsi::arg ("properties"), + gsi::method ("properties_id", &properties_id_from_dict, gsi::arg ("properties"), "@brief Gets the properties ID for a given properties set\n" "\n" "This variant accepts a hash of value vs. key for the properties instead of array of key/value pairs. " @@ -1413,10 +1433,10 @@ Class decl_Layout ("db", "Layout", "In version 0.30, this method was turned into a static (class method), providing universal conversions without need for a Layout object." ) + // backward-compatible version as method - gsi::method_ext ("properties_hash", &get_properties_hash_meth, gsi::arg ("properties_id"), + gsi::method_ext ("properties_hash", &get_properties_dict_meth, gsi::arg ("properties_id"), "@hide" ) + - gsi::method ("properties_hash", &get_properties_hash, gsi::arg ("properties_id"), + gsi::method ("properties_hash", &get_properties_dict, gsi::arg ("properties_id"), "@brief Gets the properties set for a given properties ID as a hash\n" "\n" "Returns the properties for a given properties ID as a hash.\n" diff --git a/src/db/db/gsiDeclDbShape.cc b/src/db/db/gsiDeclDbShape.cc index 6c14f1759..fe7722264 100644 --- a/src/db/db/gsiDeclDbShape.cc +++ b/src/db/db/gsiDeclDbShape.cc @@ -954,6 +954,17 @@ static void set_property (db::Shape *s, const tl::Variant &key, const tl::Varian set_prop_id (s, db::properties_id (props)); } +static void set_properties (db::Shape *shape, const std::map &dict) +{ + set_prop_id (shape, db::properties_id (dict)); +} + +static void clear_properties (db::Shape *shape) +{ + db::Shapes *shapes = shapes_checked (shape); + *shape = shapes->clear_properties (*shape); +} + static tl::Variant get_property (const db::Shape *s, const tl::Variant &key) { db::properties_id_type id = s->prop_id (); @@ -1312,6 +1323,25 @@ Class decl_Shape ("db", "Shape", "\n" "This method has been introduced in version 0.22." ) + + gsi::method_ext ("set_properties", &set_properties, gsi::arg ("dict"), + "@brief Sets all user properties from the given dict\n" + "This method is a convenience method that replaces all user properties of the shape. Using that method is more " + "convenient than creating a new property set with a new ID and assigning that properties ID.\n" + "This method may change the properties ID. " + "Note: GDS only supports integer keys. OASIS supports numeric and string keys. " + "Calling this method may invalidate any iterators. It should not be called inside a " + "loop iterating over instances.\n" + "\n" + "This method has been introduced in version 0.30.3." + ) + + gsi::method_ext ("clear_properties", &clear_properties, + "@brief Clears all user properties\n" + "This method will remove all user properties. After it has been called, \\has_prop_id? will return false.\n" + "Calling this method may invalidate any iterators. It should not be called inside a " + "loop iterating over instances.\n" + "\n" + "This method has been introduced in version 0.30.3." + ) + gsi::method_ext ("property", &get_property, gsi::arg ("key"), "@brief Gets the user property with the given key\n" "This method is a convenience method that gets the property with the given key. " diff --git a/src/db/unit_tests/dbShapesTests.cc b/src/db/unit_tests/dbShapesTests.cc index a71ca6eb8..fd584449e 100644 --- a/src/db/unit_tests/dbShapesTests.cc +++ b/src/db/unit_tests/dbShapesTests.cc @@ -2421,7 +2421,7 @@ TEST(12A) shape = topcell.shapes (lindex).begin (db::Shapes::shape_iterator::All); while (! shape.at_end ()) { - if (shape->with_props ()) { + if (shape->has_prop_id ()) { topcell.shapes (lindex).replace_prop_id (*shape, shape->prop_id () + 100); } ++shape; @@ -2494,7 +2494,7 @@ TEST(12C) shape = topcell.shapes (lindex).begin (db::Shapes::shape_iterator::All); while (! shape.at_end ()) { - if (shape->with_props ()) { + if (shape->has_prop_id ()) { topcell.shapes (lindex).replace_prop_id (*shape, shape->prop_id () + 100); } ++shape; @@ -2578,7 +2578,7 @@ TEST(12E) shape = topcell.shapes (lindex).begin (db::Shapes::shape_iterator::All); while (! shape.at_end ()) { - if (shape->with_props ()) { + if (shape->has_prop_id ()) { topcell.shapes (lindex).replace_prop_id (*shape, shape->prop_id () + 100); } ++shape; @@ -2677,7 +2677,7 @@ TEST(12G) shape = topcell.shapes (lindex).begin (db::Shapes::shape_iterator::All); while (! shape.at_end ()) { - if (shape->with_props ()) { + if (shape->has_prop_id ()) { topcell.shapes (lindex).replace_prop_id (*shape, shape->prop_id () + 100); } ++shape; @@ -2774,7 +2774,7 @@ TEST(12I) shape = topcell.shapes (lindex).begin (db::Shapes::shape_iterator::All); while (! shape.at_end ()) { - if (shape->with_props ()) { + if (shape->has_prop_id ()) { topcell.shapes (lindex).replace_prop_id (*shape, shape->prop_id () + 100); } ++shape; @@ -2834,7 +2834,7 @@ TEST(12J) shape = topcell.shapes (lindex).begin (db::Shapes::shape_iterator::All); while (! shape.at_end ()) { - if (shape->with_props ()) { + if (shape->has_prop_id ()) { topcell.shapes (lindex).replace_prop_id (*shape, shape->prop_id () + 100); } ++shape; diff --git a/testdata/ruby/dbInstanceTest.rb b/testdata/ruby/dbInstanceTest.rb index 55b3e1027..c8c66ff70 100644 --- a/testdata/ruby/dbInstanceTest.rb +++ b/testdata/ruby/dbInstanceTest.rb @@ -905,6 +905,41 @@ class DBInstance_TestClass < TestBase end + # User properties + def test_8_UserProperties + + ly = RBA::Layout::new + + ci1 = ly.add_cell("c1") + ci2 = ly.add_cell("c2") + + c1 = ly.cell(ci1) + c2 = ly.cell(ci2) + + inst = RBA::CellInstArray::new(c1.cell_index, RBA::Trans::new) + i = c2.insert(inst) + + assert_equal(i.property("k").inspect, "nil") + assert_equal(i.properties.inspect, "{}") + + i.set_property("k", 17) + + assert_equal(i.property("k").inspect, "17") + assert_equal(i.property("u").inspect, "nil") + assert_equal(i.properties.inspect, "{\"k\"=>17}") + + i.set_property("u", "42") + assert_equal(i.properties.inspect, "{\"k\"=>17, \"u\"=>\"42\"}") + + i.set_properties({ "a" => 17, 42 => "u" }) + assert_equal(i.properties, {42=>"u", "a"=>17}) + assert_equal(i.has_prop_id?, true) + i.clear_properties + assert_equal(i.properties, {}) + assert_equal(i.has_prop_id?, false) + + end + end load("test_epilogue.rb") diff --git a/testdata/ruby/dbLayoutTests2.rb b/testdata/ruby/dbLayoutTests2.rb index f5086e4a5..d4a4df86d 100644 --- a/testdata/ruby/dbLayoutTests2.rb +++ b/testdata/ruby/dbLayoutTests2.rb @@ -715,6 +715,12 @@ class DBLayoutTests2_TestClass < TestBase c1.delete_property( 17 ) assert_equal( c1.property( 17 ).inspect, "nil" ) assert_equal( c1.property( 5 ).inspect, "23" ) + c1.set_properties({ "a" => 17, 42 => "u" }) + assert_equal(c1.properties, {42=>"u", "a"=>17}) + assert_equal(c1.has_prop_id?, true) + c1.clear_properties + assert_equal(c1.properties, {}) + assert_equal(c1.has_prop_id?, false) end @@ -1057,6 +1063,13 @@ class DBLayoutTests2_TestClass < TestBase ly.delete_property("x") assert_equal(ly.property("x"), nil) + ly.set_properties({ "a" => 17, 42 => "u" }) + assert_equal(ly.properties, {42=>"u", "a"=>17}) + assert_equal(ly.has_prop_id?, true) + ly.clear_properties + assert_equal(ly.properties, {}) + assert_equal(ly.has_prop_id?, false) + end # Meta information diff --git a/testdata/ruby/dbShapesTest.rb b/testdata/ruby/dbShapesTest.rb index 6981eb1cd..e2a88c31d 100644 --- a/testdata/ruby/dbShapesTest.rb +++ b/testdata/ruby/dbShapesTest.rb @@ -1683,6 +1683,13 @@ class DBShapes_TestClass < TestBase sh.set_property("u", "42") assert_equal(sh.properties.inspect, "{\"k\"=>17, \"u\"=>\"42\"}") + sh.set_properties({ "a" => 17, 42 => "u" }) + assert_equal(sh.properties, {42=>"u", "a"=>17}) + assert_equal(sh.has_prop_id?, true) + sh.clear_properties + assert_equal(sh.properties, {}) + assert_equal(sh.has_prop_id?, false) + end # Shape objects with properties