Date: Fri, 30 Aug 2024 16:24:20 -0400
Technically you can take a suffix of a null terminated string without
moving/copying, because that just increments the head pointer (and maybe
decrements a length that may or may not still exist). However, I agree the
benefits are limited here.
On Fri, 30 Aug 2024 at 15:27, Tiago Freire via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> I would not make such a proposal.
> I have long abandoned the need for null terminated strings, they are
> inherently faulty, at to me they only exist for compatibility with C
> interfaces.
> And even so they are not a lot.
>
> One of the benefits of using std::string_view and it not guaranteeing null
> termination, is that you can substring it and essentially nothing happens
> other than some pointers moving around, the underlying memory being used
> are exactly the same.
>
> If you need to ensure null termination, then when you substring you need
> to make a copy because you need to put in that null and you can't do that
> on constant data. If you need to copy data, and null termination only
> matters for legacy interfaces, you might just as well use string_view
> everywhere and make an adaptor that copies the data before you pass it on
> to the legacy interface that expects the null. You can do this efficiently
> to since in most cases you can just allocate it on the stack to make the
> copy.
>
> The way I see it. The benefits of it are slim to none.
>
>
>
> -----Original Message-----
> From: Std-Proposals <std-proposals-bounces_at_[hidden]> On Behalf Of
> Jeremy Rifkin via Std-Proposals
> Sent: Friday, August 30, 2024 8:04 PM
> To: Jeremy Rifkin via Std-Proposals <std-proposals_at_[hidden]>
> Cc: Jeremy Rifkin <rifkin.jer_at_[hidden]>
> Subject: [std-proposals] Floating an idea: std::cstring_view
>
> Hello,
> I'm floating an idea before I spend time on a paper for it: I'd like to
> propose a std::cstring_view.
>
> I haven't found a previous paper on the topic, however, I did find an
> email thread from Tom Mason in December 2020 about null-terminated string
> views as well as mention of a zstring_view in N3921. N3921 left the idea to
> a potential later proposal while the 2020 email thread appears to have
> focused on ABI issues surrounding allowing std::string_view itself to be
> null-terminated.
>
> Motivation: When working with C APIs null-terminated C strings are
> generally needed. Current code must either pass around const char* strings,
> const std::string&, or roll their own null-terminated string view class.
>
> The API would be along the lines of:
>
> namespace std {
> template<class charT, class traits = char_traits<charT>>
> class basic_cstring_view {
> public:
> // types
> using traits_type = traits;
> using value_type = charT;
> using pointer = value_type*;
> using const_pointer = const value_type*;
> using reference = value_type&;
> using const_reference = const value_type&;
> using const_iterator = implementation-defined; // see
> [string.cstring_view.iterators]
> using iterator = const_iterator;
> using const_reverse_iterator = reverse_iterator<const_iterator>;
> using reverse_iterator = const_reverse_iterator;
> using size_type = size_t;
> using difference_type = ptrdiff_t;
> static constexpr size_type npos = size_type(-1);
>
> // [string.cstring_view.cons], construction and assignment
> constexpr basic_cstring_view() noexcept;
> constexpr basic_cstring_view(const basic_cstring_view&) noexcept =
> default;
> constexpr basic_cstring_view& operator=(const basic_cstring_view&)
> noexcept = default;
> constexpr basic_cstring_view(const charT* str);
> basic_cstring_view(nullptr_t) = delete;
>
> // [string.cstring_view.iterators], iterator support
> constexpr const_iterator begin() const noexcept;
> constexpr const_iterator end() const noexcept;
> constexpr const_iterator cbegin() const noexcept;
> constexpr const_iterator cend() const noexcept;
> constexpr const_reverse_iterator rbegin() const noexcept;
> constexpr const_reverse_iterator rend() const noexcept;
> constexpr const_reverse_iterator crbegin() const noexcept;
> constexpr const_reverse_iterator crend() const noexcept;
>
> // [string.cstring_view.capacity], capacity
> constexpr size_type size() const noexcept;
> constexpr size_type length() const noexcept;
> constexpr size_type max_size() const noexcept;
> constexpr bool empty() const noexcept;
>
> // [string.cstring_view.access], element access
> constexpr const_reference operator[](size_type pos) const;
> constexpr const_reference at(size_type pos) const; //
> freestanding-deleted
> constexpr const_reference front() const;
> constexpr const_reference back() const;
> constexpr const_pointer data() const noexcept;
> constexpr const_pointer c_str() const noexcept;
>
> // [string.cstring_view.modifiers], modifiers
> constexpr void remove_prefix(size_type n);
> constexpr void swap(basic_cstring_view& s) noexcept;
>
> // [string.cstring_view.ops], string operations
> constexpr size_type copy(charT* s, size_type n,
> size_type pos = 0) const; //
> freestanding-deleted
>
> constexpr basic_cstring_view substr(size_type pos = 0) const; //
> freestanding-deleted
>
> template<class StringViewLike>
> constexpr int compare(StringViewLike s) const noexcept;
> template<class StringViewLike>
> constexpr int compare(size_type pos1, size_type n1,
> StringViewLike s) const; // freestanding-deleted
> template<class StringViewLike>
> constexpr int compare(size_type pos1, size_type n1, StringViewLike s,
> size_type pos2, size_type n2) const; //
> freestanding-deleted
> constexpr int compare(const charT* s) const;
> constexpr int compare(size_type pos1, size_type n1,
> const charT* s) const; // freestanding-deleted
> constexpr int compare(size_type pos1, size_type n1, const charT* s,
> size_type n2) const; // freestanding-deleted
>
> template<class StringViewLike>
> constexpr bool starts_with(StringViewLike x) const noexcept;
> constexpr bool starts_with(charT x) const noexcept;
> constexpr bool starts_with(const charT* x) const;
> template<class StringViewLike>
> constexpr bool ends_with(StringViewLike x) const noexcept;
> constexpr bool ends_with(charT x) const noexcept;
> constexpr bool ends_with(const charT* x) const;
>
> template<class StringViewLike>
> constexpr bool contains(StringViewLike x) const noexcept;
> constexpr bool contains(charT x) const noexcept;
> constexpr bool contains(const charT* x) const;
>
> // [string.cstring_view.find], searching
> template<class StringViewLike>
> constexpr size_type find(StringViewLike s, size_type pos = 0) const
> noexcept;
> constexpr size_type find(charT c, size_type pos = 0) const noexcept;
> constexpr size_type find(const charT* s, size_type pos, size_type n)
> const;
> constexpr size_type find(const charT* s, size_type pos = 0) const;
> template<class StringViewLike>
> constexpr size_type rfind(StringViewLike s, size_type pos = npos)
> const noexcept;
> constexpr size_type rfind(charT c, size_type pos = npos) const
> noexcept;
> constexpr size_type rfind(const charT* s, size_type pos, size_type n)
> const;
> constexpr size_type rfind(const charT* s, size_type pos = npos) const;
>
> template<class StringViewLike>
> constexpr size_type find_first_of(StringViewLike s, size_type pos = 0)
> const noexcept;
> constexpr size_type find_first_of(charT c, size_type pos = 0) const
> noexcept;
> constexpr size_type find_first_of(const charT* s, size_type pos,
> size_type n) const;
> constexpr size_type find_first_of(const charT* s, size_type pos = 0)
> const;
> template<class StringViewLike>
> constexpr size_type find_last_of(StringViewLike s, size_type pos =
> npos) const noexcept;
> constexpr size_type find_last_of(charT c, size_type pos = npos) const
> noexcept;
> constexpr size_type find_last_of(const charT* s, size_type pos,
> size_type n) const;
> constexpr size_type find_last_of(const charT* s, size_type pos =
> npos) const;
> template<class StringViewLike>
> constexpr size_type find_first_not_of(StringViewLike s, size_type pos
> = 0) const noexcept;
> constexpr size_type find_first_not_of(charT c, size_type pos = 0)
> const noexcept;
> constexpr size_type find_first_not_of(const charT* s, size_type pos,
> size_type n) const;
> constexpr size_type find_first_not_of(const charT* s, size_type pos =
> 0) const;
> template<class StringViewLike>
> constexpr size_type find_last_not_of(StringViewLike s,
> size_type pos = npos) const
> noexcept;
> constexpr size_type find_last_not_of(charT c, size_type pos =
> npos) const noexcept;
> constexpr size_type find_last_not_of(const charT* s, size_type pos,
> size_type n) const;
> constexpr size_type find_last_not_of(const charT* s, size_type pos =
> npos) const;
>
> constexpr operator basic_string_view<charT, traits>() const noexcept;
>
> private:
> const_pointer data_; // exposition only
> size_type size_; // exposition only
> };
> }
>
> namespace std {
> // [string.cstring_view.template], class template basic_cstring_view
> template<class charT, class traits = char_traits<charT>>
> class basic_cstring_view;
> // partially freestanding
>
> template<class charT, class traits>
> constexpr bool ranges::enable_view<basic_cstring_view<charT,
> traits>> = true;
> template<class charT, class traits>
> constexpr bool
> ranges::enable_borrowed_range<basic_cstring_view<charT, traits>> = true;
>
> // comparison and IO available via operator basic_string_view
>
> // basic_cstring_view typedef-names
> using cstring_view = basic_cstring_view<char>;
> using u8cstring_view = basic_cstring_view<char8_t>;
> using u16cstring_view = basic_cstring_view<char16_t>;
> using u32cstring_view = basic_cstring_view<char32_t>;
> using wcstring_view = basic_cstring_view<wchar_t>;
>
> // [string.cstring_view.hash], hash support
> template<class T> struct hash;
> template<> struct hash<cstring_view>;
> template<> struct hash<u8cstring_view>;
> template<> struct hash<u16cstring_view>;
> template<> struct hash<u32cstring_view>;
> template<> struct hash<wcstring_view>;
>
> inline namespace literals {
> inline namespace cstring_view_literals {
> // [string.cstring_view.literals], suffix for basic_cstring_view
> literals
> constexpr cstring_view operator""csv(const char* str, size_t
> len) noexcept;
> constexpr u8cstring_view operator""csv(const char8_t* str, size_t
> len) noexcept;
> constexpr u16cstring_view operator""csv(const char16_t* str, size_t
> len) noexcept;
> constexpr u32cstring_view operator""csv(const char32_t* str, size_t
> len) noexcept;
> constexpr wcstring_view operator""csv(const wchar_t* str,
> size_t len) noexcept;
> }
> }
> }
>
> Additionally the following conversion operator would be proposed for
> std::basic_string:
>
> constexpr operator basic_cstring_view<charT, traits>() const noexcept;
>
> operator""csv up to bikeshedding, if anyone feels it may be confused with
> other uses of "csv".
>
> Cheers,
> Jeremy
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
moving/copying, because that just increments the head pointer (and maybe
decrements a length that may or may not still exist). However, I agree the
benefits are limited here.
On Fri, 30 Aug 2024 at 15:27, Tiago Freire via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> I would not make such a proposal.
> I have long abandoned the need for null terminated strings, they are
> inherently faulty, at to me they only exist for compatibility with C
> interfaces.
> And even so they are not a lot.
>
> One of the benefits of using std::string_view and it not guaranteeing null
> termination, is that you can substring it and essentially nothing happens
> other than some pointers moving around, the underlying memory being used
> are exactly the same.
>
> If you need to ensure null termination, then when you substring you need
> to make a copy because you need to put in that null and you can't do that
> on constant data. If you need to copy data, and null termination only
> matters for legacy interfaces, you might just as well use string_view
> everywhere and make an adaptor that copies the data before you pass it on
> to the legacy interface that expects the null. You can do this efficiently
> to since in most cases you can just allocate it on the stack to make the
> copy.
>
> The way I see it. The benefits of it are slim to none.
>
>
>
> -----Original Message-----
> From: Std-Proposals <std-proposals-bounces_at_[hidden]> On Behalf Of
> Jeremy Rifkin via Std-Proposals
> Sent: Friday, August 30, 2024 8:04 PM
> To: Jeremy Rifkin via Std-Proposals <std-proposals_at_[hidden]>
> Cc: Jeremy Rifkin <rifkin.jer_at_[hidden]>
> Subject: [std-proposals] Floating an idea: std::cstring_view
>
> Hello,
> I'm floating an idea before I spend time on a paper for it: I'd like to
> propose a std::cstring_view.
>
> I haven't found a previous paper on the topic, however, I did find an
> email thread from Tom Mason in December 2020 about null-terminated string
> views as well as mention of a zstring_view in N3921. N3921 left the idea to
> a potential later proposal while the 2020 email thread appears to have
> focused on ABI issues surrounding allowing std::string_view itself to be
> null-terminated.
>
> Motivation: When working with C APIs null-terminated C strings are
> generally needed. Current code must either pass around const char* strings,
> const std::string&, or roll their own null-terminated string view class.
>
> The API would be along the lines of:
>
> namespace std {
> template<class charT, class traits = char_traits<charT>>
> class basic_cstring_view {
> public:
> // types
> using traits_type = traits;
> using value_type = charT;
> using pointer = value_type*;
> using const_pointer = const value_type*;
> using reference = value_type&;
> using const_reference = const value_type&;
> using const_iterator = implementation-defined; // see
> [string.cstring_view.iterators]
> using iterator = const_iterator;
> using const_reverse_iterator = reverse_iterator<const_iterator>;
> using reverse_iterator = const_reverse_iterator;
> using size_type = size_t;
> using difference_type = ptrdiff_t;
> static constexpr size_type npos = size_type(-1);
>
> // [string.cstring_view.cons], construction and assignment
> constexpr basic_cstring_view() noexcept;
> constexpr basic_cstring_view(const basic_cstring_view&) noexcept =
> default;
> constexpr basic_cstring_view& operator=(const basic_cstring_view&)
> noexcept = default;
> constexpr basic_cstring_view(const charT* str);
> basic_cstring_view(nullptr_t) = delete;
>
> // [string.cstring_view.iterators], iterator support
> constexpr const_iterator begin() const noexcept;
> constexpr const_iterator end() const noexcept;
> constexpr const_iterator cbegin() const noexcept;
> constexpr const_iterator cend() const noexcept;
> constexpr const_reverse_iterator rbegin() const noexcept;
> constexpr const_reverse_iterator rend() const noexcept;
> constexpr const_reverse_iterator crbegin() const noexcept;
> constexpr const_reverse_iterator crend() const noexcept;
>
> // [string.cstring_view.capacity], capacity
> constexpr size_type size() const noexcept;
> constexpr size_type length() const noexcept;
> constexpr size_type max_size() const noexcept;
> constexpr bool empty() const noexcept;
>
> // [string.cstring_view.access], element access
> constexpr const_reference operator[](size_type pos) const;
> constexpr const_reference at(size_type pos) const; //
> freestanding-deleted
> constexpr const_reference front() const;
> constexpr const_reference back() const;
> constexpr const_pointer data() const noexcept;
> constexpr const_pointer c_str() const noexcept;
>
> // [string.cstring_view.modifiers], modifiers
> constexpr void remove_prefix(size_type n);
> constexpr void swap(basic_cstring_view& s) noexcept;
>
> // [string.cstring_view.ops], string operations
> constexpr size_type copy(charT* s, size_type n,
> size_type pos = 0) const; //
> freestanding-deleted
>
> constexpr basic_cstring_view substr(size_type pos = 0) const; //
> freestanding-deleted
>
> template<class StringViewLike>
> constexpr int compare(StringViewLike s) const noexcept;
> template<class StringViewLike>
> constexpr int compare(size_type pos1, size_type n1,
> StringViewLike s) const; // freestanding-deleted
> template<class StringViewLike>
> constexpr int compare(size_type pos1, size_type n1, StringViewLike s,
> size_type pos2, size_type n2) const; //
> freestanding-deleted
> constexpr int compare(const charT* s) const;
> constexpr int compare(size_type pos1, size_type n1,
> const charT* s) const; // freestanding-deleted
> constexpr int compare(size_type pos1, size_type n1, const charT* s,
> size_type n2) const; // freestanding-deleted
>
> template<class StringViewLike>
> constexpr bool starts_with(StringViewLike x) const noexcept;
> constexpr bool starts_with(charT x) const noexcept;
> constexpr bool starts_with(const charT* x) const;
> template<class StringViewLike>
> constexpr bool ends_with(StringViewLike x) const noexcept;
> constexpr bool ends_with(charT x) const noexcept;
> constexpr bool ends_with(const charT* x) const;
>
> template<class StringViewLike>
> constexpr bool contains(StringViewLike x) const noexcept;
> constexpr bool contains(charT x) const noexcept;
> constexpr bool contains(const charT* x) const;
>
> // [string.cstring_view.find], searching
> template<class StringViewLike>
> constexpr size_type find(StringViewLike s, size_type pos = 0) const
> noexcept;
> constexpr size_type find(charT c, size_type pos = 0) const noexcept;
> constexpr size_type find(const charT* s, size_type pos, size_type n)
> const;
> constexpr size_type find(const charT* s, size_type pos = 0) const;
> template<class StringViewLike>
> constexpr size_type rfind(StringViewLike s, size_type pos = npos)
> const noexcept;
> constexpr size_type rfind(charT c, size_type pos = npos) const
> noexcept;
> constexpr size_type rfind(const charT* s, size_type pos, size_type n)
> const;
> constexpr size_type rfind(const charT* s, size_type pos = npos) const;
>
> template<class StringViewLike>
> constexpr size_type find_first_of(StringViewLike s, size_type pos = 0)
> const noexcept;
> constexpr size_type find_first_of(charT c, size_type pos = 0) const
> noexcept;
> constexpr size_type find_first_of(const charT* s, size_type pos,
> size_type n) const;
> constexpr size_type find_first_of(const charT* s, size_type pos = 0)
> const;
> template<class StringViewLike>
> constexpr size_type find_last_of(StringViewLike s, size_type pos =
> npos) const noexcept;
> constexpr size_type find_last_of(charT c, size_type pos = npos) const
> noexcept;
> constexpr size_type find_last_of(const charT* s, size_type pos,
> size_type n) const;
> constexpr size_type find_last_of(const charT* s, size_type pos =
> npos) const;
> template<class StringViewLike>
> constexpr size_type find_first_not_of(StringViewLike s, size_type pos
> = 0) const noexcept;
> constexpr size_type find_first_not_of(charT c, size_type pos = 0)
> const noexcept;
> constexpr size_type find_first_not_of(const charT* s, size_type pos,
> size_type n) const;
> constexpr size_type find_first_not_of(const charT* s, size_type pos =
> 0) const;
> template<class StringViewLike>
> constexpr size_type find_last_not_of(StringViewLike s,
> size_type pos = npos) const
> noexcept;
> constexpr size_type find_last_not_of(charT c, size_type pos =
> npos) const noexcept;
> constexpr size_type find_last_not_of(const charT* s, size_type pos,
> size_type n) const;
> constexpr size_type find_last_not_of(const charT* s, size_type pos =
> npos) const;
>
> constexpr operator basic_string_view<charT, traits>() const noexcept;
>
> private:
> const_pointer data_; // exposition only
> size_type size_; // exposition only
> };
> }
>
> namespace std {
> // [string.cstring_view.template], class template basic_cstring_view
> template<class charT, class traits = char_traits<charT>>
> class basic_cstring_view;
> // partially freestanding
>
> template<class charT, class traits>
> constexpr bool ranges::enable_view<basic_cstring_view<charT,
> traits>> = true;
> template<class charT, class traits>
> constexpr bool
> ranges::enable_borrowed_range<basic_cstring_view<charT, traits>> = true;
>
> // comparison and IO available via operator basic_string_view
>
> // basic_cstring_view typedef-names
> using cstring_view = basic_cstring_view<char>;
> using u8cstring_view = basic_cstring_view<char8_t>;
> using u16cstring_view = basic_cstring_view<char16_t>;
> using u32cstring_view = basic_cstring_view<char32_t>;
> using wcstring_view = basic_cstring_view<wchar_t>;
>
> // [string.cstring_view.hash], hash support
> template<class T> struct hash;
> template<> struct hash<cstring_view>;
> template<> struct hash<u8cstring_view>;
> template<> struct hash<u16cstring_view>;
> template<> struct hash<u32cstring_view>;
> template<> struct hash<wcstring_view>;
>
> inline namespace literals {
> inline namespace cstring_view_literals {
> // [string.cstring_view.literals], suffix for basic_cstring_view
> literals
> constexpr cstring_view operator""csv(const char* str, size_t
> len) noexcept;
> constexpr u8cstring_view operator""csv(const char8_t* str, size_t
> len) noexcept;
> constexpr u16cstring_view operator""csv(const char16_t* str, size_t
> len) noexcept;
> constexpr u32cstring_view operator""csv(const char32_t* str, size_t
> len) noexcept;
> constexpr wcstring_view operator""csv(const wchar_t* str,
> size_t len) noexcept;
> }
> }
> }
>
> Additionally the following conversion operator would be proposed for
> std::basic_string:
>
> constexpr operator basic_cstring_view<charT, traits>() const noexcept;
>
> operator""csv up to bikeshedding, if anyone feels it may be confused with
> other uses of "csv".
>
> Cheers,
> Jeremy
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2024-08-30 20:24:35