mirror of https://github.com/CGAL/cgal
Orthtree: Node insertion during orthtree build has linear complexity (#8959)
## Summary of Changes Added inactive list for deleted nodes (nodes cannot be deleted for now) avoiding linear search time for node insertion during Orthtree build Reusing indices in properties from deleted nodes for insertion of a group of nodes (i.e., during Orthtree refinement) is deactivated. This has no impact as nodes cannot be deleted anyway. ## Release Management * Affected package(s): Orthtree, Property_map
This commit is contained in:
commit
8a5621e5fa
|
|
@ -50,7 +50,7 @@ public:
|
|||
|
||||
virtual void append(const Property_array_base<Index>& other) = 0;
|
||||
|
||||
virtual void reserve(std::size_t n) = 0;
|
||||
virtual void resize(std::size_t n) = 0;
|
||||
|
||||
virtual void shrink_to_fit() = 0;
|
||||
|
||||
|
|
@ -89,7 +89,6 @@ public:
|
|||
Property_array(const std::vector<bool>& active_indices, const T& default_value) :
|
||||
m_data(), m_active_indices(active_indices), m_default_value(default_value) {
|
||||
|
||||
m_data.reserve(active_indices.capacity());
|
||||
m_data.resize(active_indices.size(), m_default_value);
|
||||
}
|
||||
|
||||
|
|
@ -124,7 +123,7 @@ public:
|
|||
m_data.insert(m_data.end(), other.m_data.begin(), other.m_data.end());
|
||||
}
|
||||
|
||||
virtual void reserve(std::size_t n) override {
|
||||
virtual void resize(std::size_t n) override {
|
||||
CGAL_precondition(m_active_indices.size() == n);
|
||||
m_data.resize(n, m_default_value);
|
||||
};
|
||||
|
|
@ -248,6 +247,7 @@ class Property_container {
|
|||
|
||||
std::multimap<std::string, std::shared_ptr<Property_array_base<Index>>> m_properties;
|
||||
std::vector<bool> m_active_indices{};
|
||||
bool m_has_deleted_elements = false;
|
||||
|
||||
public:
|
||||
|
||||
|
|
@ -258,6 +258,7 @@ public:
|
|||
|
||||
Property_container(const Property_container<Index>& other) {
|
||||
m_active_indices = other.m_active_indices;
|
||||
m_has_deleted_elements = other.m_has_deleted_elements;
|
||||
|
||||
for (auto [name, array] : other.m_properties) {
|
||||
// todo: this could probably be made faster using emplace_hint
|
||||
|
|
@ -273,6 +274,7 @@ public:
|
|||
// This is not exactly an assignment as existing unique properties are kept.
|
||||
Property_container<Index>& operator=(const Property_container<Index>& other) {
|
||||
m_active_indices = other.m_active_indices;
|
||||
m_has_deleted_elements = other.m_has_deleted_elements;
|
||||
|
||||
for (auto [name, array] : other.m_properties) {
|
||||
// search if property already exists
|
||||
|
|
@ -295,6 +297,7 @@ public:
|
|||
// This is not exactly an assignment as existing unique properties are kept.
|
||||
Property_container<Index>& operator=(Property_container<Index>&& other) {
|
||||
m_active_indices = std::move(other.m_active_indices);
|
||||
m_has_deleted_elements = other.m_has_deleted_elements;
|
||||
|
||||
for (auto [name, array] : other.m_properties) {
|
||||
// search if property already exists
|
||||
|
|
@ -312,7 +315,7 @@ public:
|
|||
}
|
||||
|
||||
// The moved-from property map should retain all of its properties, but contain 0 elements
|
||||
other.reserve(0);
|
||||
other.resize(0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -441,16 +444,15 @@ public:
|
|||
}*/
|
||||
|
||||
public:
|
||||
void resize(std::size_t n) {
|
||||
|
||||
void reserve(std::size_t n) {
|
||||
m_active_indices.resize(n);
|
||||
for (auto [name, array] : m_properties)
|
||||
array->reserve(n);
|
||||
}
|
||||
array->resize(n);
|
||||
|
||||
void resize(std::size_t n) {
|
||||
reserve(n);
|
||||
std::fill(m_active_indices.begin(), m_active_indices.end(), true);
|
||||
|
||||
m_has_deleted_elements = false;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::size_t size() const { return std::count(m_active_indices.begin(), m_active_indices.end(), true); }
|
||||
|
|
@ -460,8 +462,11 @@ public:
|
|||
Index emplace_back() {
|
||||
|
||||
// Expand the storage and return the last element
|
||||
reserve(capacity() + 1);
|
||||
m_active_indices.back() = true;
|
||||
m_active_indices.push_back(true);
|
||||
|
||||
for (auto [name, array] : m_properties)
|
||||
array->resize(capacity());
|
||||
|
||||
auto first_new_index = Index(capacity() - 1);
|
||||
reset(first_new_index);
|
||||
return first_new_index;
|
||||
|
|
@ -469,6 +474,9 @@ public:
|
|||
|
||||
Index emplace() {
|
||||
|
||||
if (!m_has_deleted_elements)
|
||||
return emplace_back();
|
||||
|
||||
// If there are empty slots, return the index of one of them and mark it as full
|
||||
auto first_unused = std::find_if(m_active_indices.begin(), m_active_indices.end(), [](bool used) { return !used; });
|
||||
if (first_unused != m_active_indices.end()) {
|
||||
|
|
@ -478,20 +486,27 @@ public:
|
|||
return index;
|
||||
}
|
||||
|
||||
m_has_deleted_elements = false;
|
||||
|
||||
return emplace_back();
|
||||
}
|
||||
|
||||
Index emplace_group_back(std::size_t n) {
|
||||
|
||||
// Expand the storage and return the start of the new region
|
||||
reserve(capacity() + n);
|
||||
for (auto it = m_active_indices.end() - n; it < m_active_indices.end(); ++it)
|
||||
*it = true;
|
||||
m_active_indices.resize(capacity() + n, true);
|
||||
|
||||
for (auto [name, array] : m_properties)
|
||||
array->resize(capacity());
|
||||
|
||||
return Index(capacity() - n);
|
||||
}
|
||||
|
||||
Index emplace_group(std::size_t n) {
|
||||
|
||||
if (!m_has_deleted_elements)
|
||||
return emplace_group_back(n);
|
||||
|
||||
auto search_start = m_active_indices.begin();
|
||||
while (search_start != m_active_indices.end()) {
|
||||
|
||||
|
|
@ -544,6 +559,7 @@ public:
|
|||
|
||||
void erase(Index i) {
|
||||
m_active_indices[i] = false;
|
||||
m_has_deleted_elements = true;
|
||||
for (auto [name, array]: m_properties)
|
||||
array->reset(i);
|
||||
}
|
||||
|
|
@ -606,7 +622,7 @@ public:
|
|||
if (it != range.second)
|
||||
array->append(*it->second.get());
|
||||
else
|
||||
array->reserve(m_active_indices.size());
|
||||
array->resize(m_active_indices.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,11 +41,6 @@ void test_element_access() {
|
|||
|
||||
auto& integers = properties.add_property("integers", 5);
|
||||
|
||||
// Reserve space for 100 elements
|
||||
properties.reserve(100);
|
||||
assert(properties.capacity() == 100);
|
||||
assert(properties.size() == 0);
|
||||
|
||||
// Newly emplaced elements should go at the front
|
||||
assert(properties.emplace() == 0);
|
||||
assert(properties.emplace() == 1);
|
||||
|
|
@ -61,7 +56,6 @@ void test_element_access() {
|
|||
auto& floats = properties.add_property("floats", 6.0f);
|
||||
|
||||
// The new property array should already be of the right size
|
||||
assert(floats.capacity() == 100);
|
||||
assert(properties.size() == 3);
|
||||
|
||||
// Pre-existing elements should contain the default value
|
||||
|
|
@ -87,9 +81,8 @@ void test_element_access() {
|
|||
// Erase an element, and the size should be reduced
|
||||
properties.erase(1);
|
||||
assert(properties.size() == 2);
|
||||
assert(properties.capacity() == 100);
|
||||
assert(properties.active_list().size() == 2);
|
||||
assert(properties.inactive_list().size() == 98);
|
||||
assert(properties.inactive_list().size() == 1);
|
||||
|
||||
// A newly emplaced element should take the empty slot
|
||||
assert(properties.emplace() == 1);
|
||||
|
|
|
|||
Loading…
Reference in New Issue