Fix bug with invalidated iterators when enforcing precedence in region expressions (#2950)

This commit is contained in:
Paul Romano 2024-06-17 14:25:05 -05:00 committed by GitHub
parent 5222b343a4
commit 8be35cd7b5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 24 additions and 26 deletions

View file

@ -128,8 +128,7 @@ private:
void add_precedence();
//! Add parenthesis to enforce precedence
std::vector<int32_t>::iterator add_parentheses(
std::vector<int32_t>::iterator start);
gsl::index add_parentheses(gsl::index start);
//! Remove complement operators from the expression
void remove_complement_ops();

View file

@ -578,17 +578,14 @@ void Region::apply_demorgan(
//! precedence than unions using parentheses.
//==============================================================================
std::vector<int32_t>::iterator Region::add_parentheses(
std::vector<int32_t>::iterator start)
gsl::index Region::add_parentheses(gsl::index start)
{
int32_t start_token = *start;
// Add left parenthesis
if (start_token == OP_INTERSECTION) {
start = expression_.insert(start - 1, OP_LEFT_PAREN);
} else {
start = expression_.insert(start + 1, OP_LEFT_PAREN);
int32_t start_token = expression_[start];
// Add left parenthesis and set new position to be after parenthesis
if (start_token == OP_UNION) {
start += 2;
}
start++;
expression_.insert(expression_.begin() + start - 1, OP_LEFT_PAREN);
// Keep track of return iterator distance. If we don't encounter a left
// parenthesis, we return an iterator corresponding to wherever the right
@ -600,23 +597,23 @@ std::vector<int32_t>::iterator Region::add_parentheses(
// Add right parenthesis
// While the start iterator is within the bounds of infix
while (start < expression_.end()) {
while (start + 1 < expression_.size()) {
start++;
// If the current token is an operator and is different than the start token
if (*start >= OP_UNION && *start != start_token) {
if (expression_[start] >= OP_UNION && expression_[start] != start_token) {
// Skip wrapped regions but save iterator position to check precedence and
// add right parenthesis, right parenthesis position depends on the
// operator, when the operator is a union then do not include the operator
// in the region, when the operator is an intersection then include the
// operator and next surface
if (*start == OP_LEFT_PAREN) {
return_it_dist = std::distance(expression_.begin(), start);
if (expression_[start] == OP_LEFT_PAREN) {
return_it_dist = start;
int depth = 1;
do {
start++;
if (*start > OP_COMPLEMENT) {
if (*start == OP_RIGHT_PAREN) {
if (expression_[start] > OP_COMPLEMENT) {
if (expression_[start] == OP_RIGHT_PAREN) {
depth--;
} else {
depth++;
@ -624,10 +621,12 @@ std::vector<int32_t>::iterator Region::add_parentheses(
}
} while (depth > 0);
} else {
start = expression_.insert(
start_token == OP_UNION ? start - 1 : start, OP_RIGHT_PAREN);
if (start_token == OP_UNION) {
--start;
}
expression_.insert(expression_.begin() + start, OP_RIGHT_PAREN);
if (return_it_dist > 0) {
return expression_.begin() + return_it_dist;
return return_it_dist;
} else {
return start - 1;
}
@ -638,7 +637,7 @@ std::vector<int32_t>::iterator Region::add_parentheses(
// return iterator
expression_.push_back(OP_RIGHT_PAREN);
if (return_it_dist > 0) {
return expression_.begin() + return_it_dist;
return return_it_dist;
} else {
return start - 1;
}
@ -651,21 +650,21 @@ void Region::add_precedence()
int32_t current_op = 0;
std::size_t current_dist = 0;
for (auto it = expression_.begin(); it != expression_.end(); it++) {
int32_t token = *it;
for (gsl::index i = 0; i < expression_.size(); i++) {
int32_t token = expression_[i];
if (token == OP_UNION || token == OP_INTERSECTION) {
if (current_op == 0) {
// Set the current operator if is hasn't been set
current_op = token;
current_dist = std::distance(expression_.begin(), it);
current_dist = i;
} else if (token != current_op) {
// If the current operator doesn't match the token, add parenthesis to
// assert precedence
if (current_op == OP_INTERSECTION) {
it = add_parentheses(expression_.begin() + current_dist);
i = add_parentheses(current_dist);
} else {
it = add_parentheses(it);
i = add_parentheses(i);
}
current_op = 0;
current_dist = 0;