From 0a88349277e42b64280e7ba84324abca7326a89e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 25 Apr 2024 23:41:40 +0200 Subject: [PATCH] WIP --- src/rdb/rdb/rdb.cc | 194 +++++++++++++++++++++++++++++++++++++++++++++ src/rdb/rdb/rdb.h | 23 +++++- 2 files changed, 216 insertions(+), 1 deletion(-) diff --git a/src/rdb/rdb/rdb.cc b/src/rdb/rdb/rdb.cc index 0a532328f..2d77e5c46 100644 --- a/src/rdb/rdb/rdb.cc +++ b/src/rdb/rdb/rdb.cc @@ -403,6 +403,55 @@ Values::operator= (const Values &d) return *this; } +bool +Values::compare (const Values &other, const std::map &tag_map, const std::map &rev_tag_map) const +{ + Values::const_iterator a = begin (), b = other.begin (); + while (a != end () && b != other.end ()) { + + id_type t12 = 0; + while (a != end () && a->tag_id () != 0) { + auto j = tag_map.find (a->tag_id ()); + if (j != tag_map.end ()) { + t12 = j->second; + break; + } + ++a; + } + + id_type t2 = 0; + while (b != end () && b->tag_id () != 0) { + auto j = rev_tag_map.find (b->tag_id ()); + if (j != rev_tag_map.end ()) { + t2 = j->first; + break; + } + ++b; + } + + if (a == end () || b == other.end ()) { + return b != other.end (); + } + + if (t12 != t2) { + return t12 < t2; + } + + if (a->get () && b->get ()) { + if (a->get ()->compare (b->get ())) { + return true; + } else if (b->get ()->compare (a->get ())) { + return false; + } + } else if ((a->get () != 0) != (b->get () != 0)) { + return (a->get () != 0) < (b->get () != 0); + } + + } + + return false; +} + std::string Values::to_string (const Database *rdb) const { @@ -1659,6 +1708,151 @@ Database::load (const std::string &fn) } } +namespace +{ + class ValueMapEntryCompare + { + public: + ValueMapEntryCompare (const std::map &tag2tag, const std::map &rev_tag2tag) + { + mp_tag2tag = &tag2tag; + mp_rev_tag2tag = &rev_tag2tag; + } + + bool operator() (const Item *a, const Item *b) const + { + return a->values ().compare (b->values (), *mp_tag2tag, *mp_rev_tag2tag); + } + + private: + const std::map *mp_tag2tag; + const std::map *mp_rev_tag2tag; + }; + + class ValueMapEntry + { + public: + ValueMapEntry () + : mp_tag2tag (0), mp_rev_tag2tag (0) + { } + + void build (const rdb::Database &rdb, id_type cell_id, id_type cat_id, const std::map &tag2tag, const std::map &rev_tag2tag) + { + mp_tag2tag = &tag2tag; + mp_rev_tag2tag = &rev_tag2tag; + + auto i2i = rdb.items_by_cell_and_category (cell_id, cat_id); + + size_t n = 0; + for (auto i = i2i.first; i != i2i.second; ++i) { + ++n; + } + m_items.reserve (n); + + for (auto i = i2i.first; i != i2i.second; ++i) { + m_items.push_back ((*i).operator-> ()); + } + + ValueMapEntryCompare cmp (*mp_tag2tag, *mp_rev_tag2tag); + std::sort (m_items.begin (), m_items.end (), cmp); + } + + const Item *find (const rdb::Item &item) const + { + ValueMapEntryCompare cmp (*mp_tag2tag, *mp_rev_tag2tag); + + auto i = std::lower_bound (m_items.begin (), m_items.end (), &item, cmp); + if (i == m_items.end ()) { + return 0; + } + + if (cmp (&item, *i) || cmp (*i, &item)) { + return 0; + } else { + return *i; + } + } + + public: + std::vector m_items; + const std::map *mp_tag2tag; + const std::map *mp_rev_tag2tag; + }; +} + +void +Database::apply (const rdb::Database &other) +{ + std::map cell2cell; + std::map cat2cat; + std::map tag2tag; + std::map rev_tag2tag; + + for (auto c = other.cells ().begin (); c != other.cells ().end (); ++c) { + // TODO: do we have a consistent scheme of naming variants? What requirements + // exist towards detecting variant specific waivers + const rdb::Cell *this_cell = cell_by_qname (c->qname ()); + if (this_cell) { + cell2cell.insert (std::make_pair (this_cell->id (), c->id ())); + } + } + + for (auto c = other.categories ().begin (); c != other.categories ().end (); ++c) { + const rdb::Category *this_cat = category_by_name (c->name ()); + if (this_cat) { + cat2cat.insert (std::make_pair (this_cat->id (), c->id ())); + } + } + + std::map tags_by_name; + for (auto c = tags ().begin_tags (); c != tags ().end_tags (); ++c) { + tags_by_name.insert (std::make_pair (c->name (), c->id ())); + } + + for (auto c = other.tags ().begin_tags (); c != other.tags ().end_tags (); ++c) { + auto t = tags_by_name.find (c->name ()); + if (t != tags_by_name.end ()) { + tag2tag.insert (std::make_pair (t->second, c->id ())); + rev_tag2tag.insert (std::make_pair (c->id (), t->second)); + } + } + + std::map, ValueMapEntry> value_map; + + for (Items::iterator i = items_non_const ().begin (); i != items_non_const ().end (); ++i) { + + auto icell = cell2cell.find (i->cell_id ()); + if (icell == cell2cell.end ()) { + continue; + } + + auto icat = cat2cat.find (i->category_id ()); + if (icat == cat2cat.end ()) { + continue; + } + + // build a cache of value vs. value + auto vmap = value_map.find (std::make_pair (icell->second, icat->second)); + if (vmap == value_map.end ()) { + vmap = value_map.insert (std::make_pair (std::make_pair (icell->second, icat->second), ValueMapEntry ())).first; + vmap->second.build (other, icell->second, icat->second, tag2tag, rev_tag2tag); + } + + // find a value in the reference DB + const rdb::Item *other = vmap->second.find (*i); + if (other) { + + // actually transfer the attributes here + + // TODO: this has some optimization potential in terms of performance ... + i->set_image_str (other->image_str ()); + i->set_tag_str (other->tag_str ()); + + } + + } +} + void Database::scan_layout (const db::Layout &layout, db::cell_index_type cell_index, const std::vector > &layers_and_descriptions, bool flat) { diff --git a/src/rdb/rdb/rdb.h b/src/rdb/rdb/rdb.h index b15558a96..936ab28e6 100644 --- a/src/rdb/rdb/rdb.h +++ b/src/rdb/rdb/rdb.h @@ -679,6 +679,19 @@ public: */ Values &operator= (const Values &d); + /** + * @brief Compare two value sets (less operator) + * + * This compare function will use the tag mapping provided by tag map ("this" tag id to "other" tag id). + * Values with tags not listed in the tag map will not be compared. + * Untagged values (tag_id 0) will be compared always. + * + * "rev_tag_map" needs to be the reverse of "tag_map". + * + * The order of the values matters. + */ + bool compare (const Values &other, const std::map &tag_map, const std::map &rev_tag_map) const; + /** * @brief The const iterator (begin) */ @@ -2381,10 +2394,18 @@ public: /** * @brief Load the database from a file * - * @brief This clears the existing database. + * Note: This clears the existing database. */ void load (const std::string &filename); + /** + * @brief Applies the attributes from a different database + * + * Attributes are waived flags, images etc. + * The attributes are applied to markers with identical value(s), category and cell context. + */ + void apply (const rdb::Database &other); + /** * @brief Scans a layout into this RDB *