From e5939c6db8e64824eaec269cf31105d71fc5f009 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Thu, 31 Aug 2023 16:55:11 -0600 Subject: [PATCH] Add an assertion to IndexSet::compress(). --- source/base/index_set.cc | 134 ++++++++++++++++++++++----------------- 1 file changed, 77 insertions(+), 57 deletions(-) diff --git a/source/base/index_set.cc b/source/base/index_set.cc index f3c7b66b66..168e1ecaa0 100644 --- a/source/base/index_set.cc +++ b/source/base/index_set.cc @@ -99,64 +99,84 @@ IndexSet::IndexSet(const Epetra_BlockMap &map) void IndexSet::do_compress() const { - // we will, in the following, modify mutable variables. this can only - // work in multithreaded applications if we lock the data structures - // via a mutex, so that users can call 'const' functions from threads - // in parallel (and these 'const' functions can then call compress() - // which itself calls the current function) - std::lock_guard lock(compress_mutex); - - // see if any of the contiguous ranges can be merged. do not use - // std::vector::erase in-place as it is quadratic in the number of - // ranges. since the ranges are sorted by their first index, determining - // overlap isn't all that hard - std::vector::iterator store = ranges.begin(); - for (std::vector::iterator i = ranges.begin(); i != ranges.end();) - { - std::vector::iterator next = i; - ++next; - - size_type first_index = i->begin; - size_type last_index = i->end; - - // see if we can merge any of the following ranges - while (next != ranges.end() && (next->begin <= last_index)) - { - last_index = std::max(last_index, next->end); - ++next; - } - i = next; - - // store the new range in the slot we last occupied - *store = Range(first_index, last_index); - ++store; - } - // use a compact array with exactly the right amount of storage - if (store != ranges.end()) - { - std::vector new_ranges(ranges.begin(), store); - ranges.swap(new_ranges); - } + { + // we will, in the following, modify mutable variables. this can only + // work in multithreaded applications if we lock the data structures + // via a mutex, so that users can call 'const' functions from threads + // in parallel (and these 'const' functions can then call compress() + // which itself calls the current function) + std::lock_guard lock(compress_mutex); + + // see if any of the contiguous ranges can be merged. do not use + // std::vector::erase in-place as it is quadratic in the number of + // ranges. since the ranges are sorted by their first index, determining + // overlap isn't all that hard + std::vector::iterator store = ranges.begin(); + for (std::vector::iterator i = ranges.begin(); i != ranges.end();) + { + std::vector::iterator next = i; + ++next; + + size_type first_index = i->begin; + size_type last_index = i->end; + + // see if we can merge any of the following ranges + while (next != ranges.end() && (next->begin <= last_index)) + { + last_index = std::max(last_index, next->end); + ++next; + } + i = next; + + // store the new range in the slot we last occupied + *store = Range(first_index, last_index); + ++store; + } + // use a compact array with exactly the right amount of storage + if (store != ranges.end()) + { + std::vector new_ranges(ranges.begin(), store); + ranges.swap(new_ranges); + } + + // now compute indices within set and the range with most elements + size_type next_index = 0, largest_range_size = 0; + for (std::vector::iterator i = ranges.begin(); i != ranges.end(); + ++i) + { + Assert(i->begin < i->end, ExcInternalError()); + + i->nth_index_in_set = next_index; + next_index += (i->end - i->begin); + if (i->end - i->begin > largest_range_size) + { + largest_range_size = i->end - i->begin; + largest_range = i - ranges.begin(); + } + } + is_compressed = true; + + // check that next_index is correct. needs to be after the previous + // statement because we otherwise will get into an endless loop + Assert(next_index == n_elements(), ExcInternalError()); + } - // now compute indices within set and the range with most elements - size_type next_index = 0, largest_range_size = 0; - for (std::vector::iterator i = ranges.begin(); i != ranges.end(); ++i) - { - Assert(i->begin < i->end, ExcInternalError()); - - i->nth_index_in_set = next_index; - next_index += (i->end - i->begin); - if (i->end - i->begin > largest_range_size) - { - largest_range_size = i->end - i->begin; - largest_range = i - ranges.begin(); - } - } - is_compressed = true; - - // check that next_index is correct. needs to be after the previous - // statement because we otherwise will get into an endless loop - Assert(next_index == n_elements(), ExcInternalError()); +#ifdef DEBUG + // A consistency check: We should only ever have added indices + // that are within the range of the index set. Instead of doing + // this in every one of the many functions that add indices, + // do this in the current, central location + for (const auto &range : ranges) + Assert((range.begin < index_space_size) && (range.end <= index_space_size), + ExcMessage("In the process of creating the current IndexSet " + "object, you added indices beyond the size of the index " + "space. Specifically, you added elements that form the " + "range [" + + std::to_string(range.begin) + "," + + std::to_string(range.end) + + "), but the size of the index space is only " + + std::to_string(index_space_size) + ".")); +#endif } -- 2.39.5