1 //===--- StringView.h -------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // FIXME: Use std::string_view instead when we support C++17.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef DEMANGLE_STRINGVIEW_H
14 #define DEMANGLE_STRINGVIEW_H
15 
16 #include "DemangleConfig.h"
17 #include <algorithm>
18 #include <cassert>
19 #include <cstring>
20 
21 DEMANGLE_NAMESPACE_BEGIN
22 
23 class StringView {
24   const char *First;
25   const char *Last;
26 
27 public:
28   static const size_t npos = ~size_t(0);
29 
30   template <size_t N>
StringView(const char (& Str)[N])31   StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {}
StringView(const char * First_,const char * Last_)32   StringView(const char *First_, const char *Last_)
33       : First(First_), Last(Last_) {}
StringView(const char * First_,size_t Len)34   StringView(const char *First_, size_t Len)
35       : First(First_), Last(First_ + Len) {}
StringView(const char * Str)36   StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
StringView()37   StringView() : First(nullptr), Last(nullptr) {}
38 
substr(size_t From)39   StringView substr(size_t From) const {
40     return StringView(begin() + From, size() - From);
41   }
42 
43   size_t find(char C, size_t From = 0) const {
44     size_t FindBegin = std::min(From, size());
45     // Avoid calling memchr with nullptr.
46     if (FindBegin < size()) {
47       // Just forward to memchr, which is faster than a hand-rolled loop.
48       if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin))
49         return size_t(static_cast<const char *>(P) - First);
50     }
51     return npos;
52   }
53 
substr(size_t From,size_t To)54   StringView substr(size_t From, size_t To) const {
55     if (To >= size())
56       To = size() - 1;
57     if (From >= size())
58       From = size() - 1;
59     return StringView(First + From, First + To);
60   }
61 
62   StringView dropFront(size_t N = 1) const {
63     if (N >= size())
64       N = size();
65     return StringView(First + N, Last);
66   }
67 
68   StringView dropBack(size_t N = 1) const {
69     if (N >= size())
70       N = size();
71     return StringView(First, Last - N);
72   }
73 
front()74   char front() const {
75     assert(!empty());
76     return *begin();
77   }
78 
back()79   char back() const {
80     assert(!empty());
81     return *(end() - 1);
82   }
83 
popFront()84   char popFront() {
85     assert(!empty());
86     return *First++;
87   }
88 
consumeFront(char C)89   bool consumeFront(char C) {
90     if (!startsWith(C))
91       return false;
92     *this = dropFront(1);
93     return true;
94   }
95 
consumeFront(StringView S)96   bool consumeFront(StringView S) {
97     if (!startsWith(S))
98       return false;
99     *this = dropFront(S.size());
100     return true;
101   }
102 
startsWith(char C)103   bool startsWith(char C) const { return !empty() && *begin() == C; }
104 
startsWith(StringView Str)105   bool startsWith(StringView Str) const {
106     if (Str.size() > size())
107       return false;
108     return std::equal(Str.begin(), Str.end(), begin());
109   }
110 
111   const char &operator[](size_t Idx) const { return *(begin() + Idx); }
112 
begin()113   const char *begin() const { return First; }
end()114   const char *end() const { return Last; }
size()115   size_t size() const { return static_cast<size_t>(Last - First); }
empty()116   bool empty() const { return First == Last; }
117 };
118 
119 inline bool operator==(const StringView &LHS, const StringView &RHS) {
120   return LHS.size() == RHS.size() &&
121          std::equal(LHS.begin(), LHS.end(), RHS.begin());
122 }
123 
124 DEMANGLE_NAMESPACE_END
125 
126 #endif
127