C++ Logo

std-proposals

Advanced search

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

From: Jeremy Rifkin <rifkin.jer_at_[hidden]>
Date: Fri, 30 Aug 2024 13:04:04 -0500
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

Received on 2024-08-30 18:04:18