ESBMC
Efficient SMT-based Context-Bounded Model Checker
Loading...
Searching...
No Matches
guard_seq Class Reference

Oldest-first immutable sequence of guard conjuncts with O(1) copy. More...

#include <guard_seq.h>

Public Types

using const_iterator = vector_t::const_iterator

Public Member Functions

 guard_seq ()=default
std::size_t size () const
bool empty () const
const expr2tc & operator[] (std::size_t i) const
const expr2tc & front () const
const expr2tc & back () const
void push_back (const expr2tc &e)
guard_seq prefix (std::size_t n) const
 Logical prefix [0, n) — shares subtrees, no element copies.
guard_seq suffix (std::size_t n) const
 Logical suffix [n, size).
void clear ()
const_iterator begin () const
const_iterator end () const
bool operator== (const guard_seq &o) const
bool operator!= (const guard_seq &o) const

Detailed Description

Oldest-first immutable sequence of guard conjuncts with O(1) copy.

Replaces the flat std::vector<expr2tc> that guard2tc used to hold. The vector was deep-copied on every guard copy (O(N) element copies plus N refcount bumps on the conjuncts) and rebuilt from scratch on every set operation, giving the Θ(N²) blow-up at deep loop unwinding.

Backed by immer::vector, a persistent (structurally-shared) bit-mapped vector trie. Conjuncts stay oldest-first — the same canonical order as guard2tc's cached left-leaning and-chain, so the index correspondence the prefix/diff logic relies on is preserved exactly.

Costs: copy O(1) (shared root); push_back / index O(log32 N) ≈ O(1) for the few-hundred-element guards symex builds; prefix (take) shares subtrees; iterate O(N). We use immer::vector rather than flex_vector (the relaxed RRB tree): flex's only edge is O(log N) drop()/suffix slicing, but measured max suffix length in real symex is 1 (guards diverge one conjunct at a time at merge points), so flex's relaxed-radix bookkeeping is pure overhead. A/B: immer::vector was ~5% fewer instructions and ~15% faster symex on test_locks_13, same verdicts. suffix() rebuilds [n,size) since plain vector has no drop(); that is O(suffix) but suffix is ~1 in practice.

Ownership: NON-atomic refcount, no lock (unsafe_refcount_policy + no_lock_policy). Guards are thread-confined — the only symex parallelism (--parallel-solving) forks threads to solve an already-built equation, while the guard set-algebra runs in the single-threaded symex phase, and the conjunct list is never stored in the equation (only the expr2tc base is, and that is an atomic irep_container). So a non-atomic refcount is sound. NOTE: this is load-bearing on "symex is not parallelized" — if that ever changes, switch to refcount_policy (atomic; measured ~10-15% slower here, not the 2× the value-returning accessors below cost). immer's default policy additionally pairs the atomic refcount with spinlock_policy (a test_and_set lock around every tree op for the transient API); we never share transients across threads, so no_lock is used regardless of refcount choice.

Member Typedef Documentation

◆ const_iterator

using guard_seq::const_iterator = vector_t::const_iterator

Constructor & Destructor Documentation

◆ guard_seq()

guard_seq::guard_seq ( )
default

Member Function Documentation

◆ back()

const expr2tc & guard_seq::back ( ) const
inline

◆ begin()

const_iterator guard_seq::begin ( ) const
inline

◆ clear()

void guard_seq::clear ( )
inline

◆ empty()

bool guard_seq::empty ( ) const
inline

◆ end()

const_iterator guard_seq::end ( ) const
inline

◆ front()

const expr2tc & guard_seq::front ( ) const
inline

◆ operator!=()

bool guard_seq::operator!= ( const guard_seq & o) const
inline

◆ operator==()

bool guard_seq::operator== ( const guard_seq & o) const
inline

◆ operator[]()

const expr2tc & guard_seq::operator[] ( std::size_t i) const
inline

◆ prefix()

guard_seq guard_seq::prefix ( std::size_t n) const
inline

Logical prefix [0, n) — shares subtrees, no element copies.

◆ push_back()

void guard_seq::push_back ( const expr2tc & e)
inline

◆ size()

std::size_t guard_seq::size ( ) const
inline

◆ suffix()

guard_seq guard_seq::suffix ( std::size_t n) const
inline

Logical suffix [n, size).

immer::vector has no drop(), so rebuild [n,size) element-wise. O(suffix), but the suffix length in symex guard subtraction is ~1 in practice (guards diverge one conjunct at a time at merge points), so this is cheaper than flex_vector's relaxed-radix drop.


The documentation for this class was generated from the following file: