mirror of https://github.com/KLayout/klayout.git
Cherry-picked MacOS fixes into master
This commit is contained in:
parent
69fe4a5edf
commit
c517aa4ff7
|
|
@ -31,6 +31,9 @@ namespace db
|
|||
|
||||
static HierarchyBuilderShapeInserter def_inserter;
|
||||
|
||||
static HierarchyBuilder::cell_map_type null_map;
|
||||
static HierarchyBuilder::cell_map_type::const_iterator null_iterator = null_map.end ();
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
|
||||
int
|
||||
|
|
@ -168,7 +171,7 @@ HierarchyBuilder::reset ()
|
|||
m_cell_map.clear ();
|
||||
m_cells_seen.clear ();
|
||||
m_cell_stack.clear ();
|
||||
m_cm_entry = cell_map_type::const_iterator ();
|
||||
m_cm_entry = null_iterator;
|
||||
m_cm_new_entry = false;
|
||||
}
|
||||
|
||||
|
|
@ -263,14 +266,14 @@ HierarchyBuilder::end (const RecursiveShapeIterator *iter)
|
|||
m_cells_seen.clear ();
|
||||
mp_initial_cell = m_cell_stack.empty () ? 0 : m_cell_stack.front ().second.front ();
|
||||
m_cell_stack.clear ();
|
||||
m_cm_entry = cell_map_type::const_iterator ();
|
||||
m_cm_entry = null_iterator;
|
||||
m_cm_new_entry = false;
|
||||
}
|
||||
|
||||
void
|
||||
HierarchyBuilder::enter_cell (const RecursiveShapeIterator * /*iter*/, const db::Cell * /*cell*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
{
|
||||
tl_assert (m_cm_entry != m_cell_map.end () && m_cm_entry != cell_map_type::const_iterator ());
|
||||
tl_assert (m_cm_entry != m_cell_map.end () && m_cm_entry != null_iterator);
|
||||
|
||||
m_cells_seen.insert (m_cm_entry->first);
|
||||
|
||||
|
|
|
|||
|
|
@ -3349,26 +3349,20 @@ void align (Iter i1, Iter i2, Iter j1, Iter j2, Distance distance)
|
|||
vj.push_back (j);
|
||||
}
|
||||
|
||||
while (vi.size () < vj.size ()) {
|
||||
vi.push_back (Iter ());
|
||||
}
|
||||
size_t sz = std::max (vi.size (), vj.size ());
|
||||
|
||||
while (vj.size () < vi.size ()) {
|
||||
vj.push_back (Iter ());
|
||||
}
|
||||
|
||||
if (vi.size () <= 1) {
|
||||
if (sz <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Caution: this is an O(2) algorithm ...
|
||||
bool any_swapped = true;
|
||||
for (size_t n = 0; n < vi.size () - 1 && any_swapped; ++n) {
|
||||
for (size_t n = 0; n < sz - 1 && any_swapped; ++n) {
|
||||
|
||||
any_swapped = false;
|
||||
|
||||
for (size_t m = n + 1; m < vj.size (); ++m) {
|
||||
if (vi [n] == Iter () || vi [m] == Iter () || vj [n] == Iter () || vj [m] == Iter ()) {
|
||||
for (size_t m = n + 1; m < sz; ++m) {
|
||||
if (n >= vi.size () || m >= vi.size () || n >= vj.size () || m >= vj.size ()) {
|
||||
continue;
|
||||
} else if (distance (*vi [n], *vj [m]) + distance (*vi [m], *vj [n]) < distance (*vi [n], *vj [n]) + distance (*vi [m], *vj [m])) {
|
||||
// this will reduce the overall distance:
|
||||
|
|
|
|||
|
|
@ -2933,6 +2933,67 @@ TEST(18_ClockTree)
|
|||
"end_circuit TXEE TXEE MATCH"
|
||||
);
|
||||
EXPECT_EQ (good, true);
|
||||
|
||||
comp.set_depth_first (false);
|
||||
logger.clear ();
|
||||
good = comp.compare (&nl1, &nl2);
|
||||
|
||||
txt = logger.text ();
|
||||
// because L/R matching is ambiguous, we need to do this to
|
||||
// establish reproducability on different platforms:
|
||||
txt = tl::replaced (txt, "L", "X");
|
||||
txt = tl::replaced (txt, "R", "X");
|
||||
|
||||
EXPECT_EQ (txt,
|
||||
"begin_circuit INV INV\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets OUT OUT\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_pins IN IN\n"
|
||||
"match_pins OUT OUT\n"
|
||||
"match_pins VDD VDD\n"
|
||||
"match_pins VSS VSS\n"
|
||||
"match_devices $1 $1\n"
|
||||
"match_devices $2 $2\n"
|
||||
"end_circuit INV INV MATCH\n"
|
||||
"begin_circuit TXEE TXEE\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets S S\n"
|
||||
"match_ambiguous_nets SX SX\n"
|
||||
"match_ambiguous_nets SX SX\n"
|
||||
"match_ambiguous_nets SXX SXX\n"
|
||||
"match_ambiguous_nets SXX SXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXX SXX\n"
|
||||
"match_ambiguous_nets SXX SXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TX TX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits T T\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TX TX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"end_circuit TXEE TXEE MATCH"
|
||||
);
|
||||
EXPECT_EQ (good, true);
|
||||
}
|
||||
|
||||
TEST(19_SymmetricCircuit)
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@ namespace {
|
|||
// we do a initial scan and after this no more write access here.
|
||||
typedef std::map<const std::type_info *, const ClassBase *, type_info_compare> ti_to_class_map_t;
|
||||
static ti_to_class_map_t *sp_ti_to_class = 0;
|
||||
// NOTE: MacOS/clang seems to have some issue with RTTI across shared objects. This map provides a name-based fallback
|
||||
typedef std::map<std::string, const ClassBase *> tname_to_class_map_t;
|
||||
static tname_to_class_map_t *sp_tname_to_class = 0;
|
||||
|
||||
ClassBase::ClassBase (const std::string &doc, const Methods &mm, bool do_register)
|
||||
: m_initialized (false), mp_base (0), mp_parent (0), m_doc (doc), m_methods (mm)
|
||||
|
|
@ -68,6 +71,10 @@ ClassBase::ClassBase (const std::string &doc, const Methods &mm, bool do_registe
|
|||
delete sp_ti_to_class;
|
||||
sp_ti_to_class = 0;
|
||||
}
|
||||
if (sp_tname_to_class) {
|
||||
delete sp_tname_to_class;
|
||||
sp_tname_to_class = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -753,11 +760,18 @@ static void add_class_to_map (const gsi::ClassBase *c)
|
|||
if (! sp_ti_to_class) {
|
||||
sp_ti_to_class = new ti_to_class_map_t ();
|
||||
}
|
||||
if (! sp_tname_to_class) {
|
||||
sp_tname_to_class = new tname_to_class_map_t ();
|
||||
}
|
||||
|
||||
if (ti && c->is_of_type (*ti) && !sp_ti_to_class->insert (std::make_pair (ti, c)).second) {
|
||||
// Duplicate registration of this class
|
||||
tl::error << "Duplicate registration of class " << c->name () << " (type " << ti->name () << ")";
|
||||
tl_assert (false);
|
||||
if (ti && c->is_of_type (*ti)) {
|
||||
if (!sp_ti_to_class->insert (std::make_pair (ti, c)).second) {
|
||||
// Duplicate registration of this class
|
||||
tl::error << "Duplicate registration of class " << c->name () << " (type " << ti->name () << ")";
|
||||
tl_assert (false);
|
||||
} else {
|
||||
sp_tname_to_class->insert (std::make_pair (std::string (ti->name ()), c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -775,11 +789,19 @@ const ClassBase *class_by_typeinfo_no_assert (const std::type_info &ti)
|
|||
if (! sp_ti_to_class) {
|
||||
return 0;
|
||||
} else {
|
||||
std::map<const std::type_info *, const ClassBase *, type_info_compare>::const_iterator c = sp_ti_to_class->find (&ti);
|
||||
ti_to_class_map_t::const_iterator c = sp_ti_to_class->find (&ti);
|
||||
if (c != sp_ti_to_class->end ()) {
|
||||
return c->second;
|
||||
} else {
|
||||
return 0;
|
||||
// try name lookup
|
||||
tname_to_class_map_t::const_iterator cn = sp_tname_to_class->find (std::string (ti.name ()));
|
||||
if (cn != sp_tname_to_class->end ()) {
|
||||
// we can use this typeinfo as alias
|
||||
sp_ti_to_class->insert (std::make_pair (&ti, cn->second));
|
||||
return cn->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1106,10 +1106,22 @@ size_t
|
|||
InputPipe::read (char *b, size_t n)
|
||||
{
|
||||
tl_assert (m_file != NULL);
|
||||
size_t ret = fread (b, 1, n, m_file);
|
||||
if (ret < n) {
|
||||
if (ferror (m_file)) {
|
||||
throw FilePReadErrorException (m_source, ferror (m_file));
|
||||
|
||||
bool retry = true;
|
||||
size_t ret = 0;
|
||||
|
||||
while (retry) {
|
||||
retry = false;
|
||||
ret = fread (b, 1, n, m_file);
|
||||
if (ret < n) {
|
||||
if (ferror (m_file)) {
|
||||
if (errno != EINTR) {
|
||||
throw FilePReadErrorException (m_source, errno);
|
||||
} else if (ret == 0) {
|
||||
retry = true;
|
||||
clearerr (m_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1138,7 +1150,7 @@ OutputPipe::OutputPipe (const std::string &path)
|
|||
OutputPipe::~OutputPipe ()
|
||||
{
|
||||
if (m_file != NULL) {
|
||||
fclose (m_file);
|
||||
pclose (m_file);
|
||||
m_file = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -1147,10 +1159,11 @@ void
|
|||
OutputPipe::write (const char *b, size_t n)
|
||||
{
|
||||
tl_assert (m_file != NULL);
|
||||
|
||||
size_t ret = fwrite (b, 1, n, m_file);
|
||||
if (ret < n) {
|
||||
if (ferror (m_file)) {
|
||||
throw FilePWriteErrorException (m_source, ferror (m_file));
|
||||
if (ferror (m_file) && errno != EINTR) {
|
||||
throw FilePReadErrorException (m_source, errno);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,23 @@ TEST(InputPipe2)
|
|||
EXPECT_NE (ret, 0);
|
||||
}
|
||||
|
||||
TEST(OutputPipe1)
|
||||
{
|
||||
std::string tf = tmp_file ("pipe_out");
|
||||
|
||||
{
|
||||
tl::OutputPipe pipe ("cat >" + tf);
|
||||
tl::OutputStream str (pipe);
|
||||
str << "Hello, world!";
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream is (tf);
|
||||
std::string s = is.read_all ();
|
||||
EXPECT_EQ (s, "Hello, world!");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TextOutputStream)
|
||||
{
|
||||
std::string fn = tmp_file ("test.txt");
|
||||
|
|
|
|||
Loading…
Reference in New Issue