|
| template<class T> |
| void | esbmct::hash_combine (std::size_t &seed, const T &v) |
| | Mix a value into a running hash seed.
|
| template<class T, class... Args> |
| irep_container< typename T::base_type > | make_irep (Args &&... args) |
| | Allocate a fresh irep2 node and adopt it into an irep_container.
|
| std::string | get_type_id (const type2t &type) |
| | Fetch identifying name for a type.
|
| static std::string | get_type_id (const type2tc &type) |
| | Fetch identifying name for a type.
|
| bool | is_nil_expr (const expr2tc &exp) |
| template<class T> |
| bool | same_pointer (const irep_container< T > &a, const irep_container< T > &b) |
| | Node-identity test: true iff a and b refer to the very same hash-consed node.
|
| bool | is_nil_type (const type2tc &t) |
| std::size_t | hash_value (const expr2tc &expr) |
| std::string | get_expr_id (const expr2t &expr) |
| | Fetch string identifier for an expression.
|
| static std::string | get_expr_id (const expr2tc &expr) |
| | Fetch string identifier for an expression.
|
| template<class K, std::size_t I> |
| constexpr std::size_t | esbmct::nth_field_size_in_derived () |
| template<class K, std::size_t... Is> |
| constexpr std::size_t | esbmct::sum_derived_field_sizes (std::index_sequence< Is... >) |
| template<class K, std::size_t... Is> |
| constexpr std::size_t | esbmct::count_derived_field_entries (std::index_sequence< Is... >) |
| template<class K> |
| constexpr bool | esbmct::fields_cover_class () |
| template<class K> |
| constexpr std::size_t | esbmct::derived_field_count () |
| template<class K> |
| constexpr bool | esbmct::assert_kind_invariants () |
| std::ostream & | operator<< (std::ostream &out, const expr2tc &a) |
| void | irep2_bad_type_cast (unsigned actual, unsigned expected, const char *target) |
| void | irep2_bad_expr_cast (unsigned actual, unsigned expected, const char *target) |
| void | irep2_bad_family_cast (unsigned actual, const char *accessor) |
| template<typename Derived> |
| Derived & | irep2_checked_type_cast (type2t &t, type2t::type_ids expected, const char *target_name) |
| template<typename Derived> |
| const Derived & | irep2_checked_type_cast (const type2t &t, type2t::type_ids expected, const char *target_name) |
| template<typename Derived> |
| Derived & | irep2_checked_expr_cast (expr2t &e, expr2t::expr_ids expected, const char *target_name) |
| template<typename Derived> |
| const Derived & | irep2_checked_expr_cast (const expr2t &e, expr2t::expr_ids expected, const char *target_name) |
Classes and definitions for non-stringy internal representation.
Threading contract: irep2 nodes (type2t, expr2t) are designed for single-writer / thread-confined construction and rewriting.
Ownership is handled by an intrusive atomic refcount sitting on every node (irep2t::refcount); irep_container is a raw pointer that increments on copy, decrements on destruction, and deletes the pointee when the count drops to zero. The refcount is atomic so two containers holding the same node can be dropped from different threads safely, but the pointee's state is not — only one thread at a time may obtain a mutable view (the non-const irep_container::get() / operator-> / operator*, which detach if refcount > 1 and otherwise hand back the underlying object).
The CRC cache (irep2t::crc_val) is a single std::atomic<size_t> with 0 meaning "not yet computed". Readers do an acquire load, producers compute on a stack local and release-store the result, so concurrent readers see either 0 (and recompute, getting the same value) or the final cache entry — never a half-mixed state.
Treat an irep2 tree as owned by a single rewriter at a time; publish to other threads only once mutation is complete and only for read-only consumption.
template<class
T, class... Args>
Allocate a fresh irep2 node and adopt it into an irep_container.
The single canonical construction path for the intrusive refcount scheme. T must derive from an irep2 base (type2t / expr2t) that exposes base_type as its method-side base; the returned container is irep_container<T::base_type> (i.e. type2tc or expr2tc).
Single allocation, no separate control block, exception-safe (if any argument constructor throws, the new hasn't run yet; if the new itself throws, no leak; the only ordering between new succeeding and the container adopting it is straight-line code inside this function).
Callers should prefer this helper over a raw new-into-container so the allocation site stays in one place.