scc 2025.09
SystemC components library
ities.h
1/*******************************************************************************
2 * Copyright 2017-2022 MINRES Technologies GmbH
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *******************************************************************************/
16
17#ifndef _UTIL_ITIES_H_
18#define _UTIL_ITIES_H_
19
20#include <algorithm>
21#include <array>
22#include <assert.h>
23#include <bitset>
24#include <cctype>
25#include <climits>
26#include <iterator>
27#include <limits>
28#include <memory>
29#include <sstream>
30#include <sys/stat.h>
31#include <type_traits>
32#include <vector>
33
34#if __cplusplus < 201402L
35#define CONSTEXPR
36#else
37#define CONSTEXPR constexpr
38#endif
39
44// some helper functions
54template <unsigned int bit, unsigned int width, typename T>
55CONSTEXPR typename std::enable_if<std::is_unsigned<T>::value, T>::type bit_sub(T v) {
56 static_assert((bit + width) <= 8 * sizeof(T), "Accessed slice out of bounds");
57 static_assert(width > 0, "Width needs to be >0");
58 static_assert(width < sizeof(T) * 8, "");
59 return (v >> bit) & ((T(1) << width) - 1);
60}
61
62template <unsigned int bit, unsigned int width, typename T>
63CONSTEXPR typename std::enable_if<std::is_signed<T>::value, T>::type bit_sub(T v) {
64 static_assert((bit + width) <= 8 * sizeof(T), "Accessed slice out of bounds");
65 static_assert(width > 0, "Width needs to be >0");
66 auto field = v >> bit;
67 return (field & ~(~T(1) << (width - 1) << 1)) - (field & (T(1) << (width - 1)) << 1);
68}
69
70template <typename T> typename std::enable_if<std::is_unsigned<T>::value, T>::type bit_sub(T v, unsigned int bit, unsigned int width) {
71 assert((bit + width) <= 8 * sizeof(T) && "Accessed slice out of bounds");
72 assert(width > 0 && "Width needs to be >0");
73 T mask = width < sizeof(T) * 8 ? (T(1) << width) - 1 : std::numeric_limits<T>::max();
74 return (v >> bit) & mask;
75}
76
77template <typename T> typename std::enable_if<std::is_signed<T>::value, T>::type bit_sub(T v, unsigned int bit, unsigned int width) {
78 assert((bit + width) <= 8 * sizeof(T) && "Accessed slice out of bounds");
79 assert(width > 0 && "Width needs to be >0");
80 auto field = v >> bit;
81 return (field & ~(~T(1) << (width - 1) << 1)) - (field & (T(1) << (width - 1)) << 1);
82}
83
84template <typename T> struct bit_slice {
85 T& value;
86 unsigned base, width;
87 explicit bit_slice(T& value, unsigned base, unsigned width)
88 : value(value)
89 , base(base)
90 , width(width){};
91 explicit bit_slice(T& value, unsigned index)
92 : value(value)
93 , base(index)
94 , width(1){};
95 operator T() const { return bit_sub(value, base, width); }
96
97 bit_slice<T>& operator=(T v) {
98 T mask = ((T(1) << width) - 1);
99 value = (value & ~(mask << base)) | ((v & mask) << base);
100 return *this;
101 }
102 bit_slice<T>& operator=(bit_slice<T> const& _v) {
103 T v = static_cast<T>(_v);
104 T mask = ((T(1) << width) - 1);
105 value = (value & ~(mask << base)) | ((v & mask) << base);
106 return *this;
107 }
108};
109
110template <unsigned offset, typename R, typename T> R _bit_comb(T v) { return v << offset; }
111template <unsigned offset, typename R, typename T, typename... Args> R _bit_comb(T first, Args... args) {
112 return (first << offset) + _bit_comb<offset + 8, R>(args...);
113}
123template <typename R, typename T, typename... Args> R bit_comb(T first, Args... args) { return first + _bit_comb<8, R>(args...); }
124
133template <typename T, unsigned B> CONSTEXPR T signextend(const typename std::make_unsigned<T>::type x) {
134 struct X {
135 T x : B;
136 X(T x_)
137 : x(x_) {}
138 } s(x);
139 return s.x;
140}
141
142// according to http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend
152template <unsigned int bit, unsigned int width, typename T> inline constexpr typename std::make_signed<T>::type signed_bit_sub(T v) {
153#if __cplusplus < 201402L
154 return ((v << (sizeof(T) * 8 - bit - width)) >> (sizeof(T) * 8 - width));
155#else
156 typename std::make_signed<T>::type r = v << (sizeof(T) * 8 - bit - width);
157 typename std::make_signed<T>::type ret = (r >> (sizeof(T) * 8 - width));
158 return ret;
159#endif
160}
161
163inline constexpr uint64_t operator"" _kB(unsigned long long val) { return val * 1 << 10; }
165inline constexpr uint64_t operator"" _MB(unsigned long long val) { return val * 1 << 20; }
167inline constexpr uint64_t operator"" _GB(unsigned long long val) { return val * 1 << 30; }
168
169inline constexpr uint64_t operator"" _KiB(unsigned long long val) { return val * 1 << 10; }
171inline constexpr uint64_t operator"" _MiB(unsigned long long val) { return val * 1 << 20; }
173inline constexpr uint64_t operator"" _GiB(unsigned long long val) { return val * 1 << 30; }
175inline constexpr uint64_t operator"" _TiB(unsigned long long val) { return val * 1 << 40; }
176
178namespace util {
179template <typename T, typename... Args> std::unique_ptr<T> make_unique(Args&&... args) {
180#if __cplusplus < 201402L
181 return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
182#else
183 return std::make_unique<T>(std::forward<Args>(args)...);
184#endif
185}
186
187// according to
188// http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup
189static std::array<const int, 32> MultiplyDeBruijnBitPosition = {
190 {0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9}};
191template <size_t N> constexpr size_t find_first(std::bitset<N>& bits) {
192 static_assert(N <= 32, "find_first only supports bitsets smaller than 33");
193 return MultiplyDeBruijnBitPosition[static_cast<uint32_t>((bits.to_ulong() & -bits.to_ulong()) * 0x077CB531U) >> 27];
194}
195template <typename T> T leftmost_one(T n) {
196 for(T mask = 1; mask < sizeof(T) * 8; mask <<= 1)
197 n |= (n >> mask);
198 return n - (n >> 1);
199}
200
201// according to
202// https://stackoverflow.com/questions/8871204/count-number-of-1s-in-binary-representation
203#if defined(__GNUG__)
204constexpr inline size_t bit_count(uint32_t u) { return __builtin_popcount(u); }
205constexpr inline size_t bit_count(uint64_t u) { return __builtin_popcountl(u); }
206#elif __cplusplus < 201402L
207constexpr inline size_t uCount(uint32_t u) { return u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111); }
208constexpr inline size_t bit_count(uint32_t u) { return ((uCount(u) + (uCount(u) >> 3)) & 030707070707) % 63; }
209#else
210constexpr inline size_t bit_count(uint32_t u) {
211 size_t uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
212 return ((uCount + (uCount >> 3)) & 030707070707) % 63;
213}
214#endif
215
216template <typename T> CONSTEXPR typename std::enable_if<std::is_integral<T>::value, T>::type rotl(T n, unsigned int c) {
217 const unsigned int mask = (CHAR_BIT * sizeof(n) - 1); // assumes width is a power of 2.
218 assert((c <= mask) && "left rotate by type width or more");
219 c &= mask;
220 return (n << c) | (n >> ((-c) & mask));
221}
222
223template <typename T> CONSTEXPR typename std::enable_if<std::is_integral<T>::value, T>::type rotr(T n, unsigned int c) {
224 const unsigned int mask = (CHAR_BIT * sizeof(n) - 1);
225 assert((c <= mask) && "left rotate by type width or more");
226 c &= mask;
227 return (n >> c) | (n << ((-c) & mask));
228}
235CONSTEXPR inline unsigned ilog2(uint32_t val) {
236#ifdef __GNUG__
237 return sizeof(uint32_t) * 8 - 1 - __builtin_clz(static_cast<unsigned>(val));
238#else
239 if(val == 0)
240 return std::numeric_limits<uint32_t>::max();
241 if(val == 1)
242 return 0;
243 auto ret = 0U;
244 while(val > 1) {
245 val >>= 1;
246 ++ret;
247 }
248 return ret;
249#endif
250} // namespace util
251
252#if defined(__GNUG__)
253constexpr inline bool hasOddParity(uint32_t u) { return bit_count(u) % 2; }
254#else
255CONSTEXPR inline bool hasOddParity(uint32_t u) { return bit_count(u) % 2; }
256#endif
264inline std::vector<std::string> split(const std::string& s, char separator) {
265 std::vector<std::string> output;
266 std::string::size_type prev_pos = 0;
267 std::string::size_type pos = 0;
268 while((pos = s.find(separator, pos)) != std::string::npos) {
269 std::string substring(s.substr(prev_pos, pos - prev_pos));
270 output.push_back(substring);
271 prev_pos = ++pos;
272 }
273 output.push_back(s.substr(prev_pos, pos - prev_pos)); // Last word
274 return output;
275 /* could also be done similar to this
276 // construct a stream from the string
277 std::stringstream ss(str);
278 // use stream iterators to copy the stream to the vector as whitespace separated strings
279 std::istream_iterator<std::string> it(ss);
280 std::istream_iterator<std::string> end;
281 std::vector<std::string> results(it, end);
282 return results;
283 */
284}
285
288template <typename Range, typename Value = typename Range::value_type>
289std::string join(Range const& elements, char const* const delimiter) {
290 std::ostringstream os;
291 auto b = std::begin(elements);
292 auto e = std::end(elements);
293 if(b != e) {
294 std::copy(b, std::prev(e), std::ostream_iterator<Value>(os, delimiter));
295 b = std::prev(e);
296 }
297 if(b != e)
298 os << *b;
299 return os.str();
300}
301
304template <typename Input, typename Output, typename Value = typename Output::value_type>
305void split(char delimiter, Output& output, Input const& input) {
306 for(auto cur = std::begin(input), beg = cur;; ++cur) {
307 if(cur == std::end(input) || *cur == delimiter || !*cur) {
308 output.insert(std::end(output), Value(beg, cur));
309 if(cur == std::end(input) || !*cur)
310 break;
311 beg = std::next(cur);
312 }
313 }
314}
315
321inline std::string& ltrim(std::string& str, const std::string& chars = "\t\n\v\f\r ") {
322 str.erase(0, str.find_first_not_of(chars));
323 return str;
324}
325
331inline std::string& rtrim(std::string& str, const std::string& chars = "\t\n\v\f\r ") {
332 str.erase(str.find_last_not_of(chars) + 1);
333 return str;
334}
335
341inline std::string& trim(std::string& str, const std::string& chars = "\t\n\v\f\r ") { return ltrim(rtrim(str, chars), chars); }
347inline std::string str_tolower(std::string str) {
348 std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::tolower(c); });
349 return str;
350}
351
356inline std::string str_toupper(std::string str) {
357 std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::toupper(c); });
358 return str;
359}
360
368inline bool iequals(const std::string& a, const std::string& b) {
369#if __cplusplus < 201402L
370 auto sz = a.size();
371 if(b.size() != sz)
372 return false;
373 for(auto i = 0U; i < sz; ++i)
374 if(tolower(static_cast<unsigned>(a[i])) != tolower(static_cast<unsigned>(b[i])))
375 return false;
376 return true;
377#else
378 return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](unsigned char a, unsigned char b) { return tolower(a) == tolower(b); });
379#endif
380}
381
382inline bool ends_with(std::string const& value, std::string const& ending) {
383 // if (ending.size() > value.size()) return false;
384 // return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
385 return value.length() >= ending.length() ? !value.compare(value.length() - ending.length(), ending.length(), ending) : false;
386}
396inline std::string padded(std::string str, size_t width, bool show_ellipsis = true) {
397 if(width < 7)
398 return str;
399 if(str.length() > width) {
400 if(show_ellipsis) {
401 auto pos = str.size() - (width - 6);
402 return str.substr(0, 3) + "..." + str.substr(pos, str.size() - pos);
403 } else
404 return str.substr(0, width);
405 } else {
406 return str + std::string(width - str.size(), ' ');
407 }
408}
409
414inline bool file_exists(const std::string& name) {
415 struct stat buffer {};
416 return (stat(name.c_str(), &buffer) == 0);
417}
418
424template <class T> inline T dir_name(T const& path, T const& delims = "/\\") {
425 auto pos = path.find_last_of(delims);
426 return pos > path.length() ? "." : path.substr(0, pos);
427}
428
434template <class T> inline T base_name(T const& path, T const& delims = "/\\") {
435 auto pos = path.find_last_of(delims);
436 return pos > path.length() ? path : path.substr(pos + 1);
437}
438
443template <class T> inline T remove_ext(T const& filename) {
444 typename T::size_type const p(filename.find_last_of('.'));
445 return p > 0 && p != T::npos ? filename.substr(0, p) : filename;
446}
447
457inline std::string glob_to_regex(std::string val) {
458 const struct {
459#ifdef MTI_SYSTEMC
460 const char* question_mark = "[^/]";
461 const char* star = "[^/]*";
462#else
463 const char* question_mark = "[^.]";
464 const char* star = "[^.]*";
465#endif
466 const char* double_star = ".*";
467 } subst_table;
468 auto is_regex_meta = [](char c) -> bool {
469 switch(c) {
470 default:
471 return false;
472 case '.':
473 case '(':
474 case ')':
475 case '{':
476 case '}':
477 case '+':
478 case '^':
479 case '$':
480 case '|':
481 return true;
482 }
483 };
484 util::trim(val);
485 std::ostringstream oss;
486 oss << "^";
487 bool in_character_class = false, in_quote = false;
488 for(auto idx = 0U; idx < val.length(); ++idx) {
489 auto c = val[idx];
490 if(in_character_class) {
491 in_character_class = ((c != ']') || (val[idx - 1] == '\\'));
492 oss << c;
493 continue;
494 }
495 if(in_quote) {
496 in_quote = false;
497 oss << c;
498 continue;
499 }
500 if(c == '\\') {
501 in_quote = true;
502 oss << c;
503 continue;
504 } else if(c == '[') {
505 oss << c;
506 in_character_class = true;
507 if(val[idx + 1] == '!') {
508 oss << '^';
509 idx++;
510 }
511 } else if(is_regex_meta(c)) {
512 oss << '\\' << c;
513 } else if(c == '?') {
514 oss << subst_table.question_mark;
515 } else if(c == '*') {
516 if((idx + 1) < val.length() && val[idx + 1] == '*') {
517 idx++;
518 oss << subst_table.double_star;
519 } else
520 oss << subst_table.star;
521 } else {
522 oss << c;
523 }
524 }
525 oss << "$";
526 return oss.str();
527}
528
529} // namespace util
531#endif /* _UTIL_ITIES_H_ */
CONSTEXPR T signextend(const typename std::make_unsigned< T >::type x)
sign-extend a given value
Definition ities.h:133
CONSTEXPR std::enable_if< std::is_unsigned< T >::value, T >::type bit_sub(T v)
extract bit ranges from plain data types
Definition ities.h:55
R bit_comb(T first, Args... args)
Definition ities.h:123
constexpr std::make_signed< T >::type signed_bit_sub(T v)
a function that converts from B bits to T in one operation
Definition ities.h:152
SCC common utilities.
Definition bit_field.h:30
std::string glob_to_regex(std::string val)
Definition ities.h:457
std::string str_tolower(std::string str)
Definition ities.h:347
std::string & ltrim(std::string &str, const std::string &chars="\t\n\v\f\r ")
Definition ities.h:321
std::string padded(std::string str, size_t width, bool show_ellipsis=true)
pad a string to a given length by either cutting of the overflow or inserting an ellipsis
Definition ities.h:396
T remove_ext(T const &filename)
Definition ities.h:443
std::vector< std::string > split(const std::string &s, char separator)
Definition ities.h:264
CONSTEXPR unsigned ilog2(uint32_t val)
Definition ities.h:235
std::string & rtrim(std::string &str, const std::string &chars="\t\n\v\f\r ")
Definition ities.h:331
bool iequals(const std::string &a, const std::string &b)
compare two string ignoring case
Definition ities.h:368
bool file_exists(const std::string &name)
Definition ities.h:414
std::string join(Range const &elements, char const *const delimiter)
Definition ities.h:289
std::string & trim(std::string &str, const std::string &chars="\t\n\v\f\r ")
Definition ities.h:341
T dir_name(T const &path, T const &delims="/\\")
Definition ities.h:424
T base_name(T const &path, T const &delims="/\\")
Definition ities.h:434
std::string str_toupper(std::string str)
Definition ities.h:356