Nikolas Klauser
ad31e11ab6
[libc++] Make views::iota aware of __int128 ( #167869 )
...
Fixes #167991
2025-11-19 15:19:54 +01:00
William Tran-Viet
389a23c538
[libc++] Implement P2988R12: std::optional<T&> ( #155202 )
...
Resolves #148131
- Unlock `std::optional<T&>` implementation
- Allow instantiations of `optional<T(&)(...)>` and `optional<T(&)[]>`
but disables `value_or()` and `optional::iterator` + all `iterator`
related functions
- Update documentation
- Update tests
2025-11-12 11:00:08 +08:00
Nikolas Klauser
9b114c5d9a
[libc++] Optimize fstream::read ( #165223 )
...
```
Benchmark old new Difference % Difference
----------- -------- -------- ------------ --------------
bm_read 2468.45 736.27 -1732.18 -70.17%
```
2025-11-07 10:31:31 +00:00
A. Jiang
bfcd67c347
[libc++][docs] Update status for P2641R4 ( #166073 )
...
Follows-up 2527b071ba2e39fdd62eeb73b89318468595c316 which missed
updating the status in the documentations.
2025-11-03 11:59:10 +08:00
Connector Switch
0621fd0b88
[libcxx] Optimize rng::generate_n for segmented iterators ( #165280 )
...
Part of #102817 .
This patch optimizes `rng::generate_n` for segmented iterators by
forwarding the implementation directly to `std::generate_n`.
- before
```
rng::generate_n(deque<int>)/32 21.7 ns 22.0 ns 32000000
rng::generate_n(deque<int>)/50 30.8 ns 30.7 ns 22400000
rng::generate_n(deque<int>)/1024 492 ns 488 ns 1120000
rng::generate_n(deque<int>)/8192 3938 ns 3924 ns 179200
```
- after
```
rng::generate_n(deque<int>)/32 11.0 ns 11.0 ns 64000000
rng::generate_n(deque<int>)/50 16.2 ns 16.1 ns 40727273
rng::generate_n(deque<int>)/1024 292 ns 286 ns 2240000
rng::generate_n(deque<int>)/8192 2291 ns 2302 ns 298667
```
2025-10-28 22:22:26 +08:00
Connector Switch
c06ae43e26
[libcxx] Optimize std::generate_n for segmented iterators ( #164266 )
...
Part of #102817 .
This is a natural follow-up to #163006 . We are forwarding
`std::generate_n` to `std::__for_each_n` (`std::for_each_n` needs
c++17), resulting in improved performance for segmented iterators.
before:
```
std::generate_n(deque<int>)/32 17.5 ns 17.3 ns 40727273
std::generate_n(deque<int>)/50 25.7 ns 25.5 ns 26352941
std::generate_n(deque<int>)/1024 490 ns 487 ns 1445161
std::generate_n(deque<int>)/8192 3908 ns 3924 ns 179200
```
after:
```
std::generate_n(deque<int>)/32 11.1 ns 11.0 ns 64000000
std::generate_n(deque<int>)/50 16.1 ns 16.0 ns 44800000
std::generate_n(deque<int>)/1024 291 ns 292 ns 2357895
std::generate_n(deque<int>)/8192 2269 ns 2250 ns 298667
```
2025-10-21 12:01:36 +02:00
Nikolas Klauser
253e435908
Reapply "[libc++] Optimize __hash_table::erase(iterator, iterator)" ( #162850 )
...
This reapplication fixes the use after free caused by not properly
updating the bucket list in one case.
Original commit message:
Instead of just calling the single element `erase` on every element of
the range, we can combine some of the operations in a custom
implementation. Specifically, we don't need to search for the previous
node or re-link the list every iteration. Removing this unnecessary work
results in some nice performance improvements:
```
-----------------------------------------------------------------------------------------------------------------------
Benchmark old new
-----------------------------------------------------------------------------------------------------------------------
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/0 457 ns 459 ns
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/32 995 ns 626 ns
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/1024 18196 ns 7995 ns
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/8192 124722 ns 70125 ns
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/0 456 ns 461 ns
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/32 1183 ns 769 ns
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/1024 27827 ns 18614 ns
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/8192 266681 ns 226107 ns
std::unordered_map<int, int>::erase(iterator, iterator) (erase half the container)/0 455 ns 462 ns
std::unordered_map<int, int>::erase(iterator, iterator) (erase half the container)/32 996 ns 659 ns
std::unordered_map<int, int>::erase(iterator, iterator) (erase half the container)/1024 15963 ns 8108 ns
std::unordered_map<int, int>::erase(iterator, iterator) (erase half the container)/8192 136493 ns 71848 ns
std::unordered_multiset<int>::erase(iterator, iterator) (erase half the container)/0 454 ns 455 ns
std::unordered_multiset<int>::erase(iterator, iterator) (erase half the container)/32 985 ns 703 ns
std::unordered_multiset<int>::erase(iterator, iterator) (erase half the container)/1024 16277 ns 9085 ns
std::unordered_multiset<int>::erase(iterator, iterator) (erase half the container)/8192 125736 ns 82710 ns
std::unordered_multimap<int, int>::erase(iterator, iterator) (erase half the container)/0 457 ns 454 ns
std::unordered_multimap<int, int>::erase(iterator, iterator) (erase half the container)/32 1091 ns 646 ns
std::unordered_multimap<int, int>::erase(iterator, iterator) (erase half the container)/1024 17784 ns 7664 ns
std::unordered_multimap<int, int>::erase(iterator, iterator) (erase half the container)/8192 127098 ns 72806 ns
```
This reverts commit acc3a6234a91369b818fdd6482ded0ac32d8ffa6.
2025-10-21 10:20:06 +02:00
Connector Switch
46e8816928
[libcxx] Optimize std::generate for segmented iterators ( #163006 )
...
Part of #102817 .
This patch attempts to optimize the performance of `std::generate` for
segmented iterators. Below are the benchmark numbers from
`libcxx\test\benchmarks\algorithms\modifying\generate.bench.cpp`. Test
cases that use segmented iterators have also been added.
- before
```
std::generate(deque<int>)/32 194 ns 193 ns 3733333
std::generate(deque<int>)/50 276 ns 276 ns 2488889
std::generate(deque<int>)/1024 5096 ns 5022 ns 112000
std::generate(deque<int>)/8192 40806 ns 40806 ns 17231
```
- after
```
std::generate(deque<int>)/32 106 ns 105 ns 6400000
std::generate(deque<int>)/50 139 ns 138 ns 4977778
std::generate(deque<int>)/1024 2713 ns 2699 ns 248889
std::generate(deque<int>)/8192 18983 ns 19252 ns 37333
```
---------
Co-authored-by: A. Jiang <de34@live.cn>
2025-10-20 19:37:33 +08:00
A. Jiang
cecde43009
[libc++][docs] Retarget completion of P2944R3 to LLVM 22 ( #163753 )
...
The completion of P2944R3 (4a509f853fa4821ecdb0f6bc3b90ddd48794cc8c)
just missed LLVM 21 release, and it seems controversial that whether
such feature completion should be backported.
I'm aware of following-up cleanup and bugfix about `<tuple>`. Perhaps it
will become more and more unwise to backport the changes. So let's
retarget P2944R3 to LLVM 22 in documentations.
Drive-by: Also fixes the formatting of the entry of P3379R0.
2025-10-19 15:35:47 +08:00
Peng Liu
d0cee6939a
[libc++] Optimize std::{,ranges}::{fill,fill_n} for segmented iterators ( #132665 )
...
This patch optimizes `std::fill`, `std::fill_n`, `std::ranges::fill`,
and `std::ranges::fill_n` for segmented iterators, achieving substantial
performance improvements. Specifically, for `deque<int>` iterators, the
performance improvements are above 10x for all these algorithms. The
optimization also enables filling segmented memory of `deque<int>` to
approach the performance of filling contiguous memory of `vector<int>`.
Benchmark results comparing the before and after implementations are
provided below. For additional context, we’ve included `vector<int>`
results, which remain unchanged, as this patch specifically targets
segmented iterators and leaves non-segmented iterator behavior
untouched.
Fixes two subtasks outlined in #102817 .
#### `fill_n`
```
-----------------------------------------------------------------------------
Benchmark Before After Speedup
-----------------------------------------------------------------------------
std::fill_n(deque<int>)/32 11.4 ns 2.28 ns 5.0x
std::fill_n(deque<int>)/50 19.7 ns 3.40 ns 5.8x
std::fill_n(deque<int>)/1024 391 ns 37.3 ns 10.5x
std::fill_n(deque<int>)/8192 3174 ns 301 ns 10.5x
std::fill_n(deque<int>)/65536 26504 ns 2951 ns 9.0x
std::fill_n(deque<int>)/1048576 407960 ns 80658 ns 5.1x
rng::fill_n(deque<int>)/32 14.3 ns 2.15 ns 6.6x
rng::fill_n(deque<int>)/50 20.2 ns 3.22 ns 6.3x
rng::fill_n(deque<int>)/1024 381 ns 37.8 ns 10.1x
rng::fill_n(deque<int>)/8192 3101 ns 294 ns 10.5x
rng::fill_n(deque<int>)/65536 25098 ns 2926 ns 8.6x
rng::fill_n(deque<int>)/1048576 394342 ns 78874 ns 5.0x
std::fill_n(vector<int>)/32 1.76 ns 1.72 ns 1.0x
std::fill_n(vector<int>)/50 3.00 ns 2.73 ns 1.1x
std::fill_n(vector<int>)/1024 38.4 ns 37.9 ns 1.0x
std::fill_n(vector<int>)/8192 258 ns 252 ns 1.0x
std::fill_n(vector<int>)/65536 2993 ns 2889 ns 1.0x
std::fill_n(vector<int>)/1048576 80328 ns 80468 ns 1.0x
rng::fill_n(vector<int>)/32 1.99 ns 1.35 ns 1.5x
rng::fill_n(vector<int>)/50 2.66 ns 2.12 ns 1.3x
rng::fill_n(vector<int>)/1024 37.7 ns 35.8 ns 1.1x
rng::fill_n(vector<int>)/8192 253 ns 250 ns 1.0x
rng::fill_n(vector<int>)/65536 2922 ns 2930 ns 1.0x
rng::fill_n(vector<int>)/1048576 79739 ns 79742 ns 1.0x
```
#### `fill`
```
--------------------------------------------------------------------------
Benchmark Before After Speedup
--------------------------------------------------------------------------
std::fill(deque<int>)/32 13.7 ns 2.45 ns 5.6x
std::fill(deque<int>)/50 21.7 ns 4.57 ns 4.7x
std::fill(deque<int>)/1024 367 ns 38.5 ns 9.5x
std::fill(deque<int>)/8192 2896 ns 247 ns 11.7x
std::fill(deque<int>)/65536 23723 ns 2907 ns 8.2x
std::fill(deque<int>)/1048576 379043 ns 79885 ns 4.7x
rng::fill(deque<int>)/32 13.6 ns 2.70 ns 5.0x
rng::fill(deque<int>)/50 23.4 ns 3.94 ns 5.9x
rng::fill(deque<int>)/1024 377 ns 37.9 ns 9.9x
rng::fill(deque<int>)/8192 2914 ns 286 ns 10.2x
rng::fill(deque<int>)/65536 23612 ns 2939 ns 8.0x
rng::fill(deque<int>)/1048576 379841 ns 80079 ns 4.7x
std::fill(vector<int>)/32 1.99 ns 1.79 ns 1.1x
std::fill(vector<int>)/50 3.05 ns 3.06 ns 1.0x
std::fill(vector<int>)/1024 37.6 ns 38.0 ns 1.0x
std::fill(vector<int>)/8192 255 ns 257 ns 1.0x
std::fill(vector<int>)/65536 2966 ns 2981 ns 1.0x
std::fill(vector<int>)/1048576 78300 ns 80348 ns 1.0x
rng::fill(vector<int>)/32 1.77 ns 1.75 ns 1.0x
rng::fill(vector<int>)/50 4.85 ns 2.31 ns 2.1x
rng::fill(vector<int>)/1024 39.6 ns 36.1 ns 1.1x
rng::fill(vector<int>)/8192 238 ns 251 ns 0.9x
rng::fill(vector<int>)/65536 2941 ns 2918 ns 1.0x
rng::fill(vector<int>)/1048576 80497 ns 80442 ns 1.0x
```
---------
Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
Co-authored-by: A. Jiang <de34@live.cn>
2025-10-17 07:41:24 +08:00
Peng Liu
fd08af0a96
[libc++] Optimize {std,ranges}::distance for segmented iterators ( #133612 )
...
This patch enhances the performance of `std::distance` and
`std::ranges::distance` for non-random-access segmented iterators, e.g.,
`std::join_view` iterators. The original implementation operates in
linear time, `O(n)`, where `n` is the total number of elements. The
optimized version reduces this to approximately `O(n / segment_size)` by
leveraging segmented structure, where `segment_size` is the average size
of each segment.
The table below summarizes the peak performance improvements observed
across different segment sizes, with the total element count `n` ranging
up to `1 << 20` (1,048,576 elements), based on benchmark results.
```
----------------------------------------------------------------------------------------
Container/n/segment_size std::distance std::ranges::distance
----------------------------------------------------------------------------------------
join_view(vector<vector<int>>)/1048576/256 401.6x 422.9x
join_view(deque<deque<int>>)/1048576/256 112.1x 132.6x
join_view(vector<vector<int>>)/1048576/1024 1669.2x 1559.1x
join_view(deque<deque<int>>)/1048576/1024 487.7x 497.4x
```
## Benchmarks
#### Segment size = 1024
```
-----------------------------------------------------------------------------------------
Benchmark Before After Speedup
-----------------------------------------------------------------------------------------
std::distance(join_view(vector<vector<int>>))/50 38.8 ns 1.01 ns 38.4x
std::distance(join_view(vector<vector<int>>))/1024 660 ns 1.02 ns 647.1x
std::distance(join_view(vector<vector<int>>))/4096 2934 ns 1.98 ns 1481.8x
std::distance(join_view(vector<vector<int>>))/8192 5751 ns 3.92 ns 1466.8x
std::distance(join_view(vector<vector<int>>))/16384 11520 ns 7.06 ns 1631.7x
std::distance(join_view(vector<vector<int>>))/65536 46367 ns 32.2 ns 1440.6x
std::distance(join_view(vector<vector<int>>))/262144 182611 ns 114 ns 1601.9x
std::distance(join_view(vector<vector<int>>))/1048576 737785 ns 442 ns 1669.2x
std::distance(join_view(deque<deque<int>>))/50 53.1 ns 6.13 ns 8.7x
std::distance(join_view(deque<deque<int>>))/1024 854 ns 7.53 ns 113.4x
std::distance(join_view(deque<deque<int>>))/4096 3507 ns 14.7 ns 238.6x
std::distance(join_view(deque<deque<int>>))/8192 7114 ns 17.6 ns 404.2x
std::distance(join_view(deque<deque<int>>))/16384 13997 ns 30.7 ns 455.9x
std::distance(join_view(deque<deque<int>>))/65536 55598 ns 114 ns 487.7x
std::distance(join_view(deque<deque<int>>))/262144 214293 ns 480 ns 446.4x
std::distance(join_view(deque<deque<int>>))/1048576 833000 ns 2183 ns 381.6x
rng::distance(join_view(vector<vector<int>>))/50 39.1 ns 1.10 ns 35.5x
rng::distance(join_view(vector<vector<int>>))/1024 689 ns 1.14 ns 604.4x
rng::distance(join_view(vector<vector<int>>))/4096 2753 ns 2.15 ns 1280.5x
rng::distance(join_view(vector<vector<int>>))/8192 5530 ns 4.61 ns 1199.6x
rng::distance(join_view(vector<vector<int>>))/16384 10968 ns 7.97 ns 1376.2x
rng::distance(join_view(vector<vector<int>>))/65536 46009 ns 35.3 ns 1303.4x
rng::distance(join_view(vector<vector<int>>))/262144 190569 ns 124 ns 1536.9x
rng::distance(join_view(vector<vector<int>>))/1048576 746724 ns 479 ns 1559.1x
rng::distance(join_view(deque<deque<int>>))/50 51.6 ns 6.57 ns 7.9x
rng::distance(join_view(deque<deque<int>>))/1024 826 ns 6.50 ns 127.1x
rng::distance(join_view(deque<deque<int>>))/4096 3323 ns 12.5 ns 265.8x
rng::distance(join_view(deque<deque<int>>))/8192 6619 ns 19.1 ns 346.5x
rng::distance(join_view(deque<deque<int>>))/16384 13495 ns 33.2 ns 406.5x
rng::distance(join_view(deque<deque<int>>))/65536 53668 ns 114 ns 470.8x
rng::distance(join_view(deque<deque<int>>))/262144 236277 ns 475 ns 497.4x
rng::distance(join_view(deque<deque<int>>))/1048576 914177 ns 2157 ns 423.8x
-----------------------------------------------------------------------------------------
```
#### Segment size = 256
```
-----------------------------------------------------------------------------------------
Benchmark Before After Speedup
-----------------------------------------------------------------------------------------
std::distance(join_view(vector<vector<int>>))/50 38.1 ns 1.02 ns 37.4x
std::distance(join_view(vector<vector<int>>))/1024 689 ns 2.06 ns 334.5x
std::distance(join_view(vector<vector<int>>))/4096 2815 ns 7.01 ns 401.6x
std::distance(join_view(vector<vector<int>>))/8192 5507 ns 14.3 ns 385.1x
std::distance(join_view(vector<vector<int>>))/16384 11050 ns 33.7 ns 327.9x
std::distance(join_view(vector<vector<int>>))/65536 44197 ns 118 ns 374.6x
std::distance(join_view(vector<vector<int>>))/262144 175793 ns 449 ns 391.5x
std::distance(join_view(vector<vector<int>>))/1048576 703242 ns 2140 ns 328.7x
std::distance(join_view(deque<deque<int>>))/50 50.2 ns 6.12 ns 8.2x
std::distance(join_view(deque<deque<int>>))/1024 835 ns 11.4 ns 73.2x
std::distance(join_view(deque<deque<int>>))/4096 3353 ns 32.9 ns 101.9x
std::distance(join_view(deque<deque<int>>))/8192 6711 ns 64.2 ns 104.5x
std::distance(join_view(deque<deque<int>>))/16384 13231 ns 118 ns 112.1x
std::distance(join_view(deque<deque<int>>))/65536 53523 ns 556 ns 96.3x
std::distance(join_view(deque<deque<int>>))/262144 219101 ns 2166 ns 101.2x
std::distance(join_view(deque<deque<int>>))/1048576 880277 ns 15852 ns 55.5x
rng::distance(join_view(vector<vector<int>>))/50 37.7 ns 1.13 ns 33.4x
rng::distance(join_view(vector<vector<int>>))/1024 697 ns 2.14 ns 325.7x
rng::distance(join_view(vector<vector<int>>))/4096 2804 ns 7.52 ns 373.0x
rng::distance(join_view(vector<vector<int>>))/8192 5749 ns 15.2 ns 378.2x
rng::distance(join_view(vector<vector<int>>))/16384 11742 ns 34.8 ns 337.4x
rng::distance(join_view(vector<vector<int>>))/65536 47274 ns 116 ns 407.7x
rng::distance(join_view(vector<vector<int>>))/262144 187774 ns 444 ns 422.9x
rng::distance(join_view(vector<vector<int>>))/1048576 749724 ns 2109 ns 355.5x
rng::distance(join_view(deque<deque<int>>))/50 53.0 ns 6.09 ns 8.7x
rng::distance(join_view(deque<deque<int>>))/1024 895 ns 11.0 ns 81.4x
rng::distance(join_view(deque<deque<int>>))/4096 3825 ns 30.6 ns 125.0x
rng::distance(join_view(deque<deque<int>>))/8192 7550 ns 60.5 ns 124.8x
rng::distance(join_view(deque<deque<int>>))/16384 14847 ns 112 ns 132.6x
rng::distance(join_view(deque<deque<int>>))/65536 56888 ns 453 ns 125.6x
rng::distance(join_view(deque<deque<int>>))/262144 231395 ns 2034 ns 113.8x
rng::distance(join_view(deque<deque<int>>))/1048576 933093 ns 15012 ns 62.2x
-----------------------------------------------------------------------------------------
```
Addresses a subtask of #102817 .
---------
Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
Co-authored-by: A. Jiang <de34@live.cn>
2025-10-16 07:44:35 +08:00
Hristo Hristov
8a27b48122
[libc++][atomic] P2835R7: Expose std::atomic_ref's object address ( #162236 )
...
Implements https://wg21.link/P2835R7
Closes #118377
# References
- https://wg21.link/atomics.ref.generic.general
- https://wg21.link/atomics.ref.int
- https://wg21.link/atomics.ref.float
- https://wg21.link/atomics.ref.pointer
---------
Co-authored-by: Hristo Hristov <zingam@outlook.com>
2025-10-13 20:27:02 +08:00
Hristo Hristov
45c41247f8
[libc++][ranges] P3060R3: Add std::views::indices(n) ( #146823 )
...
Implements [P3060R3](https://wg21.link/P3060R3 )
Closes #148175
# References
- https://github.com/cplusplus/draft/issues/7966
- https://github.com/cplusplus/draft/pull/8006
- https://wg21.link/customization.point.object
- https://wg21.link/range.iota.overview
- https://wg21.link/ranges.syn
---------
Co-authored-by: Hristo Hristov <zingam@outlook.com>
Co-authored-by: A. Jiang <de34@live.cn>
2025-10-06 18:13:25 +03:00
Hristo Hristov
ccd06e4809
[libc++][istream] P3223R2: Making std::istream::ignore less surprising ( #147007 )
...
Implements https://wg21.link/P3223R2 as a DR as, as recommended in
https://github.com/cplusplus/papers/issues/1871#issuecomment-2993018698 .
Resolves -1L ambiguity.
Closes #148178
2025-09-30 11:26:30 -04:00
Nikolas Klauser
97367d1046
[libc++] Vectorize std::find ( #156431 )
...
```
Apple M4:
-----------------------------------------------------------------------------
Benchmark old new
-----------------------------------------------------------------------------
std::find(vector<char>) (bail 25%)/8 1.43 ns 1.44 ns
std::find(vector<char>) (bail 25%)/1024 5.54 ns 5.59 ns
std::find(vector<char>) (bail 25%)/8192 38.4 ns 39.1 ns
std::find(vector<char>) (bail 25%)/32768 134 ns 136 ns
std::find(vector<int>) (bail 25%)/8 1.56 ns 1.57 ns
std::find(vector<int>) (bail 25%)/1024 65.3 ns 65.4 ns
std::find(vector<int>) (bail 25%)/8192 465 ns 464 ns
std::find(vector<int>) (bail 25%)/32768 1832 ns 1832 ns
std::find(vector<long long>) (bail 25%)/8 0.920 ns 1.20 ns
std::find(vector<long long>) (bail 25%)/1024 65.2 ns 31.2 ns
std::find(vector<long long>) (bail 25%)/8192 464 ns 255 ns
std::find(vector<long long>) (bail 25%)/32768 1833 ns 992 ns
std::find(vector<char>) (process all)/8 1.21 ns 1.22 ns
std::find(vector<char>) (process all)/50 1.92 ns 1.93 ns
std::find(vector<char>) (process all)/1024 16.6 ns 16.9 ns
std::find(vector<char>) (process all)/8192 134 ns 136 ns
std::find(vector<char>) (process all)/32768 488 ns 503 ns
std::find(vector<int>) (process all)/8 2.45 ns 2.48 ns
std::find(vector<int>) (process all)/50 12.7 ns 12.7 ns
std::find(vector<int>) (process all)/1024 236 ns 236 ns
std::find(vector<int>) (process all)/8192 1830 ns 1834 ns
std::find(vector<int>) (process all)/32768 7351 ns 7346 ns
std::find(vector<long long>) (process all)/8 2.02 ns 1.45 ns
std::find(vector<long long>) (process all)/50 12.0 ns 6.12 ns
std::find(vector<long long>) (process all)/1024 235 ns 123 ns
std::find(vector<long long>) (process all)/8192 1830 ns 983 ns
std::find(vector<long long>) (process all)/32768 7306 ns 3969 ns
std::find(vector<bool>) (process all)/8 1.14 ns 1.15 ns
std::find(vector<bool>) (process all)/50 1.16 ns 1.17 ns
std::find(vector<bool>) (process all)/1024 4.51 ns 4.53 ns
std::find(vector<bool>) (process all)/8192 33.6 ns 33.5 ns
std::find(vector<bool>) (process all)/1048576 3660 ns 3660 ns
```
2025-09-29 11:10:19 +02:00
Hristo Hristov
804b46bb45
[libc++][string] P3044R2: sub-string_view from string ( #147095 )
...
Implements [P3044R2](https://wg21.link/P3044R2 )
Note: `substr.pass.cpp` is refactored to accommodate the test of
`basic_string_view`'s `subview` which is an alias of `substr` without
changing the test cases.
Closes #148140
# References
- https://github.com/cplusplus/draft/pull/7975
- https://wg21.link/string.substr
- https://wg21.link/string.view.ops
---------
Co-authored-by: Hristo Hristov <zingam@outlook.com>
Co-authored-by: Nikolas Klauser <nikolasklauser@berlin.de>
2025-09-25 03:08:15 +03:00
Nikolas Klauser
868aa5f19c
[libc++] Introduce _LIBCPP_COMPRESSED_ELEMENT ( #134253 )
...
We have multiple classes with an empty base optimization that contains
just a single type. This patch introduces `_LIBCPP_COMPRESSED_ELEMENT`
to refactor these classes to avoid having them essentially twice,
reducing the amount of code significantly.
2025-09-18 14:31:18 +02:00
Aiden Grossman
acc3a6234a
Revert "[libc++] Optimize __hash_table::erase(iterator, iterator) (#1… ( #158769 )
...
…52471)"
This reverts commit e4eccd6a3c2415c10bb8217c247d7aca76cc9ad5.
This was causing ASan failures in some situations involving unordered
multimap containers. Details and a reproducer were posted on the
original PR (#152471 ).
2025-09-17 07:52:49 -07:00
Nikolas Klauser
34d4f0c136
[libc++][NFC] Use llvm.org/PR to link to bug reports ( #156288 )
...
We've built up quite a few links directly to github within the code
base. We should instead use `llvm.org/PR<issue-number>` to link to bugs,
since that is resilient to the bug tracker changing in the future. This
is especially relevant for tests linking to bugs, since they will
probably be there for decades to come. A nice side effect is that these
links are significantly shorter than the GH links, making them much less
of an eyesore.
This patch also replaces a few links that linked to the old bugzilla
instance on llvm.org.
2025-09-04 09:20:02 +02:00
Nikolas Klauser
e8fa13ca4e
[libc++] Split ABI flag for removing iterator bases and removing the second member in reverse_iterator ( #143079 )
...
Currently `_LIBCPP_NO_ITERATOR_BASES` controls both whether specific
classes derive from `iterator` and whether `reverse_iterator` has a
second member variable. These two changes are orthogonal though, and one
can be applied in all langauge modes while the other change is only
conforming for C++17 and later.
2025-09-04 09:18:49 +02:00
Nikolas Klauser
7624c61419
[libc++] Optimize {map,set}::insert(InputIterator, InputIterator) ( #154703 )
...
```
----------------------------------------------------------------------------------------------------------------------------
Benchmark old new
----------------------------------------------------------------------------------------------------------------------------
std::map<int, int>::ctor(iterator, iterator) (unsorted sequence)/0 14.2 ns 14.8 ns
std::map<int, int>::ctor(iterator, iterator) (unsorted sequence)/32 519 ns 404 ns
std::map<int, int>::ctor(iterator, iterator) (unsorted sequence)/1024 52460 ns 36242 ns
std::map<int, int>::ctor(iterator, iterator) (unsorted sequence)/8192 724222 ns 706496 ns
std::map<int, int>::ctor(iterator, iterator) (sorted sequence)/0 14.2 ns 14.7 ns
std::map<int, int>::ctor(iterator, iterator) (sorted sequence)/32 429 ns 349 ns
std::map<int, int>::ctor(iterator, iterator) (sorted sequence)/1024 23601 ns 14734 ns
std::map<int, int>::ctor(iterator, iterator) (sorted sequence)/8192 267753 ns 112155 ns
std::map<int, int>::insert(iterator, iterator) (all new keys)/0 434 ns 448 ns
std::map<int, int>::insert(iterator, iterator) (all new keys)/32 950 ns 963 ns
std::map<int, int>::insert(iterator, iterator) (all new keys)/1024 27205 ns 25344 ns
std::map<int, int>::insert(iterator, iterator) (all new keys)/8192 294248 ns 280713 ns
std::map<int, int>::insert(iterator, iterator) (half new keys)/0 435 ns 449 ns
std::map<int, int>::insert(iterator, iterator) (half new keys)/32 771 ns 706 ns
std::map<int, int>::insert(iterator, iterator) (half new keys)/1024 30841 ns 17495 ns
std::map<int, int>::insert(iterator, iterator) (half new keys)/8192 468807 ns 285847 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from same type)/0 449 ns 453 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from same type)/32 1021 ns 932 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from same type)/1024 29796 ns 19518 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from same type)/8192 345688 ns 153966 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from zip_view)/0 449 ns 450 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from zip_view)/32 1026 ns 807 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from zip_view)/1024 31632 ns 15573 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from zip_view)/8192 303024 ns 128946 ns
std::map<int, int>::erase(iterator, iterator) (erase half the container)/0 447 ns 452 ns
std::map<int, int>::erase(iterator, iterator) (erase half the container)/32 687 ns 710 ns
std::map<int, int>::erase(iterator, iterator) (erase half the container)/1024 8604 ns 8581 ns
std::map<int, int>::erase(iterator, iterator) (erase half the container)/8192 65693 ns 67406 ns
std::map<std::string, int>::ctor(iterator, iterator) (unsorted sequence)/0 15.0 ns 15.0 ns
std::map<std::string, int>::ctor(iterator, iterator) (unsorted sequence)/32 2781 ns 1845 ns
std::map<std::string, int>::ctor(iterator, iterator) (unsorted sequence)/1024 187999 ns 182103 ns
std::map<std::string, int>::ctor(iterator, iterator) (unsorted sequence)/8192 2937242 ns 2934912 ns
std::map<std::string, int>::ctor(iterator, iterator) (sorted sequence)/0 15.0 ns 15.2 ns
std::map<std::string, int>::ctor(iterator, iterator) (sorted sequence)/32 1326 ns 2462 ns
std::map<std::string, int>::ctor(iterator, iterator) (sorted sequence)/1024 81778 ns 72193 ns
std::map<std::string, int>::ctor(iterator, iterator) (sorted sequence)/8192 1177292 ns 669152 ns
std::map<std::string, int>::insert(iterator, iterator) (all new keys)/0 439 ns 454 ns
std::map<std::string, int>::insert(iterator, iterator) (all new keys)/32 2483 ns 2465 ns
std::map<std::string, int>::insert(iterator, iterator) (all new keys)/1024 187614 ns 188072 ns
std::map<std::string, int>::insert(iterator, iterator) (all new keys)/8192 1654675 ns 1706603 ns
std::map<std::string, int>::insert(iterator, iterator) (half new keys)/0 437 ns 452 ns
std::map<std::string, int>::insert(iterator, iterator) (half new keys)/32 1836 ns 1820 ns
std::map<std::string, int>::insert(iterator, iterator) (half new keys)/1024 114885 ns 121865 ns
std::map<std::string, int>::insert(iterator, iterator) (half new keys)/8192 1151960 ns 1197318 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from same type)/0 438 ns 455 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from same type)/32 1599 ns 1614 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from same type)/1024 95935 ns 82159 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from same type)/8192 776480 ns 941043 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from zip_view)/0 435 ns 462 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from zip_view)/32 1723 ns 1550 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from zip_view)/1024 107096 ns 92850 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from zip_view)/8192 893976 ns 775046 ns
std::map<std::string, int>::erase(iterator, iterator) (erase half the container)/0 436 ns 453 ns
std::map<std::string, int>::erase(iterator, iterator) (erase half the container)/32 775 ns 824 ns
std::map<std::string, int>::erase(iterator, iterator) (erase half the container)/1024 20241 ns 20454 ns
std::map<std::string, int>::erase(iterator, iterator) (erase half the container)/8192 139038 ns 138032 ns
std::set<int>::ctor(iterator, iterator) (unsorted sequence)/0 14.8 ns 14.7 ns
std::set<int>::ctor(iterator, iterator) (unsorted sequence)/32 468 ns 426 ns
std::set<int>::ctor(iterator, iterator) (unsorted sequence)/1024 54289 ns 39028 ns
std::set<int>::ctor(iterator, iterator) (unsorted sequence)/8192 738438 ns 695720 ns
std::set<int>::ctor(iterator, iterator) (sorted sequence)/0 14.7 ns 14.6 ns
std::set<int>::ctor(iterator, iterator) (sorted sequence)/32 478 ns 391 ns
std::set<int>::ctor(iterator, iterator) (sorted sequence)/1024 24017 ns 13905 ns
std::set<int>::ctor(iterator, iterator) (sorted sequence)/8192 267862 ns 111378 ns
std::set<int>::insert(iterator, iterator) (all new keys)/0 458 ns 450 ns
std::set<int>::insert(iterator, iterator) (all new keys)/32 1066 ns 956 ns
std::set<int>::insert(iterator, iterator) (all new keys)/1024 29190 ns 25212 ns
std::set<int>::insert(iterator, iterator) (all new keys)/8192 320441 ns 279602 ns
std::set<int>::insert(iterator, iterator) (half new keys)/0 454 ns 453 ns
std::set<int>::insert(iterator, iterator) (half new keys)/32 816 ns 709 ns
std::set<int>::insert(iterator, iterator) (half new keys)/1024 32072 ns 17074 ns
std::set<int>::insert(iterator, iterator) (half new keys)/8192 403386 ns 286202 ns
std::set<int>::erase(iterator, iterator) (erase half the container)/0 451 ns 452 ns
std::set<int>::erase(iterator, iterator) (erase half the container)/32 710 ns 703 ns
std::set<int>::erase(iterator, iterator) (erase half the container)/1024 8261 ns 8499 ns
std::set<int>::erase(iterator, iterator) (erase half the container)/8192 64466 ns 67343 ns
std::set<std::string>::ctor(iterator, iterator) (unsorted sequence)/0 15.2 ns 15.0 ns
std::set<std::string>::ctor(iterator, iterator) (unsorted sequence)/32 3069 ns 3005 ns
std::set<std::string>::ctor(iterator, iterator) (unsorted sequence)/1024 189552 ns 180933 ns
std::set<std::string>::ctor(iterator, iterator) (unsorted sequence)/8192 2887579 ns 2691678 ns
std::set<std::string>::ctor(iterator, iterator) (sorted sequence)/0 15.1 ns 14.9 ns
std::set<std::string>::ctor(iterator, iterator) (sorted sequence)/32 2611 ns 2514 ns
std::set<std::string>::ctor(iterator, iterator) (sorted sequence)/1024 91581 ns 78727 ns
std::set<std::string>::ctor(iterator, iterator) (sorted sequence)/8192 1192640 ns 1158959 ns
std::set<std::string>::insert(iterator, iterator) (all new keys)/0 452 ns 457 ns
std::set<std::string>::insert(iterator, iterator) (all new keys)/32 2530 ns 2544 ns
std::set<std::string>::insert(iterator, iterator) (all new keys)/1024 195352 ns 179614 ns
std::set<std::string>::insert(iterator, iterator) (all new keys)/8192 1737890 ns 1749615 ns
std::set<std::string>::insert(iterator, iterator) (half new keys)/0 451 ns 454 ns
std::set<std::string>::insert(iterator, iterator) (half new keys)/32 1949 ns 1766 ns
std::set<std::string>::insert(iterator, iterator) (half new keys)/1024 128853 ns 109467 ns
std::set<std::string>::insert(iterator, iterator) (half new keys)/8192 1233077 ns 1177289 ns
std::set<std::string>::erase(iterator, iterator) (erase half the container)/0 450 ns 451 ns
std::set<std::string>::erase(iterator, iterator) (erase half the container)/32 809 ns 812 ns
std::set<std::string>::erase(iterator, iterator) (erase half the container)/1024 21736 ns 21922 ns
std::set<std::string>::erase(iterator, iterator) (erase half the container)/8192 135884 ns 133228 ns
```
Fixes #154650
2025-09-03 08:15:29 +02:00
Nikolas Klauser
4c5877dbc2
[libc++] Optimize map::insert_or_assign ( #155816 )
...
`__emplace_unique` uses `__find_equal`, which can be significantly
faster than `lower_bound`. As a nice side-effect, this also changes the
implementation to the "naive" implementation of trying `insert` first,
and if that fails assign instead. This also matches the
`insert_or_assign` overloads with a hint.
```
Zen 2:
--------------------------------------------------------------------------------------------------------
Benchmark old new
--------------------------------------------------------------------------------------------------------
std::map<int, int>::insert_or_assign(key, value) (already present)/0 1.62 ns 1.53 ns
std::map<int, int>::insert_or_assign(key, value) (already present)/32 5.78 ns 5.99 ns
std::map<int, int>::insert_or_assign(key, value) (already present)/1024 21.5 ns 15.4 ns
std::map<int, int>::insert_or_assign(key, value) (already present)/8192 26.2 ns 20.5 ns
std::map<int, int>::insert_or_assign(key, value) (new value)/0 22.5 ns 21.1 ns
std::map<int, int>::insert_or_assign(key, value) (new value)/32 42.9 ns 28.4 ns
std::map<int, int>::insert_or_assign(key, value) (new value)/1024 118 ns 92.0 ns
std::map<int, int>::insert_or_assign(key, value) (new value)/8192 227 ns 173 ns
std::map<std::string, int>::insert_or_assign(key, value) (already present)/0 13.2 ns 18.9 ns
std::map<std::string, int>::insert_or_assign(key, value) (already present)/32 65.6 ns 39.0 ns
std::map<std::string, int>::insert_or_assign(key, value) (already present)/1024 127 ns 64.4 ns
std::map<std::string, int>::insert_or_assign(key, value) (already present)/8192 134 ns 71.4 ns
std::map<std::string, int>::insert_or_assign(key, value) (new value)/0 45.6 ns 37.3 ns
std::map<std::string, int>::insert_or_assign(key, value) (new value)/32 142 ns 93.3 ns
std::map<std::string, int>::insert_or_assign(key, value) (new value)/1024 288 ns 147 ns
std::map<std::string, int>::insert_or_assign(key, value) (new value)/8192 368 ns 182 ns
Apple M4:
--------------------------------------------------------------------------------------------------------
Benchmark old new
--------------------------------------------------------------------------------------------------------
std::map<int, int>::insert_or_assign(key, value) (already present)/0 0.784 ns 0.740 ns
std::map<int, int>::insert_or_assign(key, value) (already present)/32 2.52 ns 1.77 ns
std::map<int, int>::insert_or_assign(key, value) (already present)/1024 8.72 ns 4.06 ns
std::map<int, int>::insert_or_assign(key, value) (already present)/8192 10.6 ns 3.98 ns
std::map<int, int>::insert_or_assign(key, value) (new value)/0 17.3 ns 17.2 ns
std::map<int, int>::insert_or_assign(key, value) (new value)/32 22.5 ns 19.3 ns
std::map<int, int>::insert_or_assign(key, value) (new value)/1024 56.8 ns 33.5 ns
std::map<int, int>::insert_or_assign(key, value) (new value)/8192 88.2 ns 41.0 ns
std::map<std::string, int>::insert_or_assign(key, value) (already present)/0 16.6 ns 11.8 ns
std::map<std::string, int>::insert_or_assign(key, value) (already present)/32 13.7 ns 30.7 ns
std::map<std::string, int>::insert_or_assign(key, value) (already present)/1024 46.7 ns 49.1 ns
std::map<std::string, int>::insert_or_assign(key, value) (already present)/8192 41.9 ns 76.9 ns
std::map<std::string, int>::insert_or_assign(key, value) (new value)/0 40.0 ns 40.5 ns
std::map<std::string, int>::insert_or_assign(key, value) (new value)/32 38.9 ns 40.0 ns
std::map<std::string, int>::insert_or_assign(key, value) (new value)/1024 84.9 ns 96.9 ns
std::map<std::string, int>::insert_or_assign(key, value) (new value)/8192 166 ns 149 ns
```
2025-08-29 18:48:11 +02:00
Nikolas Klauser
c5949f74bf
[libc++] Optimize ofstream::write ( #123337 )
...
```
----------------------------
Benchmark old new
----------------------------
bm_write 1382 ns 521 ns
```
2025-08-27 14:50:37 +02:00
Nikolas Klauser
83583b211e
[libc++][NFC] Wrap lines in ReleaseNotes/22.rst ( #155359 )
...
Some of the lines in `ReleaseNotes/22.rst` are (significantly) longer
than our usual 120 column limit. This wraps all lines in the file so
they are never more than our usual limit.
2025-08-26 09:10:41 +02:00
Nikolas Klauser
62da805f48
[libc++] Add a release note about multi{map,set}::find not returning the first element anymore ( #155252 )
...
We've modified the algorithm of `__tree::find` in #152370 , which can
change the return value. Since we're always returned the lower bound
before some users started relying on it. This patch adds a release note
so users are aware that this might break their code.
2025-08-26 08:00:13 +02:00
Nikolas Klauser
e4eccd6a3c
[libc++] Optimize __hash_table::erase(iterator, iterator) ( #152471 )
...
Instead of just calling the single element `erase` on every element of
the range, we can combine some of the operations in a custom
implementation. Specifically, we don't need to search for the previous
node or re-link the list every iteration. Removing this unnecessary work
results in some nice performance improvements:
```
-----------------------------------------------------------------------------------------------------------------------
Benchmark old new
-----------------------------------------------------------------------------------------------------------------------
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/0 457 ns 459 ns
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/32 995 ns 626 ns
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/1024 18196 ns 7995 ns
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/8192 124722 ns 70125 ns
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/0 456 ns 461 ns
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/32 1183 ns 769 ns
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/1024 27827 ns 18614 ns
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/8192 266681 ns 226107 ns
std::unordered_map<int, int>::erase(iterator, iterator) (erase half the container)/0 455 ns 462 ns
std::unordered_map<int, int>::erase(iterator, iterator) (erase half the container)/32 996 ns 659 ns
std::unordered_map<int, int>::erase(iterator, iterator) (erase half the container)/1024 15963 ns 8108 ns
std::unordered_map<int, int>::erase(iterator, iterator) (erase half the container)/8192 136493 ns 71848 ns
std::unordered_multiset<int>::erase(iterator, iterator) (erase half the container)/0 454 ns 455 ns
std::unordered_multiset<int>::erase(iterator, iterator) (erase half the container)/32 985 ns 703 ns
std::unordered_multiset<int>::erase(iterator, iterator) (erase half the container)/1024 16277 ns 9085 ns
std::unordered_multiset<int>::erase(iterator, iterator) (erase half the container)/8192 125736 ns 82710 ns
std::unordered_multimap<int, int>::erase(iterator, iterator) (erase half the container)/0 457 ns 454 ns
std::unordered_multimap<int, int>::erase(iterator, iterator) (erase half the container)/32 1091 ns 646 ns
std::unordered_multimap<int, int>::erase(iterator, iterator) (erase half the container)/1024 17784 ns 7664 ns
std::unordered_multimap<int, int>::erase(iterator, iterator) (erase half the container)/8192 127098 ns 72806 ns
```
2025-08-25 21:45:20 +02:00
Nikolas Klauser
f5e687d7bf
[libc++] Fix ABI break introduced by switching to _LIBCPP_COMPRESSED_PAIR ( #154686 )
...
LLVM 20 contained an ABI break that can result in the size of
`std::unordered_{map,set,multimap,multiset}` and `std::deque` changing
when used with an allocator type that is empty and contains a base class
that is the same across rebound allocator instantiations (e.g.
``Allocator<int>`` and ``Allocator<char>`` are both empty and contain
the same base class).
In addition, the layout of a user-defined type that:
- contains one of the following containers:
`std::unordered_{map,set,multimap,multiset}`, `std::deque`, `std::map`,
`std::set`, `std::multimap`, `std::multiset`, `std::list` or
`std::vector`, and
- passes an empty allocator, comparator or hasher type to that
container, and
- has a member of that same empty allocator, comparator or hasher type
inside the enclosing struct, and
- that member is either marked with `[[no_unique_address]]` or optimized
out via the EBO (empty base optimization) technique
saw its size increase from LLVM 19 to LLVM 20. This was caused by the
usage of `[[no_unique_address]]` within some of libc++'s containers in a
way that allowed subtle interactions with enclosing objects. This is
fixed in LLVM 21 on Clang (returning to the LLVM 19 ABI), however that
implies an ABI break from LLVM 20 to LLVM 21.
Furthermore, fixing this causes a slight regression to constant
evaluation support in `std::unique_ptr`. Specifically, constant
evaluation will now fail when the deleter relies on being
value-initialized for constant-evaluation admissibility. If a
default-initialized deleter can be used during constant evaluation, or
if the default constructor is non-trivial, the `unique_ptr` is not
affected by this regression. In particular, this regression does not
impact any `unique_ptr` using the default deleter.
Note that there is currently no way to realistically fix this ABI break
on GCC, therefore GCC will remain on the ABI introduced in LLVM 19. That
also means that Clang and GCC will have a slightly different ABI for the
small subset of types listed above until we are able to apply the same
fix we did with Clang on GCC.
We fix this regression by surrounding the members of the
`_LIBCPP_COMPRESSED_PAIR` with an anonymous struct. This restricts the
shifting of empty types to the front of the `_LIBCPP_COMPRESSED_PAIR`
instead of throughout the surrounding object. This "frees up" the zero
offset to contain another object of the same type, restoring the ability
to perform EBO or to elide the storage for a type with
`[[no_unique_address]]` in the enclosing (user-defined) struct.
Fixes #154146
Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
2025-08-23 07:58:37 +02:00
Nikolas Klauser
1c7f1407d4
[libc++] Optimize multi{map,set}::insert(InputIterator, InputIterator) ( #152691 )
2025-08-22 13:52:36 -04:00
Timothy Choi
d282452e4c
[libc++] Avoid string reallocation in std::filesystem::path::lexically_relative ( #152964 )
...
Improves runtime by around 20 to 40%. (1.3x to 1.7x)
```
Benchmark Time CPU Time Old Time New CPU Old CPU New
------------------------------------------------------------------------------------------------------------------------------------------------
BM_LexicallyRelative/small_path/2 -0.2111 -0.2082 229 181 228 180
BM_LexicallyRelative/small_path/4 -0.2579 -0.2550 455 338 452 337
BM_LexicallyRelative/small_path/8 -0.2643 -0.2616 844 621 838 619
BM_LexicallyRelative/small_path/16 -0.2582 -0.2556 1562 1158 1551 1155
BM_LexicallyRelative/small_path/32 -0.2518 -0.2496 3023 2262 3004 2254
BM_LexicallyRelative/small_path/64 -0.2806 -0.2775 6344 4564 6295 4549
BM_LexicallyRelative/small_path/128 -0.2165 -0.2137 11762 9216 11683 9186
BM_LexicallyRelative/small_path/256 -0.2672 -0.2645 24499 17953 24324 17891
BM_LexicallyRelative/large_path/2 -0.3268 -0.3236 426 287 422 285
BM_LexicallyRelative/large_path/4 -0.3274 -0.3248 734 494 729 492
BM_LexicallyRelative/large_path/8 -0.3586 -0.3560 1409 904 1399 901
BM_LexicallyRelative/large_path/16 -0.3978 -0.3951 2764 1665 2743 1659
BM_LexicallyRelative/large_path/32 -0.3934 -0.3908 5323 3229 5283 3218
BM_LexicallyRelative/large_path/64 -0.3629 -0.3605 10340 6587 10265 6564
BM_LexicallyRelative/large_path/128 -0.3450 -0.3423 19379 12694 19233 12649
BM_LexicallyRelative/large_path/256 -0.3097 -0.3054 36293 25052 35943 24965
```
---------
Co-authored-by: Nikolas Klauser <nikolasklauser@berlin.de>
2025-08-20 16:58:21 +02:00
William Tran-Viet
1c51886920
[libc++] Implement P3168R2: Give optional range support ( #149441 )
...
Resolves #105430
- Implement all required pieces of P3168R2
- Leverage existing `wrap_iter` and `bounded_iter` classes to implement
the `optional` regular and hardened iterator type, respectively
- Update documentation to match
2025-08-18 18:04:45 +03:00
Nikolas Klauser
d9bc548fac
[libc++] Optimize __tree::find and __tree::__erase_unique ( #152370 )
...
This patch changes `__tree::find` to return when it has found any equal
element instead of the lower bound of the equal elements. For `map` and
`set` there is no observable difference, since the keys are unique.
However for their `multi` versions this can mean a change in behaviour
since it's not longer guaranteed that `find` will return the first
element.
```
------------------------------------------------------------------------------------------
Benchmark old new
------------------------------------------------------------------------------------------
std::map<int, int>::erase(key) (existent)/0 24.4 ns 24.9 ns
std::map<int, int>::erase(key) (existent)/32 39.8 ns 32.1 ns
std::map<int, int>::erase(key) (existent)/1024 83.8 ns 52.5 ns
std::map<int, int>::erase(key) (existent)/8192 91.4 ns 66.4 ns
std::map<int, int>::erase(key) (non-existent)/0 0.511 ns 0.328 ns
std::map<int, int>::erase(key) (non-existent)/32 9.12 ns 5.62 ns
std::map<int, int>::erase(key) (non-existent)/1024 26.6 ns 11.3 ns
std::map<int, int>::erase(key) (non-existent)/8192 37.0 ns 16.9 ns
std::map<int, int>::find(key) (existent)/0 0.007 ns 0.007 ns
std::map<int, int>::find(key) (existent)/32 6.02 ns 4.32 ns
std::map<int, int>::find(key) (existent)/1024 13.6 ns 8.35 ns
std::map<int, int>::find(key) (existent)/8192 30.3 ns 12.8 ns
std::map<int, int>::find(key) (non-existent)/0 0.299 ns 0.545 ns
std::map<int, int>::find(key) (non-existent)/32 8.78 ns 4.60 ns
std::map<int, int>::find(key) (non-existent)/1024 26.1 ns 21.8 ns
std::map<int, int>::find(key) (non-existent)/8192 36.2 ns 27.9 ns
std::map<std::string, int>::erase(key) (existent)/0 74.1 ns 76.7 ns
std::map<std::string, int>::erase(key) (existent)/32 161 ns 114 ns
std::map<std::string, int>::erase(key) (existent)/1024 196 ns 126 ns
std::map<std::string, int>::erase(key) (existent)/8192 207 ns 160 ns
std::map<std::string, int>::erase(key) (non-existent)/0 0.754 ns 0.328 ns
std::map<std::string, int>::erase(key) (non-existent)/32 47.3 ns 40.7 ns
std::map<std::string, int>::erase(key) (non-existent)/1024 122 ns 96.1 ns
std::map<std::string, int>::erase(key) (non-existent)/8192 168 ns 123 ns
std::map<std::string, int>::find(key) (existent)/0 0.059 ns 0.058 ns
std::map<std::string, int>::find(key) (existent)/32 54.3 ns 34.6 ns
std::map<std::string, int>::find(key) (existent)/1024 125 ns 64.5 ns
std::map<std::string, int>::find(key) (existent)/8192 159 ns 79.2 ns
std::map<std::string, int>::find(key) (non-existent)/0 0.311 ns 0.299 ns
std::map<std::string, int>::find(key) (non-existent)/32 44.0 ns 42.7 ns
std::map<std::string, int>::find(key) (non-existent)/1024 120 ns 92.6 ns
std::map<std::string, int>::find(key) (non-existent)/8192 189 ns 124 ns
std::set<int>::erase(key) (existent)/0 25.1 ns 25.1 ns
std::set<int>::erase(key) (existent)/32 42.1 ns 33.1 ns
std::set<int>::erase(key) (existent)/1024 73.8 ns 55.5 ns
std::set<int>::erase(key) (existent)/8192 101 ns 68.8 ns
std::set<int>::erase(key) (non-existent)/0 0.511 ns 0.328 ns
std::set<int>::erase(key) (non-existent)/32 9.60 ns 4.67 ns
std::set<int>::erase(key) (non-existent)/1024 26.5 ns 11.2 ns
std::set<int>::erase(key) (non-existent)/8192 46.2 ns 16.8 ns
std::set<int>::find(key) (existent)/0 0.008 ns 0.007 ns
std::set<int>::find(key) (existent)/32 5.87 ns 4.51 ns
std::set<int>::find(key) (existent)/1024 14.3 ns 8.69 ns
std::set<int>::find(key) (existent)/8192 30.2 ns 12.8 ns
std::set<int>::find(key) (non-existent)/0 0.531 ns 0.530 ns
std::set<int>::find(key) (non-existent)/32 8.77 ns 4.64 ns
std::set<int>::find(key) (non-existent)/1024 26.1 ns 21.7 ns
std::set<int>::find(key) (non-existent)/8192 36.3 ns 27.8 ns
std::set<std::string>::erase(key) (existent)/0 93.2 ns 70.2 ns
std::set<std::string>::erase(key) (existent)/32 164 ns 116 ns
std::set<std::string>::erase(key) (existent)/1024 161 ns 136 ns
std::set<std::string>::erase(key) (existent)/8192 231 ns 140 ns
std::set<std::string>::erase(key) (non-existent)/0 0.532 ns 0.326 ns
std::set<std::string>::erase(key) (non-existent)/32 43.4 ns 40.1 ns
std::set<std::string>::erase(key) (non-existent)/1024 122 ns 99.5 ns
std::set<std::string>::erase(key) (non-existent)/8192 168 ns 125 ns
std::set<std::string>::find(key) (existent)/0 0.059 ns 0.059 ns
std::set<std::string>::find(key) (existent)/32 53.1 ns 35.5 ns
std::set<std::string>::find(key) (existent)/1024 124 ns 61.2 ns
std::set<std::string>::find(key) (existent)/8192 154 ns 73.9 ns
std::set<std::string>::find(key) (non-existent)/0 0.532 ns 0.301 ns
std::set<std::string>::find(key) (non-existent)/32 44.4 ns 39.5 ns
std::set<std::string>::find(key) (non-existent)/1024 120 ns 95.5 ns
std::set<std::string>::find(key) (non-existent)/8192 193 ns 119 ns
std::multimap<int, int>::erase(key) (existent)/0 26.5 ns 26.6 ns
std::multimap<int, int>::erase(key) (existent)/32 33.5 ns 32.9 ns
std::multimap<int, int>::erase(key) (existent)/1024 55.5 ns 58.0 ns
std::multimap<int, int>::erase(key) (existent)/8192 67.4 ns 70.0 ns
std::multimap<int, int>::erase(key) (non-existent)/0 0.523 ns 0.532 ns
std::multimap<int, int>::erase(key) (non-existent)/32 5.08 ns 5.09 ns
std::multimap<int, int>::erase(key) (non-existent)/1024 13.0 ns 12.9 ns
std::multimap<int, int>::erase(key) (non-existent)/8192 19.6 ns 19.8 ns
std::multimap<int, int>::find(key) (existent)/0 0.015 ns 0.037 ns
std::multimap<int, int>::find(key) (existent)/32 7.07 ns 3.85 ns
std::multimap<int, int>::find(key) (existent)/1024 22.0 ns 7.44 ns
std::multimap<int, int>::find(key) (existent)/8192 37.6 ns 12.0 ns
std::multimap<int, int>::find(key) (non-existent)/0 0.297 ns 0.305 ns
std::multimap<int, int>::find(key) (non-existent)/32 8.79 ns 4.59 ns
std::multimap<int, int>::find(key) (non-existent)/1024 26.0 ns 11.2 ns
std::multimap<int, int>::find(key) (non-existent)/8192 36.4 ns 16.8 ns
std::multimap<std::string, int>::erase(key) (existent)/0 93.4 ns 84.5 ns
std::multimap<std::string, int>::erase(key) (existent)/32 101 ns 101 ns
std::multimap<std::string, int>::erase(key) (existent)/1024 118 ns 126 ns
std::multimap<std::string, int>::erase(key) (existent)/8192 108 ns 124 ns
std::multimap<std::string, int>::erase(key) (non-existent)/0 2.39 ns 2.43 ns
std::multimap<std::string, int>::erase(key) (non-existent)/32 44.4 ns 49.7 ns
std::multimap<std::string, int>::erase(key) (non-existent)/1024 108 ns 103 ns
std::multimap<std::string, int>::erase(key) (non-existent)/8192 140 ns 125 ns
std::multimap<std::string, int>::find(key) (existent)/0 0.059 ns 0.058 ns
std::multimap<std::string, int>::find(key) (existent)/32 52.3 ns 32.6 ns
std::multimap<std::string, int>::find(key) (existent)/1024 122 ns 58.9 ns
std::multimap<std::string, int>::find(key) (existent)/8192 160 ns 72.7 ns
std::multimap<std::string, int>::find(key) (non-existent)/0 0.524 ns 0.494 ns
std::multimap<std::string, int>::find(key) (non-existent)/32 43.8 ns 38.9 ns
std::multimap<std::string, int>::find(key) (non-existent)/1024 123 ns 90.8 ns
std::multimap<std::string, int>::find(key) (non-existent)/8192 190 ns 126 ns
std::multiset<int>::erase(key) (existent)/0 27.1 ns 26.8 ns
std::multiset<int>::erase(key) (existent)/32 33.3 ns 34.1 ns
std::multiset<int>::erase(key) (existent)/1024 58.5 ns 58.8 ns
std::multiset<int>::erase(key) (existent)/8192 66.7 ns 64.1 ns
std::multiset<int>::erase(key) (non-existent)/0 0.318 ns 0.325 ns
std::multiset<int>::erase(key) (non-existent)/32 5.15 ns 5.25 ns
std::multiset<int>::erase(key) (non-existent)/1024 12.9 ns 12.7 ns
std::multiset<int>::erase(key) (non-existent)/8192 20.3 ns 20.3 ns
std::multiset<int>::find(key) (existent)/0 0.043 ns 0.015 ns
std::multiset<int>::find(key) (existent)/32 6.94 ns 4.22 ns
std::multiset<int>::find(key) (existent)/1024 21.4 ns 8.23 ns
std::multiset<int>::find(key) (existent)/8192 37.4 ns 12.6 ns
std::multiset<int>::find(key) (non-existent)/0 0.515 ns 0.300 ns
std::multiset<int>::find(key) (non-existent)/32 8.52 ns 4.62 ns
std::multiset<int>::find(key) (non-existent)/1024 25.5 ns 11.3 ns
std::multiset<int>::find(key) (non-existent)/8192 36.5 ns 27.0 ns
std::multiset<std::string>::erase(key) (existent)/0 81.9 ns 77.5 ns
std::multiset<std::string>::erase(key) (existent)/32 113 ns 129 ns
std::multiset<std::string>::erase(key) (existent)/1024 132 ns 148 ns
std::multiset<std::string>::erase(key) (existent)/8192 114 ns 165 ns
std::multiset<std::string>::erase(key) (non-existent)/0 2.33 ns 2.32 ns
std::multiset<std::string>::erase(key) (non-existent)/32 44.4 ns 42.0 ns
std::multiset<std::string>::erase(key) (non-existent)/1024 97.3 ns 95.1 ns
std::multiset<std::string>::erase(key) (non-existent)/8192 132 ns 123 ns
std::multiset<std::string>::find(key) (existent)/0 0.058 ns 0.059 ns
std::multiset<std::string>::find(key) (existent)/32 48.3 ns 34.4 ns
std::multiset<std::string>::find(key) (existent)/1024 121 ns 61.9 ns
std::multiset<std::string>::find(key) (existent)/8192 155 ns 77.7 ns
std::multiset<std::string>::find(key) (non-existent)/0 0.524 ns 0.306 ns
std::multiset<std::string>::find(key) (non-existent)/32 44.1 ns 40.4 ns
std::multiset<std::string>::find(key) (non-existent)/1024 121 ns 96.3 ns
std::multiset<std::string>::find(key) (non-existent)/8192 193 ns 121 ns
```
2025-08-15 08:59:39 +02:00
Nikolas Klauser
cbbf303ff5
[libc++] Optimize __hash_table copy constructors and assignment ( #151951 )
...
```
----------------------------------------------------------------------------------------------------------------------
Benchmark old new
----------------------------------------------------------------------------------------------------------------------
std::unordered_set<int>::ctor(const&)/0 15.4 ns 14.6 ns
std::unordered_set<int>::ctor(const&)/32 686 ns 322 ns
std::unordered_set<int>::ctor(const&)/1024 35839 ns 21490 ns
std::unordered_set<int>::ctor(const&)/8192 385790 ns 280270 ns
std::unordered_set<int>::operator=(const&) (into cleared Container)/0 15.1 ns 15.9 ns
std::unordered_set<int>::operator=(const&) (into cleared Container)/32 1077 ns 333 ns
std::unordered_set<int>::operator=(const&) (into cleared Container)/1024 31296 ns 9984 ns
std::unordered_set<int>::operator=(const&) (into cleared Container)/8192 266776 ns 109418 ns
std::unordered_set<int>::operator=(const&) (into partially populated Container)/0 15.1 ns 16.3 ns
std::unordered_set<int>::operator=(const&) (into partially populated Container)/32 962 ns 320 ns
std::unordered_set<int>::operator=(const&) (into partially populated Container)/1024 31713 ns 10128 ns
std::unordered_set<int>::operator=(const&) (into partially populated Container)/8192 266113 ns 108525 ns
std::unordered_set<int>::operator=(const&) (into populated Container)/0 0.990 ns 2.03 ns
std::unordered_set<int>::operator=(const&) (into populated Container)/32 963 ns 263 ns
std::unordered_set<int>::operator=(const&) (into populated Container)/1024 27600 ns 7793 ns
std::unordered_set<int>::operator=(const&) (into populated Container)/8192 235295 ns 66248 ns
std::unordered_set<std::string>::ctor(const&)/0 16.0 ns 15.0 ns
std::unordered_set<std::string>::ctor(const&)/32 2950 ns 1277 ns
std::unordered_set<std::string>::ctor(const&)/1024 246935 ns 73762 ns
std::unordered_set<std::string>::ctor(const&)/8192 3310895 ns 2468608 ns
std::unordered_set<std::string>::operator=(const&) (into cleared Container)/0 16.1 ns 15.8 ns
std::unordered_set<std::string>::operator=(const&) (into cleared Container)/32 5856 ns 1039 ns
std::unordered_set<std::string>::operator=(const&) (into cleared Container)/1024 170436 ns 74836 ns
std::unordered_set<std::string>::operator=(const&) (into cleared Container)/8192 1574235 ns 1096891 ns
std::unordered_set<std::string>::operator=(const&) (into partially populated Container)/0 16.0 ns 16.3 ns
std::unordered_set<std::string>::operator=(const&) (into partially populated Container)/32 5571 ns 1064 ns
std::unordered_set<std::string>::operator=(const&) (into partially populated Container)/1024 199220 ns 75462 ns
std::unordered_set<std::string>::operator=(const&) (into partially populated Container)/8192 1552465 ns 1116094 ns
std::unordered_set<std::string>::operator=(const&) (into populated Container)/0 1.70 ns 2.14 ns
std::unordered_set<std::string>::operator=(const&) (into populated Container)/32 2562 ns 645 ns
std::unordered_set<std::string>::operator=(const&) (into populated Container)/1024 228608 ns 39100 ns
std::unordered_set<std::string>::operator=(const&) (into populated Container)/8192 2013723 ns 390401 ns
```
Fixes #77657
2025-08-15 08:57:33 +02:00
Nikolas Klauser
1cac2be874
[libc++] Optimize copy construction and assignment of __tree ( #151304 )
...
```
----------------------------------------------------------------------------------------------------------
Benchmark old new
----------------------------------------------------------------------------------------------------------
std::map<int, int>::ctor(const&)/0 15.5 ns 14.9 ns
std::map<int, int>::ctor(const&)/32 474 ns 321 ns
std::map<int, int>::ctor(const&)/1024 24591 ns 11101 ns
std::map<int, int>::ctor(const&)/8192 236153 ns 98868 ns
std::map<std::string, int>::ctor(const&)/0 15.2 ns 14.9 ns
std::map<std::string, int>::ctor(const&)/32 2673 ns 2340 ns
std::map<std::string, int>::ctor(const&)/1024 115354 ns 86088 ns
std::map<std::string, int>::ctor(const&)/8192 1298510 ns 626876 ns
std::map<int, int>::operator=(const&) (into cleared Container)/0 16.5 ns 16.1 ns
std::map<int, int>::operator=(const&) (into cleared Container)/32 548 ns 323 ns
std::map<int, int>::operator=(const&) (into cleared Container)/1024 28418 ns 11026 ns
std::map<int, int>::operator=(const&) (into cleared Container)/8192 281827 ns 97113 ns
std::map<int, int>::operator=(const&) (into populated Container)/0 2.42 ns 1.85 ns
std::map<int, int>::operator=(const&) (into populated Container)/32 369 ns 73.0 ns
std::map<int, int>::operator=(const&) (into populated Container)/1024 24078 ns 2322 ns
std::map<int, int>::operator=(const&) (into populated Container)/8192 266537 ns 22963 ns
std::map<std::string, int>::operator=(const&) (into cleared Container)/0 16.6 ns 16.2 ns
std::map<std::string, int>::operator=(const&) (into cleared Container)/32 2614 ns 1622 ns
std::map<std::string, int>::operator=(const&) (into cleared Container)/1024 116826 ns 63281 ns
std::map<std::string, int>::operator=(const&) (into cleared Container)/8192 1316655 ns 649177 ns
std::map<std::string, int>::operator=(const&) (into populated Container)/0 2.42 ns 1.89 ns
std::map<std::string, int>::operator=(const&) (into populated Container)/32 1264 ns 581 ns
std::map<std::string, int>::operator=(const&) (into populated Container)/1024 238826 ns 39943 ns
std::map<std::string, int>::operator=(const&) (into populated Container)/8192 2412327 ns 379456 ns
```
Fixes #77658
Fixes #62571
2025-08-05 09:49:40 +02:00
A. Jiang
4a509f853f
[libc++] Implement comparison operators for tuple added in C++23 ( #148799 )
...
And constrain the new `operator==` since C++26.
This patch implements parts of P2165R4, P2944R3, and a possibly improved
resolution of LWG3882. Currently, libstdc++ and MSVC STL constrain the
new overloads in the same way.
Also set feature-test macro `__cpp_lib_constrained_equality` and add
related release note, as P2944R3 will completed with this patch.
Fixes #136765
Fixes #136770
Fixes #105424
2025-08-01 11:53:33 -04:00
Konstantin Varlamov
3eee9fc2c4
[libc++][hardening] Introduce assertion semantics. ( #149459 )
...
Assertion semantics closely mimic C++26 Contracts evaluation semantics.
This brings our implementation closer in line with C++26 Library Hardening
(one particular benefit is that using the `observe` semantic makes adopting
hardening easier for projects).
2025-07-29 00:19:15 -07:00
Hui
d344c383e2
[libc++][ranges] implement std::ranges::zip_transform_view ( #79605 )
...
Fixes #104977
Fixes #105035
---------
Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
Co-authored-by: A. Jiang <de34@live.cn>
2025-07-20 09:13:59 +01:00
Louis Dionne
167c695cec
[libc++] Add and empty skeleton for LLVM 22 release notes ( #149535 )
2025-07-19 14:32:54 +01:00
Louis Dionne
d737fe2c91
[libc++][NFC] Fix typos in the libc++ 21 release notes ( #149536 )
2025-07-18 11:54:27 -04:00
Nikolas Klauser
339a1f2e8f
Revert "[libc++][hardening] Introduce assertion semantics" ( #148822 )
...
Reverts llvm/llvm-project#148268
It looks like this was based on #148266 , which I reverted in #148787 .
2025-07-15 12:43:37 +02:00
Konstantin Varlamov
7345508c6f
[libc++][hardening] Introduce assertion semantics ( #148268 )
...
Assertion semantics closely mimic C++26 Contracts evaluation semantics.
This brings our implementation closer in line with C++26 Library
Hardening (one particular benefit is that using the `observe` semantic
makes adopting hardening easier for projects).
2025-07-15 02:14:30 -07:00
A. Jiang
4177bfdb46
[libc++][docs] Confirm that P2372R3 has been implemented ( #148573 )
...
In #125921 , the changes requested by P2372R3 were completed and tested
together with corresponding `chrono` types. But that PR didn't mention
P2372R3. The `__cpp_lib_format` FTM was even bumped by an earlier PR
#98275 .
This PR confirms that P2372R3 was completed in LLVM 21 (together with P1361R2).
Closes #100043
2025-07-14 10:23:27 -04:00
Kazu Hirata
ef48b7fae5
[libcxx] Fix a typo in documentation ( #148557 )
2025-07-13 22:20:03 -07:00
A. Jiang
8b171a08db
[libc++] Remove the packaged_task::result_type extension ( #147671 )
...
No escape hatch added, as there doesn't seem anyone critically relying
on this.
2025-07-10 15:04:49 +08:00
Nikolas Klauser
44d37695a5
[libc++] Optimize ctype::to{lower,upper} ( #145344 )
...
```
----------------------------------------------
Benchmark old new
--------------------------- ------------------
BM_tolower_char<char> 1.64 ns 1.41 ns
BM_tolower_char<wchar_t> 1.64 ns 1.41 ns
BM_tolower_string<char> 32.4 ns 12.8 ns
BM_tolower_string<wchar_t> 32.9 ns 15.1 ns
BM_toupper_char<char> 1.63 ns 1.64 ns
BM_toupper_char<wchar_t> 1.63 ns 1.41 ns
BM_toupper_string<char> 32.2 ns 12.7 ns
BM_toupper_string<wchar_t> 33.0 ns 15.1 ns
```
2025-07-09 16:32:01 +02:00
Hui
0d1e5ab2fd
[libc++] P2655R3 common_reference_t of reference_wrapper Should Be a Reference Type ( #141408 )
...
Fixes #105260
This patch applies the change as a DR to C++20. The rationale is that
the paper is more like a bug fix. It does not introduce new features, it
simply changes an existing behaviour (as a bug fix). MSVC STL DRed this
paper to C++20 as well.
2025-07-06 17:32:59 +01:00
Hui
5f44b5a305
[libc++][doc][NFC] update release notes on P3372R3 ( #147161 )
2025-07-06 10:51:35 +01:00
Hui
34b2e934ea
[libc++] Introduce __product_iterator_traits and optimise flat_map::insert ( #139454 )
...
Fixes #108624
This allows `flat_map::insert(Iter, Iter)` to directly forward to
underlying containers' `insert(Iter, Iter)`, instead of inserting one
element at a time, when input models "product iterator". atm,
`flat_map::iterator` and `zip_view::iterator` are "product iterator"s.
This gives about almost 10x speed up in my benchmark with -03 (for both
before and after)
```cpp
Benchmark Time CPU Time Old Time New CPU Old CPU New
-----------------------------------------------------------------------------------------------------------------------------------------------
flat_map::insert_product_iterator_flat_map/32 -0.5028 -0.5320 149 74 149 70
flat_map::insert_product_iterator_flat_map/1024 -0.8617 -0.8618 3113 430 3112 430
flat_map::insert_product_iterator_flat_map/8192 -0.8877 -0.8877 26682 2995 26679 2995
flat_map::insert_product_iterator_flat_map/65536 -0.8769 -0.8769 226235 27844 226221 27841
flat_map::insert_product_iterator_zip/32 -0.5844 -0.5844 162 67 162 67
flat_map::insert_product_iterator_zip/1024 -0.8754 -0.8754 3427 427 3427 427
flat_map::insert_product_iterator_zip/8192 -0.8934 -0.8934 28134 3000 28132 3000
flat_map::insert_product_iterator_zip/65536 -0.8783 -0.8783 229783 27960 229767 27958
OVERALL_GEOMEAN -0.8319 -0.8332 0 0 0 0
```
---------
Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
2025-06-28 13:42:50 +01:00
Hui
831fcb5e91
[libc++] constexpr flat_map ( #137453 )
...
Fixes #128673
2025-06-21 13:41:32 +01:00
Jakub Mazurkiewicz
1bb2328fd3
[libc++] Implement views::join_with ( #65536 )
...
* Implement "P2441R2 `views::join_with`" (https://wg21.link/P2441R2 ),
closes #105185
* Implement LWG4074 (https://wg21.link/LWG4074 ), closes #105346
* Complete implementation of "P2711R1 Making multi-param constructors of
views explicit" (https://wg21.link/P2711R1 ), closes #105252
* Complete implementation of "P2770R0 Stashing stashing iterators for
proper flattening" (https://wg21.link/P2770R0 ), closes #105250
2025-06-21 10:54:50 +01:00
Peng Liu
9827440f1e
[libc++] Optimize ranges::{for_each, for_each_n} for segmented iterators ( #132896 )
...
Previously, the segmented iterator optimization was limited to `std::{for_each, for_each_n}`. This patch
extends the optimization to `std::ranges::for_each` and `std::ranges::for_each_n`, ensuring consistent
optimizations across these algorithms. This patch first generalizes the `std` algorithms by introducing
a `Projection` parameter, which is set to `__identity` for the `std` algorithms. Then we let the `ranges`
algorithms to directly call their `std` counterparts with a general `__proj` argument. Benchmarks
demonstrate performance improvements of up to 21.4x for ``std::deque::iterator`` and 22.3x for
``join_view`` of ``vector<vector<char>>``.
Addresses a subtask of #102817 .
2025-06-18 12:22:47 -04:00