scc 2026.07
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 <fstream>
27#include <iterator>
28#include <limits>
29#include <memory>
30#include <sstream>
31#include <sys/stat.h>
32#include <type_traits>
33#include <vector>
34
35#if defined(__GNUC__)
36#ifndef LIKELY
37#define LIKELY(x) ::__builtin_expect(!!(x), 1)
38#endif
39#ifndef UNLIKELY
40#define UNLIKELY(x) ::__builtin_expect(!!(x), 0)
41#endif
42#else
43#ifndef LIKELY
44#define LIKELY(x) x
45#endif
46#ifndef UNLIKELY
47#define UNLIKELY(x) x
48#endif
49#endif
50
51#if __cplusplus < 201402L
52#define CONSTEXPR
53#else
54#define CONSTEXPR constexpr
55#endif
56
61// some helper functions
71template <unsigned int bit, unsigned int width, typename T>
72CONSTEXPR typename std::enable_if<std::is_unsigned<T>::value, T>::type bit_sub(T v) {
73 static_assert((bit + width) <= 8 * sizeof(T), "Accessed slice out of bounds");
74 static_assert(width > 0, "Width needs to be >0");
75 static_assert(width < sizeof(T) * 8, "");
76 return (v >> bit) & ((T(1) << width) - 1);
77}
78
79template <unsigned int bit, unsigned int width, typename T>
80CONSTEXPR typename std::enable_if<std::is_signed<T>::value, T>::type bit_sub(T v) {
81 static_assert((bit + width) <= 8 * sizeof(T), "Accessed slice out of bounds");
82 static_assert(width > 0, "Width needs to be >0");
83 auto field = v >> bit;
84 return (field & ~(~T(1) << (width - 1) << 1)) - (field & (T(1) << (width - 1)) << 1);
85}
86
87template <typename T> typename std::enable_if<std::is_unsigned<T>::value, T>::type bit_sub(T v, unsigned int bit, unsigned int width) {
88 assert((bit + width) <= 8 * sizeof(T) && "Accessed slice out of bounds");
89 assert(width > 0 && "Width needs to be >0");
90 T mask = width < sizeof(T) * 8 ? (T(1) << width) - 1 : std::numeric_limits<T>::max();
91 return (v >> bit) & mask;
92}
93
94template <typename T> typename std::enable_if<std::is_signed<T>::value, T>::type bit_sub(T v, unsigned int bit, unsigned int width) {
95 assert((bit + width) <= 8 * sizeof(T) && "Accessed slice out of bounds");
96 assert(width > 0 && "Width needs to be >0");
97 auto field = v >> bit;
98 return (field & ~(~T(1) << (width - 1) << 1)) - (field & (T(1) << (width - 1)) << 1);
99}
100
101template <typename T> struct bit_slice {
102 T& value;
103 unsigned base, width;
104 explicit bit_slice(T& value, unsigned base, unsigned width)
105 : value(value)
106 , base(base)
107 , width(width){};
108 explicit bit_slice(T& value, unsigned index)
109 : value(value)
110 , base(index)
111 , width(1){};
112 operator T() const { return bit_sub(value, base, width); }
113
114 bit_slice<T>& operator=(T v) {
115 T mask = ((T(1) << width) - 1);
116 value = (value & ~(mask << base)) | ((v & mask) << base);
117 return *this;
118 }
119 bit_slice<T>& operator=(bit_slice<T> const& _v) {
120 T v = static_cast<T>(_v);
121 T mask = ((T(1) << width) - 1);
122 value = (value & ~(mask << base)) | ((v & mask) << base);
123 return *this;
124 }
125};
126
127template <unsigned offset, typename R, typename T> R _bit_comb(T v) { return v << offset; }
128template <unsigned offset, typename R, typename T, typename... Args> R _bit_comb(T first, Args... args) {
129 return (first << offset) + _bit_comb<offset + 8, R>(args...);
130}
140template <typename R, typename T, typename... Args> R bit_comb(T first, Args... args) { return first + _bit_comb<8, R>(args...); }
141
150template <typename T, unsigned B> CONSTEXPR T signextend(const typename std::make_unsigned<T>::type x) {
151 struct X {
152 T x : B;
153 X(T x_)
154 : x(x_) {}
155 } s(x);
156 return s.x;
157}
158
159// according to http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend
169template <unsigned int bit, unsigned int width, typename T> inline constexpr typename std::make_signed<T>::type signed_bit_sub(T v) {
170#if __cplusplus < 201402L
171 return ((v << (sizeof(T) * 8 - bit - width)) >> (sizeof(T) * 8 - width));
172#else
173 typename std::make_signed<T>::type r = v << (sizeof(T) * 8 - bit - width);
174 typename std::make_signed<T>::type ret = (r >> (sizeof(T) * 8 - width));
175 return ret;
176#endif
177}
178
180inline constexpr uint64_t operator""_kB(unsigned long long val) { return val * 1 << 10; }
182inline constexpr uint64_t operator""_MB(unsigned long long val) { return val * 1 << 20; }
184inline constexpr uint64_t operator""_GB(unsigned long long val) { return val * 1 << 30; }
185
186inline constexpr uint64_t operator""_KiB(unsigned long long val) { return val * 1 << 10; }
188inline constexpr uint64_t operator""_MiB(unsigned long long val) { return val * 1 << 20; }
190inline constexpr uint64_t operator""_GiB(unsigned long long val) { return val * 1 << 30; }
192inline constexpr uint64_t operator""_TiB(unsigned long long val) { return val * 1 << 40; }
193
195namespace util {
196template <typename T, typename... Args> std::unique_ptr<T> make_unique(Args&&... args) {
197#if __cplusplus < 201402L
198 return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
199#else
200 return std::make_unique<T>(std::forward<Args>(args)...);
201#endif
202}
203
204// according to
205// http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup
206static std::array<const int, 32> MultiplyDeBruijnBitPosition = {
207 {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}};
208template <size_t N> constexpr size_t find_first(std::bitset<N>& bits) {
209 static_assert(N <= 32, "find_first only supports bitsets smaller than 33");
210 return MultiplyDeBruijnBitPosition[static_cast<uint32_t>((bits.to_ulong() & -bits.to_ulong()) * 0x077CB531U) >> 27];
211}
212template <typename T> T leftmost_one(T n) {
213 for(T mask = 1; mask < sizeof(T) * 8; mask <<= 1)
214 n |= (n >> mask);
215 return n - (n >> 1);
216}
217
218// according to
219// https://stackoverflow.com/questions/8871204/count-number-of-1s-in-binary-representation
220#if defined(__GNUG__)
221constexpr inline size_t bit_count(uint32_t u) { return __builtin_popcount(u); }
222constexpr inline size_t bit_count(uint64_t u) { return __builtin_popcountl(u); }
223#elif __cplusplus < 201402L
224constexpr inline size_t uCount(uint32_t u) { return u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111); }
225constexpr inline size_t bit_count(uint32_t u) { return ((uCount(u) + (uCount(u) >> 3)) & 030707070707) % 63; }
226#else
227constexpr inline size_t bit_count(uint32_t u) {
228 size_t uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
229 return ((uCount + (uCount >> 3)) & 030707070707) % 63;
230}
231#endif
232
233template <typename T> CONSTEXPR typename std::enable_if<std::is_integral<T>::value, T>::type rotl(T n, unsigned int c) {
234 const unsigned int mask = (CHAR_BIT * sizeof(n) - 1); // assumes width is a power of 2.
235 assert((c <= mask) && "left rotate by type width or more");
236 c &= mask;
237 return (n << c) | (n >> ((-c) & mask));
238}
239
240template <typename T> CONSTEXPR typename std::enable_if<std::is_integral<T>::value, T>::type rotr(T n, unsigned int c) {
241 const unsigned int mask = (CHAR_BIT * sizeof(n) - 1);
242 assert((c <= mask) && "left rotate by type width or more");
243 c &= mask;
244 return (n >> c) | (n << ((-c) & mask));
245}
252CONSTEXPR inline unsigned ilog2(uint32_t val) {
253#ifdef __GNUG__
254 return sizeof(uint32_t) * 8 - 1 - __builtin_clz(static_cast<unsigned>(val));
255#else
256 if(val == 0)
257 return std::numeric_limits<uint32_t>::max();
258 if(val == 1)
259 return 0;
260 auto ret = 0U;
261 while(val > 1) {
262 val >>= 1;
263 ++ret;
264 }
265 return ret;
266#endif
267} // namespace util
268
269#if defined(__GNUG__)
270constexpr inline bool hasOddParity(uint32_t u) { return bit_count(u) % 2; }
271#else
272CONSTEXPR inline bool hasOddParity(uint32_t u) { return bit_count(u) % 2; }
273#endif
281inline std::vector<std::string> split(const std::string& s, char separator) {
282 std::vector<std::string> output;
283 std::string::size_type prev_pos = 0;
284 std::string::size_type pos = 0;
285 while((pos = s.find(separator, pos)) != std::string::npos) {
286 std::string substring(s.substr(prev_pos, pos - prev_pos));
287 output.push_back(substring);
288 prev_pos = ++pos;
289 }
290 output.push_back(s.substr(prev_pos, pos - prev_pos)); // Last word
291 return output;
292 /* could also be done similar to this
293 // construct a stream from the string
294 std::stringstream ss(str);
295 // use stream iterators to copy the stream to the vector as whitespace separated strings
296 std::istream_iterator<std::string> it(ss);
297 std::istream_iterator<std::string> end;
298 std::vector<std::string> results(it, end);
299 return results;
300 */
301}
302
305template <typename Range, typename Value = typename Range::value_type>
306std::string join(Range const& elements, char const* const delimiter) {
307 std::ostringstream os;
308 auto b = std::begin(elements);
309 auto e = std::end(elements);
310 if(b != e) {
311 std::copy(b, std::prev(e), std::ostream_iterator<Value>(os, delimiter));
312 b = std::prev(e);
313 }
314 if(b != e)
315 os << *b;
316 return os.str();
317}
318
321template <typename Input, typename Output, typename Value = typename Output::value_type>
322void split(char delimiter, Output& output, Input const& input) {
323 for(auto cur = std::begin(input), beg = cur;; ++cur) {
324 if(cur == std::end(input) || *cur == delimiter || !*cur) {
325 output.insert(std::end(output), Value(beg, cur));
326 if(cur == std::end(input) || !*cur)
327 break;
328 beg = std::next(cur);
329 }
330 }
331}
332
338inline std::string& ltrim(std::string& str, const std::string& chars = "\t\n\v\f\r ") {
339 str.erase(0, str.find_first_not_of(chars));
340 return str;
341}
342
348inline std::string& rtrim(std::string& str, const std::string& chars = "\t\n\v\f\r ") {
349 str.erase(str.find_last_not_of(chars) + 1);
350 return str;
351}
352
358inline std::string& trim(std::string& str, const std::string& chars = "\t\n\v\f\r ") { return ltrim(rtrim(str, chars), chars); }
364inline std::string str_tolower(std::string str) {
365 std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::tolower(c); });
366 return str;
367}
368
373inline std::string str_toupper(std::string str) {
374 std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::toupper(c); });
375 return str;
376}
377
385inline bool iequals(const std::string& a, const std::string& b) {
386#if __cplusplus < 201402L
387 auto sz = a.size();
388 if(b.size() != sz)
389 return false;
390 for(auto i = 0U; i < sz; ++i)
391 if(tolower(static_cast<unsigned>(a[i])) != tolower(static_cast<unsigned>(b[i])))
392 return false;
393 return true;
394#else
395 return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](unsigned char a, unsigned char b) { return tolower(a) == tolower(b); });
396#endif
397}
398
399inline bool ends_with(std::string const& value, std::string const& ending) {
400 // if (ending.size() > value.size()) return false;
401 // return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
402 return value.length() >= ending.length() ? !value.compare(value.length() - ending.length(), ending.length(), ending) : false;
403}
413inline std::string padded(std::string str, size_t width, bool show_ellipsis = true) {
414 if(width < 7)
415 return str;
416 if(str.length() > width) {
417 if(show_ellipsis) {
418 auto pos = str.size() - (width - 6);
419 return str.substr(0, 3) + "..." + str.substr(pos, str.size() - pos);
420 } else
421 return str.substr(0, width);
422 } else {
423 return str + std::string(width - str.size(), ' ');
424 }
425}
426
431inline bool file_exists(const std::string& name) {
432 struct stat buffer {};
433 return (stat(name.c_str(), &buffer) == 0);
434}
435
441template <class T> inline T dir_name(T const& path, T const& delims = "/\\") {
442 auto pos = path.find_last_of(delims);
443 return pos > path.length() ? "." : path.substr(0, pos);
444}
445
451template <class T> inline T base_name(T const& path, T const& delims = "/\\") {
452 auto pos = path.find_last_of(delims);
453 return pos > path.length() ? path : path.substr(pos + 1);
454}
455
460template <class T> inline T remove_ext(T const& filename) {
461 typename T::size_type const p(filename.find_last_of('.'));
462 return p > 0 && p != T::npos ? filename.substr(0, p) : filename;
463}
464
474inline std::string glob_to_regex(std::string val) {
475 const struct {
476#ifdef MTI_SYSTEMC
477 const char* question_mark = "[^/]";
478 const char* star = "[^/]*";
479#else
480 const char* question_mark = "[^.]";
481 const char* star = "[^.]*";
482#endif
483 const char* double_star = ".*";
484 } subst_table;
485 auto is_regex_meta = [](char c) -> bool {
486 switch(c) {
487 default:
488 return false;
489 case '.':
490 case '(':
491 case ')':
492 case '{':
493 case '}':
494 case '+':
495 case '^':
496 case '$':
497 case '|':
498 return true;
499 }
500 };
501 util::trim(val);
502 std::ostringstream oss;
503 oss << "^";
504 bool in_character_class = false, in_quote = false;
505 for(auto idx = 0U; idx < val.length(); ++idx) {
506 auto c = val[idx];
507 if(in_character_class) {
508 in_character_class = ((c != ']') || (val[idx - 1] == '\\'));
509 oss << c;
510 continue;
511 }
512 if(in_quote) {
513 in_quote = false;
514 oss << c;
515 continue;
516 }
517 if(c == '\\') {
518 in_quote = true;
519 oss << c;
520 continue;
521 } else if(c == '[') {
522 oss << c;
523 in_character_class = true;
524 if(val[idx + 1] == '!') {
525 oss << '^';
526 idx++;
527 }
528 } else if(is_regex_meta(c)) {
529 oss << '\\' << c;
530 } else if(c == '?') {
531 oss << subst_table.question_mark;
532 } else if(c == '*') {
533 if((idx + 1) < val.length() && val[idx + 1] == '*') {
534 idx++;
535 oss << subst_table.double_star;
536 } else
537 oss << subst_table.star;
538 } else {
539 oss << c;
540 }
541 }
542 oss << "$";
543 return oss.str();
544}
545
546// ============================================================
547// File type detection
548// ============================================================
549
550enum class file_type_e { PLAIN, GZIP, BZIP2, XZ, ZSTD };
551
552inline file_type_e detect_file_type(const std::string& path) {
553 std::ifstream file(path, std::ios::binary);
554 if(!file)
555 throw std::runtime_error("cannot open file");
556
557 unsigned char magic[6] = {0};
558 file.read(reinterpret_cast<char*>(magic), sizeof(magic));
559
560 if(magic[0] == 0x1F && magic[1] == 0x8B)
561 return file_type_e::GZIP;
562
563 if(magic[0] == 0x42 && magic[1] == 0x5A && magic[2] == 0x68)
564 return file_type_e::BZIP2;
565
566 if(magic[0] == 0xFD && magic[1] == 0x37 && magic[2] == 0x7A && magic[3] == 0x58 && magic[4] == 0x5A && magic[5] == 0x00)
567 return file_type_e::XZ;
568
569 if(magic[0] == 0x28 && magic[1] == 0xB5 && magic[2] == 0x2F && magic[3] == 0xFD)
570 return file_type_e::ZSTD;
571 return file_type_e::PLAIN;
572}
573
574} // namespace util
576#endif /* _UTIL_ITIES_H_ */
CONSTEXPR T signextend(const typename std::make_unsigned< T >::type x)
sign-extend a given value
Definition ities.h:150
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:72
R bit_comb(T first, Args... args)
Definition ities.h:140
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:169
SCC common utilities.
Definition bit_field.h:30
std::string glob_to_regex(std::string val)
Definition ities.h:474
std::string str_tolower(std::string str)
Definition ities.h:364
std::string & ltrim(std::string &str, const std::string &chars="\t\n\v\f\r ")
Definition ities.h:338
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:413
T remove_ext(T const &filename)
Definition ities.h:460
std::vector< std::string > split(const std::string &s, char separator)
Definition ities.h:281
CONSTEXPR unsigned ilog2(uint32_t val)
Definition ities.h:252
std::string & rtrim(std::string &str, const std::string &chars="\t\n\v\f\r ")
Definition ities.h:348
bool iequals(const std::string &a, const std::string &b)
compare two string ignoring case
Definition ities.h:385
bool file_exists(const std::string &name)
Definition ities.h:431
std::string join(Range const &elements, char const *const delimiter)
Definition ities.h:306
std::string & trim(std::string &str, const std::string &chars="\t\n\v\f\r ")
Definition ities.h:358
T dir_name(T const &path, T const &delims="/\\")
Definition ities.h:441
T base_name(T const &path, T const &delims="/\\")
Definition ities.h:451
std::string str_toupper(std::string str)
Definition ities.h:373