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) { // NOLINT(runtime/explicit)
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 = 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 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 explicit 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
206 // iterate over characters
207 const char *begin() const { return str; }
208 const char *end() const { return str ? str + strlen(str) : str; }
209
210 // Search for characters. Linear time.
211 const char *find(int c) const { return str ? strchr(str, c) : nullptr; }
212 const char *findlast(int c) const { return str ? strrchr(str, c) : str; }
213
214 // Search for substring
215 const char *find(const char *s) const { return str ? strstr(str, s) : nullptr; }
216
217 // Equality tests with other cstrings. Constant time.
218 bool operator==(cstring a) const { return str == a.str; }
219 bool operator!=(cstring a) const { return str != a.str; }
220
221 bool operator==(std::nullptr_t) const { return str == nullptr; }
222 bool operator!=(std::nullptr_t) const { return str != nullptr; }
223
224 // Other comparisons and tests. Linear time.
225 bool operator==(const char *a) const { return str ? a && !strcmp(str, a) : !a; }
226 bool operator!=(const char *a) const { return str ? !a || !!strcmp(str, a) : !!a; }
227 bool operator<(cstring a) const { return *this < a.str; }
228 bool operator<(const char *a) const { return str ? a && strcmp(str, a) < 0 : !!a; }
229 bool operator<=(cstring a) const { return *this <= a.str; }
230 bool operator<=(const char *a) const { return str ? a && strcmp(str, a) <= 0 : true; }
231 bool operator>(cstring a) const { return *this > a.str; }
232 bool operator>(const char *a) const { return str ? !a || strcmp(str, a) > 0 : false; }
233 bool operator>=(cstring a) const { return *this >= a.str; }
234 bool operator>=(const char *a) const { return str ? !a || strcmp(str, a) >= 0 : !a; }
235 bool operator==(std::string_view a) const { return str ? a.compare(str) == 0 : a.empty(); }
236 bool operator!=(std::string_view a) const { return str ? a.compare(str) != 0 : !a.empty(); }
237
238 bool operator==(const std::string &a) const { return *this == a.c_str(); }
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
245 bool startsWith(std::string_view prefix) const;
246 bool endsWith(std::string_view suffix) const;
247
248 // FIXME (DanilLutsenko): We really need mutations for immutable string?
249 // Probably better do transformation in std::string-like containter and
250 // then place result to cstring if needed.
251
252 // Mutation operations. These are linear time and always trigger a copy,
253 // since the underlying string is immutable. (Note that this is true even
254 // for substr(); cstrings are always null-terminated, so a copy is
255 // required.)
256 cstring operator+=(cstring a);
257 cstring operator+=(const char *a);
258 cstring operator+=(std::string a);
259 cstring operator+=(char a);
260
261 cstring before(const char *at) const;
262 cstring substr(size_t start) const {
263 return (start >= size()) ? cstring::literal("") : substr(start, size() - start);
264 }
265 cstring substr(size_t start, size_t length) const;
266 cstring replace(char find, char replace) const;
267 cstring replace(std::string_view find, std::string_view replace) const;
268 cstring exceptLast(size_t count) { return substr(0, size() - count); }
269
270 // trim leading and trailing whitespace (or other)
271 cstring trim(const char *ws = " \t\r\n") const;
272
273 // Useful singletons.
274 static cstring newline;
275 static cstring empty;
276
277 // Static factory functions.
278 template <typename T>
279 static cstring to_cstring(const T &t) {
280 std::stringstream ss;
281 ss << t;
282 return cstring(ss.str());
283 }
284 template <typename Iterator>
285 static cstring join(Iterator begin, Iterator end, const char *delim = ", ") {
286 std::stringstream ss;
287 for (auto current = begin; current != end; ++current) {
288 if (begin != current) ss << delim;
289 ss << *current;
290 }
291 return cstring(ss.str());
292 }
293 template <class T>
294 static cstring make_unique(const T &inuse, cstring base, char sep = '.');
295 template <class T>
296 static cstring make_unique(const T &inuse, cstring base, int &counter, char sep = '.');
297
300 static size_t cache_size(size_t &count);
301
303 cstring toUpper() const;
305 cstring toLower() const;
307 cstring capitalize() const;
309 cstring indent(size_t amount) const;
310};
311
312inline bool operator==(const char *a, cstring b) { return b == a; }
313inline bool operator!=(const char *a, cstring b) { return b != a; }
314inline bool operator==(const std::string &a, cstring b) { return b == a; }
315inline bool operator!=(const std::string &a, cstring b) { return b != a; }
316
317inline std::string operator+(cstring a, cstring b) {
318 std::string rv(a);
319 rv += b;
320 return rv;
321}
322inline std::string operator+(cstring a, const char *b) {
323 std::string rv(a);
324 rv += b;
325 return rv;
326}
327inline std::string operator+(cstring a, const std::string &b) {
328 std::string rv(a);
329 rv += b;
330 return rv;
331}
332inline std::string operator+(cstring a, char b) {
333 std::string rv(a);
334 rv += b;
335 return rv;
336}
337inline std::string operator+(const char *a, cstring b) {
338 std::string rv(a);
339 rv += b;
340 return rv;
341}
342inline std::string operator+(std::string a, cstring b) {
343 a += b;
344 return a;
345}
346inline std::string operator+(char a, cstring b) {
347 std::string rv(1, a);
348 rv += b;
349 return rv;
350}
351
352inline cstring cstring::operator+=(cstring a) {
353 *this = *this + a;
354 return *this;
355}
356inline cstring cstring::operator+=(const char *a) {
357 *this = *this + a;
358 return *this;
359}
360inline cstring cstring::operator+=(std::string a) {
361 *this = *this + a;
362 return *this;
363}
364inline cstring cstring::operator+=(char a) {
365 *this = *this + a;
366 return *this;
367}
368
369inline std::string &operator+=(std::string &a, cstring b) {
370 a.append(b.c_str());
371 return a;
372}
373
374inline cstring cstring::newline = cstring::literal("\n");
375inline cstring cstring::empty = cstring::literal("");
376
377template <class T>
378cstring cstring::make_unique(const T &inuse, cstring base, int &counter, char sep) {
379 if (!inuse.count(base)) return base;
380
381 char suffix[12];
382 cstring rv = base;
383 do {
384 snprintf(suffix, sizeof(suffix) / sizeof(suffix[0]), "%c%d", sep, counter++);
385 rv = base + suffix;
386 } while (inuse.count(rv));
387 return rv;
388}
389
390template <class T>
391cstring cstring::make_unique(const T &inuse, cstring base, char sep) {
392 int counter = 0;
393 return make_unique(inuse, base, counter, sep);
394}
395
396inline std::ostream &operator<<(std::ostream &out, cstring s) {
397 return out << (s ? s.c_str() : "<null>");
398}
399
400} // namespace P4
401
404namespace P4::literals {
405
409inline cstring operator""_cs(const char *str, std::size_t len) {
410 cstring result;
411 result.construct_from_literal(str, len);
412 return result;
413}
414} // namespace P4::literals
415
416namespace std {
417template <>
418struct hash<P4::cstring> {
419 std::size_t operator()(const P4::cstring &c) const {
420 // cstrings are internalized, therefore their addresses are unique; we
421 // can just use their address to produce hash.
422 return P4::Util::Hash{}(c.c_str());
423 }
424};
425} // namespace std
426
427namespace P4::Util {
428template <>
430 size_t operator()(const cstring &c) const { return Util::Hash{}(c.c_str()); }
431};
432
433} // namespace P4::Util
434
435#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
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