Skip to content

fix: remove xpressive dependency - #566

Open
Becheler wants to merge 1 commit into
boostorg:developfrom
Becheler:fix/graphviz-remove-xpressive-writer
Open

fix: remove xpressive dependency#566
Becheler wants to merge 1 commit into
boostorg:developfrom
Becheler:fix/graphviz-remove-xpressive-writer

Conversation

@Becheler

@Becheler Becheler commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

#496

Before submitting

  • This PR targets the develop branch.
  • I searched for an existing PR or issue covering the same change.
  • My contribution is licensed under the Boost Software License 1.0.

Type of change

  • Bug fix
  • New feature or API addition
  • Refactor (no behavior change)
  • Documentation
  • Build, CI, or tooling
  • Other (specify below)

Does this PR introduce a breaking change?

  • Yes (describe migration impact below)
  • No

What this PR does

Motivation

Too many warnings come from xpressive and its dependencies proto and fusion.

Context:

DOT is the plain-text graph language Graphviz uses, the format that write_graphviz produces and read_graphviz parses (for example, digraph { a -> b [label="hello world"] }). In that text, every name and value is a token the grammar calls an ID: node names like a, attribute names like label, and attribute values like "hello world". The grammar allows an ID in four forms:

  • An identifier-like name: a letter or underscore followed by letters, digits, or underscores (foo, node_1, _x).
  • A numeral: 42, -3.14, .5.
  • A double-quoted string: "hello world", "has \"quotes\"". This form can hold any characters, with \" for an embedded quote.
  • An HTML string (<...>), not relevant here.

The first two forms may be written bare. Anything that is not a valid bare name or numeral (it contains a space, punctuation, or a quote, starts with a digit and then has letters like 9lives, has two dots like 1.2.3, or is empty) must use the quoted form, or the parser breaks. Deciding which case a value falls into is exactly the job of escape_dot_string.

Testing

Checklist

  • Existing tests pass (b2 in the test/ directory).
  • New behavior is covered by a test, or this is a docs / build / refactor change.
  • Documentation was updated if user-facing behavior changed.
  • No new compiler warnings on the platforms I built against.

@Becheler Becheler self-assigned this Aug 12, 2026
@Becheler Becheler added warning technical debt Code that works but needs refactoring, cleanup, or modernization. Not user-facing. labels Aug 12, 2026
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

Boost dependency footprint vs develop (auto-generated).
PR run 31585207693 vs develop run 31585045874 (30d31bfb2f).

Header-inclusion weights (graph files pulling each direct dependency in):

Dependency develop PR Δ
xpressive 1 0 -1

Transitive Boost modules: 68 → 67 (-1)

  • removed: xpressive

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

Compiler-warning counts vs develop (auto-generated).
PR run 31585207685 vs develop run 31585046312 (30d31bfb2f).

Job Baseline After Delta
macos (clang, 14) 703 493 -210
macos (clang, 17) 663 453 -210
macos (clang, 20) 663 453 -210
ubuntu (clang-19, 14) 703 493 -210
ubuntu (clang-19, 17) 663 453 -210
ubuntu (clang-19, 20) 663 453 -210
ubuntu (clang-19, 23) 663 453 -210
ubuntu (gcc-14, 14) 874 444 -430
ubuntu (gcc-14, 17) 1010 440 -570
ubuntu (gcc-14, 20) 1010 440 -570
ubuntu (gcc-14, 23) 1010 440 -570
windows_msvc_14_3 (msvc-14.3) 962 962 0

@Becheler
Becheler force-pushed the fix/graphviz-remove-xpressive-writer branch from 16db299 to dedb6c5 Compare August 12, 2026 07:31
@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Becheler
Becheler force-pushed the fix/graphviz-remove-xpressive-writer branch from 2ad1055 to 30d31bf Compare August 12, 2026 09:56
@jeremy-murphy

Copy link
Copy Markdown
Collaborator

I'm not convinced about the trade-off here. We already depend on Boost.Regex, so why not just replace Xpressive with Regex? Or the other way around?

@Becheler

Becheler commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator Author

@jeremy-murphy IMO doubling down with xpressive would be a mistake, and the trade-off is stark:

  • it's ~3,600 fewer warning lines across the full matrix, from a ~15-line change with no public-API or behavior change. Scanning CI logs warnings is a real PITA, and I would like that pain to disminish 😉
  • Xpressive brings 34 Boost dependencies and we are losing users by assuming it's not a problem (they keep telling us it's a problem). I do think it may have been ok in the past, as people (especially maintainers, users not so much) were happy to think of Boost as one big lib, but the landscape changed a lot.

IMO there are several reasons not to go the Boost.Regex route here:

Boost.Regex would break the writer's header-only-ness. escape_dot_string is header-only today, so write_graphviz needs nothing linked. Boost.Regex is a compiled library, so using it here would force every TU that includes graphviz.hpp to link libboost_regex.

We don't actually need a regex engine here. The pattern is:

  • fixed and known at compile time (it never comes from a DB/config/user input, which is the one thing only a runtime regex buys you),
  • trivial (a ~2-branch regular language: identifier or numeral),
  • on a header-only write path where both a linked dependency and per-call overhead matter.

Naive -O2 benchmark on a small corpus (https://godbolt.org/z/4MP8T95h8):

  • boost::regex ~91× slower than the hand-rolled predicate
  • std::regex ~47× slower
  • plus a one-time ~6–17 µs construction the hand-rolled version skips entirely

escape_dot_string runs once per written value (node id + every vertex/edge/graph attribute), so this constant factor just multiplies with graph size: on a large, attribute-heavy graph it's the same 50–90× penalty applied many times over. I haven't measured that end-to-end, but it can't be a good sign.

Overall I do think dropping dependencies is urgent, we're bleeding users over our transitive dependency weight, but happy to chat about it.

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

Labels

technical debt Code that works but needs refactoring, cleanup, or modernization. Not user-facing. warning

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants