Skip to content

Turn Expr into a proper range instead of a view - #593

Merged
Krzmbrzl merged 5 commits into
ValeevGroup:masterfrom
Krzmbrzl:make-expr-proper-range
Aug 20, 2026
Merged

Turn Expr into a proper range instead of a view#593
Krzmbrzl merged 5 commits into
ValeevGroup:masterfrom
Krzmbrzl:make-expr-proper-range

Conversation

@Krzmbrzl

Copy link
Copy Markdown
Collaborator

Previously, the Expr implementation used range-v3's view facade to
implement range semantics on Expr objects. However, views are different
things from containers which had some more or less subtle consequences.
See also https://stackoverflow.com/a/31462435

This PR replaces the view facade with virtual begin/end
implementations returning ExprIterator objects. Hence, Expr is now a
fully fledged container that is usable as a random-access range.

Previously, the Expr implementation used range-v3's view facade to
implement range semantics on Expr objects. However, views are different
things from containers which had some more or less subtle consequences.
See also https://stackoverflow.com/a/31462435

This commit replaces the view facade with virtual begin/end
implementations returning ExprIterator objects. Hence, Expr is now a
fully fledged container that is usable as a random-access range.
@Krzmbrzl

Copy link
Copy Markdown
Collaborator Author

Okay, I'll have to change the impl to make some protected helper functions like get_begin() & Co which are then called in Expr's base begin()/end() functions to get rid of these ridiculous shadowing issues.

@Krzmbrzl
Krzmbrzl marked this pull request as draft August 19, 2026 18:23
This avoids the issue of not being able to shadow begin/end in
subclasses as shadowing is not allowed for virtual functions.
@Krzmbrzl
Krzmbrzl marked this pull request as ready for review August 20, 2026 08:36
@Krzmbrzl
Krzmbrzl merged commit 3168a65 into ValeevGroup:master Aug 20, 2026
8 checks passed
@evaleev evaleev added this to the 2.3 milestone Aug 20, 2026
@evaleev

evaleev commented Aug 20, 2026

Copy link
Copy Markdown
Member

Post-merge review of this PR turned up three defects; #594 fixes them, with a regression test for each.

  1. The const/non-const iterator overloads never worked. ExprIteratorImpl's heterogeneous operator-/operator==/operator<=> read other.ptr_ of the other specialization, which is private and has no friend declaration — a hard error the moment any of them is instantiated. Nothing in tree mixes the two types, which is why CI is green, but expr.begin() != expr.cend() does not compile, and neither does pairing sequant::cbegin(ExprPtr const&) with the non-const sequant::end(ExprPtr&). There is also no ExprIteratorConstExprIterator conversion. (Also removed operator-(difference_type, ExprIteratorImpl): n - it is not a valid random-access-iterator expression and it silently computed it - n.)

  2. Expr::at() lost its bounds check. The ranges::view_interface::at() that went away used to throw; the replacement forwards to operator[], which is guarded only by SEQUANT_ASSERT. With SEQUANT_ASSERT_BEHAVIOR=IGNORE, sum.at(p) at optimize/sum.cpp:118 degrades to an out-of-bounds read. back() is worse: at(size() - 1) on any atom computes at(SIZE_MAX).

  3. Product::end_subexpr() stopped invalidating the memoized hash. The old Product::end_cursor() called reset_hash_value(). Without it, *(--product.end()) = new_factor leaves a stale hash — tripping the assert in Product::memoizing_hash(), or silently making static_equal() return false for equal products. (Conversely, Sum::begin_subexpr() gained a reset that Sum::begin_cursor() never had — that one is correct, and Follow-ups to #593: iterator interop, checked Expr::at(), hash invalidation #594 extends it to Sum::end_subexpr() for symmetry.)

#594 also moves begin/end/size/empty/operator[]/at/front/back back into the header; they are one-liners on the hottest paths in the library (Expr::is_atom() is called from visit_impl(), is_scalar(), ExprRange::next_atom(), Wick and canonicalization) and out-of-line definitions make each a non-inlinable cross-TU call on top of the virtual dispatch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants