Re: C++17's string_view (was Re: Making use of move semantics?)

2017-06-13 Thread Jonathan Wakely
On 13 June 2017 at 08:31, Murray Cumming wrote:

>
> So, I think:
> 1. We would use std::string_view everywhere if all the C functions took
>   a length instead of assuming null-termination. That's not going to
> happen.
>
> 2. Overriding all methods to take either a const char* or a std::string
> (ignoring ustring for now), would avoid the extra array copy, but I
> don't think it's worth it other than for methods that typically take
> very large strings.
>
> 3. GTK+ functions that take very large strings tend to take a length,
> to avoid the need for copying. For instance,
> gtk_text_buffer_set_text(). We could take std::string_view there, but
> then our use of std::string_view::to_string() would be wasteful when
> someone passes a std::string to our method.
>
> This is discouraging, so I hope I'm wrong about something.
>
>

Nope, you're correct. string_view is great if you stay in C++ world, but
suboptimal when you need to pass the string to libc functions or C APIs
taking null-terminated strings.

One possible approach (which I have no experience of in practice, only in
theory) is to use string_view objects which explicitly include the
null-terminator in their length:

template
inline std::basic_string_view
make_null_terminated_view(const C* s) noexcept
{ return { s, T::length() + 1 }; }

template
inline bool
is_null_terminated_view(std::basic_string_view sv) noexcept
{ return sv.length() && !sv.back(); }


And/or create your own cstring_view / zstring_view type which is guaranteed
to be null-terminated:

struct cstring_view : std::string_view {
  cstring_view(const char* s)
  : std::string_view(s, traits_type::length(s)+1)
  { }
};

Unlike std::string which has a null-terminator after its content that isn't
counted in the length, these string views would count the null character as
part of their content. You'd need a little more care to use this (i.e. when
using the length remember to subtract one where appropriate) but it does
mean you can pass around views to null-terminated strings efficiently
(along with their length, which is the advantage over a raw pointer).
___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: Making use of move semantics?

2017-06-13 Thread Murray Cumming
On Sun, 2017-05-21 at 15:03 +0100, Daniel Boles wrote:
> On 21 May 2017 at 14:29, Murray Cumming  wrote:
> > We've already used move/r-value-references in several places, but
> > not
> > for string arguments.

I assume that std::string's own move operations give us enough
efficiency, so we wouldn't gave much by adding overloads such as
  set_something(std::string&& str);
but we could discuss specific code examples that we'd like to make more
efficient.

-- 
Murray Cumming
murr...@murrayc.com
www.murrayc.com

___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list


C++17's string_view (was Re: Making use of move semantics?)

2017-06-13 Thread Murray Cumming
On Sun, 2017-05-21 at 15:03 +0100, Daniel Boles wrote:
[snip]
> > I guess we might start taking std::string_view with C++17 instead
> > of
> > std::string and this might largely take care of this.
> 
> 
> I don't see how string_view would make any difference to whether or
> not we end up copying strings. Can it?

I've tried it out now, so here are some thoughts:

I had hoped that std::string_view would avoid copying of C strings in
the temporary std::string in cases like this:

void use_string(const std::string& str) {
  gtk_label_set_text(str.c_str());
}
...
use_string("abc");

I think that the "abc" will be copied by the std::string constructor,
though we really only want a const char* anyway.

I had hoped that this would let us just use the original const char*:

void use_string_view(const std::string_view& str) {
  gtk_label_set_text(str.c_str());
}
...
use_string_view("abc");

But there is no std::string_view::c_str() because string_view doesn't
assume that its underlying array is null-terminated. It couldn't assume
that while sometimes being just a view of part an existing array.


So, we need to do this:

void use_string_view(const std::string_view& str) {
  gtk_label_set_text(str.to_string().c_str());
}
...
use_string_view("abc");

That std::string_view::to_string() does a copy, so I don't think we've
gained anything compared to taking a std::string.


And if we pass a std::string, we'd have a copy where we wouldn't have
had one before:

void use_string_view(const std::string_view& str) {
  gtk_label_set_text(str.to_string().c_str());
}
...
use_string_view(some_std_string);


So, I think:
1. We would use std::string_view everywhere if all the C functions took
  a length instead of assuming null-termination. That's not going to
happen.

2. Overriding all methods to take either a const char* or a std::string
(ignoring ustring for now), would avoid the extra array copy, but I
don't think it's worth it other than for methods that typically take
very large strings.

3. GTK+ functions that take very large strings tend to take a length,
to avoid the need for copying. For instance,
gtk_text_buffer_set_text(). We could take std::string_view there, but
then our use of std::string_view::to_string() would be wasteful when
someone passes a std::string to our method.

This is discouraging, so I hope I'm wrong about something.

> Separately, how would string_view interact with Glib::ustring?
> Glancing at the available documentation, my guess is "it wouldn't",
> since it seems to be based on fixed-width characters, not to be
> context-sensitive. So it may not be a suitable replacement for
> ustring.

I guess std::string_view deals with bytes, regardless of their
encoding, just as std::string does. If we keep using Glib::ustring,
we'd maybe want to have a Glib::ustring_view, at least as just a type
alias.

-- 
Murray Cumming
murr...@murrayc.com
www.murrayc.com

___
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list