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