264 Commits

Author SHA1 Message Date
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