1aa59c981SGuillaume Chatelet //===-- Standalone implementation std::string_view --------------*- C++ -*-===// 2aa59c981SGuillaume Chatelet // 3aa59c981SGuillaume Chatelet // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4aa59c981SGuillaume Chatelet // See https://llvm.org/LICENSE.txt for license information. 5aa59c981SGuillaume Chatelet // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6aa59c981SGuillaume Chatelet // 7aa59c981SGuillaume Chatelet //===----------------------------------------------------------------------===// 8aa59c981SGuillaume Chatelet 9270547f3SGuillaume Chatelet #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_STRING_VIEW_H 10270547f3SGuillaume Chatelet #define LLVM_LIBC_SRC___SUPPORT_CPP_STRING_VIEW_H 11aa59c981SGuillaume Chatelet 1205d9cc47SSiva Chandra Reddy #include "src/__support/common.h" 135ff3ff33SPetr Hosek #include "src/__support/macros/config.h" 1405d9cc47SSiva Chandra Reddy 15aa59c981SGuillaume Chatelet #include <stddef.h> 16aa59c981SGuillaume Chatelet 175ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL { 18aa59c981SGuillaume Chatelet namespace cpp { 19aa59c981SGuillaume Chatelet 20aa59c981SGuillaume Chatelet // This is very simple alternate of the std::string_view class. There is no 21aa59c981SGuillaume Chatelet // bounds check performed in any of the methods. The callers are expected to 22aa59c981SGuillaume Chatelet // do the checks before invoking the methods. 23aa59c981SGuillaume Chatelet // 24aa59c981SGuillaume Chatelet // This class will be extended as needed in future. 25aa59c981SGuillaume Chatelet class string_view { 26aa59c981SGuillaume Chatelet private: 27aa59c981SGuillaume Chatelet const char *Data; 28aa59c981SGuillaume Chatelet size_t Len; 29aa59c981SGuillaume Chatelet 30019a477cSRoland McGrath LIBC_INLINE static size_t min(size_t A, size_t B) { return A <= B ? A : B; } 31aa59c981SGuillaume Chatelet 3205d9cc47SSiva Chandra Reddy LIBC_INLINE static int compareMemory(const char *Lhs, const char *Rhs, 3305d9cc47SSiva Chandra Reddy size_t Length) { 34*111b062fSShourya Goel for (size_t i = 0; i < Length; ++i) 35*111b062fSShourya Goel if (int Diff = (int)Lhs[i] - (int)Rhs[i]) 36aa59c981SGuillaume Chatelet return Diff; 37aa59c981SGuillaume Chatelet return 0; 38aa59c981SGuillaume Chatelet } 39aa59c981SGuillaume Chatelet 4005d9cc47SSiva Chandra Reddy LIBC_INLINE static constexpr size_t length(const char *Str) { 411e5b3ce7SGuillaume Chatelet for (const char *End = Str;; ++End) 421e5b3ce7SGuillaume Chatelet if (*End == '\0') 431e5b3ce7SGuillaume Chatelet return End - Str; 441e5b3ce7SGuillaume Chatelet } 451e5b3ce7SGuillaume Chatelet 4605d9cc47SSiva Chandra Reddy LIBC_INLINE bool equals(string_view Other) const { 471e5b3ce7SGuillaume Chatelet return (Len == Other.Len && 481e5b3ce7SGuillaume Chatelet compareMemory(Data, Other.Data, Other.Len) == 0); 491e5b3ce7SGuillaume Chatelet } 501e5b3ce7SGuillaume Chatelet 51aa59c981SGuillaume Chatelet public: 521e5b3ce7SGuillaume Chatelet using value_type = char; 531e5b3ce7SGuillaume Chatelet using size_type = size_t; 541e5b3ce7SGuillaume Chatelet using difference_type = ptrdiff_t; 551e5b3ce7SGuillaume Chatelet using pointer = char *; 561e5b3ce7SGuillaume Chatelet using const_pointer = const char *; 571e5b3ce7SGuillaume Chatelet using reference = char &; 581e5b3ce7SGuillaume Chatelet using const_reference = const char &; 591e5b3ce7SGuillaume Chatelet using const_iterator = char *; 601e5b3ce7SGuillaume Chatelet using iterator = const_iterator; 611e5b3ce7SGuillaume Chatelet 62aa59c981SGuillaume Chatelet // special value equal to the maximum value representable by the type 63aa59c981SGuillaume Chatelet // size_type. 645bf8efd2SRoland McGrath LIBC_INLINE_VAR static constexpr size_t npos = -1; 65aa59c981SGuillaume Chatelet 6605d9cc47SSiva Chandra Reddy LIBC_INLINE constexpr string_view() : Data(nullptr), Len(0) {} 67aa59c981SGuillaume Chatelet 68aa59c981SGuillaume Chatelet // Assumes Str is a null-terminated string. The length of the string does 69aa59c981SGuillaume Chatelet // not include the terminating null character. 701e5b3ce7SGuillaume Chatelet // Preconditions: [Str, Str + length(Str)) is a valid range. 7105d9cc47SSiva Chandra Reddy LIBC_INLINE constexpr string_view(const char *Str) 7205d9cc47SSiva Chandra Reddy : Data(Str), Len(length(Str)) {} 73aa59c981SGuillaume Chatelet 741e5b3ce7SGuillaume Chatelet // Preconditions: [Str, Str + N) is a valid range. 7505d9cc47SSiva Chandra Reddy LIBC_INLINE constexpr string_view(const char *Str, size_t N) 7605d9cc47SSiva Chandra Reddy : Data(Str), Len(N) {} 77aa59c981SGuillaume Chatelet 7805d9cc47SSiva Chandra Reddy LIBC_INLINE constexpr const char *data() const { return Data; } 79aa59c981SGuillaume Chatelet 80aa59c981SGuillaume Chatelet // Returns the size of the string_view. 8105d9cc47SSiva Chandra Reddy LIBC_INLINE constexpr size_t size() const { return Len; } 82aa59c981SGuillaume Chatelet 83aa59c981SGuillaume Chatelet // Returns whether the string_view is empty. 8405d9cc47SSiva Chandra Reddy LIBC_INLINE constexpr bool empty() const { return Len == 0; } 85aa59c981SGuillaume Chatelet 86aa59c981SGuillaume Chatelet // Returns an iterator to the first character of the view. 8705d9cc47SSiva Chandra Reddy LIBC_INLINE const char *begin() const { return Data; } 88aa59c981SGuillaume Chatelet 89aa59c981SGuillaume Chatelet // Returns an iterator to the character following the last character of the 90aa59c981SGuillaume Chatelet // view. 9105d9cc47SSiva Chandra Reddy LIBC_INLINE const char *end() const { return Data + Len; } 92aa59c981SGuillaume Chatelet 93aa59c981SGuillaume Chatelet // Returns a const reference to the character at specified location pos. 94aa59c981SGuillaume Chatelet // No bounds checking is performed: the behavior is undefined if pos >= 95aa59c981SGuillaume Chatelet // size(). 9605d9cc47SSiva Chandra Reddy LIBC_INLINE constexpr const char &operator[](size_t Index) const { 9705d9cc47SSiva Chandra Reddy return Data[Index]; 9805d9cc47SSiva Chandra Reddy } 99aa59c981SGuillaume Chatelet 100aa59c981SGuillaume Chatelet /// compare - Compare two strings; the result is -1, 0, or 1 if this string 101aa59c981SGuillaume Chatelet /// is lexicographically less than, equal to, or greater than the \p Other. 10205d9cc47SSiva Chandra Reddy LIBC_INLINE int compare(string_view Other) const { 103aa59c981SGuillaume Chatelet // Check the prefix for a mismatch. 104aa59c981SGuillaume Chatelet if (int Res = compareMemory(Data, Other.Data, min(Len, Other.Len))) 105aa59c981SGuillaume Chatelet return Res < 0 ? -1 : 1; 106aa59c981SGuillaume Chatelet // Otherwise the prefixes match, so we only need to check the lengths. 107aa59c981SGuillaume Chatelet if (Len == Other.Len) 108aa59c981SGuillaume Chatelet return 0; 109aa59c981SGuillaume Chatelet return Len < Other.Len ? -1 : 1; 110aa59c981SGuillaume Chatelet } 111aa59c981SGuillaume Chatelet 11205d9cc47SSiva Chandra Reddy LIBC_INLINE bool operator==(string_view Other) const { return equals(Other); } 11305d9cc47SSiva Chandra Reddy LIBC_INLINE bool operator!=(string_view Other) const { 11405d9cc47SSiva Chandra Reddy return !(*this == Other); 11505d9cc47SSiva Chandra Reddy } 11605d9cc47SSiva Chandra Reddy LIBC_INLINE bool operator<(string_view Other) const { 1171e5b3ce7SGuillaume Chatelet return compare(Other) == -1; 1181e5b3ce7SGuillaume Chatelet } 11905d9cc47SSiva Chandra Reddy LIBC_INLINE bool operator<=(string_view Other) const { 1201e5b3ce7SGuillaume Chatelet return compare(Other) != 1; 1211e5b3ce7SGuillaume Chatelet } 12205d9cc47SSiva Chandra Reddy LIBC_INLINE bool operator>(string_view Other) const { 12305d9cc47SSiva Chandra Reddy return compare(Other) == 1; 12405d9cc47SSiva Chandra Reddy } 12505d9cc47SSiva Chandra Reddy LIBC_INLINE bool operator>=(string_view Other) const { 126aa59c981SGuillaume Chatelet return compare(Other) != -1; 127aa59c981SGuillaume Chatelet } 128aa59c981SGuillaume Chatelet 129aa59c981SGuillaume Chatelet // Moves the start of the view forward by n characters. 130aa59c981SGuillaume Chatelet // The behavior is undefined if n > size(). 13105d9cc47SSiva Chandra Reddy LIBC_INLINE void remove_prefix(size_t N) { 132aa59c981SGuillaume Chatelet Len -= N; 133aa59c981SGuillaume Chatelet Data += N; 134aa59c981SGuillaume Chatelet } 135aa59c981SGuillaume Chatelet 136aa59c981SGuillaume Chatelet // Moves the end of the view back by n characters. 137aa59c981SGuillaume Chatelet // The behavior is undefined if n > size(). 13805d9cc47SSiva Chandra Reddy LIBC_INLINE void remove_suffix(size_t N) { Len -= N; } 139aa59c981SGuillaume Chatelet 140aa59c981SGuillaume Chatelet // Check if this string starts with the given Prefix. 14105d9cc47SSiva Chandra Reddy LIBC_INLINE bool starts_with(string_view Prefix) const { 142aa59c981SGuillaume Chatelet return Len >= Prefix.Len && 143aa59c981SGuillaume Chatelet compareMemory(Data, Prefix.Data, Prefix.Len) == 0; 144aa59c981SGuillaume Chatelet } 145aa59c981SGuillaume Chatelet 146aa59c981SGuillaume Chatelet // Check if this string starts with the given Prefix. 14705d9cc47SSiva Chandra Reddy LIBC_INLINE bool starts_with(const char Prefix) const { 148aa59c981SGuillaume Chatelet return !empty() && front() == Prefix; 149aa59c981SGuillaume Chatelet } 150aa59c981SGuillaume Chatelet 151aa59c981SGuillaume Chatelet // Check if this string ends with the given Prefix. 15205d9cc47SSiva Chandra Reddy LIBC_INLINE bool ends_with(const char Suffix) const { 153aa59c981SGuillaume Chatelet return !empty() && back() == Suffix; 154aa59c981SGuillaume Chatelet } 155aa59c981SGuillaume Chatelet 156aa59c981SGuillaume Chatelet // Check if this string ends with the given Suffix. 15705d9cc47SSiva Chandra Reddy LIBC_INLINE bool ends_with(string_view Suffix) const { 158aa59c981SGuillaume Chatelet return Len >= Suffix.Len && 159aa59c981SGuillaume Chatelet compareMemory(end() - Suffix.Len, Suffix.Data, Suffix.Len) == 0; 160aa59c981SGuillaume Chatelet } 161aa59c981SGuillaume Chatelet 162aa59c981SGuillaume Chatelet // Return a reference to the substring from [Start, Start + N). 163aa59c981SGuillaume Chatelet // 164aa59c981SGuillaume Chatelet // Start The index of the starting character in the substring; if the index is 165aa59c981SGuillaume Chatelet // npos or greater than the length of the string then the empty substring will 166aa59c981SGuillaume Chatelet // be returned. 167aa59c981SGuillaume Chatelet // 168aa59c981SGuillaume Chatelet // N The number of characters to included in the substring. If N exceeds the 169aa59c981SGuillaume Chatelet // number of characters remaining in the string, the string suffix (starting 170aa59c981SGuillaume Chatelet // with Start) will be returned. 17105d9cc47SSiva Chandra Reddy LIBC_INLINE string_view substr(size_t Start, size_t N = npos) const { 172aa59c981SGuillaume Chatelet Start = min(Start, Len); 173aa59c981SGuillaume Chatelet return string_view(Data + Start, min(N, Len - Start)); 174aa59c981SGuillaume Chatelet } 175aa59c981SGuillaume Chatelet 176aa59c981SGuillaume Chatelet // front - Get the first character in the string. 17705d9cc47SSiva Chandra Reddy LIBC_INLINE char front() const { return Data[0]; } 178aa59c981SGuillaume Chatelet 179aa59c981SGuillaume Chatelet // back - Get the last character in the string. 18005d9cc47SSiva Chandra Reddy LIBC_INLINE char back() const { return Data[Len - 1]; } 181aa59c981SGuillaume Chatelet 1821e5b3ce7SGuillaume Chatelet // Finds the first occurence of c in this view, starting at position From. 183f6f42af0SSchrodinger ZHU Yifan LIBC_INLINE constexpr size_t find_first_of(const char c, 184f6f42af0SSchrodinger ZHU Yifan size_t From = 0) const { 1851e5b3ce7SGuillaume Chatelet for (size_t Pos = From; Pos < size(); ++Pos) 1861e5b3ce7SGuillaume Chatelet if ((*this)[Pos] == c) 1871e5b3ce7SGuillaume Chatelet return Pos; 1881e5b3ce7SGuillaume Chatelet return npos; 189aa59c981SGuillaume Chatelet } 190aa59c981SGuillaume Chatelet 1911e5b3ce7SGuillaume Chatelet // Finds the last occurence of c in this view, ending at position End. 192f6f42af0SSchrodinger ZHU Yifan LIBC_INLINE constexpr size_t find_last_of(const char c, 193f6f42af0SSchrodinger ZHU Yifan size_t End = npos) const { 1941e5b3ce7SGuillaume Chatelet End = End >= size() ? size() : End + 1; 1951e5b3ce7SGuillaume Chatelet for (; End > 0; --End) 1961e5b3ce7SGuillaume Chatelet if ((*this)[End - 1] == c) 1971e5b3ce7SGuillaume Chatelet return End - 1; 1981e5b3ce7SGuillaume Chatelet return npos; 199aa59c981SGuillaume Chatelet } 200f6f42af0SSchrodinger ZHU Yifan 201f6f42af0SSchrodinger ZHU Yifan // Finds the first character not equal to c in this view, starting at position 202f6f42af0SSchrodinger ZHU Yifan // From. 203f6f42af0SSchrodinger ZHU Yifan LIBC_INLINE constexpr size_t find_first_not_of(const char c, 204f6f42af0SSchrodinger ZHU Yifan size_t From = 0) const { 205f6f42af0SSchrodinger ZHU Yifan for (size_t Pos = From; Pos < size(); ++Pos) 206f6f42af0SSchrodinger ZHU Yifan if ((*this)[Pos] != c) 207f6f42af0SSchrodinger ZHU Yifan return Pos; 208f6f42af0SSchrodinger ZHU Yifan return npos; 209f6f42af0SSchrodinger ZHU Yifan } 210f6f42af0SSchrodinger ZHU Yifan 211f6f42af0SSchrodinger ZHU Yifan // Check if this view contains the given character. 212f6f42af0SSchrodinger ZHU Yifan LIBC_INLINE constexpr bool contains(char c) const { 213f6f42af0SSchrodinger ZHU Yifan return find_first_of(c) != npos; 214f6f42af0SSchrodinger ZHU Yifan } 215aa59c981SGuillaume Chatelet }; 216aa59c981SGuillaume Chatelet 217aa59c981SGuillaume Chatelet } // namespace cpp 2185ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL 219aa59c981SGuillaume Chatelet 220270547f3SGuillaume Chatelet #endif // LLVM_LIBC_SRC___SUPPORT_CPP_STRING_VIEW_H 221