Releases: sentomk/patternia
v0.7.0
Patternia v0.7.0 Release Note
Date: February 5, 2026
What's Changed
Variant Matching
Patternia now supports std::variant matching with a unified type-pattern system.
New/Updated APIs:
type::is<T>— type matchtype::as<T>— type match + bindingtype::alt<I>— index-based match (supports duplicated types)
Example:
auto r = match(v)
.when(type::is<int>() >> "int")
.when(type::as<std::string>() >> [](const std::string &s) { return s; })
.when(__ >> "other")
.end();Guards on Binding Type Patterns
Type patterns that bind can now participate in guards:
.when(type::as<std::string>()[ _ != "" ] >> [](const std::string &s) { ... })Diagnostics Improvements
- Shorter, clearer
static_assertmessages - Consistent diagnostic prefixes
- Structural
has<>members validated at match-time
Documentation Updates
- Variant matching docs expanded
- Binding/guard semantics clarified
- Navigation link fixes
Full release notes: v0.7.0.md
v0.6.3
🎆Happy NewYear!🎆
Patternia v0.6.3 Release Note
Date: January 2, 2026
What's Changed
Removed Lvalue-Qualified when() Overload
Removed: The const & qualified overload for the when() method has been removed to enforce rvalue-only usage of the match builder.
Previous Behavior (v0.6.2):
// Two overloads existed - rvalue and lvalue
template <typename CaseExpr>
constexpr auto when(CaseExpr &&expr) && { /* rvalue-qualified */ }
template <typename CaseExpr>
constexpr auto when(CaseExpr &&expr) const & { /* lvalue-qualified - REMOVED */ }New Behavior (v0.6.3):
// Only rvalue-qualified overload remains
template <typename CaseExpr>
constexpr auto when(CaseExpr &&expr) && {
static_assert(!has_pattern_fallback,
"[Patternia.match]: no cases may follow a wildcard ('__') pattern");
static_assert(ptn::core::traits::is_case_expr_v<std::decay_t<CaseExpr>>,
"Argument to .when() must be a case expression created with the '>>' operator");
static_assert(ptn::core::traits::is_handler_invocable_v<std::decay_t<CaseExpr>, subject_type>,
"Handler signature does not match the pattern's binding result");
using case_t = std::decay_t<CaseExpr>;
using new_cases = tuple_utils::tuple_append_t<cases_type, case_t>;
using builder_t = match_builder<subject_type, has_match_fallback, new_cases>;
return builder_t{
std::forward<subject_type>(subject_), std::move(new_cases)};
}Inhanced Docs
Full release notes: v0.6.3.md
v0.6.2
Patternia v0.6.2 Release Note
Date: December 23, 2025
What's Changed
Added [[nodiscard]] attribute to match_builder
The match_builder class is now marked with [[nodiscard]] to prevent incomplete or unused match expressions. This provides compile-time safety with a custom warning message that guides developers to properly terminate their match expressions.
Example:
// Generates compiler warning
match(value)
.when(lit(1) >> "one")
.when(lit(2) >> "two");
// Correct usage
auto result = match(value)
.when(lit(1) >> "one")
.when(lit(2) >> "two")
.otherwise([]() { return "other"; });Benefits:
- Compile-time detection of unused match expressions
- Clear warning messages for actionable guidance
- Prevents silent failures from incomplete pattern matches
Code Cleanup
- Removed duplicate
static_assertstatement in theotherwise()method
Migration Impact
No breaking changes - This release is fully backward compatible. The [[nodiscard]] attribute only generates compiler warnings.
For side-effect only operations, use an explicit (void) cast:
(void)match(level)
.when(lit(LOG_INFO) >> []() { log_info(); })
.otherwise([]() { log_warning(); });Performance
No runtime performance impact - [[nodiscard]] is a compile-time attribute only.
Full release notes: v0.6.2.md
v0.6.1
Patternia v0.6.1 Release Notes
Release Date: December 20, 2025
Version: 0.6.1
Overview
v0.6.1 refines Patternia’s matching API with clearer termination semantics, improved forwarding behavior in match(), and a more compact syntax for common “switch-like” matches. The release strengthens compile-time diagnostics and preserves existing matching behavior with low-friction migration paths.
Highlights
1) Clearer termination: .end() vs .otherwise() (mutually exclusive)
.end()is now the explicit terminator for exhaustive matches that include a wildcard fallback (__)..otherwise()remains the terminator for non-exhaustive matches (match-level fallback).- New compile-time validation prevents mixing these modes and improves diagnostics (e.g.,
.end()requires__,otherwise()cannot coexist with__, and no cases may follow a wildcard).
2) Improved match() perfect forwarding
match() now uses perfect forwarding to better preserve value categories and reduce unnecessary copies, improving optimization opportunities while keeping reference semantics intact.
3) New compact form: match(subject, cases(...)).end()
Introduced a concise “one expression” syntax for straightforward matching by grouping case expressions with cases(...), while remaining equivalent to the traditional .when(...).when(...).end() chain.
4) Naming alignment: case_tuple → cases
Renamed case_tuple to cases for consistency with the new cases(...) pack-based syntax. Migration is typically a direct search-and-replace.
Internal Improvements
- Builder refactor adds termination validation and tighter case-expression / handler invocability checks at compile time, improving error messages and preventing invalid match shapes early.
Migration Notes (v0.6.0 → v0.6.1)
- If you use a wildcard
__fallback case, terminate with.end()(do not add.otherwise()after it). - Rename
case_tuple→cases. - Optionally adopt the compact syntax:
match(x, cases(..., __ >> ...)).end().
v0.6.0
Patternia v0.6.0 Release Notes
Key Features:
-
Generic Lambda Support: Full support for generic lambdas in pattern matching, enabling flexible handler definitions with type deduction.
-
Multi-Value Guards: Enhanced guard system with
arg<N>placeholders to perform logical operations across multiple bound values. -
Structural Binding: Simplified field binding using
bind()with structural patterns for direct member access, including nested structures. -
Type-Safe Evaluation: Strongly-typed evaluation framework for pattern matching with compile-time type guarantees.
Technical Enhancements:
- Type Traits System: Improved detection for generic lambdas and multi-value guard expressions.
- Builder Framework: Refined pattern matching infrastructure with better type safety and error handling.
- Performance Optimizations: Maintains zero-overhead guarantees while optimizing template instantiation, tuple generation, and lambda inlining.
Example Code:
// Generic Lambda with Multi-Value Guard
match(point)
.when(bind(has<&Point::x, &Point::y>())[arg<0> + arg<1> == 0] >>
[](int x, int y) { return "on diagonal"; })
.otherwise([] { return "other"; });Bug Fixes:
- Fixed template compilation issues related to lambda detection and complex pattern instantiations.
- Resolved type system validation issues in guard predicates and structural binding.
Migration Guide:
- Generic Lambda Support: Transition from explicit types to auto-lambdas in handlers.
- Multi-Value Guards: New support for complex relationships using
arg<N>placeholders. - Structural Binding: Simplified direct binding of class members.
Compatibility:
This release is fully backward-compatible with v0.5.x, while introducing new features that do not alter existing behaviors.
v0.5.3
Patternia v0.5.3 Release Notes
Overview
Patternia v0.5.3 introduces advanced pattern matching capabilities with guard predicates, enhanced binding mechanisms, structural decomposition patterns, and range matching utilities. This release significantly expands the expressiveness of pattern matching while maintaining zero-overhead performance and type safety.
New Features
Enhanced Binding Patterns (bind() and bind(subpattern))
Enhanced: bind() function with subpattern support for conditional binding.
// Basic binding - captures the subject itself
match(value)
.when(bind() >> [](auto x) { /* use x */ })
.end();
// Binding with subpattern - first matches subpattern, then captures subject
match(number)
.when(bind(lit(42)) >> [](auto x) { /* x is 42, subject is also captured */ })
.when(bind([](auto n) { return n > 0; }) >> [](auto subject, auto n) {
return fmt::format("positive: {} (subject: {})", n, subject);
})
.otherwise("non-positive");Key Capabilities:
bind()- Captures the subject itself as a single-element tuplebind(subpattern)- First matches with subpattern, then captures both subject and subpattern bindings- Type-safe binding with compile-time validation
- Integration with all existing pattern types
Guard Predicates and Placeholder Expressions
Added: Comprehensive guard system with placeholder _ and predicate combinators.
// Placeholder-based guard expressions
match(number)
.when(bind()[_ > 10 && _ < 100] >> "two-digit")
.when(bind()[_ >= 100] >> "three-or-more-digits")
.otherwise("single-digit");
// Range predicates with different modes
match(value)
.when(bind()[rng(0, 10)] >> "small closed") // [0, 10]
.when(bind()[rng(10, 20, open)] >> "medium open") // (10, 20)
.when(bind()[rng(20, 30, open_closed)] >> "large open-closed") // (20, 30]
.when(bind()[rng(30, 40, closed_open)] >> "xlarge closed-open") // [30, 40)
.otherwise("out of range");
// Lambda guards for complex conditions
match(data)
.when(bind()[[](auto x) { return x.is_valid() && x.size() > 0; }] >> "valid")
.otherwise("invalid");Guard Features:
_placeholder for creating comparison expressions (_ > 10,_ == 42, etc.)rng()function for range predicates with four modes:closed,open,open_closed,closed_open- Predicate combinators:
&&(logical AND) and||(logical OR) - Lambda guard support for complex custom conditions
- Type-safe guard predicate evaluation
Structural Decomposition Patterns (has<>)
Added: has<&T::field...>() for aggregate and struct decomposition.
struct Point { int x, y; };
struct Circle { Point center; int radius; };
// Basic field presence checking
match(point)
.when(has<&Point::x, &Point::y> >> "valid point")
.otherwise("invalid point");
// Combining with binding for field access
match(circle)
.when(has<&Circle::center, &Circle::radius> >> bind() >> [](auto c) {
return fmt::format("circle at ({}, {}) with radius {}",
c.center.x, c.center.y, c.radius);
})
.otherwise("invalid circle");
// Multi-level structural matching
match(complex_data)
.when(has<&Data::points> >> bind()[[](auto pts) { return !pts.empty(); }]
>> [](auto data, auto pts) {
return fmt::format("data with {} points", pts.size());
})
.otherwise("empty or invalid data");Structural Pattern Features:
- Compile-time validation of member pointer parameters
- Support for multiple field pointers in single pattern
- Integration with binding patterns for field access
- Zero-overhead struct decomposition
- Type-safe member access checking
Advanced Pattern Composition
Enhanced: Seamless integration between all pattern types.
// Complex pattern combining all features
match(data)
.when(
has<&Data::value, &Data::status> >>
bind()[[](auto d) { return d.value > 0; } && [](auto d) { return d.status == Status::Active; }]
>> [](auto d, auto value, auto status) {
return fmt::format("active data: {} (status: {})", value, status);
})
.when(
has<&Data::value> >>
bind([](auto v) { return v < 0; })[_ > -100]
>> [](auto subject, auto v) {
return fmt::format("negative value: {} (subject: {})", v, subject);
})
.otherwise("no match");v0.5.2
Patternia v0.5.2 Release Notes
Release Date: December 10, 2025
Version: 0.5.2
🎯 Overview
Patternia v0.5.2 introduces the wildcard pattern __ and provides comprehensive documentation updates. This release focuses on semantic clarity, improved developer experience, and establishing a solid foundation for future exhaustiveness checking features.
✨ New Features
Wildcard Pattern (__)
Added: ptn::__ - A pattern that matches any value without binding.
// Basic wildcard usage
match(value)
.when(lit(0) >> "zero")
.when(__ >> "other") // Matches any other value
.end();Key Characteristics:
- Always matches regardless of input value
- Binds no data (returns empty tuple
std::tuple<>) - More explicit than
bind()when no capture is needed - Essential for catch-all cases and future struct destructuring
Enhanced Terminal Method Semantics
Improved: Clear distinction between .end() and .otherwise() terminal methods.
.end() - Statement-style Matching
- For void-returning matches
- Designed for exhaustiveness checking (future feature)
- Used when only side effects are needed
.otherwise(handler) - Expression-style Matching
- For value-returning matches
- Provides explicit fallback behavior
- Used when computing results from matches
Fallback Trigger Mechanism Clarification
Added: Detailed explanation of when .otherwise() is triggered:
- No Pattern Matches: When no
.when()cases match the subject - Defensive Fallback: Even with pattern coverage, provides runtime safety
Key Principle: First matching pattern wins, regardless of fallback types.
📚 Documentation Improvements
Design Overview Document
Added: docs/design-overview.md - Comprehensive guide covering:
- Three-level architecture (Pattern → Case → Match Finalizer)
- Semantic differences between
__,.end(), and.otherwise() - Usage scenarios and best practices
- Implementation details and execution flow
- Future roadmap for exhaustiveness checking
Enhanced API Reference
Updated: docs/api.md with:
- Complete wildcard pattern documentation
- Detailed comparison of terminal methods
- Implementation notes about builder execution
- Future features section with exhaustiveness checking roadmap
Improved User Guide
Updated: README.md featuring:
- Wildcard pattern examples
- Clear terminal method guidance
- Future roadmap section
- Better usage decision tables
🔧 Internal Improvements
Comment Standardization
Fixed: Consistent English comment style across all modified files:
include/ptn/pattern/wildcard.hpp- Added comprehensive file headerinclude/ptn/core/engine/detail/builder_impl.hpp- Completed member variable documentationinclude/ptn/core/common/common_traits.hpp- Enhanced type trait commentssamples/test.cpp- Added explanatory comments and examples
Builder Implementation Enhancements
Improved: Better documentation in match_builder implementation:
- Clear explanation of builder execution flow
- Documented member variable purposes
- Enhanced inline comments for complex template logic
🏗️ Architecture Changes
Three-Level Design Formalization
Patternia now explicitly follows a three-level architecture:
- Pattern Level:
lit(),bind(),__, etc. - Case Level:
.when(pattern >> handler) - Match Finalizer Level:
.end()/.otherwise()
This design ensures:
- Clear separation of concerns
- Predictable behavior matching Rust/standard proposals
- Extensible foundation for future features
Semantic Clarity Improvements
Established: Clear distinctions between:
- Pattern-level wildcards (
__) vs match-level fallbacks (.otherwise()) - Statement-style (
.end()) vs expression-style (.otherwise()) matching - Field-level ignoring vs case-level fallbacks
🚀 Usage Examples
Basic Pattern Matching
#include <ptn/patternia.hpp>
// Expression-style match
auto result = match(value)
.when(lit(1) >> "one")
.when(lit(2) >> "two")
.when(__ >> "other") // Wildcard fallback
.otherwise("default"); // Match-level fallbackStatement-style Matching
// Statement-style match with exhaustiveness (future)
match(status)
.when(lit(Status::Pending) >> [] { log("pending"); })
.when(lit(Status::Running) >> [] { log("running"); })
.when(__ >> [] { log("other"); }) // Pattern fallback
.end(); // Statement terminationEnum with Wildcard
enum class Color { Red, Green, Blue };
Color c = Color::Green;
match(c)
.when(lit(Color::Red) >> [] { std::cout << "red"; })
.when(lit(Color::Green) >> [] { std::cout << "green"; })
.when(__ >> [] { std::cout << "other"; }) // Catch-all
.end();This release continues Patternia's commitment to providing zero-overhead, expressive pattern matching for modern C++ while establishing a solid foundation for future advanced features.
v0.5.1
Patternia v0.5.1 — Architecture Stabilization
Version 0.5.1 is a major milestone release. It introduces a full redesign of the matching engine, a modernized header and namespace layout, and foundational improvements to type safety and future extensibility.
What’s New
1. New Engine-Driven Architecture
The matching system has been refactored from a DSL-embedded model into a clean and extensible engine design.
Key improvements:
- Replaced
match_builderwithengine/builderandengine/match - Introduced
engine/detail/for implementation internals - Clear separation of interface vs. engine logic
Result:
- Stronger modularity
- Better compilation performance and maintainability
- Cleaner path for future optimizations and new features
2. Unified Namespace Hierarchy
| Previous | New |
|---|---|
ptn::dsl |
ptn::core::dsl |
ptn::pattern |
ptn::pat |
Benefits:
- Clearer semantic boundaries between modules
- Reduced cross-dependency complexity
3. Updated Handler Invocation Semantics
Handlers now always receive:
-
- The subject (
const auto&)
- The subject (
-
- Followed by any bound arguments
Example:
match(value)
.when(pattern >> [](const auto& subject, auto... bound) {
/* ... */
});This ensures
-
Fully consistent invocation behavior across all patterns
-
Future-ready structure for advanced binding strategies
4. Pattern Trait System Relocated
Pattern traits, concepts and binding utilities have been moved into:
ptn/pattern/base/
This:
- Eliminates circular dependencies with
core/common - mproves compile performance and template hygiene
5. Documentation & Quality Enhancements
-
Converted internal documentation to standard C++ comment style
-
Improved type diagnostics infrastructure
-
Cleanup for future optimization phases
v0.4.6
Type Layer Release Note
Overview
This release introduces the Type Pattern Layer, a major extension to the Patternia DSL that enables compile-time, zero-overhead type-driven dispatch.
It significantly enhances Patternia’s expressiveness, enabling a unified dispatch model across values, runtime objects, and C++ static types.
The Type Layer integrates seamlessly with the existing match / when / otherwise control DSL and forms the foundation for the upcoming Variant Pattern Layer.
This release focuses on:
- expressiveness
- compile-time analyzability
- performance transparency
- full interoperability with value patterns
Key Features
1. type::is<T>
Match when the subject’s type is exactly T.
match(x)
.when(type::is<int> >> "int")
.when(type::is<float> >> "float")
.otherwise("other");2. type::in<Ts...>
Match when the subject’s type belongs to a set of types.
match(x)
.when(type::in<int, float, double> >> "numeric")
.otherwise("other");3. type::not_in<Ts...>
Negated type-set match.
match(x)
.when(type::not_in<std::string, std::vector<int>> >> "plain type")
.otherwise("container");4. type::from<Tpl>
Match any specialization of a given template.
match(v)
.when(type::from<std::vector> >> "vector")
.when(type::from<std::optional> >> "optional")
.otherwise("other");This enables a genuinely expressive, structure-aware DSL.
5. Full DSL compatibility
Type patterns interoperate with:
lit()predicate- relational operators (
&&,||,!) operator>>case binding
Example:
match(x)
.when((type::is<int> && gt(0)) >> "positive int")
.otherwise("other");6. Header-only, fully inlinable
All type patterns are implemented as lightweight structures with:
- no runtime allocations
- zero virtual dispatch
- compile-time resolvable structure
- type-based dispatch resolved by the optimizer
The generated machine code typically matches or exceeds manually written if constexpr and std::visit dispatch trees.
Example: Type-Based Router
std::variant<int, float, std::string> msg = 3.14f;
auto r = match(msg)
.when(type::is<int> >> "int")
.when(type::is<float> >> "float")
.when(type::is<std::string> >> "string")
.otherwise("unknown");This is a precursor to the upcoming native variant::is<T> patterns.
Performance Notes
- All type patterns are
constexprand trivially inlinable. - No RTTI is used unless the user explicitly relies on runtime polymorphism.
- Dispatch is resolved using a compile-time discrimination model.
- Expected branch prediction behavior matches manually optimized dispatch.
- Benchmarks (included separately) show parity with hand-tuned variant visitors.
No ABI impact, no binary bloat.
Compatibility
- C++20 or later
- Fully portable across GCC, Clang, MSVC
- API is stable and suitable for production use
- Does not require exceptions or RTTI
v0.4.3
Patternia v0.4.3 — Pattern Layer Redesign
This release introduces the first major overhaul of the Pattern Layer,
focusing on API consistency, documentation quality, and future extensibility.
Highlights
Unified Pattern Architecture (pattern_base)
All patterns (Value, Relational, Predicate) now inherit from the new CRTP base:
- Provides a consistent
.match(x)interface - Offers a default
.bind(x)implementation - Ensures predictable pattern behavior across the library
- Simplifies future pattern extensions (Type Pattern, Variant Pattern, etc.)
Refined pattern_tag Semantics
pattern_tag is no longer a base class.
It now functions purely as an identifying marker for pattern-like types,
aligning better with the Type Layer and future trait-based dispatch.
Full Refactor of Built-in Patterns
Value / Relational / Predicate patterns have been fully reworked:
- All patterns now follow the new
match()-based model - Removed legacy
operator()matching - Simplified noexcept expressions
- Improved internal structure and readability
- Better aligned with the user-facing DSL (
Pattern >> Handler)
📚 Improved Documentation (Doxygen)
Extensive Doxygen comments were added across:
pattern_base- Value / relational / predicate patterns
match_builder- DSL operator (
>>) - Public headers (
patternia.hpp)
API docs are now suitable for Sphinx + Breathe integration.
Breaking Changes
- Removed implicit
operator()matching for patterns
→ all patterns must now be invoked asp.match(x) - Some internal headers moved due to structural cleanup
- Previously undocumented behavior of some comparison expressions has been formalized
Internal Quality Improvements
- noexcept correctness fixes
- Simplified call expressions (removed misuse of
std::invoke/std::declval) - Cleaner forwarding and evaluation semantics
- Stronger guarantees for pattern composability