void CAtom::remove_guard( CAtom** ptr ) { if( !*ptr ) return; GuardMap* map = guard_map(); if( !map || map->empty() ) return; bool more = false; // if the CAtom has more pointers attached to it. GuardMap::iterator it = map->find( *ptr ); const GuardMap::iterator end = map->end(); for( ; it != end && it->first == *ptr; ++it ) { if( it->second == ptr ) { if( !more ) { ++it; more = ( it != end ) && ( it->first == *ptr ); --it; } map->erase( it ); break; } more = true; } if( !more ) ( *ptr )->set_has_guards( false ); }
z3::expr Z3AssumptionSolverImpl::getAssumption(ref<Expr> assertion) { GuardMap::iterator it = guards_.find(assertion); if (it != guards_.end()) { return it->second; } char name[16]; snprintf(name, 16, "g%lu", guard_counter_++); z3::expr result = context_.bool_const(name); guards_.insert(std::make_pair(assertion, result)); solver_.add(z3::to_expr(context_, Z3_mk_implies(context_, result, builder_->construct(assertion)))); return result; }
void CAtom::clear_guards( CAtom* o ) { GuardMap* map = 0; try { map = guard_map(); } catch( std::bad_alloc& ) { // do nothing in case of OOM - code below is safe } if( !map || map->empty() ) return; GuardMap::iterator it = map->find( o ); GuardMap::iterator first = it; const GuardMap::iterator end = map->end(); for( ; it != end && it->first == o; ++it ) *it->second = 0; map->erase( first, it ); o->set_has_guards( false ); }
// Merge adjacent blocks with identical guards. static void mergeGuards(std::deque<std::string>& file_lines, GuardMap& guard_map) { if (guard_map.size() < 2) { return; } auto current = guard_map.begin(); auto next = current; ++next; while (next != guard_map.end()) { if (current->second != next->second) { ++current; ++next; continue; } // Scan from the end of current to the beginning of next. bool in_block_comment = false; bool valid = true; FileLocation current_location = current->first.end; FileLocation end_location = next->first.start; auto nextLine = [¤t_location]() { ++current_location.line; current_location.column = 1; }; auto nextCol = [&file_lines, ¤t_location, &nextLine]() { if (current_location.column == file_lines[current_location.column - 1].length()) { nextLine(); } else { ++current_location.column; } }; // The end location will point to the semicolon, which we don't want to read, so skip it. nextCol(); while (current_location < end_location) { const std::string& line = file_lines[current_location.line - 1]; size_t line_index = current_location.column - 1; if (in_block_comment) { size_t pos = line.find("*/", line_index); if (pos == std::string::npos) { D("Didn't find block comment terminator, skipping line\n"); nextLine(); continue; } else { D("Found block comment terminator\n"); in_block_comment = false; current_location.column = pos + 2; nextCol(); continue; } } else { size_t pos = line.find_first_not_of(" \t", line_index); if (pos == std::string::npos) { nextLine(); continue; } current_location.column = pos + 1; if (line[pos] != '/') { D("Trailing character '%c' is not a slash: %s\n", line[pos], line.substr(pos).c_str()); valid = false; break; } nextCol(); if (line.length() <= pos + 1) { // Trailing slash at the end of a line? D("Trailing slash at end of line\n"); valid = false; break; } if (line[pos + 1] == '/') { // C++ style comment nextLine(); } else if (line[pos + 1] == '*') { // Block comment nextCol(); in_block_comment = true; D("In a block comment\n"); } else { // Garbage? D("Unexpected output after /: %s\n", line.substr(pos).c_str()); valid = false; break; } } } if (!valid) { D("Not merging blocks %s and %s\n", to_string(current->first).c_str(), to_string(next->first).c_str()); ++current; ++next; continue; } D("Merging blocks %s and %s\n", to_string(current->first).c_str(), to_string(next->first).c_str()); Location merged = current->first; merged.end = next->first.end; DeclarationAvailability avail = current->second; guard_map.erase(current); guard_map.erase(next); bool dummy; std::tie(current, dummy) = guard_map.insert(std::make_pair(merged, avail)); next = current; ++next; } }