mirror of https://github.com/KLayout/klayout.git
commit
9ef35d120e
|
|
@ -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 ());
|
||||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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 ()));
|
||||
|
|
@ -1328,6 +1355,15 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
) +
|
||||
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"
|
||||
|
|
@ -1336,6 +1372,14 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"\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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -2308,7 +2308,7 @@ CODE
|
|||
|
||||
def netter
|
||||
self._context("netter") do
|
||||
DRC::DRCNetter::new
|
||||
DRC::DRCNetter::new(self)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -5186,6 +5186,7 @@ CODE
|
|||
# @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), ...)
|
||||
|
|
@ -5202,7 +5203,7 @@ CODE
|
|||
# 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)
|
||||
|
|
@ -5230,6 +5231,8 @@ CODE
|
|||
|
||||
@engine._context("nets") do
|
||||
|
||||
nets = nil
|
||||
|
||||
# parse arguments
|
||||
filters = nil
|
||||
circuits = nil
|
||||
|
|
@ -5241,6 +5244,9 @@ CODE
|
|||
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
|
||||
|
|
@ -5272,13 +5278,14 @@ CODE
|
|||
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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -305,6 +305,9 @@ initialize_expressions ()
|
|||
// install the method table:
|
||||
ExpressionMethodTable::initialize_class (*c);
|
||||
|
||||
// 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 ();
|
||||
|
|
@ -313,6 +316,7 @@ initialize_expressions ()
|
|||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ public:
|
|||
Destroy,
|
||||
Create,
|
||||
IsConst,
|
||||
ConstCast,
|
||||
ToConst,
|
||||
Destroyed,
|
||||
Assign,
|
||||
Dup
|
||||
|
|
|
|||
|
|
@ -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)");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1331,6 +1331,18 @@ MainWindow::update_dock_widget_state ()
|
|||
void
|
||||
MainWindow::exit ()
|
||||
{
|
||||
if (m_busy) {
|
||||
if (QMessageBox::warning (this,
|
||||
QObject::tr ("Application Busy - Close Anyway?"),
|
||||
QObject::tr ("The application is busy.\nYou can close the application now, but this will terminate any running operations.\nDo you want to close anyway?\n\n"
|
||||
"Press 'Yes' to end the application now."),
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::Yes) != QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_exited = true;
|
||||
|
||||
// If there is a operation ongoing, request a break and delay execution of the exit operation.
|
||||
|
|
@ -1394,20 +1406,6 @@ MainWindow::dirty_files (std::string &dirty_files)
|
|||
bool
|
||||
MainWindow::can_close ()
|
||||
{
|
||||
if (m_busy) {
|
||||
|
||||
bool can_close = false;
|
||||
|
||||
can_close = (QMessageBox::warning (this,
|
||||
QObject::tr ("Application Busy"),
|
||||
QObject::tr ("The application is busy.\nYou can close the application now, but any unsaved data will be lost.\n\nPress 'Yes' to end the application now."),
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::Yes) == QMessageBox::Yes);
|
||||
|
||||
return can_close;
|
||||
|
||||
}
|
||||
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
lay::PluginDeclaration *pd = const_cast<lay::PluginDeclaration *> (&*cls);
|
||||
if (! pd->can_exit (dispatcher ())) {
|
||||
|
|
|
|||
|
|
@ -379,7 +379,7 @@ PropertiesDialog::update_controls ()
|
|||
|
||||
mp_ui->apply_to_all_cbx->setChecked (m_object_indexes.size () > 1);
|
||||
|
||||
if (m_index < 0) {
|
||||
if (m_index < 0 || m_index >= int (mp_properties_pages.size ())) {
|
||||
|
||||
mp_stack->setCurrentWidget (mp_none);
|
||||
|
||||
|
|
@ -552,6 +552,10 @@ PropertiesDialog::apply ()
|
|||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
if (m_index < 0 || m_index >= int (mp_properties_pages.size ())) {
|
||||
return;
|
||||
}
|
||||
|
||||
db::Transaction t (mp_manager, tl::to_string (QObject::tr ("Apply changes")), m_transaction_id);
|
||||
|
||||
try {
|
||||
|
|
@ -633,6 +637,12 @@ PropertiesDialog::reject ()
|
|||
QDialog::reject ();
|
||||
}
|
||||
|
||||
void
|
||||
PropertiesDialog::accept ()
|
||||
{
|
||||
// stop handling "Enter" key.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ public slots:
|
|||
|
||||
protected:
|
||||
void reject ();
|
||||
void accept ();
|
||||
|
||||
private:
|
||||
Ui::PropertiesDialog *mp_ui;
|
||||
|
|
|
|||
|
|
@ -721,6 +721,50 @@ object_is_const (PyObject *self, PyObject *args)
|
|||
return c2python (PYAObjectBase::from_pyobject (self)->const_ref ());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implements to_const and const_cast
|
||||
*/
|
||||
static PyObject *
|
||||
object_change_const (PyObject *self, PyObject *args, bool to_const)
|
||||
{
|
||||
if (PYAObjectBase::from_pyobject (self)->const_ref () == to_const) {
|
||||
return self;
|
||||
}
|
||||
|
||||
const gsi::ClassBase *cls_decl_self = PythonModule::cls_for_type (Py_TYPE (self));
|
||||
tl_assert (cls_decl_self != 0);
|
||||
|
||||
if (! PyArg_ParseTuple (args, "")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *new_object = Py_TYPE (self)->tp_alloc (Py_TYPE (self), 0);
|
||||
PythonRef obj (new_object);
|
||||
PYAObjectBase *new_pya_base = PYAObjectBase::from_pyobject_unsafe (new_object);
|
||||
new (new_pya_base) PYAObjectBase (cls_decl_self, new_object);
|
||||
new_pya_base->set (PYAObjectBase::from_pyobject (self)->obj (), false, to_const, false);
|
||||
|
||||
return obj.release ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implements to_const
|
||||
*/
|
||||
static PyObject *
|
||||
object_to_const (PyObject *self, PyObject *args)
|
||||
{
|
||||
return object_change_const (self, args, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implements const_cast
|
||||
*/
|
||||
static PyObject *
|
||||
object_const_cast (PyObject *self, PyObject *args)
|
||||
{
|
||||
return object_change_const (self, args, false);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
special_method_impl (gsi::MethodBase::special_method_type smt, PyObject *self, PyObject *args)
|
||||
{
|
||||
|
|
@ -734,6 +778,10 @@ special_method_impl (gsi::MethodBase::special_method_type smt, PyObject *self, P
|
|||
return object_create (self, args);
|
||||
} else if (smt == gsi::MethodBase::IsConst) {
|
||||
return object_is_const (self, args);
|
||||
} else if (smt == gsi::MethodBase::ToConst) {
|
||||
return object_to_const (self, args);
|
||||
} else if (smt == gsi::MethodBase::ConstCast) {
|
||||
return object_const_cast (self, args);
|
||||
} else if (smt == gsi::MethodBase::Destroyed) {
|
||||
return object_destroyed (self, args);
|
||||
} else if (smt == gsi::MethodBase::Assign) {
|
||||
|
|
|
|||
|
|
@ -913,6 +913,16 @@ handle_exception (const std::string &where)
|
|||
handle_exception ((where)); \
|
||||
}
|
||||
|
||||
static void free_proxy (void *p)
|
||||
{
|
||||
delete ((Proxy *) p);
|
||||
}
|
||||
|
||||
static void mark_proxy (void *p)
|
||||
{
|
||||
((Proxy *) p)->mark ();
|
||||
}
|
||||
|
||||
static VALUE
|
||||
destroy (VALUE self)
|
||||
{
|
||||
|
|
@ -971,6 +981,37 @@ is_const (VALUE self)
|
|||
return c2ruby<bool> (p->const_ref ());
|
||||
}
|
||||
|
||||
static VALUE
|
||||
to_const (VALUE self)
|
||||
{
|
||||
Proxy *p = 0;
|
||||
Data_Get_Struct (self, Proxy, p);
|
||||
if (! p->const_ref ()) {
|
||||
// promote to const object
|
||||
// NOTE: there is only ONE instance we're going to change this instance
|
||||
// to const here. This has a global effect and this is the reason why this
|
||||
// method is not public. It is provided for testing purposes mainly.
|
||||
p->set_const_ref (true);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
const_cast_ (VALUE self)
|
||||
{
|
||||
Proxy *p = 0;
|
||||
Data_Get_Struct (self, Proxy, p);
|
||||
if (p->const_ref ()) {
|
||||
// promote to non-const object
|
||||
// NOTE: this is a global change of constness and will affect all references
|
||||
// that exist for this object.
|
||||
p->set_const_ref (false);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
assign (VALUE self, VALUE src)
|
||||
{
|
||||
|
|
@ -1024,6 +1065,12 @@ special_method_impl (const gsi::MethodBase *meth, int argc, VALUE *argv, VALUE s
|
|||
} else if (smt == gsi::MethodBase::IsConst) {
|
||||
tl_assert (!ctor);
|
||||
return is_const (self);
|
||||
} else if (smt == gsi::MethodBase::ToConst) {
|
||||
tl_assert (!ctor);
|
||||
return to_const (self);
|
||||
} else if (smt == gsi::MethodBase::ConstCast) {
|
||||
tl_assert (!ctor);
|
||||
return const_cast_ (self);
|
||||
} else if (smt == gsi::MethodBase::Destroyed) {
|
||||
tl_assert (!ctor);
|
||||
return destroyed (self);
|
||||
|
|
@ -1043,16 +1090,6 @@ special_method_impl (const gsi::MethodBase *meth, int argc, VALUE *argv, VALUE s
|
|||
}
|
||||
}
|
||||
|
||||
static void free_proxy (void *p)
|
||||
{
|
||||
delete ((Proxy *) p);
|
||||
}
|
||||
|
||||
static void mark_proxy (void *p)
|
||||
{
|
||||
((Proxy *) p)->mark ();
|
||||
}
|
||||
|
||||
static VALUE alloc_proxy (VALUE klass)
|
||||
{
|
||||
tl_assert (TYPE (klass) == T_CLASS);
|
||||
|
|
|
|||
|
|
@ -3192,6 +3192,17 @@ Eval::set_var (const std::string &name, const tl::Variant &var)
|
|||
m_local_vars.insert (std::make_pair (name, tl::Variant ())).first->second = var;
|
||||
}
|
||||
|
||||
tl::Variant *
|
||||
Eval::var (const std::string &name)
|
||||
{
|
||||
auto f = m_local_vars.find (name);
|
||||
if (f != m_local_vars.end ()) {
|
||||
return &f->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Eval::define_function (const std::string &name, EvalFunction *function)
|
||||
{
|
||||
|
|
@ -3202,6 +3213,17 @@ Eval::define_function (const std::string &name, EvalFunction *function)
|
|||
f = function;
|
||||
}
|
||||
|
||||
EvalFunction *
|
||||
Eval::function (const std::string &name)
|
||||
{
|
||||
auto f = m_local_functions.find (name);
|
||||
if (f != m_local_functions.end ()) {
|
||||
return f->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Eval::eval_top (ExpressionParserContext &ex, std::unique_ptr<ExpressionNode> &n)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -448,6 +448,12 @@ public:
|
|||
*/
|
||||
void define_function (const std::string &name, EvalFunction *function);
|
||||
|
||||
/**
|
||||
* @brief Gets the function for the given name
|
||||
* Returns 0 if there is no such function.
|
||||
*/
|
||||
EvalFunction *function (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Define a global variable for use within an expression
|
||||
*/
|
||||
|
|
@ -461,6 +467,12 @@ public:
|
|||
*/
|
||||
void set_var (const std::string &name, const tl::Variant &var);
|
||||
|
||||
/**
|
||||
* @brief Gets the function for the given name
|
||||
* Returns 0 if there is no such function.
|
||||
*/
|
||||
tl::Variant *var (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Parse an expression from the extractor
|
||||
*
|
||||
|
|
@ -543,6 +555,30 @@ public:
|
|||
return m_match_substrings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the global context
|
||||
*/
|
||||
static tl::Eval &global_context ()
|
||||
{
|
||||
return m_global;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the global context for this context
|
||||
*/
|
||||
tl::Eval *global ()
|
||||
{
|
||||
return mp_global;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the parent context for this context
|
||||
*/
|
||||
tl::Eval *parent ()
|
||||
{
|
||||
return mp_parent;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Expression;
|
||||
|
||||
|
|
|
|||
|
|
@ -2738,6 +2738,17 @@ void *Variant::user_unshare () const
|
|||
return const_cast<void *> (to_user ());
|
||||
}
|
||||
|
||||
void Variant::user_change_constness (bool constness)
|
||||
{
|
||||
tl_assert (is_user ());
|
||||
|
||||
if (m_type == t_user) {
|
||||
m_var.mp_user.cls = m_var.mp_user.cls->change_constness (constness);
|
||||
} else if (m_type == t_user_ref) {
|
||||
m_var.mp_user_ref.cls = m_var.mp_user_ref.cls->change_constness (constness);
|
||||
}
|
||||
}
|
||||
|
||||
void Variant::user_assign (const tl::Variant &other)
|
||||
{
|
||||
tl_assert (is_user ());
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ public:
|
|||
virtual const gsi::ClassBase *gsi_cls () const = 0;
|
||||
virtual const tl::EvalClass *eval_cls () const = 0;
|
||||
virtual void *deref_proxy (tl::Object *proxy) const = 0;
|
||||
virtual const tl::VariantUserClassBase *change_constness (bool constness) const = 0;
|
||||
|
||||
const void *deref_proxy_const (const tl::Object *proxy) const
|
||||
{
|
||||
|
|
@ -126,6 +127,11 @@ public:
|
|||
return VariantUserClassBase::instance (typeid (T), is_const);
|
||||
}
|
||||
|
||||
const tl::VariantUserClassBase *change_constness (bool constness) const
|
||||
{
|
||||
return instance (constness);
|
||||
}
|
||||
|
||||
private:
|
||||
static const tl::VariantUserClassBase *ms_instances[4];
|
||||
|
||||
|
|
@ -1001,6 +1007,11 @@ public:
|
|||
*/
|
||||
void *user_unshare () const;
|
||||
|
||||
/**
|
||||
* @brief Changes the constness of the user object
|
||||
*/
|
||||
void user_change_constness (bool constness);
|
||||
|
||||
/**
|
||||
* @brief Assigns the object stored in other to self
|
||||
*
|
||||
|
|
|
|||
|
|
@ -465,6 +465,7 @@ public:
|
|||
virtual bool is_ref () const { return false; }
|
||||
virtual void *deref_proxy (tl::Object *) const { return 0; }
|
||||
virtual const gsi::ClassBase*gsi_cls() const { return 0; }
|
||||
virtual const tl::VariantUserClassBase *change_constness (bool) const { return this; }
|
||||
static BoxClassClass instance;
|
||||
};
|
||||
|
||||
|
|
@ -533,6 +534,7 @@ public:
|
|||
virtual bool is_ref () const { return false; }
|
||||
virtual void *deref_proxy (tl::Object *) const { return 0; }
|
||||
virtual const gsi::ClassBase*gsi_cls() const { return 0; }
|
||||
virtual const tl::VariantUserClassBase *change_constness (bool) const { return this; }
|
||||
static EdgeClassClass instance;
|
||||
};
|
||||
|
||||
|
|
@ -1209,3 +1211,4 @@ TEST(20)
|
|||
v = e.parse ("i2.dtrans.disp.y").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("0.3"));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,11 +68,14 @@ l1.nets(self._netter).output(101, 0)
|
|||
l1.nets(prop(1)).output(102, 0)
|
||||
l1.nets(prop(nil)).output(103, 0)
|
||||
|
||||
l1.nets("X").output(110, 0)
|
||||
x1 = l1.nets("X")
|
||||
x1.output(110, 0)
|
||||
l1.nets("TOP", "X").output(111, 0)
|
||||
l1.nets("TOP", "NOTEXIST").output(112, 0)
|
||||
l1.nets("NOTEXIST", "NOTEXIST").output(113, 0)
|
||||
|
||||
x2 = l1.nets(*netlist.nets_by_name("X"))
|
||||
(x1 ^ x2).output(114, 0)
|
||||
|
||||
# checks with property constraints
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
# Moved implementation
|
||||
|
||||
source($drc_test_source)
|
||||
target($drc_test_target)
|
||||
|
||||
if $drc_test_deep
|
||||
deep
|
||||
end
|
||||
|
||||
l1 = input(1, 0)
|
||||
l2 = input(2, 0)
|
||||
l3 = input(3, 0)
|
||||
|
||||
# dump to output
|
||||
|
||||
l1.output(1, 0)
|
||||
l2.output(2, 0)
|
||||
l3.output(3, 0)
|
||||
|
||||
ctx1 = netter
|
||||
ctx1.connect(l1, l2)
|
||||
|
||||
connect(l1, l3)
|
||||
|
||||
l1.nets.output(100, 0)
|
||||
begin
|
||||
l2.nets.output(101, 0)
|
||||
raise "internal error - l2 was not used in connectivity"
|
||||
rescue => ex
|
||||
end
|
||||
l3.nets.output(102, 0)
|
||||
|
||||
l1.nets(ctx1).output(110, 0)
|
||||
l2.nets(ctx1).output(111, 0)
|
||||
begin
|
||||
l3.nets(ctx1).output(112, 0)
|
||||
raise "internal error - l3 was not used in connectivity"
|
||||
rescue => ex
|
||||
end
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -3280,6 +3280,44 @@ class BasicTest(unittest.TestCase):
|
|||
self.assertEqual(bb.d4(1, "a", d=pya.BB.E.E3B, c=2.5), "1,a,2.5,101,nil")
|
||||
self.assertEqual(bb.d4(1, "a", 2.0, pya.BB.E.E3B, 42), "1,a,2,101,42")
|
||||
|
||||
# constness
|
||||
def test_93(self):
|
||||
|
||||
b = pya.B()
|
||||
self.assertEqual(b.is_const_object(), False)
|
||||
|
||||
bc = b._to_const_object()
|
||||
self.assertEqual(bc.is_const_object(), True)
|
||||
|
||||
m = ""
|
||||
try:
|
||||
bc.set_str("abc")
|
||||
self.assertEqual(1, 0)
|
||||
except Exception as ex:
|
||||
m = str(ex)
|
||||
|
||||
self.assertEqual(m, "Cannot call non-const method on a const reference in B.set_str")
|
||||
|
||||
b = pya.B()
|
||||
bc = b
|
||||
self.assertEqual(b._is_const_object(), False)
|
||||
self.assertEqual(bc._is_const_object(), False)
|
||||
bc = bc._to_const_object()
|
||||
b.set_str("abc")
|
||||
self.assertEqual(b._is_const_object(), False)
|
||||
self.assertEqual(bc._is_const_object(), True)
|
||||
self.assertEqual(b.str(), "abc")
|
||||
self.assertEqual(bc.str(), "abc")
|
||||
|
||||
bnc = bc._const_cast()
|
||||
self.assertEqual(b._is_const_object(), False)
|
||||
self.assertEqual(bc._is_const_object(), True)
|
||||
self.assertEqual(bnc._is_const_object(), False)
|
||||
bnc.set_str("xyz")
|
||||
self.assertEqual(b.str(), "xyz")
|
||||
self.assertEqual(bc.str(), "xyz")
|
||||
self.assertEqual(bnc.str(), "xyz")
|
||||
|
||||
# run unit tests
|
||||
if __name__ == '__main__':
|
||||
suite = unittest.TestSuite()
|
||||
|
|
|
|||
|
|
@ -75,13 +75,20 @@ class DBLayoutTest(unittest.TestCase):
|
|||
self.assertEqual( ly.cell_name(ci), "new_cell" )
|
||||
|
||||
self.assertEqual( ly.cell_by_name("new_cell"), ci )
|
||||
self.assertEqual( ly.cell(ci).cell_index(), ci )
|
||||
self.assertEqual( ly.cell("new_cell").name, "new_cell" )
|
||||
self.assertEqual( repr(ly.cell("x")), "None" )
|
||||
lyc = ly.dup()
|
||||
self.assertEqual( lyc._to_const_object().cell("new_cell").name, "new_cell" )
|
||||
self.assertEqual( lyc._to_const_object().cell(ci).cell_index(), ci )
|
||||
|
||||
ci2 = ly.add_cell( "new_cell_b" )
|
||||
self.assertEqual( ly.cells(), 2 )
|
||||
self.assertEqual( ly.cell_by_name("new_cell_b"), ci2 )
|
||||
self.assertEqual( sorted([ c.name for c in ly.cells("new*") ]), ['new_cell', 'new_cell_b'] )
|
||||
self.assertEqual( ci != ci2, True )
|
||||
lyc = ly.dup()
|
||||
self.assertEqual( sorted([ c.name for c in lyc._to_const_object().cells("new*") ]), ['new_cell', 'new_cell_b'] )
|
||||
|
||||
ly.rename_cell( ci2, "x" )
|
||||
self.assertEqual( ly.cell_by_name("x"), ci2 )
|
||||
|
|
@ -918,6 +925,8 @@ class DBLayoutTest(unittest.TestCase):
|
|||
tc.append(l.cell(t).name)
|
||||
self.assertEqual(",".join(tc), "c0")
|
||||
self.assertEqual(l.top_cell().name, "c0")
|
||||
lc = l.dup()
|
||||
self.assertEqual(lc._to_const_object().top_cell().name, "c0") # const version
|
||||
tc = []
|
||||
for t in l.top_cells():
|
||||
tc.append(t.name)
|
||||
|
|
@ -939,6 +948,11 @@ class DBLayoutTest(unittest.TestCase):
|
|||
for t in l.top_cells():
|
||||
tc.append(t.name)
|
||||
self.assertEqual(",".join(tc), "c0,c1")
|
||||
tc = []
|
||||
lc = l.dup()
|
||||
for t in lc._to_const_object().top_cells(): # const version
|
||||
tc.append(t.name)
|
||||
self.assertEqual(",".join(tc), "c0,c1")
|
||||
|
||||
c2 = l.create_cell("c1")
|
||||
self.assertEqual(c2.name, "c1$1")
|
||||
|
|
|
|||
|
|
@ -3233,4 +3233,45 @@ class Basic_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
# constness
|
||||
def test_82
|
||||
|
||||
b = RBA::B::new
|
||||
assert_equal(b.is_const_object, false)
|
||||
|
||||
bc = b._to_const_object
|
||||
assert_equal(bc.is_const_object, true)
|
||||
|
||||
m = ""
|
||||
begin
|
||||
bc.set_str("abc")
|
||||
assert_equal(1, 0)
|
||||
rescue => ex
|
||||
m = ex.to_s
|
||||
end
|
||||
|
||||
assert_equal(m, "Cannot call non-const method on a const reference in B::set_str")
|
||||
|
||||
b = RBA::B::new
|
||||
bc = b
|
||||
assert_equal(b._is_const_object, false)
|
||||
assert_equal(bc._is_const_object, false)
|
||||
b.set_str("abc")
|
||||
bc._to_const_object
|
||||
assert_equal(b._is_const_object, true) # special
|
||||
assert_equal(bc._is_const_object, true)
|
||||
assert_equal(b.str, "abc")
|
||||
assert_equal(bc.str, "abc")
|
||||
|
||||
bnc = bc._const_cast
|
||||
assert_equal(b._is_const_object, false) # special
|
||||
assert_equal(bc._is_const_object, false) # special
|
||||
assert_equal(bnc._is_const_object, false)
|
||||
bnc.set_str("xyz")
|
||||
assert_equal(b.str, "xyz")
|
||||
assert_equal(bc.str, "xyz")
|
||||
assert_equal(bnc.str, "xyz")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -83,14 +83,21 @@ class DBLayoutTests2_TestClass < TestBase
|
|||
assert_equal( ly.cell_name(ci), "new_cell" )
|
||||
|
||||
assert_equal( ly.cell_by_name("new_cell"), ci )
|
||||
assert_equal( ly.cell(ci).cell_index, ci )
|
||||
assert_equal( ly.cells("A*"), [] )
|
||||
assert_equal( ly.cell("new_cell").name, "new_cell" )
|
||||
assert_equal( ly.cell("x").inspect, "nil" )
|
||||
lyc = ly.dup
|
||||
assert_equal( lyc._to_const_object.cell("new_cell").name, "new_cell" )
|
||||
assert_equal( lyc._to_const_object.cell(ci).cell_index, ci )
|
||||
|
||||
ci2 = ly.add_cell( "new_cell_b" )
|
||||
assert_equal( ly.cells, 2 )
|
||||
assert_equal( ly.cell_by_name("new_cell_b"), ci2 )
|
||||
assert_equal( ly.cells("new*").collect { |c| c.name }.sort, ['new_cell', 'new_cell_b'] )
|
||||
assert_equal( ci != ci2, true )
|
||||
lyc = ly.dup
|
||||
assert_equal( lyc._to_const_object.cells("new*").collect { |c| c.name }.sort, ['new_cell', 'new_cell_b'] )
|
||||
|
||||
ly.rename_cell( ci2, "x" )
|
||||
assert_equal( ly.cell_by_name("x"), ci2 )
|
||||
|
|
@ -900,6 +907,9 @@ class DBLayoutTests2_TestClass < TestBase
|
|||
assert_equal(tc.collect { |s| s.to_s }.join(","), "c0")
|
||||
assert_equal(l.top_cell.name, "c0")
|
||||
assert_equal(l.top_cells.collect { |t| t.name }.join(","), "c0")
|
||||
lc = l.dup
|
||||
assert_equal(lc._to_const_object.top_cell.name, "c0")
|
||||
assert_equal(lc._to_const_object.top_cells.collect { |t| t.name }.join(","), "c0")
|
||||
|
||||
c1 = l.create_cell("c1")
|
||||
assert_equal(c1.name, "c1")
|
||||
|
|
|
|||
|
|
@ -900,5 +900,41 @@ class DBPCell_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
class DBPCellParameterStates_TestClass < TestBase
|
||||
|
||||
def test_1
|
||||
|
||||
ps = RBA::PCellParameterState::new
|
||||
|
||||
ps.value = 17
|
||||
assert_equal(ps.value, 17)
|
||||
ps.value = "u"
|
||||
assert_equal(ps.value, "u")
|
||||
|
||||
ps.visible = true
|
||||
assert_equal(ps.is_visible?, true)
|
||||
ps.visible = false
|
||||
assert_equal(ps.is_visible?, false)
|
||||
|
||||
ps.enabled = true
|
||||
assert_equal(ps.is_enabled?, true)
|
||||
ps.enabled = false
|
||||
assert_equal(ps.is_enabled?, false)
|
||||
|
||||
ps.readonly = true
|
||||
assert_equal(ps.is_readonly?, true)
|
||||
ps.readonly = false
|
||||
assert_equal(ps.is_readonly?, false)
|
||||
|
||||
ps.tooltip = "uvw"
|
||||
assert_equal(ps.tooltip, "uvw")
|
||||
|
||||
ps.icon = RBA::PCellParameterState::InfoIcon
|
||||
assert_equal(ps.icon, RBA::PCellParameterState::InfoIcon)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue