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 <cassert>
18 #include <cstring>
19 
20 DEMANGLE_NAMESPACE_BEGIN
21 
22 class StringView {
23   const char *First;
24   const char *Last;
25 
26 public:
27   static const size_t npos = ~size_t(0);
28 
29   template <size_t N>
30   StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {}
31   StringView(const char *First_, const char *Last_)
32       : First(First_), Last(Last_) {}
33   StringView(const char *First_, size_t Len)
34       : First(First_), Last(First_ + Len) {}
35   StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
36   StringView() : First(nullptr), Last(nullptr) {}
37 
38   StringView substr(size_t Pos, size_t Len = npos) const {
39     assert(Pos <= size());
40     if (Len > size() - Pos)
41       Len = size() - Pos;
42     return StringView(begin() + Pos, Len);
43   }
44 
45   size_t find(char C, size_t From = 0) const {
46     // Avoid calling memchr with nullptr.
47     if (From < size()) {
48       // Just forward to memchr, which is faster than a hand-rolled loop.
49       if (const void *P = ::memchr(First + From, C, size() - From))
50         return size_t(static_cast<const char *>(P) - First);
51     }
52     return npos;
53   }
54 
55   StringView dropFront(size_t N = 1) const {
56     if (N >= size())
57       N = size();
58     return StringView(First + N, Last);
59   }
60 
61   StringView dropBack(size_t N = 1) const {
62     if (N >= size())
63       N = size();
64     return StringView(First, Last - N);
65   }
66 
67   char front() const {
68     assert(!empty());
69     return *begin();
70   }
71 
72   char back() const {
73     assert(!empty());
74     return *(end() - 1);
75   }
76 
77   char popFront() {
78     assert(!empty());
79     return *First++;
80   }
81 
82   bool consumeFront(char C) {
83     if (!startsWith(C))
84       return false;
85     *this = dropFront(1);
86     return true;
87   }
88 
89   bool consumeFront(StringView S) {
90     if (!startsWith(S))
91       return false;
92     *this = dropFront(S.size());
93     return true;
94   }
95 
96   bool startsWith(char C) const { return !empty() && *begin() == C; }
97 
98   bool startsWith(StringView Str) const {
99     if (Str.size() > size())
100       return false;
101     return std::strncmp(Str.begin(), begin(), Str.size()) == 0;
102   }
103 
104   const char &operator[](size_t Idx) const { return *(begin() + Idx); }
105 
106   const char *begin() const { return First; }
107   const char *end() const { return Last; }
108   size_t size() const { return static_cast<size_t>(Last - First); }
109   bool empty() const { return First == Last; }
110 };
111 
112 inline bool operator==(const StringView &LHS, const StringView &RHS) {
113   return LHS.size() == RHS.size() &&
114          std::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0;
115 }
116 
117 DEMANGLE_NAMESPACE_END
118 
119 #endif
120