Skip to content
14 changes: 14 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ option(
${PROJECT_IS_TOP_LEVEL}
)

# [CMAKE.CPP17_MODE]
option(
BEMAN_CSTRING_VIEW_CPP17_MODE
"Use the C++17 compatible implementation. Default: OFF. Values: { ON, OFF }."
OFF
)

# [CMAKE.SKIP_EXAMPLES]
option(
BEMAN_CSTRING_VIEW_BUILD_EXAMPLES
Expand Down Expand Up @@ -44,6 +51,13 @@ add_subdirectory(include/beman/cstring_view)

beman_install_library(beman.cstring_view TARGETS beman.cstring_view)

if(BEMAN_CSTRING_VIEW_CPP17_MODE)
target_compile_options(
beman.cstring_view
INTERFACE -DUSE_CPP17_VARIANT
)
Comment on lines +55 to +58
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[pre-commit] reported by reviewdog 🐶

Suggested change
target_compile_options(
beman.cstring_view
INTERFACE -DUSE_CPP17_VARIANT
)
target_compile_options(beman.cstring_view INTERFACE -DUSE_CPP17_VARIANT)

endif()

if(BEMAN_CSTRING_VIEW_BUILD_TESTS)
enable_testing()
add_subdirectory(tests/beman/cstring_view)
Expand Down
156 changes: 51 additions & 105 deletions include/beman/cstring_view/cstring_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,13 @@

namespace beman {

namespace detail {

#if !defined(USE_CPP17_VARIANT)
static_assert(__cpp_concepts >= 201907L);
template <typename T>
struct type_identity {
using type = T;
concept cstring_like = requires(const T& t) {
{ t.c_str() } -> std::same_as<const typename T::value_type*>;
};

template <typename T>
using type_identity_t = typename type_identity<T>::type;

} // namespace detail
#endif

// [cstring.view.template], class template basic_cstring_view
template <class charT, class traits = std::char_traits<charT>>
Expand All @@ -43,33 +39,6 @@ namespace ranges {
}
#endif
*/
// [cstring.view.comparison], non-member comparison functions
template <class charT, class traits>
constexpr bool operator==(basic_cstring_view<charT, traits> x,
detail::type_identity_t<basic_cstring_view<charT, traits>> y) noexcept;

#if __cpp_lib_three_way_comparison
template <class charT, class traits>
constexpr auto operator<=>(basic_cstring_view<charT, traits> x,
detail::type_identity_t<basic_cstring_view<charT, traits>> y) noexcept;
#else
template <class charT, class traits>
constexpr bool operator!=(basic_cstring_view<charT, traits> x,
detail::type_identity_t<basic_cstring_view<charT, traits>> y) noexcept;
template <class charT, class traits>
constexpr bool operator<(basic_cstring_view<charT, traits> x,
detail::type_identity_t<basic_cstring_view<charT, traits>> y) noexcept;
template <class charT, class traits>
constexpr bool operator>(basic_cstring_view<charT, traits> x,
detail::type_identity_t<basic_cstring_view<charT, traits>> y) noexcept;
template <class charT, class traits>
constexpr bool operator<=(basic_cstring_view<charT, traits> x,
detail::type_identity_t<basic_cstring_view<charT, traits>> y) noexcept;
template <class charT, class traits>
constexpr bool operator>=(basic_cstring_view<charT, traits> x,
detail::type_identity_t<basic_cstring_view<charT, traits>> y) noexcept;
#endif

// [cstring.view.io], inserters and extractors
template <class charT, class traits>
std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os,
Expand All @@ -84,22 +53,6 @@ using u16cstring_view = basic_cstring_view<char16_t>;
using u32cstring_view = basic_cstring_view<char32_t>;
using wcstring_view = basic_cstring_view<wchar_t>;

// [cstring.view.hash], hash support
template <class T>
struct hash;
template <>
struct hash<cstring_view>;
#if __cpp_char8_t >= 201811L
template <>
struct hash<u8cstring_view>;
#endif
template <>
struct hash<u16cstring_view>;
template <>
struct hash<u32cstring_view>;
template <>
struct hash<wcstring_view>;

inline namespace literals {
inline namespace cstring_view_literals {
#ifndef _MSC_VER
Expand All @@ -114,13 +67,13 @@ inline namespace cstring_view_literals {
#pragma warning(disable : 4455)
#endif
// [cstring.view.literals], suffix for basic_cstring_view literals
constexpr cstring_view operator"" csv(const char* str, size_t len) noexcept;
constexpr cstring_view operator""_csv(const char* str, size_t len) noexcept;
#if __cpp_char8_t >= 201811L
constexpr u8cstring_view operator"" csv(const char8_t* str, size_t len) noexcept;
constexpr u8cstring_view operator""_csv(const char8_t* str, size_t len) noexcept;
#endif
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;
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;
#ifndef _MSC_VER
#pragma GCC diagnostic pop
#else
Expand All @@ -146,8 +99,8 @@ class basic_cstring_view {
using iterator = const_iterator;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using reverse_iterator = const_reverse_iterator;
using size_type = size_t;
using difference_type = ptrdiff_t;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
static constexpr size_type npos = size_type(-1);

private:
Expand All @@ -164,11 +117,16 @@ class basic_cstring_view {
}
constexpr basic_cstring_view(std::nullptr_t) = delete;

// NOTE: Not part of proposal, just to make examples work since I can't add the conversion operator to
// basic_string.
template <typename Traits, typename Allocator>
constexpr basic_cstring_view(const std::basic_string<charT, Traits, Allocator>& str)
: basic_cstring_view(str.c_str(), str.size()) {}
#if defined(USE_CPP17_VARIANT)
// Just pretend this is doing the concept match that the paper proposes
template <typename R, typename = decltype((*(R*)0).c_str())>
constexpr basic_cstring_view(const R& r)
#else
static_assert(__cpp_concepts >= 201907L);
constexpr basic_cstring_view(const cstring_like auto& r)
#endif
: basic_cstring_view(r.c_str(), r.size()) {
}

// [cstring.view.iterators], iterator support
constexpr const_iterator begin() const noexcept { return data_; }
Expand Down Expand Up @@ -360,6 +318,34 @@ class basic_cstring_view {
return std::basic_string_view<charT, traits>(*this).find_last_not_of(s, pos);
}

#if __cpp_lib_three_way_comparison
friend constexpr bool operator==(basic_cstring_view x, basic_cstring_view y) noexcept {
return std::basic_string_view<charT, traits>(x) == std::basic_string_view<charT, traits>(y);
}
friend constexpr auto operator<=>(basic_cstring_view x, basic_cstring_view y) noexcept {
return std::basic_string_view<charT, traits>(x) <=> std::basic_string_view<charT, traits>(y);
}
#else
friend constexpr bool operator==(basic_cstring_view x, basic_cstring_view y) noexcept {
return std::basic_string_view<charT, traits>(x) == std::basic_string_view<charT, traits>(y);
}
friend constexpr bool operator!=(basic_cstring_view x, basic_cstring_view y) noexcept {
return std::basic_string_view<charT, traits>(x) != std::basic_string_view<charT, traits>(y);
}
friend constexpr bool operator<(basic_cstring_view x, basic_cstring_view y) noexcept {
return std::basic_string_view<charT, traits>(x) < std::basic_string_view<charT, traits>(y);
}
friend constexpr bool operator>(basic_cstring_view x, basic_cstring_view y) noexcept {
return std::basic_string_view<charT, traits>(x) > std::basic_string_view<charT, traits>(y);
}
friend constexpr bool operator<=(basic_cstring_view x, basic_cstring_view y) noexcept {
return std::basic_string_view<charT, traits>(x) <= std::basic_string_view<charT, traits>(y);
}
friend constexpr bool operator>=(basic_cstring_view x, basic_cstring_view y) noexcept {
return std::basic_string_view<charT, traits>(x) >= std::basic_string_view<charT, traits>(y);
}
#endif

private:
const_pointer data_; // exposition only
size_type size_; // exposition only
Expand All @@ -386,47 +372,6 @@ constexpr wcstring_view operator""_csv(const wchar_t* str, size_t len) noexcept
} // namespace cstring_view_literals
} // namespace literals

template <class charT, class traits>
constexpr bool operator==(basic_cstring_view<charT, traits> x,
detail::type_identity_t<basic_cstring_view<charT, traits>> y) noexcept {
return std::basic_string_view<charT, traits>(x) == std::basic_string_view<charT, traits>(y);
}

#if __cpp_lib_three_way_comparison
template <class charT, class traits>
constexpr auto operator<=>(basic_cstring_view<charT, traits> x,
detail::type_identity_t<basic_cstring_view<charT, traits>> y) noexcept {
return std::basic_string_view<charT, traits>(x) <=> std::basic_string_view<charT, traits>(y);
}
#else
template <class charT, class traits>
constexpr bool operator!=(basic_cstring_view<charT, traits> x,
detail::type_identity_t<basic_cstring_view<charT, traits>> y) noexcept {
return std::basic_string_view<charT, traits>(x) != std::basic_string_view<charT, traits>(y);
}
// Definitions
template <class charT, class traits>
constexpr bool operator<(basic_cstring_view<charT, traits> x,
detail::type_identity_t<basic_cstring_view<charT, traits>> y) noexcept {
return std::basic_string_view<charT, traits>(x) < std::basic_string_view<charT, traits>(y);
}
template <class charT, class traits>
constexpr bool operator>(basic_cstring_view<charT, traits> x,
detail::type_identity_t<basic_cstring_view<charT, traits>> y) noexcept {
return std::basic_string_view<charT, traits>(x) > std::basic_string_view<charT, traits>(y);
}
template <class charT, class traits>
constexpr bool operator<=(basic_cstring_view<charT, traits> x,
detail::type_identity_t<basic_cstring_view<charT, traits>> y) noexcept {
return std::basic_string_view<charT, traits>(x) <= std::basic_string_view<charT, traits>(y);
}
template <class charT, class traits>
constexpr bool operator>=(basic_cstring_view<charT, traits> x,
detail::type_identity_t<basic_cstring_view<charT, traits>> y) noexcept {
return std::basic_string_view<charT, traits>(x) >= std::basic_string_view<charT, traits>(y);
}
#endif

template <class charT, class traits>
std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os,
basic_cstring_view<charT, traits> str) {
Expand All @@ -451,6 +396,7 @@ struct std::formatter<beman::basic_cstring_view<charT, traits>, charT> {
};
#endif

// [cstring.view.hash], hash support
template <>
struct std::hash<beman::cstring_view> {
auto operator()(const beman::cstring_view& sv) const noexcept { return std::hash<string_view>{}(sv); }
Expand Down
1 change: 1 addition & 0 deletions tests/beman/cstring_view/cstring_view.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ TEST(StringView, ConstructionDestruction) {
EXPECT_NE(h1.c_str(), s.c_str());
EXPECT_TRUE(h1 == h2);
EXPECT_TRUE(h1 == s);
EXPECT_TRUE(s == h1);
#if __cpp_lib_starts_ends_with >= 201711L
EXPECT_TRUE(h1.starts_with("he"));
EXPECT_TRUE(h1.ends_with("lo"));
Expand Down
Loading