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