mirror of https://github.com/KLayout/klayout.git
Merge pull request #1744 from KLayout/wip
OASIS reader: avoiding slight rounding of DBU In python read/write cy…
This commit is contained in:
commit
6e2c11435b
|
|
@ -758,6 +758,9 @@ bool run_deep_xor (const XORData &xor_data)
|
|||
{
|
||||
db::DeepShapeStore dss;
|
||||
dss.set_threads (xor_data.threads);
|
||||
|
||||
// TODO: this conflicts with the "set_for_merged_input" optimization below.
|
||||
// It seems not to be very effective then. Why?
|
||||
dss.set_wants_all_cells (true); // saves time for less cell mapping operations
|
||||
|
||||
double dbu = std::min (xor_data.layout_a->dbu (), xor_data.layout_b->dbu ());
|
||||
|
|
|
|||
|
|
@ -407,7 +407,7 @@ DeepRegion::begin_iter () const
|
|||
} else {
|
||||
|
||||
const db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||
db::RecursiveShapeIterator iter (deep_layer ().layout (), top_cell, deep_layer ().layer ());
|
||||
db::RecursiveShapeIterator iter (layout, top_cell, deep_layer ().layer ());
|
||||
return std::make_pair (iter, db::ICplxTrans ());
|
||||
|
||||
}
|
||||
|
|
@ -803,7 +803,7 @@ DeepRegion::and_with (const Region &other, PropertyConstraint property_constrain
|
|||
|
||||
} else {
|
||||
|
||||
return new DeepRegion (and_or_not_with (other_deep, true, property_constraint));
|
||||
return new DeepRegion (and_with_impl (other_deep, property_constraint));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -827,7 +827,7 @@ DeepRegion::not_with (const Region &other, PropertyConstraint property_constrain
|
|||
|
||||
} else {
|
||||
|
||||
return new DeepRegion (and_or_not_with (other_deep, false, property_constraint));
|
||||
return new DeepRegion (not_with_impl (other_deep, property_constraint));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -875,13 +875,13 @@ DeepRegion::andnot_with (const Region &other, PropertyConstraint property_constr
|
|||
}
|
||||
|
||||
DeepLayer
|
||||
DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op, db::PropertyConstraint property_constraint) const
|
||||
DeepRegion::and_with_impl (const DeepRegion *other, db::PropertyConstraint property_constraint) const
|
||||
{
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
|
||||
if (pc_skip (property_constraint)) {
|
||||
|
||||
db::BoolAndOrNotLocalOperation op (and_op);
|
||||
db::BoolAndOrNotLocalOperation op (true);
|
||||
|
||||
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
|
||||
configure_proc (proc);
|
||||
|
|
@ -893,7 +893,7 @@ DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op, db::PropertyC
|
|||
|
||||
} else {
|
||||
|
||||
db::BoolAndOrNotLocalOperationWithProperties op (and_op, &dl_out.layout ().properties_repository (), &deep_layer ().layout ().properties_repository (), &other->deep_layer ().layout ().properties_repository (), property_constraint);
|
||||
db::BoolAndOrNotLocalOperationWithProperties op (true, &dl_out.layout ().properties_repository (), &deep_layer ().layout ().properties_repository (), &other->deep_layer ().layout ().properties_repository (), property_constraint);
|
||||
|
||||
db::local_processor<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRefWithProperties> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
|
||||
configure_proc (proc);
|
||||
|
|
@ -908,6 +908,109 @@ DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op, db::PropertyC
|
|||
return dl_out;
|
||||
}
|
||||
|
||||
DeepLayer
|
||||
DeepRegion::not_with_impl (const DeepRegion *other, db::PropertyConstraint property_constraint) const
|
||||
{
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
DeepLayer dl_prep;
|
||||
|
||||
// first run a local-only task, which is trivial if the layouts are the same
|
||||
// TODO: consider property constraints too.
|
||||
|
||||
if (deep_layer ().layout_index () == other->deep_layer ().layout_index () && pc_skip (property_constraint)) {
|
||||
|
||||
dl_prep = deep_layer ().derived ();
|
||||
|
||||
unsigned int layer_this = deep_layer ().layer ();
|
||||
unsigned int layer_other = other->deep_layer ().layer ();
|
||||
unsigned int layer_out = dl_prep.layer ();
|
||||
|
||||
db::Layout &layout = dl_prep.layout ();
|
||||
|
||||
bool any = false;
|
||||
|
||||
if (layer_this != layer_other) {
|
||||
|
||||
std::set<db::cell_index_type> called;
|
||||
deep_layer ().initial_cell ().collect_called_cells (called);
|
||||
called.insert (deep_layer ().initial_cell ().cell_index ());
|
||||
|
||||
for (auto ci = called.begin (); ci != called.end (); ++ci) {
|
||||
|
||||
db::Cell &cell = layout.cell (*ci);
|
||||
db::Shapes &shapes_out = cell.shapes (layer_out);
|
||||
const db::Shapes &shapes_this = cell.shapes (layer_this);
|
||||
const db::Shapes &shapes_other = cell.shapes (layer_other);
|
||||
|
||||
db::Box overlap = (shapes_this.bbox () & shapes_other.bbox ());
|
||||
|
||||
if (! overlap.empty ()) {
|
||||
|
||||
std::set<db::PolygonRef> others;
|
||||
for (auto si = shapes_other.begin (db::ShapeIterator::Polygons); ! si.at_end (); ++si) {
|
||||
if (si->type () == db::Shape::PolygonRef) {
|
||||
others.insert (si->polygon_ref ());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto si = shapes_this.begin (db::ShapeIterator::Polygons); ! si.at_end (); ++si) {
|
||||
if (si->type () == db::Shape::PolygonRef && others.find (si->polygon_ref ()) != others.end ()) {
|
||||
// drop duplicate
|
||||
} else {
|
||||
any = true;
|
||||
shapes_out.insert (*si);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (! shapes_this.empty ()) {
|
||||
|
||||
any = true;
|
||||
shapes_out = shapes_this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// stop if empty
|
||||
if (! any) {
|
||||
return dl_prep;
|
||||
}
|
||||
|
||||
} else {
|
||||
dl_prep = deep_layer ();
|
||||
}
|
||||
|
||||
if (pc_skip (property_constraint)) {
|
||||
|
||||
db::BoolAndOrNotLocalOperation op (false);
|
||||
|
||||
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
|
||||
configure_proc (proc);
|
||||
proc.set_threads (deep_layer ().store ()->threads ());
|
||||
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
|
||||
|
||||
proc.run (&op, dl_prep.layer (), other->deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
} else {
|
||||
|
||||
db::BoolAndOrNotLocalOperationWithProperties op (false, &dl_out.layout ().properties_repository (), &deep_layer ().layout ().properties_repository (), &other->deep_layer ().layout ().properties_repository (), property_constraint);
|
||||
|
||||
db::local_processor<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRefWithProperties> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
|
||||
configure_proc (proc);
|
||||
proc.set_threads (deep_layer ().store ()->threads ());
|
||||
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
|
||||
|
||||
proc.run (&op, dl_prep.layer (), other->deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
}
|
||||
|
||||
return dl_out;
|
||||
}
|
||||
|
||||
std::pair<DeepLayer, DeepLayer>
|
||||
DeepRegion::and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const
|
||||
{
|
||||
|
|
@ -1008,8 +1111,8 @@ DeepRegion::xor_with (const Region &other, db::PropertyConstraint property_const
|
|||
other_deep_mapped->disable_progress ();
|
||||
}
|
||||
|
||||
DeepLayer n1 (and_or_not_with (other_deep_mapped.get (), false, property_constraint));
|
||||
DeepLayer n2 (other_deep_mapped->and_or_not_with (this, false, property_constraint));
|
||||
DeepLayer n1 (not_with_impl (other_deep_mapped.get (), property_constraint));
|
||||
DeepLayer n2 (other_deep_mapped->not_with_impl (this, property_constraint));
|
||||
n1.add_from (n2);
|
||||
|
||||
return new DeepRegion (n1);
|
||||
|
|
|
|||
|
|
@ -178,7 +178,8 @@ private:
|
|||
|
||||
void init ();
|
||||
void ensure_merged_polygons_valid () const;
|
||||
DeepLayer and_or_not_with(const DeepRegion *other, bool and_op, PropertyConstraint property_constraint) const;
|
||||
DeepLayer not_with_impl (const DeepRegion *other, PropertyConstraint property_constraint) const;
|
||||
DeepLayer and_with_impl (const DeepRegion *other, PropertyConstraint property_constraint) const;
|
||||
std::pair<DeepLayer, DeepLayer> and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const;
|
||||
DeepRegion *apply_filter (const PolygonFilterBase &filter) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -1737,12 +1737,14 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
|
|||
CRONOLOGY_COLLECTION_BRACKET(event_compute_contexts_unlocked)
|
||||
std::map<unsigned int, const db::Shapes *> intruder_shapes;
|
||||
if (intruder_cell) {
|
||||
|
||||
for (std::vector<unsigned int>::const_iterator l = contexts.intruder_layers ().begin (); l != contexts.intruder_layers ().end (); ++l) {
|
||||
const db::Shapes *s = &intruder_cell->shapes (contexts.actual_intruder_layer (*l));
|
||||
if (! s->empty ()) {
|
||||
intruder_shapes.insert (std::make_pair (*l, s));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
db::box_convert <db::CellInstArray, true> inst_bcs (*mp_subject_layout, contexts.subject_layer ());
|
||||
|
|
@ -1824,8 +1826,8 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
|
|||
|
||||
}
|
||||
|
||||
// TODO: can we shortcut this if interactions is empty?
|
||||
{
|
||||
if (! intruders.second.empty () || ! intruder_shapes.empty ()) {
|
||||
|
||||
db::box_scanner2<db::CellInstArray, int, TI, int> scanner;
|
||||
db::addressable_object_from_shape<TI> heap;
|
||||
interaction_registration_inst2shape<TS, TI, TR> rec (mp_subject_layout, contexts.subject_layer (), dist, &interactions);
|
||||
|
|
@ -1849,6 +1851,7 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
|
|||
}
|
||||
|
||||
scanner.process (rec, dist, inst_bcs, db::box_convert<TI> ());
|
||||
|
||||
}
|
||||
|
||||
// produce the tasks for computing the next-level interactions
|
||||
|
|
|
|||
|
|
@ -1008,7 +1008,7 @@ std::string LayoutToNetlist::name (const ShapeCollection &coll) const
|
|||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlist::register_layer (const ShapeCollection &collection, const std::string &n_in)
|
||||
unsigned int LayoutToNetlist::register_layer (const ShapeCollection &collection, const std::string &n_in)
|
||||
{
|
||||
if (m_region_by_original.find (tl::id_of (collection.get_delegate ())) != m_region_by_original.end ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("The layer is already registered")));
|
||||
|
|
@ -1042,10 +1042,14 @@ void LayoutToNetlist::register_layer (const ShapeCollection &collection, const s
|
|||
|
||||
}
|
||||
|
||||
unsigned int layer = dl.layer ();
|
||||
|
||||
m_region_by_original [tl::id_of (collection.get_delegate ())] = dl;
|
||||
m_region_of_layer [dl.layer ()] = dl;
|
||||
m_region_of_layer [layer] = dl;
|
||||
m_named_regions [n] = dl;
|
||||
m_name_of_layer [dl.layer ()] = n;
|
||||
m_name_of_layer [layer] = n;
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
db::DeepLayer LayoutToNetlist::deep_layer_of (const db::ShapeCollection &coll) const
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ public:
|
|||
* In addition to regions, text collections can be registered too.
|
||||
* Including texts in "connect" makes net names begin assigned from the text strings.
|
||||
*/
|
||||
void register_layer (const ShapeCollection &collection, const std::string &name = std::string ());
|
||||
unsigned int register_layer (const ShapeCollection &collection, const std::string &name = std::string ());
|
||||
|
||||
/**
|
||||
* @brief Gets the name of the given collection
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ class RecursiveShapeReceiver;
|
|||
* shape classes and shape properties.
|
||||
*/
|
||||
class DB_PUBLIC RecursiveShapeIterator
|
||||
: public gsi::ObjectBase
|
||||
{
|
||||
public:
|
||||
typedef db::Layout layout_type;
|
||||
|
|
|
|||
|
|
@ -330,11 +330,16 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
gsi::method ("layer_name", (std::string (db::LayoutToNetlist::*) (const db::ShapeCollection ®ion) const) &db::LayoutToNetlist::name, gsi::arg ("l"),
|
||||
"@brief Gets the name of the given layer\n"
|
||||
) +
|
||||
gsi::method ("layer_index", (unsigned int (db::LayoutToNetlist::*) (const db::ShapeCollection ®ion) const) &db::LayoutToNetlist::layer_of<db::ShapeCollection>, gsi::arg ("l"),
|
||||
"@brief Gets the layer index for the given data object\n"
|
||||
"This method has been introduced in version 0.29.3.\n"
|
||||
) +
|
||||
gsi::method ("layer_name", (std::string (db::LayoutToNetlist::*) (unsigned int) const) &db::LayoutToNetlist::name, gsi::arg ("l"),
|
||||
"@brief Gets the name of the given layer (by index)\n"
|
||||
) +
|
||||
gsi::method ("register", (void (db::LayoutToNetlist::*) (const db::ShapeCollection &collection, const std::string &)) &db::LayoutToNetlist::register_layer, gsi::arg ("l"), gsi::arg ("n", std::string ()),
|
||||
gsi::method ("register", (unsigned int (db::LayoutToNetlist::*) (const db::ShapeCollection &collection, const std::string &)) &db::LayoutToNetlist::register_layer, gsi::arg ("l"), gsi::arg ("n", std::string ()),
|
||||
"@brief Names the given layer\n"
|
||||
"@return The index of the layer registered\n"
|
||||
"'l' must be a \\Region or \\Texts object.\n"
|
||||
"Flat regions or text collections must be registered with this function, before they can be used in \\connect. "
|
||||
"Registering will copy the shapes into the LayoutToNetlist object in this step to enable "
|
||||
|
|
@ -346,7 +351,7 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"\n"
|
||||
"If required, the system will assign a name automatically."
|
||||
"\n"
|
||||
"This method has been generalized in version 0.27.\n"
|
||||
"This method has been generalized in version 0.27. Starting with version 0.29.3, the index of the layer is returned.\n"
|
||||
) +
|
||||
gsi::method_ext ("layer_names", &l2n_layer_names,
|
||||
"@brief Returns a list of names of the layers kept inside the LayoutToNetlist object."
|
||||
|
|
|
|||
|
|
@ -299,6 +299,8 @@ module DRC
|
|||
# @name name
|
||||
# @brief Assigns a name to a layer
|
||||
# @synopsis name(layer, name)
|
||||
# @synopsis name(layer, name, layer_number, datatype_number)
|
||||
# @synopsis name(layer, name, layer_info)
|
||||
# Layer names are listed in the LayoutToNetlist (L2N) or LVS database. They
|
||||
# are used to identify the layers, the net or device terminal geometries are
|
||||
# on. It is usual to have computed layers, so it is necessary to indicate the
|
||||
|
|
@ -325,6 +327,12 @@ module DRC
|
|||
#
|
||||
# \name can only be used once on a layer and the layer names must be
|
||||
# unique (not taken by another layer).
|
||||
#
|
||||
# The layer/datatype or LayerInfo specification is optional and will
|
||||
# be used to configure the internal layout. This information is also
|
||||
# persisted inside database files. Specifying a layer/datatype information
|
||||
# is useful, if a layer is not an original layer, but is to be restored
|
||||
# to an actual layout layer later.
|
||||
|
||||
# %DRC%
|
||||
# @name name_prefix
|
||||
|
|
@ -332,13 +340,33 @@ module DRC
|
|||
# @synopsis name_prefix(prefix)
|
||||
# See \\name for details. The default prefix is "l".
|
||||
|
||||
def name(l, name)
|
||||
def name(*args)
|
||||
|
||||
@engine._context("name") do
|
||||
|
||||
if args.size < 2 || args.size > 4
|
||||
raise("Two to four arguments expected (layer, name, [layer, datatype / layer properties])")
|
||||
end
|
||||
|
||||
l = args[0]
|
||||
l.is_a?(DRC::DRCLayer) || raise("First argument must be a layer")
|
||||
|
||||
name = args[1]
|
||||
(name.is_a?(String) && name != "") || raise("Second argument must be a non-empty string")
|
||||
|
||||
lp = args[2]
|
||||
if lp
|
||||
if !lp.is_a?(RBA::LayerInfo)
|
||||
lnum = args[2]
|
||||
dnum = args[3] || 0
|
||||
lnum.is_a?(1.class) || raise("Layer argument needs to be a RBA::LayerInfo object or a layer number")
|
||||
dnum.is_a?(1.class) || raise("Datatype argument needs to be an integer")
|
||||
lp = RBA::LayerInfo::new(lnum, dnum)
|
||||
elsif args[3]
|
||||
raise("Three arguments are enough with RBA::LayerInfo")
|
||||
end
|
||||
end
|
||||
|
||||
id = l.data.data_id
|
||||
|
||||
if @layers && @layers[id]
|
||||
|
|
@ -349,7 +377,7 @@ module DRC
|
|||
return
|
||||
end
|
||||
|
||||
self._register_layer(l.data, "name", name)
|
||||
self._register_layer(l.data, "name", name, lp)
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -828,7 +856,7 @@ module DRC
|
|||
|
||||
protected
|
||||
|
||||
def _register_layer(data, context, name = nil)
|
||||
def _register_layer(data, context, name = nil, lp = nil)
|
||||
|
||||
id = data.data_id
|
||||
ensure_data
|
||||
|
|
@ -846,7 +874,12 @@ module DRC
|
|||
@layers[id] = [ data, name, context ]
|
||||
|
||||
# every layer gets registered and intra-layer connections are made
|
||||
@l2n.register(data, name)
|
||||
index = @l2n.register(data, name)
|
||||
|
||||
# set the layer properties if requested
|
||||
if lp
|
||||
@l2n.internal_layout.set_info(index, lp)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1911,3 +1911,35 @@ TEST(121_ShapesOfTerminal)
|
|||
|
||||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
TEST(122_NamedLayers)
|
||||
{
|
||||
std::string rs = tl::testdata ();
|
||||
rs += "/drc/drcSimpleTests_122.drc";
|
||||
|
||||
std::string input = tl::testdata ();
|
||||
input += "/drc/drcSimpleTests_122.gds";
|
||||
|
||||
std::string au_output = tl::testdata ();
|
||||
au_output += "/drc/drcSimpleTests_au122.l2n";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.l2n");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$drc_test_source = '%s'\n"
|
||||
"$drc_test_target = '%s'\n"
|
||||
, input, output)
|
||||
);
|
||||
config.set_interpreter (lym::Macro::Ruby);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
}
|
||||
|
||||
lym::Macro drc;
|
||||
drc.load_from (rs);
|
||||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
compare_text_files (output, au_output);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1297,10 +1297,10 @@ static gsi::Class<B> decl_b ("", "B",
|
|||
gsi::method ("an_cref", &B::an_cref) +
|
||||
// implemented by extension below:
|
||||
// gsi::iterator_ext ("b10", &b10b_ext, &b10e_ext) +
|
||||
gsi::iterator ("b10_nc", &B::b10b_nc, &B::b10e_nc) +
|
||||
gsi::iterator ("b11", &B::b11b, &B::b11e) +
|
||||
gsi::iterator ("b12", &B::b12b, &B::b12e) +
|
||||
gsi::iterator ("b13", &B::b13b, &B::b13e) +
|
||||
gsi::iterator ("b10_nc|each_a_be_nc", &B::b10b_nc, &B::b10e_nc) +
|
||||
gsi::iterator ("b11|each_a_be_v", &B::b11b, &B::b11e) +
|
||||
gsi::iterator ("b12|each_a_be_p", &B::b12b, &B::b12e) +
|
||||
gsi::iterator ("b13|each_a_be_cp", &B::b13b, &B::b13e) +
|
||||
gsi::method ("amember_or_nil_alt|amember_or_nil", &B::amember_or_nil) +
|
||||
gsi::method ("amember_ptr_alt|amember_ptr", &B::amember_ptr) +
|
||||
gsi::method ("xxx|amember_cptr", &B::amember_cptr) +
|
||||
|
|
@ -1444,8 +1444,8 @@ static gsi::Class<B> decl_b ("", "B",
|
|||
|
||||
// extending B
|
||||
static gsi::ClassExt<B> b_ext (
|
||||
gsi::iterator_ext ("b10", &b10b_ext, &b10e_ext) +
|
||||
gsi::iterator_ext ("b10p", &b10bp_ext, &b10ep_ext)
|
||||
gsi::iterator_ext ("b10|each_a_be", &b10b_ext, &b10e_ext) +
|
||||
gsi::iterator_ext ("b10p|each_a_be_pp", &b10bp_ext, &b10ep_ext)
|
||||
);
|
||||
|
||||
CopyDetector *new_cd (int x)
|
||||
|
|
|
|||
|
|
@ -516,7 +516,7 @@ MacroController::sync_macro_sources ()
|
|||
if (! t->base_path ().empty ()) {
|
||||
QDir base_dir (tl::to_qstring (t->base_path ()));
|
||||
if (base_dir.exists ()) {
|
||||
std::string path = tl::to_string (base_dir.absolutePath ());
|
||||
std::string path = tl::to_string (base_dir.canonicalPath ());
|
||||
tech_names_by_path [path].push_back (t->name ());
|
||||
if (t->is_readonly ()) {
|
||||
readonly_paths.insert (path);
|
||||
|
|
@ -559,7 +559,7 @@ MacroController::sync_macro_sources ()
|
|||
description += " - " + tl::to_string (tr ("%1 branch").arg (tl::to_qstring (*f)));
|
||||
}
|
||||
|
||||
external_paths.push_back (ExternalPathDescriptor (tl::to_string (macro_dir.path ()), description, macro_categories () [c].name, lym::MacroCollection::TechFolder, readonly_paths.find (t->first) != readonly_paths.end ()));
|
||||
external_paths.push_back (ExternalPathDescriptor (tl::to_string (macro_dir.canonicalPath ()), description, macro_categories () [c].name, lym::MacroCollection::TechFolder, readonly_paths.find (t->first) != readonly_paths.end ()));
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -591,7 +591,7 @@ MacroController::sync_macro_sources ()
|
|||
if (*f != macro_categories () [c].name) {
|
||||
description += " - " + tl::to_string (tr ("%1 branch").arg (tl::to_qstring (*f)));
|
||||
}
|
||||
external_paths.push_back (ExternalPathDescriptor (tl::to_string (macro_dir.path ()), description, macro_categories () [c].name, lym::MacroCollection::SaltFolder, g->is_readonly (), g->version ()));
|
||||
external_paths.push_back (ExternalPathDescriptor (tl::to_string (macro_dir.canonicalPath ()), description, macro_categories () [c].name, lym::MacroCollection::SaltFolder, g->is_readonly (), g->version ()));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1507,29 +1507,39 @@ MacroEditorDialog::eventFilter (QObject *obj, QEvent *event)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (lay::BusySection::is_busy () && (m_in_breakpoint || m_in_exec) && (dynamic_cast <QInputEvent *> (event) != 0 || dynamic_cast <QPaintEvent *> (event) != 0)) {
|
||||
if (m_in_exec) {
|
||||
|
||||
if (lay::BusySection::is_busy ()) {
|
||||
|
||||
#if 0
|
||||
if (dynamic_cast <QInputEvent *> (event) != 0 || dynamic_cast <QPaintEvent *> (event) != 0) {
|
||||
|
||||
// In breakpoint or execution mode and while processing the events inside the debugger,
|
||||
// ignore all input or paint events targeted to widgets which are not children of this or the assistant dialog.
|
||||
// Ignoring the paint event is required because otherwise a repaint action would be triggered on a layout which
|
||||
// is potentially unstable or inconsistent.
|
||||
// We nevertheless allow events send to a HelpDialog or ProgressWidget since those are vital for the application's
|
||||
// functionality and are known not to cause any interference.
|
||||
QObject *rec = obj;
|
||||
while (rec && (rec != this && !dynamic_cast<lay::HelpDialog *> (rec) && !dynamic_cast<lay::ProgressWidget *> (rec))) {
|
||||
rec = rec->parent ();
|
||||
}
|
||||
if (! rec) {
|
||||
// TODO: reschedule the paint events (?)
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
// While no explicit event processing is in progress and we are executing, this is an indication that
|
||||
// "real" events are processed. In that case, we can postpone excplit processing. This avoids interference
|
||||
// with GUI code run in the debugger.
|
||||
m_last_process_events = tl::Clock::current ();
|
||||
|
||||
// In breakpoint or execution mode and while processing the events from the debugger,
|
||||
// ignore all input or paint events targeted to widgets which are not children of this or the assistant dialog.
|
||||
// Ignoring the paint event is required because otherwise a repaint action would be triggered on a layout which
|
||||
// is potentially unstable or inconsistent.
|
||||
// We nevertheless allow events send to a HelpDialog or ProgressWidget since those are vital for the application's
|
||||
// functionality and are known not to cause any interference.
|
||||
QObject *rec = obj;
|
||||
while (rec && (rec != this && !dynamic_cast<lay::HelpDialog *> (rec) && !dynamic_cast<lay::ProgressWidget *> (rec))) {
|
||||
rec = rec->parent ();
|
||||
}
|
||||
if (! rec) {
|
||||
// TODO: reschedule the paint events (?)
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if (! lay::BusySection::is_busy () && m_in_exec) {
|
||||
|
||||
// While no explicit event processing is in progress and we are executing, this is an indication that
|
||||
// "real" events are processed. In that case, we can postpone excplit processing. This avoids interference
|
||||
// with GUI code run in the debugger.
|
||||
m_last_process_events = tl::Clock::current ();
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -3054,6 +3064,8 @@ MacroEditorDialog::start_exec (gsi::Interpreter *ec)
|
|||
return;
|
||||
} else if (m_ignore_exec_events) {
|
||||
return;
|
||||
} else if (lay::BusySection::is_busy () || m_in_breakpoint) {
|
||||
return;
|
||||
}
|
||||
|
||||
// prevents recursion
|
||||
|
|
@ -3215,7 +3227,7 @@ MacroEditorDialog::exception_thrown (gsi::Interpreter *interpreter, size_t file_
|
|||
exit_if_needed ();
|
||||
|
||||
// avoid recursive breakpoints and exception catches from the console while in a breakpoint or exception stop
|
||||
if (lay::BusySection::is_busy ()) {
|
||||
if (lay::BusySection::is_busy () || m_in_breakpoint) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -3317,7 +3329,7 @@ MacroEditorDialog::trace (gsi::Interpreter *interpreter, size_t file_id, int lin
|
|||
exit_if_needed ();
|
||||
|
||||
// avoid recursive breakpoints and exception catches from the console while in a breakpoint or exception stop
|
||||
if (lay::BusySection::is_busy ()) {
|
||||
if (lay::BusySection::is_busy () || m_in_breakpoint) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -3682,7 +3694,7 @@ MacroEditorDialog::stop_button_clicked ()
|
|||
{
|
||||
if (QApplication::activeModalWidget () == this) {
|
||||
// close this window if it was shown in modal mode
|
||||
accept ();
|
||||
QDialog::accept ();
|
||||
}
|
||||
|
||||
m_in_exec = false;
|
||||
|
|
@ -3748,12 +3760,9 @@ MacroEditorDialog::run (int stop_stack_depth, lym::Macro *macro)
|
|||
|
||||
if (QApplication::activeModalWidget () == this) {
|
||||
// close this window if it was shown in modal mode
|
||||
accept ();
|
||||
QDialog::accept ();
|
||||
}
|
||||
|
||||
// in a breakpoint
|
||||
m_in_breakpoint = false;
|
||||
|
||||
} else {
|
||||
|
||||
if (! macro) {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ namespace db
|
|||
OASISReader::OASISReader (tl::InputStream &s)
|
||||
: m_stream (s),
|
||||
m_progress (tl::to_string (tr ("Reading OASIS file")), 10000),
|
||||
m_dbu (0.001),
|
||||
m_expect_strict_mode (-1),
|
||||
mm_repetition (this, "repetition"),
|
||||
mm_placement_cell (this, "placement-cell"),
|
||||
|
|
@ -648,8 +647,7 @@ OASISReader::do_read (db::Layout &layout)
|
|||
}
|
||||
|
||||
// compute database unit in pixel per meter
|
||||
m_dbu = 1.0e-6 / res;
|
||||
layout.dbu (m_dbu * 1e6);
|
||||
layout.dbu (1.0 / res);
|
||||
|
||||
// read over table offsets if required
|
||||
bool table_offsets_at_end = get_uint ();
|
||||
|
|
|
|||
|
|
@ -124,7 +124,6 @@ private:
|
|||
tl::InputStream &m_stream;
|
||||
tl::AbsoluteProgress m_progress;
|
||||
std::string m_cellname;
|
||||
double m_dbu;
|
||||
int m_expect_strict_mode;
|
||||
size_t m_first_cellname;
|
||||
size_t m_first_propname;
|
||||
|
|
|
|||
|
|
@ -869,6 +869,12 @@ handle_exception (const std::string & /*where*/, rba::RubyError &ex)
|
|||
handle_exception (ex.exc (), ex.first_chance ());
|
||||
}
|
||||
|
||||
static void
|
||||
handle_exception (rba::RubyContinueException &ex)
|
||||
{
|
||||
rb_jump_tag (ex.state ());
|
||||
}
|
||||
|
||||
static void
|
||||
handle_exception (const std::string &where, tl::Exception &ex)
|
||||
{
|
||||
|
|
@ -897,6 +903,8 @@ handle_exception (const std::string &where)
|
|||
handle_exception ((where), ex); \
|
||||
} catch (tl::ExitException &ex) { \
|
||||
handle_exception ((where), ex); \
|
||||
} catch (rba::RubyContinueException &ex) { \
|
||||
handle_exception (ex); \
|
||||
} catch (rba::RubyError &ex) { \
|
||||
handle_exception ((where), ex); \
|
||||
} catch (tl::Exception &ex) { \
|
||||
|
|
@ -1381,23 +1389,17 @@ method_adaptor (int mid, int argc, VALUE *argv, VALUE self, bool ctor)
|
|||
std::unique_ptr<gsi::IterAdaptorAbstractBase> iter ((gsi::IterAdaptorAbstractBase *) retlist.read<void *> (heap));
|
||||
if (iter.get ()) {
|
||||
|
||||
try {
|
||||
gsi::SerialArgs rr (iter->serial_size ());
|
||||
while (! iter->at_end ()) {
|
||||
|
||||
gsi::SerialArgs rr (iter->serial_size ());
|
||||
while (! iter->at_end ()) {
|
||||
rr.reset ();
|
||||
iter->get (rr);
|
||||
|
||||
rr.reset ();
|
||||
iter->get (rr);
|
||||
VALUE value = pull_arg (meth->ret_type (), p, rr, heap);
|
||||
rba_yield_checked (value);
|
||||
|
||||
VALUE value = pull_arg (meth->ret_type (), p, rr, heap);
|
||||
rba_yield_checked (value);
|
||||
iter->inc ();
|
||||
|
||||
iter->inc ();
|
||||
|
||||
}
|
||||
|
||||
} catch (tl::CancelException &) {
|
||||
// break encountered
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2402,7 +2404,7 @@ RubyInterpreter::require (const std::string &filename_utf8)
|
|||
RUBY_END_EXEC
|
||||
|
||||
if (error) {
|
||||
rba_check_error ();
|
||||
rba_check_error (error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2423,7 +2425,7 @@ RubyInterpreter::load_file (const std::string &filename_utf8)
|
|||
RUBY_END_EXEC
|
||||
|
||||
if (error) {
|
||||
rba_check_error ();
|
||||
rba_check_error (error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,26 @@ private:
|
|||
VALUE m_exc;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A class responsible for forwarding exceptions raised from "break", "return" and other flow control functions
|
||||
*/
|
||||
class RubyContinueException
|
||||
: public tl::CancelException
|
||||
{
|
||||
public:
|
||||
RubyContinueException (int state)
|
||||
: tl::CancelException (), m_state (state)
|
||||
{ }
|
||||
|
||||
int state () const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_state;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The proxy object that represents the C++ object on the Ruby side
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -127,26 +127,23 @@ exceptions_blocked ()
|
|||
}
|
||||
|
||||
void
|
||||
rba_check_error ()
|
||||
rba_check_error (int state)
|
||||
{
|
||||
VALUE lasterr = rb_errinfo ();
|
||||
|
||||
// NOTE: this seems to be required to avoid segfaults on Ruby 2.3.1 after
|
||||
// a break was encountered.
|
||||
rb_set_errinfo (Qnil);
|
||||
|
||||
// Ruby employs this pseudo-exception to indicate a "break" of a loop
|
||||
// Ruby employs this pseudo-exception to indicate a "break" or "return" of a loop.
|
||||
// As this is an opaque condition, we continue Ruby execution later through a "RubyContinueException".
|
||||
#if HAVE_RUBY_VERSION_CODE < 10900
|
||||
if (lasterr == Qnil) {
|
||||
throw tl::CancelException ();
|
||||
throw RubyContinueException (state);
|
||||
}
|
||||
#elif HAVE_RUBY_VERSION_CODE < 20300
|
||||
if (TYPE (lasterr) == T_NODE) {
|
||||
throw tl::CancelException ();
|
||||
throw RubyContinueException (state);
|
||||
}
|
||||
#else
|
||||
if (TYPE (lasterr) == T_IMEMO) {
|
||||
throw tl::CancelException ();
|
||||
throw RubyContinueException (state);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -405,7 +402,7 @@ rba_class_new_instance_checked (int argc, VALUE *argv, VALUE klass)
|
|||
RUBY_END_EXEC
|
||||
|
||||
if (error) {
|
||||
rba_check_error ();
|
||||
rba_check_error (error);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -458,7 +455,7 @@ VALUE rba_funcall2_checked (VALUE obj, ID id, int argc, VALUE *args)
|
|||
RUBY_END_EXEC
|
||||
|
||||
if (error) {
|
||||
rba_check_error ();
|
||||
rba_check_error (error);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -497,7 +494,7 @@ rba_f_eval_checked (int argc, VALUE *argv, VALUE self)
|
|||
RUBY_END_EXEC
|
||||
|
||||
if (error) {
|
||||
rba_check_error ();
|
||||
rba_check_error (error);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -513,7 +510,7 @@ rba_yield_checked (VALUE value)
|
|||
RUBY_END_EXEC
|
||||
|
||||
if (error) {
|
||||
rba_check_error ();
|
||||
rba_check_error (error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ namespace rba
|
|||
|
||||
tl::BacktraceElement rba_split_bt_information (const char *m, size_t l);
|
||||
void rba_get_backtrace_from_array (VALUE backtrace, std::vector<tl::BacktraceElement> &bt, unsigned int skip);
|
||||
void rba_check_error ();
|
||||
void rba_check_error (int state);
|
||||
VALUE rba_string_value_f (VALUE obj);
|
||||
VALUE rba_safe_string_value (VALUE obj);
|
||||
VALUE rba_safe_obj_as_string (VALUE obj);
|
||||
|
|
@ -265,7 +265,7 @@ R rba_safe_func (R (*f) (A), A arg)
|
|||
RUBY_END_EXEC
|
||||
|
||||
if (error) {
|
||||
rba_check_error ();
|
||||
rba_check_error (error);
|
||||
}
|
||||
return cp.r;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,10 +62,32 @@ public:
|
|||
virtual void read (Database &db)
|
||||
{
|
||||
try {
|
||||
// TODO: do not allow waivers here?
|
||||
// (otherwise, description lines like "WE0 ..." would be read as waivers)
|
||||
do_read (db);
|
||||
} catch (tl::Exception &ex) {
|
||||
error (ex.msg ());
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
// try to find a waiver database and apply it if possible
|
||||
std::string waived_source = m_input_stream.source () + ".waived";
|
||||
|
||||
tl::InputStream is_waived (waived_source);
|
||||
|
||||
try {
|
||||
Database db_waived;
|
||||
RVEReader reader_waived (is_waived);
|
||||
reader_waived.do_read (db_waived);
|
||||
db.apply (db_waived);
|
||||
} catch (tl::Exception &ex) {
|
||||
warn (ex.msg ());
|
||||
}
|
||||
|
||||
} catch (...) {
|
||||
// ignore stream errors
|
||||
}
|
||||
}
|
||||
|
||||
void do_read (Database &db)
|
||||
|
|
@ -157,7 +179,16 @@ public:
|
|||
while (*cp && isspace (*cp)) {
|
||||
++cp;
|
||||
}
|
||||
waivers.insert (std::make_pair (n, std::string ())).first->second = cp;
|
||||
|
||||
auto wi = waivers.insert (std::make_pair (n, std::string ()));
|
||||
// NOTE: first line is skipped (author, time)
|
||||
if (! wi.second) {
|
||||
std::string &s = wi.first->second;
|
||||
if (! s.empty ()) {
|
||||
s += "\n";
|
||||
}
|
||||
s += cp;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -176,7 +207,6 @@ public:
|
|||
|
||||
std::map<size_t, std::string>::const_iterator w = waivers.find (shape);
|
||||
bool waived = (w != waivers.end ());
|
||||
// TODO: add waiver string somehow ...
|
||||
|
||||
if (at_end ()) {
|
||||
warn (tl::to_string (tr ("Unexpected end of file before the specified number of shapes was read - stopping.")));
|
||||
|
|
@ -406,6 +436,7 @@ public:
|
|||
Item *item = db.create_item (cell->id (), cath->id ());
|
||||
if (waived) {
|
||||
db.add_item_tag (item, waived_tag_id);
|
||||
item->set_comment (w->second);
|
||||
}
|
||||
|
||||
item->values ().swap (values);
|
||||
|
|
|
|||
|
|
@ -81,3 +81,13 @@ TEST(3)
|
|||
{
|
||||
run_rve_test (_this, "rve3.db", "rve3_au_2.txt");
|
||||
}
|
||||
|
||||
TEST(4)
|
||||
{
|
||||
run_rve_test (_this, "rve4.db", "rve4_au.txt");
|
||||
}
|
||||
|
||||
TEST(5)
|
||||
{
|
||||
run_rve_test (_this, "rve5.db", "rve5_au.txt");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ gate = active & poly
|
|||
name(l1, "l1")
|
||||
name(l2, "l2")
|
||||
name(l3, "l3")
|
||||
name(sd, "sd")
|
||||
name(sd, "sd", 17, 0)
|
||||
name(poly, "poly")
|
||||
name(gate, "gate")
|
||||
name(gate, "gate", RBA::LayerInfo::new(18, 0))
|
||||
name(contact, "contact")
|
||||
|
||||
mos_ex = RBA::DeviceExtractorMOS3Transistor::new("MOS")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
source $drc_test_source
|
||||
report_netlist $drc_test_target
|
||||
|
||||
deep
|
||||
|
||||
l1 = input(1, 0)
|
||||
l2 = input(2, 0)
|
||||
l3 = input(3, 0)
|
||||
|
||||
active = input(10, 0)
|
||||
poly = input(11, 0)
|
||||
contact = input(12, 0)
|
||||
|
||||
sd = active - poly
|
||||
gate = active & poly
|
||||
|
||||
name(l1, "l1")
|
||||
name(l2, "l2")
|
||||
name(l3, "l3", RBA::LayerInfo::new(3, 0, "l3"))
|
||||
name(sd, "sd", 17, 0)
|
||||
name(poly, "poly", 11)
|
||||
name(gate, "gate")
|
||||
name(contact, "contact")
|
||||
|
||||
mos_ex = RBA::DeviceExtractorMOS3Transistor::new("MOS")
|
||||
extract_devices(mos_ex, { "SD" => sd, "G" => gate, "P" => poly })
|
||||
|
||||
connect(contact, poly)
|
||||
connect(contact, sd)
|
||||
connect(l1, contact)
|
||||
connect(l1, l2)
|
||||
connect(l2, l3)
|
||||
|
||||
netlist
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,113 @@
|
|||
#%l2n-klayout
|
||||
W(TOP)
|
||||
U(0.001)
|
||||
L(l1 '1/0')
|
||||
L(l2 '2/0')
|
||||
L(l3 'l3 (3/0)')
|
||||
L(poly '11/0')
|
||||
L(contact '12/0')
|
||||
L(sd '17/0')
|
||||
C(l1 l1 l2 contact)
|
||||
C(l2 l1 l2 l3)
|
||||
C(l3 l2 l3)
|
||||
C(poly poly contact)
|
||||
C(contact l1 poly contact sd)
|
||||
C(sd contact sd)
|
||||
K(MOS MOS3)
|
||||
D(D$MOS MOS
|
||||
T(S
|
||||
R(sd (-2000 -2600) (4000 800))
|
||||
)
|
||||
T(G
|
||||
R(poly (-2000 -1800) (4000 3600))
|
||||
)
|
||||
T(D
|
||||
R(sd (-2000 1800) (4000 800))
|
||||
)
|
||||
)
|
||||
X(A
|
||||
R((-2800 -2500) (5600 5200))
|
||||
N(1
|
||||
R(contact (-1900 2000) (600 600))
|
||||
R(contact (-600 -600) (600 600))
|
||||
R(contact (2600 -600) (600 600))
|
||||
R(contact (-600 -600) (600 600))
|
||||
R(contact (-2200 -600) (600 600))
|
||||
R(contact (-600 -600) (600 600))
|
||||
R(sd (-2300 -700) (4000 800))
|
||||
)
|
||||
N(2
|
||||
R(contact (-1900 -2400) (600 600))
|
||||
R(contact (2600 -600) (600 600))
|
||||
R(contact (-2200 -600) (600 600))
|
||||
R(sd (-2300 -700) (4000 800))
|
||||
)
|
||||
N(3
|
||||
R(poly (-2800 -1700) (5600 3600))
|
||||
)
|
||||
P(1)
|
||||
P(2)
|
||||
P(3)
|
||||
D(1 D$MOS
|
||||
Y(0 100)
|
||||
E(L 3.6)
|
||||
E(W 4)
|
||||
E(AS 3.2)
|
||||
E(AD 3.2)
|
||||
E(PS 9.6)
|
||||
E(PD 9.6)
|
||||
T(S 2)
|
||||
T(G 3)
|
||||
T(D 1)
|
||||
)
|
||||
)
|
||||
X(AA
|
||||
R((-2050 -1950) (5600 5200))
|
||||
N(1)
|
||||
N(2)
|
||||
N(3)
|
||||
P(1)
|
||||
P(2)
|
||||
P(3)
|
||||
X(1 A O(180) Y(750 750)
|
||||
P(0 2)
|
||||
P(1 1)
|
||||
P(2 3)
|
||||
)
|
||||
)
|
||||
X(TOP
|
||||
R((-3150 -3500) (8050 12650))
|
||||
N(1 I(B)
|
||||
R(l1 (1650 5200) (3250 2800))
|
||||
R(l1 (-3300 -10700) (800 4000))
|
||||
R(l2 (1100 5100) (700 700))
|
||||
R(l2 (-2500 -8200) (700 700))
|
||||
Q(l3 (-790 -810) (0 1000) (1790 0) (0 7510) (1000 0) (0 -8510))
|
||||
R(l3 (-500 3410) (0 0))
|
||||
R(contact (-2100 3300) (600 600))
|
||||
R(contact (-600 1000) (600 600))
|
||||
)
|
||||
N(2 I(A)
|
||||
R(l1 (-1400 1300) (2600 3000))
|
||||
R(l1 (-3550 -350) (4000 750))
|
||||
R(l1 (-1650 -1700) (0 0))
|
||||
R(contact (-1200 -1600) (600 600))
|
||||
R(contact (1000 -600) (600 600))
|
||||
)
|
||||
N(3
|
||||
R(l1 (-2350 8300) (4000 850))
|
||||
)
|
||||
N(4
|
||||
R(l1 (-2800 -2800) (800 4100))
|
||||
)
|
||||
X(1 AA Y(-1100 5900)
|
||||
P(0 3)
|
||||
P(1 2)
|
||||
P(2 1)
|
||||
)
|
||||
X(2 A O(90) Y(-100 -700)
|
||||
P(0 4)
|
||||
P(1 1)
|
||||
P(2 2)
|
||||
)
|
||||
)
|
||||
|
|
@ -665,7 +665,7 @@ class Basic_TestClass < TestBase
|
|||
if !$leak_check
|
||||
|
||||
begin
|
||||
b.b10 { |a| arr.push(a.get_n) } # b10 is a const iterator - cannot call a1 on it
|
||||
b.each_a_be { |a| arr.push(a.get_n) } # b10 is a const iterator - cannot call a1 on it
|
||||
rescue
|
||||
err_caught = true
|
||||
end
|
||||
|
|
@ -679,7 +679,7 @@ class Basic_TestClass < TestBase
|
|||
if !$leak_check
|
||||
|
||||
begin
|
||||
b.b10p { |a| arr.push(a.get_n) } # b10p is a const iterator - cannot call a1 on it
|
||||
b.each_a_be_pp { |a| arr.push(a.get_n) } # b10p is a const iterator - cannot call a1 on it
|
||||
rescue
|
||||
err_caught = true
|
||||
end
|
||||
|
|
@ -689,85 +689,85 @@ class Basic_TestClass < TestBase
|
|||
end
|
||||
|
||||
arr = []
|
||||
b.b10 { |a| arr.push(a.dup.get_n) }
|
||||
b.each_a_be { |a| arr.push(a.dup.get_n) }
|
||||
assert_equal(arr, [100, 121, 144])
|
||||
|
||||
arr = []
|
||||
b.dup.b10 { |a| arr.push(a.dup.get_n) }
|
||||
b.dup.each_a_be { |a| arr.push(a.dup.get_n) }
|
||||
assert_equal(arr, [100, 121, 144])
|
||||
|
||||
arr = []
|
||||
b.b10 { |a| arr.push(a.get_n_const) }
|
||||
b.each_a_be { |a| arr.push(a.get_n_const) }
|
||||
assert_equal(arr, [100, 121, 144])
|
||||
|
||||
arr = []
|
||||
b.b10p { |a| arr.push(a.dup.get_n) }
|
||||
b.each_a_be_pp { |a| arr.push(a.dup.get_n) }
|
||||
assert_equal(arr, [100, 121, 144])
|
||||
|
||||
arr = []
|
||||
b.dup.b10p { |a| arr.push(a.dup.get_n) }
|
||||
b.dup.each_a_be_pp { |a| arr.push(a.dup.get_n) }
|
||||
assert_equal(arr, [100, 121, 144])
|
||||
|
||||
arr = []
|
||||
b.b10p { |a| arr.push(a.get_n_const) }
|
||||
b.each_a_be_pp { |a| arr.push(a.get_n_const) }
|
||||
assert_equal(arr, [100, 121, 144])
|
||||
|
||||
arr = []
|
||||
b.b11 { |a| arr.push(a.get_n) }
|
||||
b.each_a_be_v { |a| arr.push(a.get_n) }
|
||||
assert_equal(arr, [100, 121, 144])
|
||||
|
||||
arr = []
|
||||
b.dup.b11 { |a| arr.push(a.get_n) }
|
||||
b.dup.each_a_be_v { |a| arr.push(a.get_n) }
|
||||
assert_equal(arr, [100, 121, 144])
|
||||
|
||||
arr = []
|
||||
b.b12 { |a| arr.push(a.get_n) }
|
||||
b.each_a_be_p { |a| arr.push(a.get_n) }
|
||||
assert_equal(arr, [7100, 7121, 7144, 7169])
|
||||
|
||||
arr = []
|
||||
b.dup.b12 { |a| arr.push(a.get_n) }
|
||||
b.dup.each_a_be_p { |a| arr.push(a.get_n) }
|
||||
assert_equal(arr, [7100, 7121, 7144, 7169])
|
||||
|
||||
aarr = b.b16a
|
||||
aarr = b.av
|
||||
arr = []
|
||||
aarr.each { |a| arr.push(a.get_n) }
|
||||
assert_equal(arr, [100, 121, 144])
|
||||
|
||||
aarr = b.b16b
|
||||
aarr = b.av_cref
|
||||
arr = []
|
||||
aarr.each { |a| arr.push(a.get_n) }
|
||||
assert_equal(arr, [100, 121, 144])
|
||||
|
||||
aarr = b.b16c
|
||||
aarr = b.av_ref
|
||||
arr = []
|
||||
aarr.each { |a| arr.push(a.get_n) }
|
||||
assert_equal(arr, [100, 121, 144])
|
||||
|
||||
b.b17a( [ RBA::A.new_a( 101 ), RBA::A.new_a( -122 ) ] )
|
||||
b.av_cref = [ RBA::A.new_a( 101 ), RBA::A.new_a( -122 ) ]
|
||||
arr = []
|
||||
b.b11 { |a| arr.push(a.get_n) }
|
||||
b.each_a_be_v { |a| arr.push(a.get_n) }
|
||||
assert_equal(arr, [101, -122])
|
||||
|
||||
b.b17a( [] )
|
||||
b.av_cref = []
|
||||
arr = []
|
||||
b.b11 { |a| arr.push(a.get_n) }
|
||||
b.each_a_be_v { |a| arr.push(a.get_n) }
|
||||
assert_equal(arr, [])
|
||||
|
||||
b.b17b( [ RBA::A.new_a( 102 ), RBA::A.new_a( -123 ) ] )
|
||||
b.av_ref = [ RBA::A.new_a( 102 ), RBA::A.new_a( -123 ) ]
|
||||
arr = []
|
||||
b.b11 { |a| arr.push(a.get_n) }
|
||||
b.each_a_be_v { |a| arr.push(a.get_n) }
|
||||
assert_equal(arr, [102, -123])
|
||||
|
||||
b.b17c( [ RBA::A.new_a( 100 ), RBA::A.new_a( 121 ), RBA::A.new_a( 144 ) ] )
|
||||
b.av = [ RBA::A.new_a( 100 ), RBA::A.new_a( 121 ), RBA::A.new_a( 144 ) ]
|
||||
arr = []
|
||||
b.b11 { |a| arr.push(a.get_n) }
|
||||
b.each_a_be_v { |a| arr.push(a.get_n) }
|
||||
assert_equal(arr, [100, 121, 144])
|
||||
|
||||
if !$leak_check
|
||||
|
||||
arr = []
|
||||
begin
|
||||
b.b13 { |a| arr.push(a.get_n) }
|
||||
b.each_a_be_cp { |a| arr.push(a.get_n) }
|
||||
rescue
|
||||
err_caught = true
|
||||
end
|
||||
|
|
@ -777,11 +777,11 @@ class Basic_TestClass < TestBase
|
|||
end
|
||||
|
||||
arr = []
|
||||
b.b13 { |a| arr.push(a.get_n_const) }
|
||||
b.each_a_be_cp { |a| arr.push(a.get_n_const) }
|
||||
assert_equal(arr, [-3100, -3121])
|
||||
|
||||
arr = []
|
||||
b.dup.b13 { |a| arr.push(a.get_n_const) }
|
||||
b.dup.each_a_be_cp { |a| arr.push(a.get_n_const) }
|
||||
assert_equal(arr, [-3100, -3121])
|
||||
|
||||
arr = []
|
||||
|
|
@ -938,6 +938,38 @@ class Basic_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
def _iter_find(b, find)
|
||||
b.each_a_be do |a|
|
||||
if a.get_n_const == find
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
# Iterator break, return, continue
|
||||
def test_13c
|
||||
|
||||
b = RBA::B.new
|
||||
|
||||
arr = []
|
||||
b.each_a_be { |a| arr.push(a.get_n_const) }
|
||||
assert_equal(arr, [100, 121, 144])
|
||||
|
||||
arr = []
|
||||
b.each_a_be do |a|
|
||||
if a.get_n_const == 121
|
||||
next
|
||||
end
|
||||
arr.push(a.get_n_const)
|
||||
end
|
||||
assert_equal(arr, [100, 144])
|
||||
|
||||
assert_equal(_iter_find(b, 121), true)
|
||||
assert_equal(_iter_find(b, 122), false)
|
||||
|
||||
end
|
||||
|
||||
def test_14
|
||||
|
||||
a = RBA::A.new
|
||||
|
|
|
|||
Loading…
Reference in New Issue