[PATCH] libstdc++: Optimize fs::path::operator+=(const path&) alias check
Jonathan Wakely
jwakely.gcc@gmail.com
Fri Mar 20 08:22:00 GMT 2026
On Fri, 20 Mar 2026, 08:07 Tomasz Kaminski, <tkaminsk@redhat.com> wrote:
>
>
> On Fri, Mar 20, 2026 at 9:04 AM Jonathan Wakely <jwakely.gcc@gmail.com>
> wrote:
>
>>
>>
>> On Fri, 20 Mar 2026, 06:43 Tomasz Kaminski, <tkaminsk@redhat.com> wrote:
>>
>>>
>>>
>>> On Fri, Mar 20, 2026 at 2:17 AM Jonathan Wakely <jwakely@redhat.com>
>>> wrote:
>>>
>>>> Instead of a loop that compares &p to the address of each path
>>>> component, we can just do two pointer comparisons to see if &p is within
>>>> the contiguous array of components.
>>>>
>>>> We don't need to make the same change to experimental::filesystem::path
>>>> because as noted in r15-9709-gbeb0ffd36eedf0 the TS implementation
>>>> doesn't attempt to optimize operator+= so doesn't care if the parameter
>>>> aliases *this.
>>>>
>>>> libstdc++-v3/ChangeLog:
>>>>
>>>> * src/c++17/fs_path.cc (path::operator+=): Use pointer
>>>> comparison to detect aliasing instead of a loop.
>>>> ---
>>>>
>>>> Tested x86_64-linux.
>>>>
>>> LGTM.
>>>
>>>>
>>>> libstdc++-v3/src/c++17/fs_path.cc | 6 ++++--
>>>> 1 file changed, 4 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/libstdc++-v3/src/c++17/fs_path.cc
>>>> b/libstdc++-v3/src/c++17/fs_path.cc
>>>> index c217dc278018..763d5609c7f7 100644
>>>> --- a/libstdc++-v3/src/c++17/fs_path.cc
>>>> +++ b/libstdc++-v3/src/c++17/fs_path.cc
>>>> @@ -927,9 +927,11 @@ path::operator+=(const path& p)
>>>> return *this += p.native();
>>>> // Handle p += *i where i is in [p.begin(),p.end()), for the same
>>>> reason.
>>>> if (_M_type() == _Type::_Multi && p._M_type() != _Type::_Multi)
>>>> - for (const path& cmpt : *this)
>>>> - if (&cmpt == &p) [[unlikely]]
>>>> + {
>>>> + const auto first = _M_cmpts.begin(), last = first +
>>>> _M_cmpts.size();
>>>> + if (!std::less<>()(&p, first) && std::less<>()(&p, last))
>>>> [[unlikely]]
>>>>
>>> I teory for some architectures, pointers to distinct objects may be
>>> interleaved,
>>>
>> so we may have situation when !std::less<>()(q, first) &&
>>> !std::less<>()(q, last)
>>> but q is not within the range. I assume we are not targeting anything
>>> where this would
>>> be the case.
>>>
>>
>> Definitely not.
>>
>> Anyway, I think we'd need to change std::less to deal with that case, so
>> that the total order for pointers still worked sensibly.
>>
> Standard allows such interleaving, so we guarantee that if p < q is
> well-specified, then less<>{}(p, q) is true, but nothing about
> less{}<>(r,v) if r < v is not specified. That why there are proposal for
> is_inpointer_in_range.
>
Yes, the standard allows such an implementation, but I think it would be so
hostile that we'd need to make std::less work sanely despite the underlying
pointer weirdness.
But it doesn't matter for our implementation anyway.
>>
>>
>>>
>>>> return *this += p.native();
>>>> + }
>>>>
>>>> #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
>>>> if (_M_type() == _Type::_Root_name
>>>> --
>>>> 2.53.0
>>>>
>>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260320/dc4d37ca/attachment-0001.htm>
More information about the Libstdc++
mailing list