Merge pull request #1820 from KLayout/wip

WIP branch
This commit is contained in:
Matthias Köfferlein 2024-08-10 13:33:12 +02:00 committed by GitHub
commit 9ef35d120e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 586 additions and 40 deletions

View File

@ -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"
) +

View File

@ -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"

View File

@ -2308,7 +2308,7 @@ CODE
def netter
self._context("netter") do
DRC::DRCNetter::new
DRC::DRCNetter::new(self)
end
end

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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));
}
}
}
}
@ -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) {

View File

@ -83,6 +83,8 @@ public:
Destroy,
Create,
IsConst,
ConstCast,
ToConst,
Destroyed,
Assign,
Dup

View File

@ -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)");
}
}

View File

@ -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 ())) {

View File

@ -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

View File

@ -116,6 +116,7 @@ public slots:
protected:
void reject ();
void accept ();
private:
Ui::PropertiesDialog *mp_ui;

View File

@ -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) {

View File

@ -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);

View File

@ -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)
{

View File

@ -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;

View File

@ -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 ());

View File

@ -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
*

View File

@ -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"));
}

View File

@ -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

41
testdata/drc/drcSimpleTests_71.drc vendored Normal file
View File

@ -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

BIN
testdata/drc/drcSimpleTests_71.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au71.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au71d.gds vendored Normal file

Binary file not shown.

View File

@ -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()

View File

@ -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")

View File

@ -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

View File

@ -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")

View File

@ -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")