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
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