Skip to content

Instantly share code, notes, and snippets.

@klemens-morgenstern
Created May 11, 2022 03:03

Revisions

  1. klemens-morgenstern created this gist May 11, 2022.
    202 changes: 202 additions & 0 deletions cstring_view.hpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,202 @@
    //
    // boost/utility/cstring_view.hpp
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // Copyright (c) 2022 Klemens D. Morgenstern
    // (klemens dot morgenstern at gmx dot net)
    //
    // Distributed under the Boost Software License, Version 1.0. (See accompanying
    // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
    //
    #ifndef BOOST_UTILITY_CSTRING_VIEW_HPP
    #define BOOST_UTILITY_CSTRING_VIEW_HPP

    #include <boost/core/detail/string_view.hpp>
    #include <type_traits>
    #include <limits>

    namespace boost
    {


    //based on http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1402r0.pdf
    ///cstring_view is simply a forwarding adapter around string_view.
    /** Operations are delegated to a private member string_view, with some minor modifications
    to the interface to maintain the null-terminated class invariant. */
    template<typename CharT, typename Traits = std::char_traits<CharT>>
    struct basic_cstring_view
    {
    using value_type = CharT;
    using traits_type = Traits;

    BOOST_CONSTEXPR basic_cstring_view() : view_(null_char_(value_type{})) {};
    BOOST_CONSTEXPR basic_cstring_view(std::nullptr_t) = delete;

    BOOST_CONSTEXPR basic_cstring_view( const value_type* s ) : view_(s) {}

    template<typename Source,
    typename =
    typename std::enable_if<
    std::is_same<const value_type,
    typename std::remove_pointer<decltype(std::declval<Source>().c_str())>::type
    >::value>::type>
    BOOST_CONSTEXPR basic_cstring_view(Source && src) : view_(src.c_str()) {}

    BOOST_CONSTEXPR typename std::basic_string_view<value_type, Traits>::const_pointer c_str() const BOOST_NOEXCEPT
    {
    return this->data();
    }

    using string_view_type = basic_string_view<value_type, Traits>;
    operator string_view_type() const {return view_;}

    using pointer = CharT *;
    using const_pointer = const CharT *;
    using reference = CharT &;
    using const_reference = const CharT &;
    using const_iterator = const_pointer;
    using iterator = const_iterator;
    using const_reverse_iterator = typename std::reverse_iterator<const_iterator>;
    using reverse_iterator = typename std::reverse_iterator<iterator>;
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;

    static BOOST_CONSTEXPR size_type npos = -1;

    BOOST_CONSTEXPR const_iterator begin() const BOOST_NOEXCEPT {return view_;};
    BOOST_CONSTEXPR const_iterator end() const BOOST_NOEXCEPT {return view_ + length();};
    BOOST_CONSTEXPR const_iterator cbegin() const BOOST_NOEXCEPT {return view_;};
    BOOST_CONSTEXPR const_iterator cend() const BOOST_NOEXCEPT {return view_ + length();};
    BOOST_CONSTEXPR const_reverse_iterator rbegin() const BOOST_NOEXCEPT {return std::make_reverse_iterator(view_ + length());};
    BOOST_CONSTEXPR const_reverse_iterator rend() const BOOST_NOEXCEPT {return std::make_reverse_iterator(view_);};
    BOOST_CONSTEXPR const_reverse_iterator crbegin() const BOOST_NOEXCEPT {return std::make_reverse_iterator(view_ + length());};
    BOOST_CONSTEXPR const_reverse_iterator crend() const BOOST_NOEXCEPT {return std::make_reverse_iterator(view_);};

    BOOST_CONSTEXPR size_type size() const BOOST_NOEXCEPT {return length(); }
    BOOST_CONSTEXPR size_type length() const BOOST_NOEXCEPT {return traits_type::length(view_); }
    BOOST_CONSTEXPR size_type max_size() const BOOST_NOEXCEPT {return std::numeric_limits<int64_t>::max() / sizeof(CharT); }
    BOOST_ATTRIBUTE_NODISCARD BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT {return *view_ == *null_char_(CharT{}); }

    BOOST_CONSTEXPR const_reference operator[](size_type pos) const {return view_[pos] ;}
    BOOST_CONSTEXPR const_reference at(size_type pos) const
    {
    if (pos >= size())
    throw std::out_of_range("cstring-view out of range");
    return view_[pos];
    }
    BOOST_CONSTEXPR const_reference front() const {return *view_;}
    BOOST_CONSTEXPR const_reference back() const {return view_[length() - 1];}
    BOOST_CONSTEXPR const_pointer data() const BOOST_NOEXCEPT {return view_;}
    BOOST_CONSTEXPR void remove_prefix(size_type n) {view_ = view_ + n;}
    BOOST_CONSTEXPR void swap(basic_cstring_view& s) BOOST_NOEXCEPT {std::swap(view_, s.view_);}

    BOOST_CONSTEXPR size_type copy(value_type* s, size_type n, size_type pos = 0) const
    {
    return traits_type::copy(s, view_ + pos, n) - view_;
    }
    BOOST_CONSTEXPR basic_cstring_view substr(size_type pos = 0) const
    {
    return basic_cstring_view(view_ + pos);
    }
    BOOST_CONSTEXPR string_view_type substr(size_type pos , size_type n) const {return string_view_type(view_+ pos, n);}

    BOOST_CONSTEXPR int compare(string_view_type s) const BOOST_NOEXCEPT
    {
    return traits_type::compare(view_, s.data(), std::min(length(), s.length()));
    }
    BOOST_CONSTEXPR int compare(size_type pos1, size_type n1, string_view_type s) const
    {
    return traits_type::compare(view_ + pos1, s.data(), std::min(n1, s.length()));
    }

    BOOST_CONSTEXPR int compare(size_type pos1, size_type n1, string_view_type s, size_type pos2, size_type n2) const
    {
    return traits_type::compare(view_ + pos1, s.data() + pos2, std::min(n1, n2));
    }

    #if (__cplusplus >= 202002)
    BOOST_CONSTEXPR bool starts_with(string_view_type x) const BOOST_NOEXCEPT
    {
    return std::equal(view_, view_ + x.size(), x.begin(), x.end(), &traits_type::eq);
    }
    BOOST_CONSTEXPR bool starts_with(value_type x) const BOOST_NOEXCEPT
    {
    return traits_type::eq(view_[0], x);
    }
    BOOST_CONSTEXPR bool ends_with(string_view_type x) const BOOST_NOEXCEPT
    {
    return std::equal(view_ + x.size() - length(), view_ + length(), x.begin(), x.end(), &traits_type::eq);
    }
    BOOST_CONSTEXPR bool ends_with(value_type x) const BOOST_NOEXCEPT
    {
    return !empty() && traits_type::eq(view_[length() - 1], x);
    }
    #endif

    BOOST_CONSTEXPR size_type find(basic_cstring_view s, size_type pos = 0) const BOOST_NOEXCEPT
    {
    const auto e = end();
    const auto itr = std::search(begin(), e, s.begin(), s.end(), &traits_type::eq);
    return (itr != e) ? (itr - begin()) : npos;
    }
    BOOST_CONSTEXPR size_type find(value_type c, size_type pos = 0) const BOOST_NOEXCEPT
    {
    const auto e = end();
    const auto itr = std::find_if(begin(), e, [c](value_type cc) {return traits_type::eq(c, cc);});
    return (itr != e) ? (itr - begin()) : npos;
    }

    BOOST_CONSTEXPR size_type rfind(basic_cstring_view s, size_type pos = npos) const BOOST_NOEXCEPT
    {
    const auto b = rbegin();
    const auto itr = std::search(b, rend(), s.rbegin(), s.rend(), &traits_type::eq);
    return (itr != rend()) ? (itr - b) : npos;
    }
    BOOST_CONSTEXPR size_type rfind(value_type c, size_type pos = npos) const BOOST_NOEXCEPT
    {
    const auto b = rbegin();
    const auto itr = std::find_if(b, rend(), [c](value_type cc) {return traits_type::eq(c, cc);});
    return (itr != rend()) ? (itr - b) : npos;
    }


    friend BOOST_CONSTEXPR bool operator==(basic_cstring_view x, basic_cstring_view y) BOOST_NOEXCEPT {return x.compare(y) == 0;}
    friend BOOST_CONSTEXPR bool operator!=(basic_cstring_view x, basic_cstring_view y) BOOST_NOEXCEPT {return x.compare(y) != 0;}
    friend BOOST_CONSTEXPR bool operator< (basic_cstring_view x, basic_cstring_view y) BOOST_NOEXCEPT {return x.compare(y) < 0;}
    friend BOOST_CONSTEXPR bool operator> (basic_cstring_view x, basic_cstring_view y) BOOST_NOEXCEPT {return x.compare(y) > 0;}
    friend BOOST_CONSTEXPR bool operator<=(basic_cstring_view x, basic_cstring_view y) BOOST_NOEXCEPT {return x.compare(y) <= 0;}
    friend BOOST_CONSTEXPR bool operator>=(basic_cstring_view x, basic_cstring_view y) BOOST_NOEXCEPT {return x.compare(y) >= 0;}

    private:
    friend struct std::hash<basic_cstring_view>;
    BOOST_CONSTEXPR static const_pointer null_char_() {return null_char_(CharT{});}
    BOOST_CONSTEXPR static const char* null_char_(char) {return "\0";}
    BOOST_CONSTEXPR static const wchar_t* null_char_(wchar_t) {return L"\0";}
    BOOST_CONSTEXPR static const char16_t* null_char_(char16_t) {return u"\0";}
    BOOST_CONSTEXPR static const char32_t* null_char_(char32_t) {return U"\0";}
    #if ASIO_HAS_CHAR8_T
    BOOST_CONSTEXPR static const char8_t* null_char_(char8_t) {return u8"\0";}
    #endif

    const_pointer view_;
    };

    using cstring_view = basic_cstring_view<char>;
    using wcstring_view = basic_cstring_view<wchar_t>;

    #if !defined(BOOST_NO_CXX11_CHAR16_T)
    using u16cstring_view = basic_cstring_view<char16_t>;
    #endif

    #if !defined(BOOST_NO_CXX11_CHAR32_T)
    using u32cstring_view = basic_cstring_view<char32_t>;
    #endif

    #if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
    using u8cstring_view = basic_cstring_view<char8_t>;
    #endif

    }


    #endif //BOOST_UTILITY_CSTRING_VIEW_HPP