blob: 1a478cb7554be6cd60189915b3ad53d45e4dffee [file] [log] [blame]
#pragma once
#include <fmt/core.h>
#include <stdplus/str/cexpr.hpp>
#include <stdplus/zstring.hpp>
#include <stdexcept>
#include <string>
#include <string_view>
#include <type_traits>
namespace stdplus
{
/**
* @brief Provides a class for expressing a string_view that is guaranteed to
* have nul termination. Most of the functions of this class are identical to
* std::string_view with needed modifier functions removed to guarantee safety.
*/
template <typename CharT, typename Traits = std::char_traits<CharT>>
class basic_zstring_view;
namespace detail
{
template <typename CharT, typename Traits>
constexpr auto
unsafe_zstring_view(std::basic_string_view<CharT, Traits> sv) noexcept
{
using SV = basic_zstring_view<CharT, Traits>;
return SV(typename SV::unsafe(), sv);
}
template <typename CharT, std::size_t N>
struct compile_zstring_view
{
CharT data[N] = {};
bool valid = true;
constexpr compile_zstring_view(const CharT (&str)[N]) noexcept
{
valid = zstring_find_term(str, N - 1, N) >= 0;
for (std::size_t i = 0; i < N - 1; ++i)
{
data[i] = str[i];
}
}
constexpr auto getzsv() const noexcept
{
return unsafe_zstring_view(std::basic_string_view<CharT>(data, N - 1));
}
};
} // namespace detail
template <typename CharT, typename Traits>
class basic_zstring_view
{
private:
using string_view_base = std::basic_string_view<CharT, Traits>;
using zstring_base = basic_zstring<const CharT, Traits>;
public:
using traits_type = string_view_base::traits_type;
using value_type = string_view_base::value_type;
using pointer = string_view_base::pointer;
using const_pointer = string_view_base::const_pointer;
using reference = string_view_base::reference;
using const_reference = string_view_base::const_reference;
using iterator = string_view_base::iterator;
using const_iterator = string_view_base::const_iterator;
using reverse_iterator = string_view_base::reverse_iterator;
using const_reverse_iterator = string_view_base::const_reverse_iterator;
using size_type = string_view_base::size_type;
using difference_type = string_view_base::difference_type;
static constexpr size_type npos = string_view_base::npos;
template <typename T, size_type N>
constexpr basic_zstring_view(T (&str)[N])
#ifdef NDEBUG
noexcept :
sv(str)
#else
:
sv(str, detail::zstring_validate(str, 0, N))
#endif
{}
template <typename T, std::enable_if_t<std::is_pointer_v<T>, bool> = true>
constexpr basic_zstring_view(T str) noexcept : sv(str)
{}
template <typename T,
std::enable_if_t<detail::same_string<T, CharT, Traits>::value,
bool> = true>
constexpr basic_zstring_view(const T& str)
#ifdef NDEBUG
noexcept :
sv(str)
#else
:
sv(str.data(),
detail::zstring_validate(str.data(), str.size(), str.size() + 1))
#endif
{}
template <
typename T,
std::enable_if_t<std::is_same_v<value_type, std::remove_const_t<T>>,
bool> = true>
constexpr basic_zstring_view(basic_zstring<T, Traits> str) noexcept :
sv(str.data())
{}
constexpr operator string_view_base() const noexcept
{
return sv;
}
constexpr operator zstring_base() const noexcept
{
return zstring_base(data());
}
constexpr const_iterator begin() const noexcept
{
return sv.begin();
}
constexpr const_iterator end() const noexcept
{
return sv.end();
}
constexpr const_reverse_iterator rbegin() const noexcept
{
return sv.rbegin();
}
constexpr const_reverse_iterator rend() const noexcept
{
return sv.rend();
}
constexpr const_reference operator[](size_type pos) const noexcept
{
return sv[pos];
}
constexpr const_reference at(size_type pos) const
{
return sv.at(pos);
}
constexpr const_reference front() const noexcept
{
return sv.front();
}
constexpr const_reference back() const noexcept
{
return sv.back();
}
constexpr const_pointer data() const noexcept
{
return sv.data();
}
constexpr size_type size() const noexcept
{
return sv.size();
}
constexpr size_type length() const noexcept
{
return sv.length();
}
constexpr size_type max_size() noexcept
{
return sv.max_size();
}
[[nodiscard]] constexpr bool empty() const noexcept
{
return sv.empty();
}
constexpr void swap(basic_zstring_view& v) noexcept
{
sv.swap(v.sv);
}
constexpr size_type copy(pointer dest, size_type count,
size_type pos = 0) const
{
return sv.copy(dest, count, pos);
}
constexpr string_view_base substr(size_type pos = 0,
size_type count = npos) const
{
return sv.substr(pos, count);
}
constexpr int compare(string_view_base v) const noexcept
{
return sv.compare(v);
}
constexpr int compare(size_type pos1, size_type count1,
string_view_base v) const
{
return sv.compare(pos1, count1, v);
}
constexpr int compare(size_type pos1, size_type count1, string_view_base v,
size_type pos2, size_type count2) const
{
return sv.compare(pos1, count1, v, pos2, count2);
}
constexpr int compare(const_pointer s) const
{
return sv.compare(s);
}
constexpr int compare(size_type pos1, size_type count1,
const_pointer s) const
{
return sv.compare(pos1, count1, s);
}
constexpr int compare(size_type pos1, size_type count1, const_pointer s,
size_type count2) const
{
return sv.compare(pos1, count1, s, count2);
}
#define zstring_view_has(func) \
constexpr bool func(string_view_base sv) const noexcept \
{ \
return sv.func(sv); \
} \
constexpr bool func(value_type c) const noexcept \
{ \
return sv.func(c); \
} \
constexpr bool func(const_pointer s) const \
{ \
return sv.func(s); \
}
zstring_view_has(starts_with);
zstring_view_has(ends_with);
#undef zstring_view_has
#define zstring_view_find(func, def) \
constexpr size_type func(string_view_base v, size_type pos = def) \
const noexcept \
{ \
return sv.func(v, pos); \
} \
constexpr size_type func(value_type ch, size_type pos = def) \
const noexcept \
{ \
return sv.func(ch, pos); \
} \
constexpr size_type func(const_pointer s, size_type pos, size_type count) \
const \
{ \
return sv.func(s, pos, count); \
} \
constexpr size_type func(const_pointer s, size_type pos = def) const \
{ \
return sv.func(s, pos); \
}
zstring_view_find(find, 0);
zstring_view_find(rfind, npos);
zstring_view_find(find_first_of, 0);
zstring_view_find(find_last_of, npos);
zstring_view_find(find_first_not_of, 0);
zstring_view_find(find_last_not_of, npos);
#undef zstring_view_find
constexpr const_pointer c_str() const noexcept
{
return sv.data();
}
constexpr basic_zstring_view suffix(size_type pos = 0) const
{
if (pos > sv.size())
{
throw std::out_of_range("stdplus::zstring_view");
}
return basic_zstring_view(unsafe(), sv.substr(pos));
}
constexpr bool
operator==(std::basic_string_view<CharT, Traits> rhs) const noexcept
{
return size() == rhs.size() && compare(rhs) == 0;
}
constexpr Traits::comparison_category
operator<=>(std::basic_string_view<CharT, Traits> rhs) const noexcept
{
return compare(rhs) <=> 0;
}
private:
string_view_base sv;
struct unsafe
{};
constexpr basic_zstring_view(unsafe, string_view_base sv) noexcept : sv(sv)
{}
friend constexpr auto detail::unsafe_zstring_view<CharT, Traits>(
string_view_base sv) noexcept;
};
template <typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os,
basic_zstring_view<CharT, Traits> v)
{
return os << static_cast<std::basic_string_view<CharT, Traits>>(v);
}
inline namespace zstring_view_literals
{
template <detail::compile_zstring_view Str>
constexpr auto operator"" _zsv() noexcept
{
static_assert(Str.valid, "stdplus::zstring_view");
return Str.getzsv();
}
} // namespace zstring_view_literals
template <auto f>
consteval auto cexprToZsv()
{
constexpr auto& d = cexprStrArr<f, /*nul=*/true>;
static_assert(detail::zstring_find_term(d.data(), d.size() - 1, d.size()) >=
0);
return detail::unsafe_zstring_view(
std::basic_string_view(d.begin(), d.end() - 1));
}
template <auto f>
inline constexpr auto cexprZsv = cexprToZsv<f>();
} // namespace stdplus
#define zstring_view_all(char_t, pfx) \
namespace stdplus \
{ \
using pfx##zstring_view = basic_zstring_view<char_t>; \
} \
namespace std \
{ \
template <> \
struct hash<stdplus::basic_zstring_view<char_t>> : \
hash<basic_string_view<char_t>> \
{}; \
}
zstring_view_all(char, );
zstring_view_all(char8_t, u8);
zstring_view_all(char16_t, u16);
zstring_view_all(char32_t, u32);
zstring_view_all(wchar_t, w);
#undef zstring_view_all
namespace fmt
{
template <typename CharT, typename Traits>
struct formatter<stdplus::basic_zstring_view<CharT, Traits>, CharT> :
formatter<basic_string_view<CharT>, CharT>
{
template <typename FormatContext>
inline auto format(stdplus::basic_zstring_view<CharT, Traits> str,
FormatContext& ctx) const
{
return formatter<basic_string_view<CharT>, CharT>::format(
static_cast<std::basic_string_view<CharT, Traits>>(str), ctx);
}
};
} // namespace fmt
namespace std
{
template <typename CharT, typename Traits>
struct formatter<stdplus::basic_zstring_view<CharT, Traits>, CharT> :
formatter<basic_string_view<CharT>, CharT>
{
template <typename FormatContext>
inline auto format(stdplus::basic_zstring_view<CharT, Traits> str,
FormatContext& ctx) const
{
return formatter<basic_string_view<CharT>, CharT>::format(
static_cast<std::basic_string_view<CharT, Traits>>(str), ctx);
}
};
} // namespace std