Skip to content

Commit

Permalink
Enhanced tl::Variant so it can capture all possible default values. A…
Browse files Browse the repository at this point in the history
…dded a self-diagnosis step in debug builds.
  • Loading branch information
Matthias Koefferlein committed Jul 20, 2024
1 parent 9a79838 commit a8eaead
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 19 deletions.
4 changes: 2 additions & 2 deletions src/db/db/dbLayoutToNetlist.cc
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ void LayoutToNetlist::join_nets (const tl::GlobPattern &cell, const std::set<std
m_joined_nets_per_cell.push_back (std::make_pair (cell, gp));
}

#if defined(_DEBUG)
#if defined(HAVE_DEBUG)
static bool check_many_pins (const db::Netlist *netlist)
{
bool ok = true;
Expand Down Expand Up @@ -430,7 +430,7 @@ void LayoutToNetlist::extract_netlist ()
do_soft_connections ();

// implement the "join_nets" (aka "must connect") feature
#if defined(_DEBUG)
#if defined(HAVE_DEBUG)
// NOTE: the join_nets feature only works for "one pin per net" case
// TODO: either fix that or make sure we do not get multiple pins per net.
// Right now, there no known case that produces multiple pins on a net at
Expand Down
14 changes: 12 additions & 2 deletions src/gsi/gsi/gsiClassBase.cc
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ static const std::set<std::pair<std::string, bool> > &name_map_for_class (const
return cc->second;
}

#if defined(_DEBUG)
#if defined(HAVE_DEBUG)
static std::string type_signature (const gsi::ArgType &t)
{
gsi::ArgType tr (t);
Expand Down Expand Up @@ -622,7 +622,7 @@ ClassBase::merge_declarations ()
tl_assert (! c->declaration () || c->declaration () == &*c);
}

#if defined(_DEBUG)
#if defined(HAVE_DEBUG)
// do a sanity check
for (gsi::ClassBase::class_iterator c = gsi::ClassBase::begin_classes (); c != gsi::ClassBase::end_classes (); ++c) {

Expand All @@ -634,6 +634,16 @@ ClassBase::merge_declarations ()
method_counts [signature (*m, *s)] += 1;
}
}
// try to obtain the default values to find potential binding issues
for (gsi::MethodBase::argument_iterator a = (*m)->begin_arguments (); a != (*m)->end_arguments (); ++a) {
if (a->spec ()) {
try {
a->spec ()->default_value ();
} catch (tl::Exception &ex) {
tl::warn << "Method " << signature (*m, *(*m)->begin_synonyms ()) << ": error obtaining default value for argument '" << a->spec ()->name () << "': " << ex.msg ();
}
}
}
}

for (std::map<std::string, int>::const_iterator mc = method_counts.begin (); mc != method_counts.end (); ++mc) {
Expand Down
3 changes: 3 additions & 0 deletions src/klayout.pri
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,6 @@ DEFINES += \

VERSION = $$KLAYOUT_VERSION

debug {
DEFINES += HAVE_DEBUG
}
40 changes: 27 additions & 13 deletions src/tl/tl/tlVariant.cc
Original file line number Diff line number Diff line change
Expand Up @@ -317,15 +317,19 @@ Variant::Variant (const std::vector<char> &ba)
#if defined(HAVE_QT)

Variant::Variant (const QByteArray &qba)
: m_type (t_qbytearray), m_string (0)
: m_type (qba.isNull () ? t_nil : t_qbytearray), m_string (0)
{
m_var.m_qbytearray = new QByteArray (qba);
if (! qba.isNull ()) {
m_var.m_qbytearray = new QByteArray (qba);
}
}

Variant::Variant (const QString &qs)
: m_type (t_qstring), m_string (0)
: m_type (qs.isNull () ? t_nil : t_qstring), m_string (0)
{
m_var.m_qstring = new QString (qs);
if (! qs.isNull ()) {
m_var.m_qstring = new QString (qs);
}
}

Variant::Variant (const QVariant &v)
Expand Down Expand Up @@ -526,10 +530,14 @@ Variant::Variant (const std::string &s)
}

Variant::Variant (const char *s)
: m_type (t_string)
: m_type (s != 0 ? t_string : t_nil)
{
m_string = new char [strlen (s) + 1];
strcpy (m_string, s);
if (s) {
m_string = new char [strlen (s) + 1];
strcpy (m_string, s);
} else {
m_string = 0;
}
}

Variant::Variant (double d)
Expand Down Expand Up @@ -676,7 +684,9 @@ Variant::reset ()
Variant &
Variant::operator= (const char *s)
{
if (m_type == t_string && s == m_string) {
if (! s) {
reset ();
} else if (m_type == t_string && s == m_string) {
// we are assigning to ourselves
} else {
char *snew = new char [strlen (s) + 1];
Expand Down Expand Up @@ -721,7 +731,9 @@ Variant::operator= (const std::vector<char> &s)
Variant &
Variant::operator= (const QByteArray &qs)
{
if (m_type == t_qbytearray && &qs == m_var.m_qbytearray) {
if (qs.isNull ()) {
reset ();
} else if (m_type == t_qbytearray && &qs == m_var.m_qbytearray) {
// we are assigning to ourselves
} else {
QByteArray *snew = new QByteArray (qs);
Expand All @@ -735,7 +747,9 @@ Variant::operator= (const QByteArray &qs)
Variant &
Variant::operator= (const QString &qs)
{
if (m_type == t_qstring && &qs == m_var.m_qstring) {
if (qs.isNull ()) {
reset ();
} else if (m_type == t_qstring && &qs == m_var.m_qstring) {
// we are assigning to ourselves
} else {
QString *snew = new QString (qs);
Expand Down Expand Up @@ -1761,9 +1775,9 @@ Variant::to_string () const
if (m_type == t_nil) {
r = "nil";
} else if (m_type == t_double) {
r = tl::to_string (m_var.m_double);
r = tl::to_string (m_var.m_double, 15);
} else if (m_type == t_float) {
r = tl::to_string (m_var.m_float);
r = tl::to_string (m_var.m_float, 7);
} else if (m_type == t_char) {
r = tl::to_string ((int) m_var.m_char);
} else if (m_type == t_schar) {
Expand Down Expand Up @@ -2398,7 +2412,7 @@ Variant::to_parsable_string () const
} else if (is_ulonglong ()) {
return "#lu" + tl::to_string (to_ulonglong ());
} else if (is_double ()) {
return "##" + tl::to_string (to_double ());
return "##" + tl::to_string (to_double (), 15);
} else if (is_bool ()) {
return m_var.m_bool ? "true" : "false";
} else if (is_nil ()) {
Expand Down
105 changes: 104 additions & 1 deletion src/tl/tl/tlVariant.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <string>
#include <vector>
#include <map>
#include <set>
#include <list>
#include <stdexcept>
#include <typeinfo>

Expand Down Expand Up @@ -358,14 +360,115 @@ class TL_PUBLIC Variant
}

/**
* @brief Initialize the Variant with an explicit vector or variants
* @brief Initialize with a const user type (will always create a reference and NOT own the object)
*/
template <class T>
Variant (const T *obj)
: m_type (t_nil), m_string (0)
{
if (obj) {
*this = make_variant_ref (obj);
}
}

/**
* @brief Initialize with a non-const user type (will always create a reference and NOT own the object)
*/
template <class T>
Variant (T *obj)
: m_type (t_nil), m_string (0)
{
if (obj) {
*this = make_variant_ref (obj);
}
}

/**
* @brief Initialize the Variant with a STL vector
*/
template <class T>
Variant (const std::vector<T> &list)
: m_type (t_list), m_string (0)
{
m_var.m_list = new std::vector<tl::Variant> ();
m_var.m_list->reserve (list.size ());
for (auto i = list.begin (); i != list.end (); ++i) {
m_var.m_list->push_back (tl::Variant (*i));
}
}

/**
* @brief Initialize the Variant with a STL list
*/
template <class T>
Variant (const std::list<T> &list)
: m_type (t_list), m_string (0)
{
m_var.m_list = new std::vector<tl::Variant> ();
m_var.m_list->reserve (list.size ());
for (auto i = list.begin (); i != list.end (); ++i) {
m_var.m_list->push_back (tl::Variant (*i));
}
}

/**
* @brief Initialize the Variant with a STL set (not maintaining the set character)
*/
template <class T>
Variant (const std::set<T> &list)
: m_type (t_list), m_string (0)
{
m_var.m_list = new std::vector<tl::Variant> ();
m_var.m_list->reserve (list.size ());
for (auto i = list.begin (); i != list.end (); ++i) {
m_var.m_list->push_back (tl::Variant (*i));
}
}

/**
* @brief Initialize the Variant with a STL pair
*/
template <class A, class B>
Variant (const std::pair<A, B> &pair)
: m_type (t_list), m_string (0)
{
m_var.m_list = new std::vector<tl::Variant> ();
m_var.m_list->reserve (2);
m_var.m_list->push_back (tl::Variant (pair.first));
m_var.m_list->push_back (tl::Variant (pair.second));
}

/**
* @brief Initialize the Variant with a STL map
*/
template <class K, class V>
Variant (const std::map<K, V> &map)
: m_type (t_array), m_string (0)
{
m_var.m_array = new std::map<tl::Variant, tl::Variant> ();
for (auto i = map.begin (); i != map.end (); ++i) {
m_var.m_array->insert (std::make_pair (tl::Variant (i->first), tl::Variant (i->second)));
}
}

/**
* @brief Initialize the Variant with an explicit vector of variants
*/
Variant (const std::vector<tl::Variant> &list)
: m_type (t_list), m_string (0)
{
m_var.m_list = new std::vector<tl::Variant> (list);
}

/**
* @brief Initialize the Variant with an explicit map of variants
*/
Variant (const std::map<tl::Variant, tl::Variant> &map)
: m_type (t_array), m_string (0)
{
m_var.m_array = new std::map<tl::Variant, tl::Variant> (map);
}

/**
* @brief Initialize the Variant with a list
*/
Expand Down
2 changes: 1 addition & 1 deletion src/tl/unit_tests/tlExpressionTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -927,7 +927,7 @@ TEST(8)
bool t;

v = e.parse ("1==2?log('a'):log(2)").execute ();
EXPECT_EQ (v.to_string (), std::string ("0.69314718056"));
EXPECT_EQ (v.to_string (), std::string ("0.693147180559945"));
t = false;
try {
v = e.parse ("1==1?log('a'):log(2)").execute ();
Expand Down
76 changes: 76 additions & 0 deletions src/tl/unit_tests/tlVariantTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1090,4 +1090,80 @@ TEST(6)
EXPECT_EQ (tl::Variant (-0.1 * (1.0 + 1.1e-13)) < tl::Variant (0.1), true);
}

// precision of double serialization
TEST(7a)
{
tl::Variant v (M_PI);
tl::Variant vx;
std::string s (v.to_parsable_string ());
tl::Extractor ex (s.c_str ());
ex.read (vx);

EXPECT_EQ (fabs (M_PI - vx.to_double ()) < 4e-15, true);
}

TEST(7b)
{
tl::Variant v ((float) M_PI);
tl::Variant vx;
std::string s (v.to_parsable_string ());
tl::Extractor ex (s.c_str ());
ex.read (vx);

EXPECT_EQ (fabs (M_PI - vx.to_double ()) < 1e-7, true);
}

// null strings
TEST(8)
{
tl::Variant v ((const char *) 0);
EXPECT_EQ (v.to_parsable_string (), "nil");
v = tl::Variant ("abc");
EXPECT_EQ (v.to_parsable_string (), "'abc'");
v = (const char *) 0;
EXPECT_EQ (v.to_parsable_string (), "nil");

#if defined(HAVE_QT)
v = tl::Variant (QString ());
EXPECT_EQ (v.to_parsable_string (), "nil");
v = tl::Variant (QString::fromUtf8 ("abc"));
EXPECT_EQ (v.to_parsable_string (), "'abc'");
v = QString ();
EXPECT_EQ (v.to_parsable_string (), "nil");

v = tl::Variant (QByteArray ());
EXPECT_EQ (v.to_parsable_string (), "nil");
v = tl::Variant (QByteArray ("abc"));
EXPECT_EQ (v.to_parsable_string (), "'abc'");
v = QByteArray ();
EXPECT_EQ (v.to_parsable_string (), "nil");
#endif
}

// create from STL containers
TEST(9)
{
tl::Variant v;

std::vector<int> vi;
vi.push_back (17);
vi.push_back (1);
std::list<int> li;
li.push_back (42);
li.push_back (-17);
std::set<int> si;
si.insert (31);
si.insert (63);
std::pair<int, int> pi (1, 3);
std::map<int, int> mi;
mi[17] = 42;
mi[-1] = 31;

EXPECT_EQ (tl::Variant (vi).to_parsable_string (), "(#17,#1)");
EXPECT_EQ (tl::Variant (li).to_parsable_string (), "(#42,#-17)");
EXPECT_EQ (tl::Variant (si).to_parsable_string (), "(#31,#63)");
EXPECT_EQ (tl::Variant (pi).to_parsable_string (), "(#1,#3)");
EXPECT_EQ (tl::Variant (mi).to_parsable_string (), "{#-1=>#31,#17=>#42}");
}

}

0 comments on commit a8eaead

Please sign in to comment.