//===-- Standalone implementation std::string_view --------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_STRING_VIEW_H #define LLVM_LIBC_SRC___SUPPORT_CPP_STRING_VIEW_H #include "src/__support/common.h" #include "src/__support/macros/config.h" #include namespace LIBC_NAMESPACE_DECL { namespace cpp { // This is very simple alternate of the std::string_view class. There is no // bounds check performed in any of the methods. The callers are expected to // do the checks before invoking the methods. // // This class will be extended as needed in future. class string_view { private: const char *Data; size_t Len; LIBC_INLINE static size_t min(size_t A, size_t B) { return A <= B ? A : B; } LIBC_INLINE static int compareMemory(const char *Lhs, const char *Rhs, size_t Length) { for (size_t i = 0; i < Length; ++i) if (int Diff = (int)Lhs[i] - (int)Rhs[i]) return Diff; return 0; } LIBC_INLINE static constexpr size_t length(const char *Str) { for (const char *End = Str;; ++End) if (*End == '\0') return End - Str; } LIBC_INLINE bool equals(string_view Other) const { return (Len == Other.Len && compareMemory(Data, Other.Data, Other.Len) == 0); } public: using value_type = char; using size_type = size_t; using difference_type = ptrdiff_t; using pointer = char *; using const_pointer = const char *; using reference = char &; using const_reference = const char &; using const_iterator = char *; using iterator = const_iterator; // special value equal to the maximum value representable by the type // size_type. LIBC_INLINE_VAR static constexpr size_t npos = -1; LIBC_INLINE constexpr string_view() : Data(nullptr), Len(0) {} // Assumes Str is a null-terminated string. The length of the string does // not include the terminating null character. // Preconditions: [Str, Str + ​length(Str)) is a valid range. LIBC_INLINE constexpr string_view(const char *Str) : Data(Str), Len(length(Str)) {} // Preconditions: [Str, Str + N) is a valid range. LIBC_INLINE constexpr string_view(const char *Str, size_t N) : Data(Str), Len(N) {} LIBC_INLINE constexpr const char *data() const { return Data; } // Returns the size of the string_view. LIBC_INLINE constexpr size_t size() const { return Len; } // Returns whether the string_view is empty. LIBC_INLINE constexpr bool empty() const { return Len == 0; } // Returns an iterator to the first character of the view. LIBC_INLINE const char *begin() const { return Data; } // Returns an iterator to the character following the last character of the // view. LIBC_INLINE const char *end() const { return Data + Len; } // Returns a const reference to the character at specified location pos. // No bounds checking is performed: the behavior is undefined if pos >= // size(). LIBC_INLINE constexpr const char &operator[](size_t Index) const { return Data[Index]; } /// compare - Compare two strings; the result is -1, 0, or 1 if this string /// is lexicographically less than, equal to, or greater than the \p Other. LIBC_INLINE int compare(string_view Other) const { // Check the prefix for a mismatch. if (int Res = compareMemory(Data, Other.Data, min(Len, Other.Len))) return Res < 0 ? -1 : 1; // Otherwise the prefixes match, so we only need to check the lengths. if (Len == Other.Len) return 0; return Len < Other.Len ? -1 : 1; } LIBC_INLINE bool operator==(string_view Other) const { return equals(Other); } LIBC_INLINE bool operator!=(string_view Other) const { return !(*this == Other); } LIBC_INLINE bool operator<(string_view Other) const { return compare(Other) == -1; } LIBC_INLINE bool operator<=(string_view Other) const { return compare(Other) != 1; } LIBC_INLINE bool operator>(string_view Other) const { return compare(Other) == 1; } LIBC_INLINE bool operator>=(string_view Other) const { return compare(Other) != -1; } // Moves the start of the view forward by n characters. // The behavior is undefined if n > size(). LIBC_INLINE void remove_prefix(size_t N) { Len -= N; Data += N; } // Moves the end of the view back by n characters. // The behavior is undefined if n > size(). LIBC_INLINE void remove_suffix(size_t N) { Len -= N; } // Check if this string starts with the given Prefix. LIBC_INLINE bool starts_with(string_view Prefix) const { return Len >= Prefix.Len && compareMemory(Data, Prefix.Data, Prefix.Len) == 0; } // Check if this string starts with the given Prefix. LIBC_INLINE bool starts_with(const char Prefix) const { return !empty() && front() == Prefix; } // Check if this string ends with the given Prefix. LIBC_INLINE bool ends_with(const char Suffix) const { return !empty() && back() == Suffix; } // Check if this string ends with the given Suffix. LIBC_INLINE bool ends_with(string_view Suffix) const { return Len >= Suffix.Len && compareMemory(end() - Suffix.Len, Suffix.Data, Suffix.Len) == 0; } // Return a reference to the substring from [Start, Start + N). // // Start The index of the starting character in the substring; if the index is // npos or greater than the length of the string then the empty substring will // be returned. // // N The number of characters to included in the substring. If N exceeds the // number of characters remaining in the string, the string suffix (starting // with Start) will be returned. LIBC_INLINE string_view substr(size_t Start, size_t N = npos) const { Start = min(Start, Len); return string_view(Data + Start, min(N, Len - Start)); } // front - Get the first character in the string. LIBC_INLINE char front() const { return Data[0]; } // back - Get the last character in the string. LIBC_INLINE char back() const { return Data[Len - 1]; } // Finds the first occurence of c in this view, starting at position From. LIBC_INLINE constexpr size_t find_first_of(const char c, size_t From = 0) const { for (size_t Pos = From; Pos < size(); ++Pos) if ((*this)[Pos] == c) return Pos; return npos; } // Finds the last occurence of c in this view, ending at position End. LIBC_INLINE constexpr size_t find_last_of(const char c, size_t End = npos) const { End = End >= size() ? size() : End + 1; for (; End > 0; --End) if ((*this)[End - 1] == c) return End - 1; return npos; } // Finds the first character not equal to c in this view, starting at position // From. LIBC_INLINE constexpr size_t find_first_not_of(const char c, size_t From = 0) const { for (size_t Pos = From; Pos < size(); ++Pos) if ((*this)[Pos] != c) return Pos; return npos; } // Check if this view contains the given character. LIBC_INLINE constexpr bool contains(char c) const { return find_first_of(c) != npos; } }; } // namespace cpp } // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC___SUPPORT_CPP_STRING_VIEW_H