diff mbox series

Add __cow_string C string constructor

Message ID 9a2de7f9-7ac3-4d4a-a4cd-6a379c4217bc@gmail.com
State New
Headers show
Series Add __cow_string C string constructor | expand

Commit Message

François Dumont Jan. 7, 2024, 12:56 p.m. UTC
Hi

While working on the patch to use the cxx11 abi in gnu version namespace 
mode I got a small problem with this missing constructor. I'm not sure 
that the main patch will be integrated in gcc 14 so I think it is better 
if I propose this patch independently.

     libstdc++: Add __cow_string constructor from C string

     The __cow_string is instantiated from a C string in 
cow-stdexcept.cc. At the moment
     the constructor from std::string is being used with the drawback of 
an intermediate
     potential allocation/deallocation and copy. With the C string 
constructor we bypass
     all those operations.

     libstdc++-v3/ChangeLog:

             * include/std/stdexcept (__cow_string(const char*)): New 
definition.
             * src/c++11/cow-stdexcept.cc (__cow_string(const char*)): 
New definition and
             declaration.

Tested under Linux x64, ok to commit ?

François

Comments

Jonathan Wakely Jan. 7, 2024, 4:34 p.m. UTC | #1
On Sun, 7 Jan 2024 at 12:57, François Dumont <frs.dumont@gmail.com> wrote:
>
> Hi
>
> While working on the patch to use the cxx11 abi in gnu version namespace
> mode I got a small problem with this missing constructor. I'm not sure
> that the main patch will be integrated in gcc 14 so I think it is better
> if I propose this patch independently.
>
>      libstdc++: Add __cow_string constructor from C string
>
>      The __cow_string is instantiated from a C string in
> cow-stdexcept.cc. At the moment
>      the constructor from std::string is being used with the drawback of
> an intermediate
>      potential allocation/deallocation and copy. With the C string
> constructor we bypass
>      all those operations.

But in that file, the std::string is the COW string, which means that
when we construct a std::string and copy it, it's cheap. It's just a
reference count increment/decrement. There should be no additional
allocation or deallocation.

Am I missing something?


>
>      libstdc++-v3/ChangeLog:
>
>              * include/std/stdexcept (__cow_string(const char*)): New
> definition.
>              * src/c++11/cow-stdexcept.cc (__cow_string(const char*)):
> New definition and
>              declaration.
>
> Tested under Linux x64, ok to commit ?
>
> François
>
François Dumont Jan. 7, 2024, 6:50 p.m. UTC | #2
On 07/01/2024 17:34, Jonathan Wakely wrote:
> On Sun, 7 Jan 2024 at 12:57, François Dumont <frs.dumont@gmail.com> wrote:
>> Hi
>>
>> While working on the patch to use the cxx11 abi in gnu version namespace
>> mode I got a small problem with this missing constructor. I'm not sure
>> that the main patch will be integrated in gcc 14 so I think it is better
>> if I propose this patch independently.
>>
>>       libstdc++: Add __cow_string constructor from C string
>>
>>       The __cow_string is instantiated from a C string in
>> cow-stdexcept.cc. At the moment
>>       the constructor from std::string is being used with the drawback of
>> an intermediate
>>       potential allocation/deallocation and copy. With the C string
>> constructor we bypass
>>       all those operations.
> But in that file, the std::string is the COW string, which means that
> when we construct a std::string and copy it, it's cheap. It's just a
> reference count increment/decrement. There should be no additional
> allocation or deallocation.

Good remark but AFAI understand in this case std::string is the cxx11 
one. I'll take a second look.

Clearly in my gnu version namespace patch it is the cxx11 implementation.

Even if so, why do we want to do those additional operations ? Adding 
this C string constructor will make sure that no useless operations will 
be done.

>
> Am I missing something?
>
>
>>       libstdc++-v3/ChangeLog:
>>
>>               * include/std/stdexcept (__cow_string(const char*)): New
>> definition.
>>               * src/c++11/cow-stdexcept.cc (__cow_string(const char*)):
>> New definition and
>>               declaration.
>>
>> Tested under Linux x64, ok to commit ?
>>
>> François
>>
Jonathan Wakely Jan. 7, 2024, 8:53 p.m. UTC | #3
On Sun, 7 Jan 2024 at 18:50, François Dumont <frs.dumont@gmail.com> wrote:
>
>
> On 07/01/2024 17:34, Jonathan Wakely wrote:
> > On Sun, 7 Jan 2024 at 12:57, François Dumont <frs.dumont@gmail.com> wrote:
> >> Hi
> >>
> >> While working on the patch to use the cxx11 abi in gnu version namespace
> >> mode I got a small problem with this missing constructor. I'm not sure
> >> that the main patch will be integrated in gcc 14 so I think it is better
> >> if I propose this patch independently.
> >>
> >>       libstdc++: Add __cow_string constructor from C string
> >>
> >>       The __cow_string is instantiated from a C string in
> >> cow-stdexcept.cc. At the moment
> >>       the constructor from std::string is being used with the drawback of
> >> an intermediate
> >>       potential allocation/deallocation and copy. With the C string
> >> constructor we bypass
> >>       all those operations.
> > But in that file, the std::string is the COW string, which means that
> > when we construct a std::string and copy it, it's cheap. It's just a
> > reference count increment/decrement. There should be no additional
> > allocation or deallocation.
>
> Good remark but AFAI understand in this case std::string is the cxx11
> one. I'll take a second look.
>
> Clearly in my gnu version namespace patch it is the cxx11 implementation.

I hope not! The whole point of that type is to always be a COW string,
which it does by storing a COW std::basic_string in the union, but
wrapping it in a class with a different name, __cow_string.

If your patch to use the SSO string in the versioned namespace doesn't
change that file to guarantee that __cow_string is still a
copy-on-write type then the patch is wrong and must be fixed.

>
> Even if so, why do we want to do those additional operations ? Adding
> this C string constructor will make sure that no useless operations will
> be done.

Yes, we could avoid an atomic increment and decrement, but that type
is only used when throwing an exception so the overhead of allocating
memory and calling __cxa_throw etc. is far higher than an atomic
inc/dec pair.

I was going to say that the new constructor would need to be exported
from the shared lib, but I think the new constructor is only ever used
in these two places, both defined in that same file:

  logic_error::logic_error(const char* __arg)
  : exception(), _M_msg(__arg) { }

  runtime_error::runtime_error(const char* __arg)
  : exception(), _M_msg(__arg) { }

So I think the change is safe, but I don't think it's urgent, and
certainly not needed for the reasons claimed in the patch description.
François Dumont Jan. 8, 2024, 5:58 a.m. UTC | #4
On 07/01/2024 21:53, Jonathan Wakely wrote:
> On Sun, 7 Jan 2024 at 18:50, François Dumont <frs.dumont@gmail.com> wrote:
>>
>> On 07/01/2024 17:34, Jonathan Wakely wrote:
>>> On Sun, 7 Jan 2024 at 12:57, François Dumont <frs.dumont@gmail.com> wrote:
>>>> Hi
>>>>
>>>> While working on the patch to use the cxx11 abi in gnu version namespace
>>>> mode I got a small problem with this missing constructor. I'm not sure
>>>> that the main patch will be integrated in gcc 14 so I think it is better
>>>> if I propose this patch independently.
>>>>
>>>>        libstdc++: Add __cow_string constructor from C string
>>>>
>>>>        The __cow_string is instantiated from a C string in
>>>> cow-stdexcept.cc. At the moment
>>>>        the constructor from std::string is being used with the drawback of
>>>> an intermediate
>>>>        potential allocation/deallocation and copy. With the C string
>>>> constructor we bypass
>>>>        all those operations.
>>> But in that file, the std::string is the COW string, which means that
>>> when we construct a std::string and copy it, it's cheap. It's just a
>>> reference count increment/decrement. There should be no additional
>>> allocation or deallocation.
>> Good remark but AFAI understand in this case std::string is the cxx11
>> one. I'll take a second look.
>>
>> Clearly in my gnu version namespace patch it is the cxx11 implementation.
> I hope not! The whole point of that type is to always be a COW string,
> which it does by storing a COW std::basic_string in the union, but
> wrapping it in a class with a different name, __cow_string.
>
> If your patch to use the SSO string in the versioned namespace doesn't
> change that file to guarantee that __cow_string is still a
> copy-on-write type then the patch is wrong and must be fixed.

Don't worry, __cow_string is indeed wrapping a COW string.

What I meant is that in this constructor in <stdexcept>:

__cow_string(const std::string&);

The std::string parameter is the SSO string.

However, as you said, in cow-stdexcept.cc the similar constructor is in 
fact taking a COW string so it has less importance. It's just a ODR issue.

In my gnu version namespace patch however this type is still the SSO 
string in cow-stdexcept.cc so I'll keep it in this context.


>> Even if so, why do we want to do those additional operations ? Adding
>> this C string constructor will make sure that no useless operations will
>> be done.
> Yes, we could avoid an atomic increment and decrement, but that type
> is only used when throwing an exception so the overhead of allocating
> memory and calling __cxa_throw etc. is far higher than an atomic
> inc/dec pair.
>
> I was going to say that the new constructor would need to be exported
> from the shared lib, but I think the new constructor is only ever used
> in these two places, both defined in that same file:
>
>    logic_error::logic_error(const char* __arg)
>    : exception(), _M_msg(__arg) { }
>
>    runtime_error::runtime_error(const char* __arg)
>    : exception(), _M_msg(__arg) { }
>
> So I think the change is safe, but I don't think it's urgent, and
> certainly not needed for the reasons claimed in the patch description.
>
The ODR violation has no side effect, it confirms your statement, looks 
like the __cow_string(const std::string&) could be removed from <stdexcept>.
diff mbox series

Patch

diff --git a/libstdc++-v3/include/std/stdexcept b/libstdc++-v3/include/std/stdexcept
index 66c8572d0cd..2e3c9f3bf71 100644
--- a/libstdc++-v3/include/std/stdexcept
+++ b/libstdc++-v3/include/std/stdexcept
@@ -54,6 +54,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
     __cow_string();
     __cow_string(const std::string&);
+    __cow_string(const char*);
     __cow_string(const char*, size_t);
     __cow_string(const __cow_string&) _GLIBCXX_NOTHROW;
     __cow_string& operator=(const __cow_string&) _GLIBCXX_NOTHROW;
diff --git a/libstdc++-v3/src/c++11/cow-stdexcept.cc b/libstdc++-v3/src/c++11/cow-stdexcept.cc
index 8d1cc4605d4..12b189b43b5 100644
--- a/libstdc++-v3/src/c++11/cow-stdexcept.cc
+++ b/libstdc++-v3/src/c++11/cow-stdexcept.cc
@@ -127,6 +127,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
     __cow_string();
     __cow_string(const std::string& s);
+    __cow_string(const char*);
     __cow_string(const char*, size_t n);
     __cow_string(const __cow_string&) noexcept;
     __cow_string& operator=(const __cow_string&) noexcept;
@@ -139,6 +140,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   __cow_string::__cow_string(const std::string& s) : _M_str(s) { }
 
+  __cow_string::__cow_string(const char* s) : _M_str(s) { }
+
   __cow_string::__cow_string(const char* s, size_t n) : _M_str(s, n) { }
 
   __cow_string::__cow_string(const __cow_string& s) noexcept