diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index 53e08b6d4..f396b50d7 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -46,6 +46,7 @@ Pin::Pin (const std::string &name) // Device class implementation Device::Device () + : mp_device_class (0), m_id (0) { // .. nothing yet .. } @@ -60,12 +61,13 @@ Device::~Device () } Device::Device (DeviceClass *device_class, const std::string &name) - : mp_device_class (device_class), m_name (name) + : mp_device_class (device_class), m_name (name), m_id (0) { // .. nothing yet .. } Device::Device (const Device &other) + : mp_device_class (0), m_id (0) { operator= (other); } @@ -470,13 +472,13 @@ void Net::set_circuit (Circuit *circuit) // Circuit class implementation Circuit::Circuit () - : mp_netlist (0) + : mp_netlist (0), m_valid_device_id_table (false) { // .. nothing yet .. } Circuit::Circuit (const Circuit &other) - : mp_netlist (0) + : mp_netlist (0), m_valid_device_id_table (false) { operator= (other); } @@ -486,6 +488,7 @@ Circuit &Circuit::operator= (const Circuit &other) if (this != &other) { m_name = other.m_name; + invalidate_device_id_table (); for (const_pin_iterator i = other.begin_pins (); i != other.end_pins (); ++i) { add_pin (*i); @@ -589,12 +592,47 @@ void Circuit::remove_net (Net *net) void Circuit::add_device (Device *device) { + size_t id = 0; + if (! m_devices.empty ()) { + tl_assert (m_devices.back () != 0); + id = m_devices.back ()->id (); + } + device->set_id (id + 1); + m_devices.push_back (device); + invalidate_device_id_table (); } void Circuit::remove_device (Device *device) { m_devices.erase (device); + invalidate_device_id_table (); +} + +void Circuit::validate_device_id_table () +{ + m_device_id_table.clear (); + for (device_iterator d = begin_devices (); d != end_devices (); ++d) { + m_device_id_table.insert (std::make_pair (d->id (), d.operator-> ())); + } + + m_valid_device_id_table = true; +} + +void Circuit::invalidate_device_id_table () +{ + m_valid_device_id_table = false; + m_device_id_table.clear (); +} + +Device *Circuit::device_by_id (size_t id) +{ + if (! m_valid_device_id_table) { + validate_device_id_table (); + } + + std::map::const_iterator d = m_device_id_table.find (id); + return d != m_device_id_table.end () ? d->second : 0; } void Circuit::add_sub_circuit (SubCircuit *sub_circuit) diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index e674a46d7..e9ceec255 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -589,6 +589,17 @@ public: return mp_device_class; } + /** + * @brief Gets the device ID + * The ID is a unique integer which identifies the device. + * It can be used to retrieve the device from the circuit using Circuit::device_by_id. + * When assigned, the device ID is not 0. + */ + size_t id () const + { + return m_id; + } + /** * @brief Sets the name */ @@ -655,6 +666,7 @@ private: std::string m_name; std::vector m_terminal_refs; std::vector m_parameters; + size_t m_id; /** * @brief Sets the terminal reference for a specific terminal @@ -668,6 +680,14 @@ private: { mp_device_class = dc; } + + /** + * @brief Sets the device ID + */ + void set_id (size_t id) + { + m_id = id; + } }; /** @@ -999,6 +1019,23 @@ public: */ void remove_device (Device *device); + /** + * @brief Gets the device from a given ID (const version) + * + * If the ID is not valid, null is returned. + */ + const Device *device_by_id (size_t id) const + { + return (const_cast (this)->device_by_id (id)); + } + + /** + * @brief Gets the device from a given ID (const version) + * + * If the ID is not valid, null is returned. + */ + Device *device_by_id (size_t id); + /** * @brief Begin iterator for the devices of the circuit (non-const version) */ @@ -1127,6 +1164,8 @@ private: sub_circuit_list m_sub_circuits; Netlist *mp_netlist; std::vector m_pin_refs; + bool m_valid_device_id_table; + std::map m_device_id_table; /** * @brief Sets the pin reference for a specific pin @@ -1138,6 +1177,9 @@ private: void set_netlist (Netlist *netlist); void combine_parallel_devices (const db::DeviceClass &cls); void combine_serial_devices (const db::DeviceClass &cls); + + void validate_device_id_table (); + void invalidate_device_id_table (); }; /** diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 9cee3ee5e..cd52b6ee8 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -51,6 +51,12 @@ Class decl_dbDevice ("db", "Device", gsi::method ("device_class", &db::Device::device_class, "@brief Gets the device class the device belongs to.\n" ) + + gsi::method ("id", &db::Device::id, + "@brief Gets the device ID.\n" + "The ID is a unique integer which identifies the device.\n" + "It can be used to retrieve the device from the circuit using \\Circuit#device_by_id.\n" + "When assigned, the device ID is not 0.\n" + ) + gsi::method ("name=", &db::Device::set_name, gsi::arg ("name"), "@brief Sets the name of the device.\n" "Device names are used to name a device inside a netlist file. " @@ -607,6 +613,10 @@ Class decl_dbCircuit ("db", "Circuit", gsi::iterator ("each_pin", (db::Circuit::pin_iterator (db::Circuit::*) ()) &db::Circuit::begin_pins, (db::Circuit::pin_iterator (db::Circuit::*) ()) &db::Circuit::end_pins, "@brief Iterates over the pins of the circuit" ) + + gsi::method ("device_by_id", (db::Device *(db::Circuit::*) (size_t)) &db::Circuit::device_by_id, gsi::arg ("id"), + "@brief Gets the device object for a given ID.\n" + "If the ID is not a valid device ID, nil is returned." + ) + gsi::method ("pin_by_id", &db::Circuit::pin_by_id, gsi::arg ("id"), "@brief Gets the \\Pin object corresponding to a specific ID\n" "If the ID is not a valid pin ID, nil is returned." diff --git a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc index c1a5c14f4..f74ab9487 100644 --- a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc @@ -526,8 +526,7 @@ static std::string netlist2string (const db::Netlist &nl) res += std::string ("Circuit ") + c->name () + " (" + ps + "):\n"; -// @@@ good for debugging -#if 0 +#if 0 // for debugging for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) { res += " N" + net_name (n.operator-> ()) + " pins=" + tl::to_string (n->pin_count ()) + " terminals=" + tl::to_string (n->terminal_count ()) + "\n"; } diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc index d8cd7907c..1f7a9009e 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -264,12 +264,26 @@ TEST(4_CircuitDevices) "c:\n" ); + db::Device *dd = new db::Device (&dc1, "dd"); db::Device *d1 = new db::Device (&dc1, "d1"); db::Device *d2a = new db::Device (&dc2, "d2a"); db::Device *d2b = new db::Device (&dc2, "d2b"); c->add_device (d1); + EXPECT_EQ (d1->id (), 1); + EXPECT_EQ (c->device_by_id (d1->id ()) == d1, true); + c->add_device (dd); + EXPECT_EQ (dd->id (), 2); + EXPECT_EQ (c->device_by_id (dd->id ()) == dd, true); c->add_device (d2a); + EXPECT_EQ (d2a->id (), 3); + EXPECT_EQ (c->device_by_id (d2a->id ()) == d2a, true); c->add_device (d2b); + EXPECT_EQ (d2b->id (), 4); + EXPECT_EQ (c->device_by_id (d2b->id ()) == d2b, true); + c->remove_device (dd); + dd = 0; + EXPECT_EQ (c->device_by_id (d2a->id ()) == d2a, true); + EXPECT_EQ (c->device_by_id (2) == 0, true); EXPECT_EQ (d1->parameter_value (0), 1.0); EXPECT_EQ (d1->parameter_value (1), 2.0); diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index 5d9d503a9..aad2539e3 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -157,6 +157,9 @@ class DBNetlist_TestClass < TestBase d1 = c.create_device(dc) d1.name = "D1" assert_equal(d1.name, "D1") + assert_equal(d1.id, 1) + assert_equal(c.device_by_id(d1.id).id, 1) + assert_equal(c.device_by_id(2).inspect, "nil") d2 = c.create_device(dc) assert_equal(d2.device_class.id, dc.id)