Skip to content

Commit

Permalink
Merge pull request #1820 from KLayout/wip
Browse files Browse the repository at this point in the history
WIP branch
  • Loading branch information
klayoutmatthias authored Aug 10, 2024
2 parents a5ea8eb + a601447 commit 9ef35d1
Show file tree
Hide file tree
Showing 29 changed files with 586 additions and 40 deletions.
78 changes: 77 additions & 1 deletion src/db/db/gsiDeclDbLayout.cc
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,11 @@ static db::Cell *cell_from_index (db::Layout *ly, db::cell_index_type ci)
return &ly->cell (ci);
}

static const db::Cell *cell_from_index_const (const db::Layout *layout, db::cell_index_type ci)
{
return cell_from_index (const_cast <db::Layout *> (layout), ci);
}

static db::Cell *cell_from_name (db::Layout *ly, const std::string &name)
{
std::pair<bool, db::cell_index_type> cn = ly->cell_by_name (name.c_str ());
Expand All @@ -864,6 +869,11 @@ static db::Cell *cell_from_name (db::Layout *ly, const std::string &name)
}
}

static const db::Cell *cell_from_name_const (const db::Layout *layout, const std::string &name)
{
return cell_from_name (const_cast <db::Layout *> (layout), name);
}

static std::vector<db::Cell *> cells_from_name (db::Layout *layout, const std::string &filter)
{
tl::GlobPattern gp (filter);
Expand All @@ -880,6 +890,12 @@ static std::vector<db::Cell *> cells_from_name (db::Layout *layout, const std::s
return result;
}

static std::vector<const db::Cell *> cells_from_name_const (const db::Layout *layout, const std::string &filter)
{
std::vector<db::Cell *> tcs = cells_from_name (const_cast <db::Layout *> (layout), filter);
return std::vector<const db::Cell *> (tcs.begin (), tcs.end ());
}

static std::vector<db::Cell *> top_cells (db::Layout *layout)
{
std::vector<db::Cell *> tc;
Expand All @@ -891,6 +907,12 @@ static std::vector<db::Cell *> top_cells (db::Layout *layout)
return tc;
}

static std::vector<const db::Cell *> top_cells_const (const db::Layout *layout)
{
std::vector<db::Cell *> tcs = top_cells (const_cast <db::Layout *> (layout));
return std::vector<const db::Cell *> (tcs.begin (), tcs.end ());
}

static db::Cell *top_cell (db::Layout *layout)
{
db::Cell *tc = 0;
Expand All @@ -906,6 +928,11 @@ static db::Cell *top_cell (db::Layout *layout)
return tc;
}

static const db::Cell *top_cell_const (const db::Layout *layout)
{
return top_cell (const_cast <db::Layout *> (layout));
}

static db::Cell *create_cell (db::Layout *layout, const std::string &name)
{
return &layout->cell (layout->add_cell (name.c_str ()));
Expand Down Expand Up @@ -1328,14 +1355,31 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"This method has been introduced in version 0.23."
) +
gsi::method_ext ("top_cells", &top_cells,
gsi::method_ext ("top_cell", &top_cell_const,
"@brief Returns the top cell object (const version)\n"
"@return The \\Cell object of the top cell\n"
"If the layout has a single top cell, this method returns the top cell's \\Cell object.\n"
"If the layout does not have a top cell, this method returns \"nil\". If the layout has multiple\n"
"top cells, this method raises an error.\n"
"\n"
"This variant has been introduced in version 0.29.6."
) +
gsi::method_ext ("top_cells", &top_cells,
"@brief Returns the top cell objects\n"
"@return The \\Cell objects of the top cells\n"
"This method returns and array of \\Cell objects representing the top cells of the layout.\n"
"This array can be empty, if the layout does not have a top cell (i.e. no cell at all).\n"
"\n"
"This method has been introduced in version 0.23."
) +
gsi::method_ext ("top_cells", &top_cells_const,
"@brief Returns the top cell objects (const version)\n"
"@return The \\Cell objects of the top cells\n"
"This method returns and array of \\Cell objects representing the top cells of the layout.\n"
"This array can be empty, if the layout does not have a top cell (i.e. no cell at all).\n"
"\n"
"This variant has been introduced in version 0.29.6."
) +
gsi::method ("has_cell?", &db::Layout::has_cell, gsi::arg ("name"),
"@brief Returns true if a cell with a given name exists\n"
"Returns true, if the layout has a cell with the given name"
Expand Down Expand Up @@ -1780,6 +1824,16 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"This method has been introduced in version 0.27.3.\n"
) +
gsi::method_ext ("cells", &cells_from_name_const, gsi::arg ("name_filter"),
"@brief Gets the cell objects for a given name filter (const version)\n"
"\n"
"@param name_filter The cell name filter (glob pattern)\n"
"@return A list of \\Cell object of the cells matching the pattern\n"
"\n"
"This method has been introduced in version 0.27.3.\n"
"\n"
"This variant has been introduced in version 0.29.6."
) +
gsi::method_ext ("cell", &cell_from_name, gsi::arg ("name"),
"@brief Gets a cell object from the cell name\n"
"\n"
Expand All @@ -1789,6 +1843,17 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"If name is not a valid cell name, this method will return \"nil\".\n"
"This method has been introduced in version 0.23 and replaces \\cell_by_name.\n"
) +
gsi::method_ext ("cell", &cell_from_name_const, gsi::arg ("name"),
"@brief Gets a cell object from the cell name (const version)\n"
"\n"
"@param name The cell name\n"
"@return A reference to the cell (a \\Cell object)\n"
"\n"
"If name is not a valid cell name, this method will return \"nil\".\n"
"This method has been introduced in version 0.23 and replaces \\cell_by_name.\n"
"\n"
"This variant has been introduced in version 0.29.6."
) +
gsi::method_ext ("cell", &cell_from_index, gsi::arg ("i"),
"@brief Gets a cell object from the cell index\n"
"\n"
Expand All @@ -1798,6 +1863,17 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"If the cell index is not a valid cell index, this method will raise an error. "
"Use \\is_valid_cell_index? to test whether a given cell index is valid.\n"
) +
gsi::method_ext ("cell", &cell_from_index_const, gsi::arg ("i"),
"@brief Gets a cell object from the cell index (const version)\n"
"\n"
"@param i The cell index\n"
"@return A reference to the cell (a \\Cell object)\n"
"\n"
"If the cell index is not a valid cell index, this method will raise an error. "
"Use \\is_valid_cell_index? to test whether a given cell index is valid.\n"
"\n"
"This variant has been introduced in version 0.29.6."
) +
gsi::iterator ("each_cell", (db::Layout::iterator (db::Layout::*) ()) &db::Layout::begin, (db::Layout::iterator (db::Layout::*) ()) &db::Layout::end,
"@brief Iterates the unsorted cell list\n"
) +
Expand Down
2 changes: 1 addition & 1 deletion src/db/db/gsiDeclDbLibrary.cc
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ Class<db::ParameterState> decl_PCellParameterState ("db", "PCellParameterState",
gsi::method("icon=", &db::ParameterState::set_icon, gsi::arg ("i"),
"@brief Sets the icon for the parameter\n"
) +
gsi::method("tooltip", &db::ParameterState::tooltip,
gsi::method("icon", &db::ParameterState::icon,
"@brief Gets the icon for the parameter\n"
),
"@brief Provides access to the attributes of a single parameter within \\PCellParameterStates.\n"
Expand Down
2 changes: 1 addition & 1 deletion src/drc/drc/built-in-macros/_drc_engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2308,7 +2308,7 @@ def #{f}(*args)

def netter
self._context("netter") do
DRC::DRCNetter::new
DRC::DRCNetter::new(self)
end
end

Expand Down
15 changes: 11 additions & 4 deletions src/drc/drc/built-in-macros/_drc_layer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5186,6 +5186,7 @@ def map_props(arg)
# @brief Pulls net shapes from selected or all nets, optionally annotating nets with properties
# @synopsis layer.nets
# @synopsis layer.nets(net_filter)
# @synopsis layer.nets(net_object)
# @synopsis layer.nets(circuit_filter, net_filter)
# @synopsis layer.nets(netter, ...)
# @synopsis layer.nets(prop(key), ...)
Expand All @@ -5202,7 +5203,7 @@ def map_props(arg)
# complete - subnets from subcircuits are not selected. The net name is taken from
# the net's home circuit (to topmost location where all net connections are formed).
# You can specify a circuit filter to select nets from certain circuits only or
# give a RBA::Circuit object explicitly.
# give a RBA::Circuit object explicitly. You can also specify RBA::Net objects directly.
#
# @code
# connect(metal1, via1)
Expand Down Expand Up @@ -5230,6 +5231,8 @@ def nets(*args)

@engine._context("nets") do

nets = nil

# parse arguments
filters = nil
circuits = nil
Expand All @@ -5241,6 +5244,9 @@ def nets(*args)
filters << a
elsif a.is_a?(1.class)
prop_id = a
elsif a.is_a?(RBA::Net)
nets ||= []
nets << a
elsif a.is_a?(RBA::Circuit)
circuits ||= []
circuits << a
Expand Down Expand Up @@ -5272,13 +5278,14 @@ def nets(*args)
circuits ||= []
circuits += netlist.circuits_by_name(circuit_filter)
end
nets = nil
if !circuits
if filters
nets = filters.collect { |f| netlist.nets_by_name(f) }.flatten
nets ||= []
nets += filters.collect { |f| netlist.nets_by_name(f) }.flatten
end
else
nets = circuits.collect do |circuit|
nets ||= []
nets += circuits.collect do |circuit|
(filters || ["*"]).collect { |f| circuit.nets_by_name(f) }.flatten
end.flatten
end
Expand Down
10 changes: 10 additions & 0 deletions src/drc/unit_tests/drcSimpleTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1568,6 +1568,16 @@ TEST(70d_props)
run_test (_this, "70", true);
}

TEST(71_netter)
{
run_test (_this, "71", false);
}

TEST(71d_netter)
{
run_test (_this, "71", true);
}

TEST(80_deep_with_mag_width)
{
run_test (_this, "80", true);
Expand Down
45 changes: 45 additions & 0 deletions src/gsi/gsi/gsiClassBase.cc
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,48 @@ sm_is_const (const char *name)
return sm;
}

static SpecialMethod *
sm_to_const (const char *name, const gsi::ClassBase *cls)
{
SpecialMethod *sm = new SpecialMethod (name,
tl::to_string (tr ("@hide")), // provided for test purposes mainly
true, // const
false, // non-static
MethodBase::ToConst);

gsi::ArgType ret;
ret.set_is_cptr (true);
ret.set_type (gsi::T_object);
ret.set_pass_obj (false);
ret.set_cls (cls);
sm->set_return (ret);

return sm;
}

static SpecialMethod *
sm_const_cast (const char *name, const gsi::ClassBase *cls)
{
SpecialMethod *sm = new SpecialMethod (name,
tl::to_string (tr ("@brief Returns a non-const reference to self.\n"
"Basically, this method allows turning a const object reference to a non-const one. "
"This method is provided as last resort to remove the constness from an object. Usually there is a good reason for a const object reference, so using this method may have undesired side effects.\n"
"\n"
"This method has been introduced in version 0.29.6.")),
true, // const
false, // non-static
MethodBase::ConstCast);

gsi::ArgType ret;
ret.set_is_ptr (true);
ret.set_type (gsi::T_object);
ret.set_pass_obj (false);
ret.set_cls (cls);
sm->set_return (ret);

return sm;
}

static SpecialMethod *
sm_destroyed (const char *name)
{
Expand Down Expand Up @@ -598,6 +640,9 @@ ClassBase::merge_declarations ()
non_const_decl->add_method (sm_is_const ("_is_const_object?"));
}

non_const_decl->add_method (sm_to_const ("_to_const_object", &*c));
non_const_decl->add_method (sm_const_cast ("_const_cast", &*c));

}

// finally merge the new classes into the existing ones
Expand Down
24 changes: 18 additions & 6 deletions src/gsi/gsi/gsiExpression.cc
Original file line number Diff line number Diff line change
Expand Up @@ -305,13 +305,17 @@ initialize_expressions ()
// install the method table:
ExpressionMethodTable::initialize_class (*c);

// register a function that creates a class object (use a function to avoid issues with
// late destruction of global variables which the class object is already gone)
const tl::VariantUserClassBase *cc = (*c)->var_cls_cls ();
if (cc) {
tl::Eval::define_global_function ((*c)->name (), new EvalClassFunction (cc));
}
// Note: skip non-top-level classes
if ((*c)->parent () == 0) {

// register a function that creates a class object (use a function to avoid issues with
// late destruction of global variables which the class object is already gone)
const tl::VariantUserClassBase *cc = (*c)->var_cls_cls ();
if (cc) {
tl::Eval::define_global_function ((*c)->name (), new EvalClassFunction (cc));
}

}
}
}

Expand Down Expand Up @@ -630,6 +634,14 @@ special_method_impl (gsi::MethodBase::special_method_type smt, tl::Variant &self
// nothing to do here for GSI objects
} else if (smt == gsi::MethodBase::IsConst) {
return tl::Variant (self.user_is_const ());
} else if (smt == gsi::MethodBase::ToConst) {
tl::Variant res (self);
res.user_change_constness (true);
return res;
} else if (smt == gsi::MethodBase::ConstCast) {
tl::Variant res (self);
res.user_change_constness (false);
return res;
} else if (smt == gsi::MethodBase::Destroyed) {

if (self.type_code () == tl::Variant::t_user) {
Expand Down
4 changes: 3 additions & 1 deletion src/gsi/gsi/gsiMethods.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ class GSI_PUBLIC MethodBase
Destroy,
Create,
IsConst,
Destroyed,
ConstCast,
ToConst,
Destroyed,
Assign,
Dup
};
Expand Down
34 changes: 34 additions & 0 deletions src/gsi/unit_tests/gsiExpressionTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -829,3 +829,37 @@ TEST(15)
v = e.parse("var bb = BB.new; bb.d4(1, 'a', 2.0, BB.E.E3B, 42)").execute();
EXPECT_EQ (v.to_string (), "1,a,2,101,42");
}

// constness
TEST(16)
{
tl::Eval e;
tl::Variant v;
v = e.parse ("var b=B.new(); b._is_const_object").execute ();
EXPECT_EQ (v.to_string (), std::string ("false"));
try {
v = e.parse ("var b=B.new(); var bc=b._to_const_object; bc.set_str('abc')").execute ();
EXPECT_EQ (1, 0);
} catch (tl::Exception &ex) {
EXPECT_EQ (ex.msg (), "Cannot call non-const method set_str, class B on a const reference at position 44 (...set_str('abc'))");
}
v = e.parse ("var e=E.new(); var ec=e.dup; [e._is_const_object, ec._to_const_object._is_const_object]").execute ();
EXPECT_EQ (v.to_string (), std::string ("false,true"));
v = e.parse ("var e=E.new(); var ec=e._to_const_object; e.x=17; [e.x, ec.x]").execute ();
EXPECT_EQ (v.to_string (), std::string ("17,17"));
v = e.parse ("var e=E.new(); var ec=e._to_const_object; ec._is_const_object").execute ();
EXPECT_EQ (v.to_string (), std::string ("true"));
v = e.parse ("var e=E.new(); var ec=e._to_const_object; ec=ec._const_cast; ec._is_const_object").execute ();
EXPECT_EQ (v.to_string (), std::string ("false"));
v = e.parse ("var e=E.new(); var ec=e._to_const_object; ec=ec._const_cast; ec.x=42; e.x").execute ();
EXPECT_EQ (v.to_string (), std::string ("42"));
v = e.parse ("var e=E.new(); var ec=e._to_const_object; e.x=17; ec.x").execute ();
EXPECT_EQ (v.to_string (), std::string ("17"));
try {
v = e.parse ("var e=E.new(); var ec=e._to_const_object; e.x=17; e._destroy; ec.x").execute ();
EXPECT_EQ (1, 0);
} catch (tl::Exception &ex) {
EXPECT_EQ (ex.msg (), "Object has been destroyed already at position 64 (...x)");
}
}

Loading

0 comments on commit 9ef35d1

Please sign in to comment.