diff --git a/src/db/db/dbCell.cc b/src/db/db/dbCell.cc index bda9d71f8..e8d2a1c9f 100644 --- a/src/db/db/dbCell.cc +++ b/src/db/db/dbCell.cc @@ -93,7 +93,7 @@ Cell::box_type Cell::ms_empty_box = Cell::box_type (); Cell::Cell (cell_index_type ci, db::Layout &l) : db::Object (l.manager ()), m_cell_index (ci), mp_layout (&l), m_instances (this), m_prop_id (0), m_hier_levels (0), - m_instances_need_sort (false), m_instances_need_sort_box_tree (false), m_bbox_needs_update (false), m_ghost_cell (false), + m_bbox_needs_update (false), m_ghost_cell (false), mp_last (0), mp_next (0) { // .. nothing yet @@ -132,10 +132,6 @@ Cell::operator= (const Cell &d) m_prop_id = d.m_prop_id; m_bbox_needs_update = d.m_bbox_needs_update; - // need to update the instances inst_by_cell_index pointers - m_instances_need_sort = true; - m_instances_need_sort_box_tree = true; - } return *this; } @@ -618,8 +614,6 @@ Cell::invalidate_insts () { mp_layout->invalidate_hier (); // HINT: must come before the change is done! mp_layout->invalidate_bboxes (std::numeric_limits::max ()); - m_instances_need_sort = true; - m_instances_need_sort_box_tree = true; m_bbox_needs_update = true; } @@ -707,10 +701,7 @@ Cell::clear_parent_insts (size_t sz) void Cell::sort_child_insts () { - if (m_instances_need_sort) { - m_instances.sort_child_insts (); - } - m_instances_need_sort = false; + m_instances.sort_child_insts (); } std::pair @@ -756,10 +747,7 @@ Cell::change_pcell_parameters (const instance_type &ref, const std::vectorlayout () ? mp_cell->layout ()->is_editable () : true; + return cell () && cell ()->layout () ? cell ()->layout ()->is_editable () : true; } db::Layout * Instances::layout () const { - return mp_cell ? mp_cell->layout () : 0; + return cell () ? cell ()->layout () : 0; +} + +void +Instances::invalidate_insts () +{ + if (cell ()) { + cell ()->invalidate_insts (); + } + + set_instance_by_cell_index_needs_made (true); + set_instance_tree_needs_sort (true); } template @@ -962,14 +976,15 @@ Instances::erase_positions (Tag tag, ET editable_tag, I first, I last) { typedef instances_editable_traits editable_traits; - if (mp_cell) { - mp_cell->invalidate_insts (); // HINT: must come before the change is done! - if (mp_cell->manager () && mp_cell->manager ()->transacting ()) { + invalidate_insts (); // HINT: must come before the change is done! + + if (cell ()) { + if (cell ()->manager () && cell ()->manager ()->transacting ()) { check_is_editable_for_undo_redo (this); if (! is_editable ()) { throw tl::Exception (tl::to_string (tr ("No undo/redo support for non-editable instance lists in 'erase_positions'"))); } - mp_cell->manager ()->queue (mp_cell, new db::InstOp (false /*not insert*/, first, last, true /*dummy*/)); + cell ()->manager ()->queue (cell (), new db::InstOp (false /*not insert*/, first, last, true /*dummy*/)); } } @@ -983,18 +998,19 @@ Instances::insert (const InstArray &inst) { bool editable = is_editable (); - if (mp_cell) { - if (mp_cell->manager () && mp_cell->manager ()->transacting ()) { + if (cell ()) { + if (cell ()->manager () && cell ()->manager ()->transacting ()) { check_is_editable_for_undo_redo (this); if (editable) { - mp_cell->manager ()->queue (mp_cell, new db::InstOp (true /*insert*/, inst)); + cell ()->manager ()->queue (cell (), new db::InstOp (true /*insert*/, inst)); } else { - mp_cell->manager ()->queue (mp_cell, new db::InstOp (true /*insert*/, inst)); + cell ()->manager ()->queue (cell (), new db::InstOp (true /*insert*/, inst)); } } - mp_cell->invalidate_insts (); } + invalidate_insts (); + // TODO: simplify this, i.e. through instance_from_pointer if (editable) { return instance_type (this, inst_tree (typename InstArray::tag (), InstancesEditableTag ()).insert (inst)); @@ -1010,14 +1026,14 @@ Instances::insert (I from, I to) typedef std::iterator_traits it_traits; typedef typename it_traits::value_type value_type; - if (mp_cell) { - if (mp_cell->manager () && mp_cell->manager ()->transacting ()) { + if (cell ()) { + if (cell ()->manager () && cell ()->manager ()->transacting ()) { check_is_editable_for_undo_redo (this); - mp_cell->manager ()->queue (mp_cell, new db::InstOp (true /*insert*/, from, to)); + cell ()->manager ()->queue (cell (), new db::InstOp (true /*insert*/, from, to)); } - mp_cell->invalidate_insts (); } + invalidate_insts (); inst_tree (typename value_type::tag (), ET ()).insert (from, to); } @@ -1061,20 +1077,21 @@ template void Instances::replace (const InstArray *replace, const InstArray &with) { - if (mp_cell) { - if (mp_cell->manager () && mp_cell->manager ()->transacting ()) { + if (cell ()) { + if (cell ()->manager () && cell ()->manager ()->transacting ()) { check_is_editable_for_undo_redo (this); if (is_editable ()) { - mp_cell->manager ()->queue (mp_cell, new db::InstOp (false /*not insert*/, *replace)); - mp_cell->manager ()->queue (mp_cell, new db::InstOp (true /*insert*/, with)); + cell ()->manager ()->queue (cell (), new db::InstOp (false /*not insert*/, *replace)); + cell ()->manager ()->queue (cell (), new db::InstOp (true /*insert*/, with)); } else { - mp_cell->manager ()->queue (mp_cell, new db::InstOp (false /*not insert*/, *replace)); - mp_cell->manager ()->queue (mp_cell, new db::InstOp (true /*insert*/, with)); + cell ()->manager ()->queue (cell (), new db::InstOp (false /*not insert*/, *replace)); + cell ()->manager ()->queue (cell (), new db::InstOp (true /*insert*/, with)); } } - mp_cell->invalidate_insts (); } + invalidate_insts (); + // HINT: this only works because we know our box trees well: *((InstArray *)replace) = with; } @@ -1150,11 +1167,12 @@ Instances::erase_inst_by_iter (Tag tag, ET editable_tag, I iter) throw tl::Exception (tl::to_string (tr ("Trying to erase an object from a list that it does not belong to"))); } - if (mp_cell) { - mp_cell->invalidate_insts (); - if (mp_cell->manager () && mp_cell->manager ()->transacting ()) { + invalidate_insts (); + + if (cell ()) { + if (cell ()->manager () && cell ()->manager ()->transacting ()) { check_is_editable_for_undo_redo (this); - mp_cell->manager ()->queue (mp_cell, new db::InstOp (false /*not insert*/, *iter)); + cell ()->manager ()->queue (cell (), new db::InstOp (false /*not insert*/, *iter)); } } @@ -1165,11 +1183,12 @@ template void Instances::erase_inst_by_tag (Tag tag, ET editable_tag, const typename Tag::object_type &obj) { - if (mp_cell) { - mp_cell->invalidate_insts (); - if (mp_cell->manager () && mp_cell->manager ()->transacting ()) { + invalidate_insts (); + + if (cell ()) { + if (cell ()->manager () && cell ()->manager ()->transacting ()) { check_is_editable_for_undo_redo (this); - mp_cell->manager ()->queue (mp_cell, new db::InstOp (false /*not insert*/, obj)); + cell ()->manager ()->queue (cell (), new db::InstOp (false /*not insert*/, obj)); } } @@ -1197,16 +1216,17 @@ template void Instances::clear_insts (ET editable_tag) { - if (mp_cell) { - mp_cell->invalidate_insts (); - if (mp_cell->manager () && mp_cell->manager ()->transacting ()) { + invalidate_insts (); + + if (cell ()) { + if (cell ()->manager () && cell ()->manager ()->transacting ()) { check_is_editable_for_undo_redo (this); const Instances *const_this = this; if (! const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).empty ()) { - mp_cell->manager ()->queue (mp_cell, new db::InstOp (false /*not insert*/, const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).end ())); + cell ()->manager ()->queue (cell (), new db::InstOp (false /*not insert*/, const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).end ())); } if (! const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).empty ()) { - mp_cell->manager ()->queue (mp_cell, new db::InstOp (false /*not insert*/, const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).end ())); + cell ()->manager ()->queue (cell (), new db::InstOp (false /*not insert*/, const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).end ())); } } } @@ -1227,9 +1247,7 @@ Instances::clear_insts () void Instances::clear (Instances::cell_inst_array_type::tag) { - if (mp_cell) { - mp_cell->invalidate_insts (); - } + invalidate_insts (); if (m_generic.any) { if (is_editable ()) { @@ -1244,9 +1262,7 @@ Instances::clear (Instances::cell_inst_array_type::tag) void Instances::clear (Instances::cell_inst_wp_array_type::tag) { - if (mp_cell) { - mp_cell->invalidate_insts (); - } + invalidate_insts (); if (m_generic_wp.any) { if (is_editable ()) { @@ -1373,6 +1389,11 @@ struct cell_inst_compare_f void Instances::sort_child_insts () { + if (! instance_by_cell_index_needs_made ()) { + return; + } + set_instance_by_cell_index_needs_made (false); + m_insts_by_cell_index = sorted_inst_vector (); m_insts_by_cell_index.reserve (cell_instances ()); @@ -1406,8 +1427,13 @@ Instances::sort_child_insts () } void -Instances::sort_inst_tree (const Layout *g) +Instances::sort_inst_tree (const Layout *g, bool force) { + if (! force && ! instance_tree_needs_sort ()) { + return; + } + set_instance_tree_needs_sort (false); + if (m_generic.any) { if (is_editable ()) { m_generic.stable_tree->sort (cell_inst_array_box_converter (*g)); @@ -1603,16 +1629,17 @@ void Instances::apply_op (const Op &op, ET editable_tag) bool has_insts = ! const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).empty (); bool has_wp_insts = ! const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).empty (); - if (mp_cell) { - mp_cell->invalidate_insts (); - if (mp_cell->manager () && mp_cell->manager ()->transacting ()) { + invalidate_insts (); + + if (cell ()) { + if (cell ()->manager () && cell ()->manager ()->transacting ()) { check_is_editable_for_undo_redo (this); transacting = true; if (has_insts) { - mp_cell->manager ()->queue (mp_cell, new db::InstOp (false /*not insert*/, const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).end ())); + cell ()->manager ()->queue (cell (), new db::InstOp (false /*not insert*/, const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).end ())); } if (has_wp_insts) { - mp_cell->manager ()->queue (mp_cell, new db::InstOp (false /*not insert*/, const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).end ())); + cell ()->manager ()->queue (cell (), new db::InstOp (false /*not insert*/, const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).end ())); } } } @@ -1637,10 +1664,10 @@ void Instances::apply_op (const Op &op, ET editable_tag) if (transacting) { if (has_insts) { - mp_cell->manager ()->queue (mp_cell, new db::InstOp (true /*insert*/, const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).end ())); + cell ()->manager ()->queue (cell (), new db::InstOp (true /*insert*/, const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).end ())); } if (has_wp_insts) { - mp_cell->manager ()->queue (mp_cell, new db::InstOp (true /*insert*/, const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).end ())); + cell ()->manager ()->queue (cell (), new db::InstOp (true /*insert*/, const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).end ())); } } } diff --git a/src/db/db/dbInstances.h b/src/db/db/dbInstances.h index 9a7575941..e57b64eac 100644 --- a/src/db/db/dbInstances.h +++ b/src/db/db/dbInstances.h @@ -1553,10 +1553,11 @@ public: /** * @brief Sort the cell instance list * - * This will sort the cell instance list. As a prerequesite + * This will sort the cell instance list (quad tree sort). As a prerequesite * the cell's bounding boxes must have been computed. + * If force is true, the instance tree is always sorted. */ - void sort_inst_tree (const layout_type *g); + void sort_inst_tree (const layout_type *g, bool force); /** * @brief Update the child-parent relationships @@ -1701,14 +1702,6 @@ public: return m_parent_insts.end () == m_parent_insts.begin (); } - /** - * @brief Gets the cell pointer the instance container is in - */ - db::Cell *cell () const - { - return mp_cell; - } - /** * @brief Gets the layout the instances collection lives in */ @@ -1724,6 +1717,14 @@ public: */ bool is_editable () const; + /** + * @brief Gets the cell pointer + */ + cell_type *cell () const + { + return reinterpret_cast (size_t (mp_cell) & ~size_t (3)); + } + /** * @brief Delegate for the undo method */ @@ -1735,6 +1736,7 @@ public: void redo (db::Op *op); private: + friend class Instance; friend struct NormalInstanceIteratorTraits; friend struct TouchingInstanceIteratorTraits; friend struct OverlappingInstanceIteratorTraits; @@ -1761,6 +1763,43 @@ private: static stable_cell_inst_wp_tree_type ms_empty_stable_wp_tree; static stable_cell_inst_tree_type ms_empty_stable_tree; + /** + * @brief Sets a flag indicating that the instance tree needs sorting + */ + void set_instance_tree_needs_sort (bool f) + { + mp_cell = reinterpret_cast ((size_t (mp_cell) & ~size_t (1)) | size_t (f ? 1 : 0)); + } + + /** + * @brief Sets a flag indicating that the instance tree needs sorting + */ + bool instance_tree_needs_sort () const + { + return (size_t (mp_cell) & 1) != 0; + } + + /** + * @brief Sets a flag indicating that the instance by cell index cache needs made + */ + void set_instance_by_cell_index_needs_made (bool f) + { + mp_cell = reinterpret_cast ((size_t (mp_cell) & ~size_t (2)) | size_t (f ? 2 : 0)); + } + + /** + * @brief Sets a flag indicating that the instance tree needs sorting + */ + bool instance_by_cell_index_needs_made () const + { + return (size_t (mp_cell) & 2) != 0; + } + + /** + * @brief Invalidates the instance information - called whenever something changes + */ + void invalidate_insts (); + /** * @brief Get the non-editable instance tree by instance type */ diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index dc550432c..a02ffa949 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -1097,15 +1097,17 @@ Layout::do_prune_cell_or_subcell (cell_index_type id, int levels, bool subcells) // collect the called cells std::set called; cref.collect_called_cells (called, levels); - called.insert (id); + if (! subcells) { + called.insert (id); + } // From these cells erase all cells that have parents outside the subtree of our cell. // Make sure this is done recursively by doing this top-down. for (top_down_iterator c = begin_top_down (); c != end_top_down (); ++c) { - if (called.find (*c) != called.end () && *c != id) { + if (*c != id && called.find (*c) != called.end ()) { db::Cell &ccref = cell (*c); for (db::Cell::parent_cell_iterator pc = ccref.begin_parent_cells (); pc != ccref.end_parent_cells (); ++pc) { - if (called.find (*pc) == called.end ()) { + if (*pc != id && called.find (*pc) == called.end ()) { // we have a parent outside the subset considered currently (either the cell was never in or // it was removed itself already): remove this cell from the set of valid subcells. called.erase (*c); @@ -1115,17 +1117,8 @@ Layout::do_prune_cell_or_subcell (cell_index_type id, int levels, bool subcells) } } - // order the called cells bottom-up - std::vector cells_to_delete; - cells_to_delete.reserve (called.size ()); - for (bottom_up_iterator c = begin_bottom_up (); c != end_bottom_up (); ++c) { - if (called.find (*c) != called.end () && (!subcells || *c != id)) { - cells_to_delete.push_back (*c); - } - } - - // and delete these cells - delete_cells (cells_to_delete.begin (), cells_to_delete.end ()); + // and delete the cells + delete_cells (called); // erase all instances in the subcells case (because, by definition we don't have any more instances) if (subcells) {