P4C
The P4 Compiler
Loading...
Searching...
No Matches
cstring.h
1/*
2Copyright 2013-present Barefoot Networks, Inc.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#ifndef LIB_CSTRING_H_
18#define LIB_CSTRING_H_
19
20#include <cstddef>
21#include <cstring>
22#include <functional>
23#include <ostream>
24#include <sstream>
25#include <string>
26#include <string_view>
27#include <type_traits>
28
29#include "hash.h"
30
76namespace P4 {
77class cstring;
78} // namespace P4
79
80namespace P4::literals {
81inline cstring operator""_cs(const char *str, std::size_t len);
82}
83
84namespace P4 {
85class cstring {
86 const char *str = nullptr;
87
88 public:
89 cstring() = default;
90
91 cstring(std::nullptr_t) {} // NOLINT(runtime/explicit)
92
93 // Copy and assignment from other kinds of strings
94
95 // Owner of string is someone else, but we know size of string.
96 // Do not use if possible, this is linear time operation if string
97 // not exists in table, because the underlying string must be copied.
98 cstring(const char *string, std::size_t length) { // NOLINT(runtime/explicit)
99 if (string != nullptr) {
100 construct_from_shared(string, length);
101 }
102 }
103
104 // Owner of string is someone else, we do not know size of string.
105 // Do not use if possible, this is linear time operation if string
106 // not exists in table, because the underlying string must be copied.
107 explicit cstring(const char *string) {
108 if (string != nullptr) {
109 construct_from_shared(string, std::strlen(string));
110 }
111 }
112
113 // construct cstring from std::string. Do not use if possible, this is linear
114 // time operation if string not exists in table, because the underlying string must be copied.
115 cstring(const std::string &string) { // NOLINT(runtime/explicit)
116 construct_from_shared(string.data(), string.length());
117 }
118
119 // construct cstring from std::string_view. Do not use if possible, this is linear
120 // time operation if string not exists in table, because the underlying string must be copied.
121 explicit cstring(std::string_view string) {
122 construct_from_shared(string.data(), string.length());
123 }
124
125 // TODO (DanilLutsenko): Make special case for r-value std::string?
126
127 // Just helper function, for lazies, who do not like to write .str()
128 // Do not use it, implicit std::string construction with implicit overhead
129 // TODO (DanilLutsenko): Remove it?
130 cstring(const std::stringstream &stream) // NOLINT(runtime/explicit)
131 : cstring(stream.str()) {}
132
133 // TODO (DanilLutsenko): Construct from StringRef?
134
135 // String was created outside and cstring is unique owner of it.
136 // cstring will control lifetime of passed object
137 static cstring own(const char *string, std::size_t length) {
138 if (string == nullptr) {
139 return {};
140 }
141
142 cstring result;
143 result.construct_from_unique(string, length);
144 return result;
145 }
146
147 // construct cstring wrapper for literal
148 template <typename T, std::size_t N,
149 typename = typename std::enable_if<std::is_same<T, const char>::value>::type>
150 static cstring literal(T (&string)[N]) { // NOLINT(runtime/explicit)
151 cstring result;
152 result.construct_from_literal(string, N - 1 /* String length without null terminator */);
153 return result;
154 }
155
157 static bool is_cached(std::string_view s);
159 static cstring get_cached(std::string_view s);
160
161 private:
162 // passed string is shared, we not unique owners
163 void construct_from_shared(const char *string, std::size_t length);
164
165 // we are unique owners of passed string
166 void construct_from_unique(const char *string, std::size_t length);
167
168 // string is literal
169 void construct_from_literal(const char *string, std::size_t length);
170
171 friend cstring P4::literals::operator""_cs(const char *str, std::size_t len);
172
173 public:
177 cstring escapeJson() const;
178
179 template <typename Iter>
180 cstring(Iter begin, Iter end) {
181 *this = cstring(std::string(begin, end));
182 }
183
184 char get(unsigned index) const { return (index < size()) ? str[index] : 0; }
185 const char *c_str() const { return str; }
186 explicit operator const char *() const { return str; }
187
188 std::string string() const { return str ? std::string(str) : std::string(""); }
189 explicit operator std::string() const { return string(); }
190
191 std::string_view string_view() const {
192 return str ? std::string_view(str) : std::string_view("");
193 }
194 operator std::string_view() const { return string_view(); }
195
196 // Size tests. Constant time except for size(), which is linear time.
197 size_t size() const {
198 // TODO (DanilLutsenko): We store size of string in table on object construction,
199 // compiler cannot optimize strlen if str not points to string literal.
200 // Probably better fetch size from table or store it to cstring on construction.
201 return str ? strlen(str) : 0;
202 }
203 bool isNull() const { return str == nullptr; }
204 bool isNullOrEmpty() const { return str == nullptr ? true : str[0] == 0; }
205 explicit operator bool() const { return str; }
206
207 // iterate over characters
208 const char *begin() const { return str; }
209 const char *end() const { return str ? str + strlen(str) : str; }
210
211 // Search for characters. Linear time.
212 const char *find(int c) const { return str ? strchr(str, c) : nullptr; }
213 const char *findlast(int c) const { return str ? strrchr(str, c) : str; }
214
215 // Search for substring
216 const char *find(const char *s) const { return str ? strstr(str, s) : nullptr; }
217
218 // Equality tests with other cstrings. Constant time.
219 bool operator==(cstring a) const { return str == a.str; }
220 bool operator!=(cstring a) const { return str != a.str; }
221
222 bool operator==(std::nullptr_t) const { return str == nullptr; }
223 bool operator!=(std::nullptr_t) const { return str != nullptr; }
224
225 // Other comparisons and tests. Linear time.
226 bool operator==(const char *a) const { return str ? a && !strcmp(str, a) : !a; }
227 bool operator!=(const char *a) const { return str ? !a || !!strcmp(str, a) : !!a; }
228 bool operator<(cstring a) const { return *this < a.str; }
229 bool operator<(const char *a) const { return str ? a && strcmp(str, a) < 0 : !!a; }
230 bool operator<=(cstring a) const { return *this <= a.str; }
231 bool operator<=(const char *a) const { return str ? a && strcmp(str, a) <= 0 : true; }
232 bool operator>(cstring a) const { return *this > a.str; }
233 bool operator>(const char *a) const { return str ? !a || strcmp(str, a) > 0 : false; }
234 bool operator>=(cstring a) const { return *this >= a.str; }
235 bool operator>=(const char *a) const { return str ? !a || strcmp(str, a) >= 0 : !a; }
236 bool operator==(std::string_view a) const { return str ? a.compare(str) == 0 : a.empty(); }
237 bool operator!=(std::string_view a) const { return str ? a.compare(str) != 0 : !a.empty(); }
238
239 bool operator==(const std::string &a) const { return *this == a.c_str(); }
240 bool operator!=(const std::string &a) const { return *this != a.c_str(); }
241 bool operator<(const std::string &a) const { return *this < a.c_str(); }
242 bool operator<=(const std::string &a) const { return *this <= a.c_str(); }
243 bool operator>(const std::string &a) const { return *this > a.c_str(); }
244 bool operator>=(const std::string &a) const { return *this >= a.c_str(); }
245
246 bool startsWith(std::string_view prefix) const;
247 bool endsWith(std::string_view suffix) const;
248
249 // FIXME (DanilLutsenko): We really need mutations for immutable string?
250 // Probably better do transformation in std::string-like containter and
251 // then place result to cstring if needed.
252
253 // Mutation operations. These are linear time and always trigger a copy,
254 // since the underlying string is immutable. (Note that this is true even
255 // for substr(); cstrings are always null-terminated, so a copy is
256 // required.)
257 cstring operator+=(cstring a);
258 cstring operator+=(const char *a);
259 cstring operator+=(std::string a);
260 cstring operator+=(char a);
261
262 cstring before(const char *at) const;
263 cstring substr(size_t start) const {
264 return (start >= size()) ? cstring::literal("") : substr(start, size() - start);
265 }
266 cstring substr(size_t start, size_t length) const;
267 cstring replace(char find, char replace) const;
268 cstring replace(std::string_view find, std::string_view replace) const;
269 cstring exceptLast(size_t count) { return substr(0, size() - count); }
270
271 // trim leading and trailing whitespace (or other)
272 cstring trim(const char *ws = " \t\r\n") const;
273
274 // Useful singletons.
275 static cstring newline;
276 static cstring empty;
277
278 // Static factory functions.
279 template <typename T>
280 static cstring to_cstring(const T &t) {
281 std::stringstream ss;
282 ss << t;
283 return cstring(ss.str());
284 }
285 template <typename Iterator>
286 static cstring join(Iterator begin, Iterator end, const char *delim = ", ") {
287 std::stringstream ss;
288 for (auto current = begin; current != end; ++current) {
289 if (begin != current) ss << delim;
290 ss << *current;
291 }
292 return cstring(ss.str());
293 }
294 template <class T>
295 static cstring make_unique(const T &inuse, cstring base, char sep = '.');
296 template <class T>
297 static cstring make_unique(const T &inuse, cstring base, int &counter, char sep = '.');
298
301 static size_t cache_size(size_t &count);
302
304 cstring toUpper() const;
306 cstring toLower() const;
308 cstring capitalize() const;
310 cstring indent(size_t amount) const;
311
314 template <typename Sink>
315 friend void AbslStringify(Sink &sink, cstring s) {
316 sink.Append(s.string_view());
317 }
318};
319
320inline bool operator==(const char *a, cstring b) { return b == a; }
321inline bool operator!=(const char *a, cstring b) { return b != a; }
322inline bool operator==(const std::string &a, cstring b) { return b == a; }
323inline bool operator!=(const std::string &a, cstring b) { return b != a; }
324
325inline std::string operator+(cstring a, cstring b) {
326 std::string rv(a);
327 rv += b;
328 return rv;
329}
330inline std::string operator+(cstring a, const char *b) {
331 std::string rv(a);
332 rv += b;
333 return rv;
334}
335inline std::string operator+(cstring a, const std::string &b) {
336 std::string rv(a);
337 rv += b;
338 return rv;
339}
340inline std::string operator+(cstring a, char b) {
341 std::string rv(a);
342 rv += b;
343 return rv;
344}
345inline std::string operator+(const char *a, cstring b) {
346 std::string rv(a);
347 rv += b;
348 return rv;
349}
350inline std::string operator+(std::string a, cstring b) {
351 a += b;
352 return a;
353}
354inline std::string operator+(char a, cstring b) {
355 std::string rv(1, a);
356 rv += b;
357 return rv;
358}
359
360inline cstring cstring::operator+=(cstring a) {
361 *this = cstring(*this + a);
362 return *this;
363}
364inline cstring cstring::operator+=(const char *a) {
365 *this = cstring(*this + a);
366 return *this;
367}
368inline cstring cstring::operator+=(std::string a) {
369 *this = cstring(*this + a);
370 return *this;
371}
372inline cstring cstring::operator+=(char a) {
373 *this = cstring(*this + a);
374 return *this;
375}
376
377inline std::string &operator+=(std::string &a, cstring b) {
378 a.append(b.c_str());
379 return a;
380}
381
382inline cstring cstring::newline = cstring::literal("\n");
383inline cstring cstring::empty = cstring::literal("");
384
385template <class T>
386cstring cstring::make_unique(const T &inuse, cstring base, int &counter, char sep) {
387 if (!inuse.count(base)) return base;
388
389 char suffix[12];
390 cstring rv = base;
391 do {
392 snprintf(suffix, sizeof(suffix) / sizeof(suffix[0]), "%c%d", sep, counter++);
393 rv = cstring(base + (const char *)suffix);
394 } while (inuse.count(rv));
395 return rv;
396}
397
398template <class T>
399cstring cstring::make_unique(const T &inuse, cstring base, char sep) {
400 int counter = 0;
401 return make_unique(inuse, base, counter, sep);
402}
403
404inline std::ostream &operator<<(std::ostream &out, cstring s) {
405 return out << (s.isNull() ? "<null>" : s.string_view());
406}
407
408} // namespace P4
409
412namespace P4::literals {
413
417inline cstring operator""_cs(const char *str, std::size_t len) {
418 cstring result;
419 result.construct_from_literal(str, len);
420 return result;
421}
422} // namespace P4::literals
423
424namespace std {
425template <>
426struct hash<P4::cstring> {
427 std::size_t operator()(const P4::cstring &c) const {
428 // cstrings are internalized, therefore their addresses are unique; we
429 // can just use their address to produce hash.
430 return P4::Util::Hash{}(c.c_str());
431 }
432};
433} // namespace std
434
435namespace P4::Util {
436template <>
438 size_t operator()(const cstring &c) const { return Util::Hash{}(c.c_str()); }
439};
440
441} // namespace P4::Util
442
443#endif /* LIB_CSTRING_H_ */
Definition cstring.h:85
cstring toUpper() const
Convert the cstring to uppercase.
Definition cstring.cpp:311
static size_t cache_size(size_t &count)
Definition cstring.cpp:217
cstring escapeJson() const
Definition cstring.cpp:272
friend void AbslStringify(Sink &sink, cstring s)
Definition cstring.h:315
cstring indent(size_t amount) const
Append this many spaces after each newline (and before the first string).
Definition cstring.cpp:265
static cstring get_cached(std::string_view s)
Definition cstring.cpp:194
cstring toLower() const
Convert the cstring to lowercase.
Definition cstring.cpp:317
static bool is_cached(std::string_view s)
Definition cstring.cpp:192
cstring capitalize() const
Capitalize the first symbol.
Definition cstring.cpp:323
Definition cstring.h:80
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
STL namespace.
Definition hash.h:125
Definition hash.h:123