Warning: This file is not a C or C++ file. It does not have highlighting.
1 | //===-- include/flang/Parser/char-block.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 | #ifndef FORTRAN_PARSER_CHAR_BLOCK_H_ |
10 | #define FORTRAN_PARSER_CHAR_BLOCK_H_ |
11 | |
12 | // Describes a contiguous block of characters; does not own their storage. |
13 | |
14 | #include "flang/Common/interval.h" |
15 | #include <algorithm> |
16 | #include <cstddef> |
17 | #include <cstring> |
18 | #include <iosfwd> |
19 | #include <string> |
20 | #include <utility> |
21 | |
22 | namespace llvm { |
23 | class raw_ostream; |
24 | } |
25 | |
26 | namespace Fortran::parser { |
27 | |
28 | class CharBlock { |
29 | public: |
30 | constexpr CharBlock() {} |
31 | constexpr CharBlock(const char *x, std::size_t n = 1) : interval_{x, n} {} |
32 | constexpr CharBlock(const char *b, const char *ep1) |
33 | : interval_{b, static_cast<std::size_t>(ep1 - b)} {} |
34 | CharBlock(const std::string &s) : interval_{s.data(), s.size()} {} |
35 | constexpr CharBlock(const CharBlock &) = default; |
36 | constexpr CharBlock(CharBlock &&) = default; |
37 | constexpr CharBlock &operator=(const CharBlock &) = default; |
38 | constexpr CharBlock &operator=(CharBlock &&) = default; |
39 | |
40 | constexpr bool empty() const { return interval_.empty(); } |
41 | constexpr std::size_t size() const { return interval_.size(); } |
42 | constexpr const char *begin() const { return interval_.start(); } |
43 | constexpr const char *end() const { |
44 | return interval_.start() + interval_.size(); |
45 | } |
46 | constexpr const char &operator[](std::size_t j) const { |
47 | return interval_.start()[j]; |
48 | } |
49 | |
50 | bool Contains(const CharBlock &that) const { |
51 | return interval_.Contains(that.interval_); |
52 | } |
53 | |
54 | void ExtendToCover(const CharBlock &that) { |
55 | interval_.ExtendToCover(that.interval_); |
56 | } |
57 | |
58 | // Returns the block's first non-blank character, if it has |
59 | // one; otherwise ' '. |
60 | char FirstNonBlank() const { |
61 | for (char ch : *this) { |
62 | if (ch != ' ' && ch != '\t') { |
63 | return ch; |
64 | } |
65 | } |
66 | return ' '; // non no-blank character |
67 | } |
68 | |
69 | // Returns the block's only non-blank character, if it has |
70 | // exactly one non-blank character; otherwise ' '. |
71 | char OnlyNonBlank() const { |
72 | char result{' '}; |
73 | for (char ch : *this) { |
74 | if (ch != ' ' && ch != '\t') { |
75 | if (result == ' ') { |
76 | result = ch; |
77 | } else { |
78 | return ' '; |
79 | } |
80 | } |
81 | } |
82 | return result; |
83 | } |
84 | |
85 | std::size_t CountLeadingBlanks() const { |
86 | std::size_t n{size()}; |
87 | std::size_t j{0}; |
88 | for (; j < n; ++j) { |
89 | char ch{(*this)[j]}; |
90 | if (ch != ' ' && ch != '\t') { |
91 | break; |
92 | } |
93 | } |
94 | return j; |
95 | } |
96 | |
97 | bool IsBlank() const { return FirstNonBlank() == ' '; } |
98 | |
99 | std::string ToString() const { |
100 | return std::string{interval_.start(), interval_.size()}; |
101 | } |
102 | |
103 | // Convert to string, stopping early at any embedded '\0'. |
104 | std::string NULTerminatedToString() const { |
105 | return std::string{interval_.start(), |
106 | /*not in std::*/ strnlen(interval_.start(), interval_.size())}; |
107 | } |
108 | |
109 | bool operator<(const CharBlock &that) const { return Compare(that) < 0; } |
110 | bool operator<=(const CharBlock &that) const { return Compare(that) <= 0; } |
111 | bool operator==(const CharBlock &that) const { return Compare(that) == 0; } |
112 | bool operator!=(const CharBlock &that) const { return Compare(that) != 0; } |
113 | bool operator>=(const CharBlock &that) const { return Compare(that) >= 0; } |
114 | bool operator>(const CharBlock &that) const { return Compare(that) > 0; } |
115 | |
116 | bool operator<(const char *that) const { return Compare(that) < 0; } |
117 | bool operator<=(const char *that) const { return Compare(that) <= 0; } |
118 | bool operator==(const char *that) const { return Compare(that) == 0; } |
119 | bool operator!=(const char *that) const { return Compare(that) != 0; } |
120 | bool operator>=(const char *that) const { return Compare(that) >= 0; } |
121 | bool operator>(const char *that) const { return Compare(that) > 0; } |
122 | |
123 | friend bool operator<(const char *, const CharBlock &); |
124 | friend bool operator<=(const char *, const CharBlock &); |
125 | friend bool operator==(const char *, const CharBlock &); |
126 | friend bool operator!=(const char *, const CharBlock &); |
127 | friend bool operator>=(const char *, const CharBlock &); |
128 | friend bool operator>(const char *, const CharBlock &); |
129 | |
130 | private: |
131 | int Compare(const CharBlock &that) const { |
132 | // "memcmp" in glibc has "nonnull" attributes on the input pointers. |
133 | // Avoid passing null pointers, since it would result in an undefined |
134 | // behavior. |
135 | if (size() == 0) { |
136 | return that.size() == 0 ? 0 : -1; |
137 | } else if (that.size() == 0) { |
138 | return 1; |
139 | } else { |
140 | std::size_t bytes{std::min(size(), that.size())}; |
141 | int cmp{std::memcmp(static_cast<const void *>(begin()), |
142 | static_cast<const void *>(that.begin()), bytes)}; |
143 | if (cmp != 0) { |
144 | return cmp; |
145 | } else { |
146 | return size() < that.size() ? -1 : size() > that.size(); |
147 | } |
148 | } |
149 | } |
150 | |
151 | int Compare(const char *that) const { |
152 | std::size_t bytes{size()}; |
153 | if (int cmp{std::strncmp(begin(), that, bytes)}) { |
154 | return cmp; |
155 | } |
156 | return that[bytes] == '\0' ? 0 : -1; |
157 | } |
158 | |
159 | common::Interval<const char *> interval_{nullptr, 0}; |
160 | }; |
161 | |
162 | inline bool operator<(const char *left, const CharBlock &right) { |
163 | return right > left; |
164 | } |
165 | inline bool operator<=(const char *left, const CharBlock &right) { |
166 | return right >= left; |
167 | } |
168 | inline bool operator==(const char *left, const CharBlock &right) { |
169 | return right == left; |
170 | } |
171 | inline bool operator!=(const char *left, const CharBlock &right) { |
172 | return right != left; |
173 | } |
174 | inline bool operator>=(const char *left, const CharBlock &right) { |
175 | return right <= left; |
176 | } |
177 | inline bool operator>(const char *left, const CharBlock &right) { |
178 | return right < left; |
179 | } |
180 | |
181 | // An alternative comparator based on pointer values; use with care! |
182 | struct CharBlockPointerComparator { |
183 | bool operator()(CharBlock x, CharBlock y) const { |
184 | return x.end() < y.begin(); |
185 | } |
186 | }; |
187 | |
188 | llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const CharBlock &x); |
189 | |
190 | } // namespace Fortran::parser |
191 | |
192 | // Specializations to enable std::unordered_map<CharBlock, ...> &c. |
193 | template <> struct std::hash<Fortran::parser::CharBlock> { |
194 | std::size_t operator()(const Fortran::parser::CharBlock &x) const { |
195 | std::size_t hash{0}, bytes{x.size()}; |
196 | for (std::size_t j{0}; j < bytes; ++j) { |
197 | hash = (hash * 31) ^ x[j]; |
198 | } |
199 | return hash; |
200 | } |
201 | }; |
202 | #endif // FORTRAN_PARSER_CHAR_BLOCK_H_ |
203 |
Warning: This file is not a C or C++ file. It does not have highlighting.