Skip to content

Commit

Permalink
Merge pull request #1791 from KLayout/bugfix/issue-1782
Browse files Browse the repository at this point in the history
Fixing issue #1782
  • Loading branch information
klayoutmatthias authored Jul 21, 2024
2 parents 951905d + 6456675 commit d392184
Show file tree
Hide file tree
Showing 7 changed files with 408 additions and 8 deletions.
4 changes: 4 additions & 0 deletions src/db/db/built-in-macros/pcell_declaration_helper.lym
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,10 @@ module RBA

def param(name, type, description, args = {})

if ! args.is_a?(Hash)
raise("Too many positional arguments for 'param' (3 expected) - use named arguments for default value etc.")
end

if name !~ /^[_A-Za-z]\w*$/
raise "Invalid parameter name #{name} (needs to be a word)"
end
Expand Down
21 changes: 18 additions & 3 deletions src/db/db/dbLayout.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2526,10 +2526,25 @@ Layout::register_pcell (const std::string &name, pcell_declaration_type *declara
// replace any existing PCell declaration with that name.
id = pcid->second;
if (m_pcells [id]) {
delete m_pcells [id];
}

m_pcells [id] = new pcell_header_type (id, name, declaration);
std::unique_ptr<pcell_header_type> org_header (m_pcells [id]);
std::vector<pcell_variant_type *> variants;
for (auto v = org_header->begin (); v != org_header->end (); ++v) {
variants.push_back (v->second);
}
for (auto v = variants.begin (); v != variants.end (); ++v) {
(*v)->unregister ();
}

m_pcells [id] = new pcell_header_type (id, name, declaration);

for (auto v = variants.begin (); v != variants.end (); ++v) {
(*v)->reregister ();
}

} else {
m_pcells [id] = new pcell_header_type (id, name, declaration);
}

} else {

Expand Down
60 changes: 58 additions & 2 deletions src/tl/tl/tlString.cc
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,28 @@ bool skip_newline (const char *&cp)
}
}

// -------------------------------------------------------------------------
// Utility: case-insensitive compare of the first characters

static bool local_compare (const char *s1, const char *s2)
{
while (*s1 && *s2) {
uint32_t c1 = utf32_downcase (utf32_from_utf8 (s1));
uint32_t c2 = utf32_downcase (utf32_from_utf8 (s2));
if (c1 != c2) {
return false;
}
}
return true;
}

// -------------------------------------------------------------------------
// Utility: a strtod version that is independent of the locale

static std::string inf_string = "inf";
static std::string ninf_string = "-inf";
static std::string nan_string = "nan";

static std::string micron_format ("%.5f");
static std::string dbu_format ("%.2f");

Expand All @@ -244,12 +263,24 @@ void set_db_resolution (unsigned int ndigits)

std::string micron_to_string (double d)
{
return tl::sprintf (micron_format.c_str (), d);
if (std::isnan (d)) {
return nan_string;
} else if (std::isinf (d)) {
return d < 0 ? ninf_string : inf_string;
} else {
return tl::sprintf (micron_format.c_str (), d);
}
}

std::string db_to_string (double d)
{
return tl::sprintf (dbu_format.c_str (), d);
if (std::isnan (d)) {
return nan_string;
} else if (std::isinf (d)) {
return d < 0 ? ninf_string : inf_string;
} else {
return tl::sprintf (dbu_format.c_str (), d);
}
}

std::string to_upper_case (const std::string &s)
Expand Down Expand Up @@ -317,6 +348,18 @@ static double local_strtod (const char *cp, const char *&cp_new)
{
const char *cp0 = cp;

// special numerical values
if (local_compare (cp, nan_string.c_str ())) {
cp_new = cp + nan_string.size ();
return NAN;
} else if (local_compare (cp, inf_string.c_str ())) {
cp_new = cp + inf_string.size ();
return INFINITY;
} else if (local_compare (cp, ninf_string.c_str ())) {
cp_new = cp + ninf_string.size ();
return -INFINITY;
}

// Extract sign
double s = 1.0;
if (*cp == '-') {
Expand Down Expand Up @@ -376,6 +419,12 @@ static double local_strtod (const char *cp, const char *&cp_new)
std::string
to_string (double d, int prec)
{
if (std::isnan (d)) {
return nan_string;
} else if (std::isinf (d)) {
return d < 0 ? ninf_string : inf_string;
}

// For small values less than 1e-(prec) simply return "0" to avoid ugly values like "1.2321716e-14".
if (fabs (d) < pow (10.0, -prec)) {
return "0";
Expand All @@ -393,6 +442,12 @@ to_string (double d, int prec)
std::string
to_string (float d, int prec)
{
if (std::isnan (d)) {
return nan_string;
} else if (std::isinf (d)) {
return d < 0 ? ninf_string : inf_string;
}

// For small values less than 1e-(prec) simply return "0" to avoid ugly values like "1.2321716e-14".
if (fabs (d) < pow (10.0, -prec)) {
return "0";
Expand Down Expand Up @@ -813,6 +868,7 @@ from_string_numeric (const std::string &s, double &v, bool eval)
if (! *cp) {
throw tl::Exception (tl::to_string (tr ("Got empty string where a real number was expected")));
}

const char *cp_end = cp;
v = local_strtod (cp, cp_end);
while (safe_isspace (*cp_end)) {
Expand Down
29 changes: 26 additions & 3 deletions src/tl/tl/tlVariant.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1057,15 +1057,38 @@ normalized_type (Variant::type type1, Variant::type type2)

static const double epsilon = 1e-13;

// NOTE: in order to be able to use Variant for std::map or std::set
// keys we have to establish a weak order. This means we need to
// consider NAN and INFINITY too.

static int numeric_class (double x)
{
if (std::isnan (x)) {
return 2;
} else {
return std::isinf (x) ? (x < 0 ? -1 : 1) : 0;
}
}

static inline bool fequal (double a, double b)
{
double avg = 0.5 * (fabs (a) + fabs (b));
return fabs (a - b) <= epsilon * avg;
if (numeric_class (a) != 0 || numeric_class (b) != 0) {
return numeric_class (a) == numeric_class (b);
} else {
double avg = 0.5 * (fabs (a) + fabs (b));
return fabs (a - b) <= epsilon * avg;
}
}

static inline bool fless (double a, double b)
{
return fequal (a, b) ? false : a < b;
if (fequal (a, b)) {
return false;
} else if (numeric_class (a) != 0 || numeric_class (b) != 0) {
return numeric_class (a) < numeric_class (b);
} else {
return a < b;
}
}

bool
Expand Down
59 changes: 59 additions & 0 deletions src/tl/unit_tests/tlStringTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -589,3 +589,62 @@ TEST(15)
EXPECT_EQ (tl::to_upper_case ("nOrMaliI(\xc3\xa4\xc3\x84\xc3\xbc\xc3\x9c\xc3\xb6\xc3\x96\xc3\x9f-42\xc2\xb0+6\xe2\x82\xac)"), "NORMALII(\xc3\x84\xc3\x84\xc3\x9c\xc3\x9c\xc3\x96\xc3\x96\xc3\x9f-42\xc2\xb0+6\xe2\x82\xac)");
EXPECT_EQ (tl::to_lower_case ("nOrMaliI(\xc3\xa4\xc3\x84\xc3\xbc\xc3\x9c\xc3\xb6\xc3\x96\xc3\x9f-42\xc2\xb0+6\xe2\x82\xac)"), "normalii(\xc3\xa4\xc3\xa4\xc3\xbc\xc3\xbc\xc3\xb6\xc3\xb6\xc3\x9f-42\xc2\xb0+6\xe2\x82\xac)");
}

// Special numerical values
TEST(16)
{
EXPECT_EQ (tl::to_string (NAN), "nan");
EXPECT_EQ (tl::to_string (INFINITY), "inf");
EXPECT_EQ (tl::to_string (-INFINITY), "-inf");

EXPECT_EQ (tl::to_string ((float) NAN), "nan");
EXPECT_EQ (tl::to_string ((float) INFINITY), "inf");
EXPECT_EQ (tl::to_string ((float) -INFINITY), "-inf");

EXPECT_EQ (tl::micron_to_string (NAN), "nan");
EXPECT_EQ (tl::micron_to_string (INFINITY), "inf");
EXPECT_EQ (tl::micron_to_string (-INFINITY), "-inf");

EXPECT_EQ (tl::db_to_string (NAN), "nan");
EXPECT_EQ (tl::db_to_string (INFINITY), "inf");
EXPECT_EQ (tl::db_to_string (-INFINITY), "-inf");

double x = 0.0;
tl::from_string ("nan", x);
EXPECT_EQ (tl::to_string (x), "nan");
x = 0.0;
tl::from_string ("NaN", x);
EXPECT_EQ (tl::to_string (x), "nan");
x = 0.0;
tl::from_string ("inf", x);
EXPECT_EQ (tl::to_string (x), "inf");
x = 0.0;
tl::from_string ("INF", x);
EXPECT_EQ (tl::to_string (x), "inf");
x = 0.0;
tl::from_string ("-inf", x);
EXPECT_EQ (tl::to_string (x), "-inf");
x = 0.0;
tl::from_string ("-INF", x);
EXPECT_EQ (tl::to_string (x), "-inf");

std::string s;
tl::Extractor ex;
x = 0.0;
s = " inf nan\t -inf";
ex = tl::Extractor (s.c_str ());
EXPECT_EQ (ex.try_read (x), true);
EXPECT_EQ (tl::to_string (x), "inf");
EXPECT_EQ (ex.try_read (x), true);
EXPECT_EQ (tl::to_string (x), "nan");
EXPECT_EQ (ex.try_read (x), true);
EXPECT_EQ (tl::to_string (x), "-inf");
s = " Inf NaN\t -INF";
ex = tl::Extractor (s.c_str ());
EXPECT_EQ (ex.try_read (x), true);
EXPECT_EQ (tl::to_string (x), "inf");
EXPECT_EQ (ex.try_read (x), true);
EXPECT_EQ (tl::to_string (x), "nan");
EXPECT_EQ (ex.try_read (x), true);
EXPECT_EQ (tl::to_string (x), "-inf");
}
108 changes: 108 additions & 0 deletions src/tl/unit_tests/tlVariantTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#include "tlObject.h"
#include "tlTypeTraits.h"
#include "tlUnitTest.h"

#include <cmath>
#include <cstdio>
#include <memory>

Expand Down Expand Up @@ -1090,4 +1092,110 @@ TEST(6)
EXPECT_EQ (tl::Variant (-0.1 * (1.0 + 1.1e-13)) < tl::Variant (0.1), true);
}

// special numeric values
TEST(7)
{
std::string s;
tl::Extractor ex;
tl::Variant v;

s = " ##\t 0.5";
ex = tl::Extractor (s.c_str ());
EXPECT_EQ (ex.try_read (v), true);
EXPECT_EQ (v.to_parsable_string (), "##0.5");

s = "## nan";
ex = tl::Extractor (s.c_str ());
EXPECT_EQ (ex.try_read (v), true);
EXPECT_EQ (v.to_parsable_string (), "##nan");

s = "## NaN";
ex = tl::Extractor (s.c_str ());
EXPECT_EQ (ex.try_read (v), true);
EXPECT_EQ (v.to_parsable_string (), "##nan");

s = "## inf";
ex = tl::Extractor (s.c_str ());
EXPECT_EQ (ex.try_read (v), true);
EXPECT_EQ (v.to_parsable_string (), "##inf");

s = "## Inf";
ex = tl::Extractor (s.c_str ());
EXPECT_EQ (ex.try_read (v), true);
EXPECT_EQ (v.to_parsable_string (), "##inf");

s = "## -inf";
ex = tl::Extractor (s.c_str ());
EXPECT_EQ (ex.try_read (v), true);
EXPECT_EQ (v.to_parsable_string (), "##-inf");

s = "## -Inf";
ex = tl::Extractor (s.c_str ());
EXPECT_EQ (ex.try_read (v), true);
EXPECT_EQ (v.to_parsable_string (), "##-inf");

v = tl::Variant ("nan");
v = tl::Variant (v.to_double ());
EXPECT_EQ (v.to_parsable_string (), "##nan");
EXPECT_EQ (v.to_string (), "nan");

v = tl::Variant ("Inf");
v = tl::Variant (v.to_double ());
EXPECT_EQ (v.to_parsable_string (), "##inf");
EXPECT_EQ (v.to_string (), "inf");

v = tl::Variant (INFINITY);
EXPECT_EQ (v.to_parsable_string (), "##inf");
EXPECT_EQ (v.to_string (), "inf");

v = tl::Variant (-INFINITY);
EXPECT_EQ (v.to_parsable_string (), "##-inf");
EXPECT_EQ (v.to_string (), "-inf");

tl::Variant vinf (INFINITY);
tl::Variant vninf (-INFINITY);
tl::Variant vnan (NAN);
tl::Variant vzero (0.0);

EXPECT_EQ (vninf == vninf, true);
EXPECT_EQ (vninf == vzero, false);
EXPECT_EQ (vninf == vinf, false);
EXPECT_EQ (vninf == vnan, false);

EXPECT_EQ (vninf < vninf, false);
EXPECT_EQ (vninf < vzero, true);
EXPECT_EQ (vninf < vinf, true);
EXPECT_EQ (vninf < vnan, true);

EXPECT_EQ (vzero == vninf, false);
EXPECT_EQ (vzero == vzero, true);
EXPECT_EQ (vzero == vinf, false);
EXPECT_EQ (vzero == vnan, false);

EXPECT_EQ (vzero < vninf, false);
EXPECT_EQ (vzero < vzero, false);
EXPECT_EQ (vzero < vinf, true);
EXPECT_EQ (vzero < vnan, true);

EXPECT_EQ (vinf == vninf, false);
EXPECT_EQ (vinf == vzero, false);
EXPECT_EQ (vinf == vinf, true);
EXPECT_EQ (vinf == vnan, false);

EXPECT_EQ (vinf < vninf, false);
EXPECT_EQ (vinf < vzero, false);
EXPECT_EQ (vinf < vinf, false);
EXPECT_EQ (vinf < vnan, true);

EXPECT_EQ (vnan == vninf, false);
EXPECT_EQ (vnan == vzero, false);
EXPECT_EQ (vnan == vinf, false);
EXPECT_EQ (vnan == vnan, true);

EXPECT_EQ (vnan < vninf, false);
EXPECT_EQ (vnan < vzero, false);
EXPECT_EQ (vnan < vinf, false);
EXPECT_EQ (vnan < vnan, false);
}

}
Loading

0 comments on commit d392184

Please sign in to comment.