libshit

Just some random shit
git clone https://git.neptards.moe/neptards/libshit.git
Log | Files | Refs | Submodules | README | LICENSE

string_view (11436B)


      1 // -*- c++ -*-
      2 #pragma once
      3 
      4 #include <libshit/assert.hpp>
      5 
      6 #include <algorithm> // std::min
      7 #include <cstddef>
      8 #include <iosfwd>
      9 #include <iterator>
     10 #include <limits>
     11 #include <stdexcept>
     12 #include <type_traits>
     13 
     14 namespace std
     15 {
     16 
     17   template <typename Char, typename Traits>
     18   class basic_string_view
     19   {
     20   public:
     21     using traits_type = Traits;
     22     using value_type = Char;
     23     using pointer = Char*;
     24     using const_pointer = const Char*;
     25     using reference = Char&;
     26     using const_reference = const Char&;
     27     using const_iterator = const Char*;
     28     using iterator = const_iterator;
     29     using const_reverse_iterator = reverse_iterator<const_iterator>;
     30     using reverse_iterator = const_reverse_iterator;
     31     using size_type = size_t;
     32     using difference_type = ptrdiff_t;
     33 
     34     using unsigned_value_type = make_unsigned_t<Char>;
     35     using unsigned_pointer = unsigned_value_type*;
     36     using unsigned_const_pointer = const unsigned_value_type*;
     37     using unsigned_reference = unsigned_value_type&;
     38     using unsigned_const_reference = const unsigned_value_type&;
     39 
     40     static constexpr const size_type npos = numeric_limits<size_type>::max();
     41 
     42     constexpr basic_string_view() noexcept : str{nullptr}, len{0} {}
     43 
     44     constexpr basic_string_view(const_pointer str) noexcept
     45       : str{str}, len{str ? Traits::length(str) : 0} {}
     46 
     47     basic_string_view(unsigned_const_pointer str) noexcept
     48       : basic_string_view{reinterpret_cast<const_pointer>(str)} {}
     49 
     50     constexpr basic_string_view(
     51       const_pointer str, size_type len) noexcept
     52       : str{str}, len{len}
     53     { LIBSHIT_ASSERT(str != nullptr || len == 0); }
     54 
     55     constexpr basic_string_view(
     56       unsigned_const_pointer str, size_type len) noexcept
     57       : basic_string_view{reinterpret_cast<const_pointer>(str), len} {}
     58 
     59     template <typename Allocator>
     60     basic_string_view(
     61       const basic_string<Char, Traits, Allocator>& str) noexcept
     62       : str{str.c_str()}, len{str.size()} {}
     63 
     64     template <size_t N>
     65     constexpr basic_string_view(const Char (&str)[N]) noexcept
     66       : str{str}, len{N-1} {}
     67 
     68     constexpr const_iterator  begin() const noexcept { return str; }
     69     constexpr const_iterator cbegin() const noexcept { return str; }
     70     constexpr const_iterator  end() const noexcept { return str+len; }
     71     constexpr const_iterator cend() const noexcept { return str+len; }
     72 
     73     constexpr const_reverse_iterator  rbegin() const noexcept
     74     { return const_reverse_iterator{end()}; }
     75     constexpr const_reverse_iterator crbegin() const noexcept
     76     { return const_reverse_iterator{end()}; }
     77     constexpr const_reverse_iterator  rend() const noexcept
     78     { return const_reverse_iterator{begin()}; }
     79     constexpr const_reverse_iterator crend() const noexcept
     80     { return const_reverse_iterator{begin()}; }
     81 
     82     constexpr const_reference operator[](size_type i) const noexcept
     83     {
     84       LIBSHIT_ASSERT(i < len);
     85       return str[i];
     86     }
     87     constexpr const_reference at(size_type i) const
     88     {
     89       if (i >= len)
     90         throw out_of_range("NonowningString");
     91       return str[i];
     92     }
     93 
     94     // undefined if string is empty
     95     constexpr const_reference front() const noexcept
     96     { LIBSHIT_ASSERT(len); return str[0]; }
     97     constexpr const_reference back() const noexcept
     98     { LIBSHIT_ASSERT(len); return str[len-1]; }
     99 
    100     // can return nullptr or pointer to '\0' in case of empty string
    101     constexpr const_pointer data() const noexcept { return str; }
    102 
    103     constexpr size_type size() const noexcept { return len; }
    104     constexpr size_type length() const noexcept { return len; }
    105     constexpr size_type max_size() const noexcept
    106     { return numeric_limits<size_type>::max(); }
    107     constexpr bool empty() const noexcept { return len == 0; }
    108 
    109     constexpr void remove_prefix(size_type n) noexcept
    110     { LIBSHIT_ASSERT(len >= n); str += n; len -= n; }
    111 
    112     constexpr void remove_suffix(size_type n) noexcept
    113     { LIBSHIT_ASSERT(len >= n); len -= n; }
    114 
    115     constexpr void swap(basic_string_view& o) noexcept
    116     {
    117       swap(str, o.str);
    118       swap(len, o.len);
    119     }
    120 
    121     // todo: does this solve the missing std::string ctor problem?
    122     template <typename Allocator>
    123     operator basic_string<Char, Traits, Allocator>() const
    124     { return {str, len}; }
    125 
    126     // copy, *find*: too lazy
    127     constexpr basic_string_view substr(
    128       size_type pos, size_type n = npos) const noexcept
    129     {
    130       LIBSHIT_ASSERT(pos <= len);
    131       return {str+pos, min(n, len-pos)};
    132     }
    133 
    134     // search functions
    135     constexpr size_type find(
    136       basic_string_view o, size_type pos = 0) const noexcept
    137     {
    138       if (pos >= len || pos + o.size() > len) return npos;
    139       for (; pos <= len - o.len; ++pos)
    140         if (!Traits::compare(str + pos, o.str, o.len))
    141           return pos;
    142       return npos;
    143     }
    144     constexpr size_type find(Char ch, size_type pos = 0) const noexcept
    145     {
    146       for (; pos < len; ++pos)
    147         if (Traits::eq(str[pos], ch)) return pos;
    148       return npos;
    149     }
    150     constexpr size_type find(const Char* s, size_type pos, size_type count) const
    151     { return find(basic_string_view(s, count), pos); }
    152     constexpr size_type find(const Char* s, size_type pos = 0) const
    153     { return find(basic_string_view(s), pos); }
    154 
    155 
    156     constexpr size_type rfind(
    157       basic_string_view o, size_type pos = npos) const noexcept
    158     {
    159       if (o.size() > len) return npos;
    160       if (pos > len - o.len) pos = len - o.len;
    161       while (true)
    162       {
    163         if (!Traits::compare(str + pos, o.str, o.len))
    164           return pos;
    165         if (pos == 0) return npos;
    166         --pos;
    167       }
    168     }
    169     constexpr size_type rfind(Char ch, size_type pos = npos) const noexcept
    170     {
    171       if (pos > len-1) pos = len-1;
    172       while (true)
    173       {
    174         if (Traits::eq(str[pos], ch)) return pos;
    175         if (pos == 0) return npos;
    176         --pos;
    177       }
    178     }
    179     constexpr size_type rfind(const Char* s, size_type pos, size_type count) const
    180     { return rfind(basic_string_view(s, count), pos); }
    181     constexpr size_type rfind(const Char* s, size_type pos = npos) const
    182     { return rfind(basic_string_view(s), pos); }
    183 
    184 
    185     constexpr size_type find_first_of(
    186       basic_string_view o, size_type pos = 0) const noexcept
    187     {
    188       if (pos >= len || o.len == 0) return npos;
    189       for (; pos < len; ++pos)
    190         for (size_t i = 0; i < o.len; ++i)
    191           if (Traits::eq(str[pos], o.str[i]))
    192             return pos;
    193       return npos;
    194     }
    195     constexpr size_type find_first_of(Char ch, size_type pos = 0) const noexcept
    196     { return find(ch, pos); }
    197     constexpr size_type find_first_of(const Char* s, size_type pos, size_type count) const
    198     { return find_first_of(basic_string_view(s, count), pos); }
    199     constexpr size_type find_first_of(const Char* s, size_type pos = 0) const
    200     { return find_first_of(basic_string_view(s), pos); }
    201 
    202 
    203     constexpr size_type find_last_of(
    204       basic_string_view o, size_type pos = npos) const noexcept
    205     {
    206       if (o.len == 0) return npos;
    207       if (pos > len-1) pos = len-1;
    208       while (true)
    209       {
    210         for (size_t i = 0; i < o.len; ++i)
    211           if (Traits::eq(str[pos], o.str[i]))
    212             return pos;
    213         if (pos == 0) return npos;
    214         --pos;
    215       }
    216     }
    217     constexpr size_type find_last_of(Char ch, size_type pos = npos) const noexcept
    218     { return rfind(ch, pos); }
    219     constexpr size_type find_last_of(const Char* s, size_type pos, size_type count) const
    220     { return find_last_of(basic_string_view(s, count), pos); }
    221     constexpr size_type find_last_of(const Char* s, size_type pos = npos) const
    222     { return find_last_of(basic_string_view(s), pos); }
    223 
    224 
    225     constexpr size_type find_first_not_of(
    226       basic_string_view o, size_type pos = 0) const noexcept
    227     {
    228       if (pos >= len || o.len == 0) return npos;
    229       for (; pos < len; ++pos)
    230       {
    231         bool found = false;
    232         for (size_t i = 0; i < o.len; ++i)
    233           if (Traits::eq(str[pos], o.str[i]))
    234           { found = true; break; } // can't goto in constexpr :'(
    235         if (!found) return pos;
    236       }
    237       return npos;
    238     }
    239     constexpr size_type find_first_not_of(Char ch, size_type pos = 0) const noexcept
    240     {
    241       for (; pos < len; ++pos)
    242         if (!Traits::eq(str[pos], ch)) return pos;
    243       return npos;
    244     }
    245     constexpr size_type find_first_not_of(const Char* s, size_type pos, size_type count) const
    246     { return find_first_not_of(basic_string_view(s, count), pos); }
    247     constexpr size_type find_first_not_of(const Char* s, size_type pos = 0) const
    248     { return find_first_not_of(basic_string_view(s), pos); }
    249 
    250 
    251     constexpr size_type find_last_not_of(
    252       basic_string_view o, size_type pos = npos) const noexcept
    253     {
    254       if (o.len == 0) return npos;
    255       if (pos > len-1) pos = len-1;
    256       while (true)
    257       {
    258         bool found = false;
    259         for (size_t i = 0; i < o.len; ++i)
    260           if (Traits::eq(str[pos], o.str[i]))
    261           { found = true; break; } // can't goto in constexpr :'(
    262         if (!found) return pos;
    263         if (pos == 0) return npos;
    264         --pos;
    265       }
    266     }
    267     constexpr size_type find_last_not_of(Char ch, size_type pos = npos) const noexcept
    268     {
    269       if (pos > len-1) pos = len-1;
    270       while (true)
    271       {
    272         if (!Traits::eq(str[pos], ch)) return pos;
    273         if (pos == 0) return npos;
    274         --pos;
    275       }
    276     }
    277     constexpr size_type find_last_not_of(const Char* s, size_type pos, size_type count) const
    278     { return find_last_not_of(basic_string_view(s, count), pos); }
    279     constexpr size_type find_last_not_of(const Char* s, size_type pos = npos) const
    280     { return find_last_not_of(basic_string_view(s), pos); }
    281 
    282 
    283     constexpr int compare(basic_string_view o) const noexcept
    284     {
    285       auto cmp = Traits::compare(str, o.str, min(len, o.len));
    286       if (cmp == 0) cmp = (len == o.len ? 0 : (len < o.len ? -1 : 1));
    287       return cmp;
    288     }
    289     // too lazy for the other overloads
    290 
    291     constexpr bool operator==(basic_string_view o) const noexcept
    292     {
    293       return len == o.len &&
    294         (str == o.str || Traits::compare(str, o.str, len) == 0);
    295     }
    296     constexpr bool operator!=(basic_string_view o) const noexcept
    297     { return !(*this == o); }
    298 
    299 #define X_GEN_OP(op)                                               \
    300     constexpr bool operator op(basic_string_view o) const noexcept \
    301     { return compare(o) op 0; }
    302     X_GEN_OP(<) X_GEN_OP(<=) X_GEN_OP(>) X_GEN_OP(>=)
    303 #undef X_GEN_OP
    304 
    305   private:
    306     const_pointer str;
    307     size_type len;
    308   };
    309 
    310 #define X_GEN_OP(op)                                            \
    311   template <typename Char, typename Traits, typename Allocator> \
    312   inline bool operator op(                                      \
    313     const basic_string<Char, Traits, Allocator>& lhs,           \
    314     basic_string_view<Char, Traits> rhs)                        \
    315   {                                                             \
    316     return basic_string_view<Char, Traits>{lhs} op rhs;         \
    317   }
    318   X_GEN_OP(==)
    319   X_GEN_OP(!=)
    320   X_GEN_OP(<)
    321   X_GEN_OP(<=)
    322   X_GEN_OP(>)
    323   X_GEN_OP(>=)
    324 #undef X_GEN_OP
    325 
    326   using string_view = basic_string_view<char>;
    327   using wstring_view = basic_string_view<wchar_t>;
    328   using u16string_view = basic_string_view<char16_t>;
    329   using u32string_view = basic_string_view<char32_t>;
    330 
    331   template <typename T, typename U>
    332   inline basic_ostream<T>& operator<<(
    333     basic_ostream<T>& os, basic_string_view<T, U> s)
    334   {
    335     os.write(s.data(), s.size());
    336     return os;
    337   }
    338 
    339 }