C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Floating an idea: std::cstring_view

From: Tiago Freire <tmiguelf_at_[hidden]>
Date: Fri, 30 Aug 2024 19:27:12 +0000
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_lists.isocpp.org> 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_lists.isocpp.org>
Cc: Jeremy Rifkin <rifkin.jer_at_gmail.com>
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_lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2024-08-30 19:27:16