Releases: purpleclay/chomp
v0.7.0
v0.7.0 - February 03, 2026
Contributors
@purpleclay (
7commits)
Performance Improvements
-
841e0d9optimize Take using utf8.DecodeRuneInString avoiding allocations (#106) (@purpleclay)Use
utf8.DecodeRuneInStringto iterate through runes instead of converting the entire string to[]rune, eliminating unnecessary allocations.benchstat results (n=10):
│ baseline │ optimized │ │ sec/op │ sec/op vs base │ Take/Ascii-12 75.35n ± 1% 15.65n ± 0% -79.24% (p=0.000) Take/Unicode-12 95.28n ± 0% 10.17n ± 1% -89.32% (p=0.000) -
a54ca13optimize AnyChar and Satisfy using utf8.DecodeRuneInString avoiding allocations (#104) (@purpleclay)Use
utf8.DecodeRuneInStringinstead of[]rune(s)conversion to extract the first character, eliminating unnecessary allocations.benchstat results (n=10):
│ baseline │ optimized │ │ sec/op │ sec/op vs base │ AnyChar/Ascii-10 56.51n ± 1% 1.80n ± 11% -96.81% (p=0.000) AnyChar/Unicode-10 55.43n ± 0% 1.65n ± 10% -97.03% (p=0.000) Satisfy/Ascii-10 56.94n ± 1% 2.06n ± 7% -96.39% (p=0.000) Satisfy/Unicode-10 54.70n ± 2% 1.78n ± 5% -96.74% (p=0.000) -
04bb974pre-compute character sets for Any and Not combinators (#103) (@purpleclay)Build a
map[rune]struct{}at combinator creation time to reduce character lookup complexity fromO(m)toO(1)per input character, where m is the charset length.A threshold of 8 characters is used to determine when to use the map-based approach versus linear scanning. For small charsets (<8 chars), linear scanning is faster due to better cache locality and lower overhead. For larger charsets, the map lookup becomes more efficient.
benchstat results (n=10):
│ baseline │ optimized │ │ sec/op │ sec/op vs base │ Any/Small/Ascii-12 11.45n ± 1% 9.53n ± 1% -16.73% (p=0.000) Any/Large/Ascii-12 92.95n ± 0% 67.51n ± 2% -27.38% (p=0.000) Any/Small/Unicode-12 29.05n ± 1% 27.92n ± 1% -3.87% (p=0.000) Any/Large/Unicode-12 129.10n ± 1% 60.27n ± 2% -53.32% (p=0.000) Not/Small/Ascii-12 62.27n ± 1% 52.23n ± 3% -16.12% (p=0.000) Not/Large/Ascii-12 142.9n ± 1% 109.8n ± 0% -23.20% (p=0.000) Not/Small/Unicode-12 98.23n ± 0% 96.01n ± 1% -2.26% (p=0.000) Not/Large/Unicode-12 273.8n ± 0% 110.3n ± 1% -59.70% (p=0.000) -
b27af34replace len(string(rune)) with utf8.RuneLen avoiding temporary string allocations (#100) (@purpleclay)Replace the
len(string(c))pattern withutf8.RuneLen(c)across predicate loops in basic.go and predicate.go. This avoids creating temporary string allocations when calculating rune byte lengths.Also optimized
EscapedandEscapedTransformto useutf8.DecodeRuneInStringinstead of converting the entire remaining string to[]runejust to check the first character.benchstat results (n=10):
│ baseline │ optimized │ │ sec/op │ sec/op vs base │ Any/Ascii-12 40.65n ± 1% 38.29n ± 0% -5.79% (p=0.000) Any/Unicode-12 62.34n ± 1% 54.76n ± 2% -12.17% (p=0.000) Not/Ascii-12 67.46n ± 1% 63.11n ± 1% -6.44% (p=0.000) Not/Unicode-12 116.65n ± 1% 98.93n ± 0% -15.19% (p=0.000) While/Digit-12 28.36n ± 0% 23.43n ± 0% -17.39% (p=0.000) While/Letter/Ascii-12 10.480n ± 1% 8.715n ± 1% -16.85% (p=0.000) While/Letter/Unicode-12 249.9n ± 0% 222.9n ± 1% -10.80% (p=0.000) While/Alphanumeric-12 60.57n ± 0% 50.73n ± 0% -16.25% (p=0.000) While/Space-12 21.95n ± 0% 17.52n ± 6% -20.19% (p=0.000) WhileNot/Digit/Ascii-12 125.7n ± 1% 103.6n ± 0% -17.55% (p=0.000) WhileNot/Digit/Unicode-12 205.6n ± 1% 178.8n ± 1% -13.04% (p=0.000) -
742117boptimize Eol by inlining logic avoiding combinator composition overhead (#99) (@purpleclay)Replace the composed combinator chain
Suffixed(WhileNotN(IsLineEnding, 0), Opt(Crlf()))with inlined logic using direct string iteration and byte comparisons to avoid heap allocations from combinator composition on each call.benchstat results (n=10):
│ baseline │ optimized │ │ sec/op │ sec/op vs base │ Eol/Ascii-12 159.95n ± 1% 54.90n ± 0% -65.67% (p=0.000) Eol/Unicode-12 146.55n ± 0% 55.17n ± 1% -62.35% (p=0.000) -
ba03235optimize Char, OneOf, and NoneOf using utf8.DecodeRuneInString avoiding allocations (#98) (@purpleclay)Replace
[]rune(s)conversions withutf8.DecodeRuneInStringto avoid heap allocations when checking the first character of input strings.benchstat results (n=10):
│ baseline │ optimized │ │ sec/op │ sec/op vs base │ Char/Ascii-12 60.20n ± 3% 1.75n ± 6% -97.09% (p=0.000) Char/Unicode-12 81.64n ± 1% 2.34n ± 1% -97.13% (p=0.000) OneOf/Ascii-12 63.33n ± 1% 11.12n ± 2% -82.44% (p=0.000) OneOf/Unicode-12 77.16n ± 1% 4.34n ± 1% -94.37% (p=0.000) NoneOf/Ascii-12 55.41n ± 2% 3.35n ± 1% -93.95% (p=0.000) NoneOf/Unicode-12 79.86n ± 1% 6.13n ± 1% -92.33% (p=0.000)
Generated with release-note
v0.6.0
v0.6.0 - January 26, 2026
2 new features
Contributors
@purpleclay (
4commits)
New Features
-
7661a47add dedicated control flow combinators (#89) (@purpleclay)Add new control flow combinators to improve parser validation, error handling, and flow control:
Verify: validate parsed results against a predicateRecognize: return consumed input as outputConsumed: return both raw consumed text and parsed outputEof: match only at end of inputAllConsuming: ensure entire input is consumedRest: return all remaining unconsumed inputValue: return fixed value on parser successCond: conditionally apply parser based on booleanCut: convert recoverable errors to fatal failures (prevents backtracking)PeekNot: negative lookahead (succeed when inner parser fails)
-
1c613d3add repetition combinators and single-character matchers (#87) (@purpleclay)
Generated with release-note
v0.5.0
v0.5.0 - January 24, 2026
2 new features
Contributors
@purpleclay (
7commits)
New Features
dc31059add character parsers and convenience aliases (#80) (@purpleclay)16ee341extend existing suite of basic supporters (#78) (@purpleclay)
Dependency Updates
f520db9update go to 1.22.12 (#82) (@purpleclay)2b4deaaupdate module github.com/stretchr/testify to v1.11.1 (#67) (@renovate[bot])
Generated with release-note
v0.4.0
Changelog
New Features
- 12c9d0e: feat: add a flatten combinator, that will flatten a slice of strings into a single string (#65) (@purpleclay)
Full Changelog: v0.3.0...v0.4.0
What to do next?
v0.3.0
Changelog
New Features
- a065c1a: feat: write a utility parser that will consumer text until the end of a line (#52) (@purpleclay)
- 4aebf35: feat: support mapping the output of a combinator to any other type (#61) (@purpleclay)
- db938ef: feat: extend existing predicate combinators to support variable number of matches (#51) (@purpleclay)
- 9cfe72f: feat: add the ability to peek into the input text without chomping any of the input (#56) (@purpleclay)
Documentation Updates
- bba4768: docs: include documentation on available combinators and parsers (#63) (@purpleclay)
- c5ff172: docs: add new example to chomp for parsing a git diff (#62) (@purpleclay)
Other Work
- 6798a29: feat!: switch around the order of arguments to both prefixed and suffixed to match strings standard library (#58) (@purpleclay)
Full Changelog: v0.2.2...v0.3.0
What to do next?
v0.2.2
Changelog
Bug Fixes
- 47ee954: fix: ensure failed predicates return input text on error (@purpleclay)
Full Changelog: v0.2.1...v0.2.2
What to do next?
v0.2.1
Changelog
Bug Fixes
- 63b52a5: fix: remaining text should be returned when a combinator errors is raised (#44) (@purpleclay)
- 1effcee: fix(deps): update module github.com/stretchr/testify to v1.9.0 (#40) (@renovate[bot])
Full Changelog: v0.2.0...v0.2.1
What to do next?
v0.2.0
Changelog
New Features
- bec3e33: feat: support repeating a combinator between a configurable range of times (#31) (@purpleclay)
- e7df717: feat: add combinators to handle text that is prefixed or suffixed (#33) (@purpleclay)
- 4ac5038: feat: add a new combinator that will keep parsing input text until it no longer matches (#35) (@purpleclay)
Full Changelog: v0.1.0...v0.2.0
What to do next?
v0.1.0
Changelog
New Features
- 60f4194: feat: clear and concise error messages when parsers fail (#29) (@purpleclay)
Full Changelog: v0.1.0-beta.2...v0.1.0
What to do next?
v0.1.0-beta.2
Changelog
New Features
- 2e080ea: feat: add basic conversion combinators to enable greater chaining of combinators (#27) (@purpleclay)
Full Changelog: v0.1.0-beta.1...v0.1.0-beta.2