Skip to content

Add fast paths for class/style string arguments in BlazeAttributeBag#168

Open
SanderMuller wants to merge 1 commit intolivewire:mainfrom
SanderMuller:autoresearch/attribute-bag-fast-paths
Open

Add fast paths for class/style string arguments in BlazeAttributeBag#168
SanderMuller wants to merge 1 commit intolivewire:mainfrom
SanderMuller:autoresearch/attribute-bag-fast-paths

Conversation

@SanderMuller
Copy link
Copy Markdown
Contributor

When merge(), class(), or style() receive a simple string argument (the most common usage), skip the general-purpose loops and handle the merge directly.

The shared class-merging logic is extracted into withMergedClass() to avoid duplication between merge() and class().

This replaces both PR #157 and #161 with a single combined PR.

@SanderMuller
Copy link
Copy Markdown
Contributor Author

/benchmark class

@SanderMuller
Copy link
Copy Markdown
Contributor Author

/benchmark merge

@github-actions
Copy link
Copy Markdown
Contributor

Benchmark Result: Class

Attempt Blade Blaze Improvement
#1 240.77ms 13.68ms 94.3%
#2 234.65ms 13.61ms 94.2%
#3 236.62ms 13.60ms 94.3%
#4 228.92ms 13.25ms 94.2%
#5 237.33ms 13.55ms 94.3%
#6 231.15ms 13.47ms 94.2%
#7 234.94ms 13.41ms 94.3%
#8 230.39ms 13.66ms 94.1%
#9 231.89ms 13.48ms 94.2%
#10 235.80ms 13.38ms 94.3%
Snapshot 235.27ms 17.91ms 92.4%
Result 234.80ms (~) 13.52ms (-24.5%) 94.2% (+1.8%)

Median of 10 attempts, 5000 iterations x 10 rounds, 31.77s total

To run a specific benchmark, comment /benchmark <name> where name is one of: attributes, aware, class, default, forwarding, merge, named-slots, no-attributes, slot

@github-actions
Copy link
Copy Markdown
Contributor

Benchmark Result: Merge

Attempt Blade Blaze Improvement
#1 170.01ms 11.64ms 93.2%
#2 166.45ms 11.74ms 92.9%
#3 165.58ms 11.71ms 92.9%
#4 169.72ms 11.69ms 93.1%
#5 169.87ms 11.62ms 93.2%
#6 167.13ms 11.70ms 93%
#7 169.59ms 11.65ms 93.1%
#8 169.31ms 11.62ms 93.1%
#9 166.73ms 11.73ms 93%
#10 166.29ms 11.73ms 92.9%
Snapshot 166.13ms 13.64ms 91.8%
Result 168.22ms (~) 11.70ms (-14.2%) 93% (+1.2%)

Median of 10 attempts, 5000 iterations x 10 rounds, 23.32s total

To run a specific benchmark, comment /benchmark <name> where name is one of: attributes, aware, class, default, forwarding, merge, named-slots, no-attributes, slot

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 29, 2026

Benchmark Result: Default

Attempt Blade Blaze Improvement
#1 339.93ms 15.92ms 95.3%
#2 340.90ms 16.09ms 95.3%
#3 350.71ms 15.87ms 95.5%
#4 351.00ms 15.89ms 95.5%
#5 347.52ms 15.98ms 95.4%
#6 * 354.52ms 16.57ms 95.3%
#7 343.42ms 15.97ms 95.3%
#8 341.95ms 15.77ms 95.4%
#9 347.23ms 15.72ms 95.5%
#10 343.08ms 16.12ms 95.3%
Snapshot 345.08ms 15.91ms 95.4%
Result 343.42ms (~) 15.92ms (~) 95.4% (~)

Median of 10 attempts (* = outlier, excluded from result), 5000 iterations x 10 rounds, 45.63s total

To run a specific benchmark, comment /benchmark <name> where name is one of: attributes, aware, class, default, forwarding, merge, named-slots, no-attributes, slot

@ganyicz
Copy link
Copy Markdown
Collaborator

ganyicz commented Mar 29, 2026

Looks like this causes an attribute ordering issue in the FluxPro tests (you would need to dev-require Flux Pro with a valid license to run these):

Tests\FluxProTest > chart:

- <ui-chart wire:model="data" class="block [:where(&amp;)]:relative w-full aspect-2/1" wire:ignore.children >
+ <ui-chart class="block [:where(&amp;)]:relative w-full aspect-2/1" wire:model="data" wire:ignore.children >

Alternatively feel free to add a separate comparison test for this

When merge(), class(), or style() receive a simple string argument
(the most common usage), skip the general-purpose loops and handle
the merge directly.

The shared class-merging logic is extracted into withMergedClass()
to avoid duplication between merge() and class().

Uses array union to place the merged key first, matching the attribute
ordering of the general merge() path's array_merge($defaults, $attrs).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@SanderMuller SanderMuller force-pushed the autoresearch/attribute-bag-fast-paths branch from 22dea7d to c7e51ea Compare March 29, 2026 19:55
@SanderMuller
Copy link
Copy Markdown
Contributor Author

Looks like this causes an attribute ordering issue in the FluxPro tests (you would need to dev-require Flux Pro with a valid license to run these):

Tests\FluxProTest > chart:

- <ui-chart wire:model="data" class="block [:where(&amp;)]:relative w-full aspect-2/1" wire:ignore.children >
+ <ui-chart class="block [:where(&amp;)]:relative w-full aspect-2/1" wire:model="data" wire:ignore.children >

Alternatively feel free to add a separate comparison test for this

Thanks. I do have a Flux Pro license, but figured it would be good to have a CI test so I took the option to add a test for it (and make the code pass it)

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