scc  2024.06
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 <memory>
28 #include <sstream>
29 #include <sys/stat.h>
30 #include <type_traits>
31 #include <vector>
32 
33 #if __cplusplus < 201402L
34 #define CONSTEXPR
35 #else
36 #define CONSTEXPR constexpr
37 #endif
38 
43 // some helper functions
53 template <unsigned int bit, unsigned int width, typename T>
54 CONSTEXPR typename std::enable_if<std::is_unsigned<T>::value, T>::type bit_sub(T v) {
55  static_assert((bit + width) <= 8 * sizeof(T));
56  T res = (v >> bit) & ((T(1) << width) - 1);
57  return res;
58 }
59 
60 template <unsigned int bit, unsigned int width, typename T>
61 CONSTEXPR typename std::enable_if<std::is_signed<T>::value, T>::type bit_sub(T v) {
62  static_assert((bit + width) <= 8 * sizeof(T));
63  static_assert(width > 0);
64  auto field = v >> bit;
65  auto amount = (field & ~(~T(1) << (width - 1) << 1)) - (field & (T(1) << (width - 1)) << 1);
66  return amount;
67 }
68 
69 template <unsigned offset, typename R, typename T> R _bit_comb(T v) { return v << offset; }
70 template <unsigned offset, typename R, typename T, typename... Args> R _bit_comb(T first, Args... args) {
71  return (first << offset) + _bit_comb<offset + 8, R>(args...);
72 }
82 template <typename R, typename T, typename... Args> R bit_comb(T first, Args... args) { return first + _bit_comb<8, R>(args...); }
83 
92 template <typename T, unsigned B> CONSTEXPR T signextend(const typename std::make_unsigned<T>::type x) {
93  struct X {
94  T x : B;
95  X(T x_)
96  : x(x_) {}
97  } s(x);
98  return s.x;
99 }
100 
101 // according to http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend
111 template <unsigned int bit, unsigned int width, typename T> inline constexpr typename std::make_signed<T>::type signed_bit_sub(T v) {
112 #if __cplusplus < 201402L
113  return ((v << (sizeof(T) * 8 - bit - width)) >> (sizeof(T) * 8 - width));
114 #else
115  typename std::make_signed<T>::type r = v << (sizeof(T) * 8 - bit - width);
116  typename std::make_signed<T>::type ret = (r >> (sizeof(T) * 8 - width));
117  return ret;
118 #endif
119 }
120 
122 inline constexpr uint64_t operator"" _kB(unsigned long long val) { return val * 1 << 10; }
124 inline constexpr uint64_t operator"" _MB(unsigned long long val) { return val * 1 << 20; }
126 inline constexpr uint64_t operator"" _GB(unsigned long long val) { return val * 1 << 30; }
127 
128 inline constexpr uint64_t operator"" _KiB(unsigned long long val) { return val * 1 << 10; }
130 inline constexpr uint64_t operator"" _MiB(unsigned long long val) { return val * 1 << 20; }
132 inline constexpr uint64_t operator"" _GiB(unsigned long long val) { return val * 1 << 30; }
134 inline constexpr uint64_t operator"" _TiB(unsigned long long val) { return val * 1 << 40; }
135 
137 namespace util {
138 template <typename T, typename... Args> std::unique_ptr<T> make_unique(Args&&... args) {
139 #if __cplusplus < 201402L
140  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
141 #else
142  return std::make_unique<T>(std::forward<Args>(args)...);
143 #endif
144 }
145 
146 // according to
147 // http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup
148 static std::array<const int, 32> MultiplyDeBruijnBitPosition = {
149  {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}};
150 template <size_t N> constexpr size_t find_first(std::bitset<N>& bits) {
151  static_assert(N <= 32, "find_first only supports bitsets smaller than 33");
152  return MultiplyDeBruijnBitPosition[static_cast<uint32_t>((bits.to_ulong() & -bits.to_ulong()) * 0x077CB531U) >> 27];
153 }
154 template <typename T> T leftmost_one(T n) {
155  for(T mask = 1; mask < sizeof(T) * 8; mask <<= 1)
156  n |= (n >> mask);
157  return n - (n >> 1);
158 }
159 
160 // according to
161 // https://stackoverflow.com/questions/8871204/count-number-of-1s-in-binary-representation
162 #if defined(__GNUG__)
163 constexpr inline size_t bit_count(uint32_t u) { return __builtin_popcount(u); }
164 constexpr inline size_t bit_count(uint64_t u) { return __builtin_popcountl(u); }
165 #elif __cplusplus < 201402L
166 constexpr inline size_t uCount(uint32_t u) { return u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111); }
167 constexpr inline size_t bit_count(uint32_t u) { return ((uCount(u) + (uCount(u) >> 3)) & 030707070707) % 63; }
168 #else
169 constexpr inline size_t bit_count(uint32_t u) {
170  size_t uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
171  return ((uCount + (uCount >> 3)) & 030707070707) % 63;
172 }
173 #endif
174 
175 template <typename T> CONSTEXPR typename std::enable_if<std::is_integral<T>::value, T>::type rotl(T n, unsigned int c) {
176  const unsigned int mask = (CHAR_BIT * sizeof(n) - 1); // assumes width is a power of 2.
177  assert((c <= mask) && "left rotate by type width or more");
178  c &= mask;
179  return (n << c) | (n >> ((-c) & mask));
180 }
181 
182 template <typename T> CONSTEXPR typename std::enable_if<std::is_integral<T>::value, T>::type rotr(T n, unsigned int c) {
183  const unsigned int mask = (CHAR_BIT * sizeof(n) - 1);
184  assert((c <= mask) && "left rotate by type width or more");
185  c &= mask;
186  return (n >> c) | (n << ((-c) & mask));
187 }
194 CONSTEXPR inline unsigned ilog2(uint32_t val) {
195 #ifdef __GNUG__
196  return sizeof(uint32_t) * 8 - 1 - __builtin_clz(static_cast<unsigned>(val));
197 #else
198  if(val == 0)
199  return std::numeric_limits<uint32_t>::max();
200  if(val == 1)
201  return 0;
202  auto ret = 0U;
203  while(val > 1) {
204  val >>= 1;
205  ++ret;
206  }
207  return ret;
208 #endif
209 } // namespace util
210 
211 #if defined(__GNUG__)
212 constexpr inline bool hasOddParity(uint32_t u) { return bit_count(u) % 2; }
213 #else
214 CONSTEXPR inline bool hasOddParity(uint32_t u) { return bit_count(u) % 2; }
215 #endif
223 inline std::vector<std::string> split(const std::string& s, char separator) {
224  std::vector<std::string> output;
225  std::string::size_type prev_pos = 0;
226  std::string::size_type pos = 0;
227  while((pos = s.find(separator, pos)) != std::string::npos) {
228  std::string substring(s.substr(prev_pos, pos - prev_pos));
229  output.push_back(substring);
230  prev_pos = ++pos;
231  }
232  output.push_back(s.substr(prev_pos, pos - prev_pos)); // Last word
233  return output;
234  /* could also be done similar to this
235  // construct a stream from the string
236  std::stringstream ss(str);
237  // use stream iterators to copy the stream to the vector as whitespace separated strings
238  std::istream_iterator<std::string> it(ss);
239  std::istream_iterator<std::string> end;
240  std::vector<std::string> results(it, end);
241  return results;
242  */
243 }
244 
247 template <typename Range, typename Value = typename Range::value_type>
248 std::string join(Range const& elements, char const* const delimiter) {
249  std::ostringstream os;
250  auto b = std::begin(elements);
251  auto e = std::end(elements);
252  if(b != e) {
253  std::copy(b, std::prev(e), std::ostream_iterator<Value>(os, delimiter));
254  b = std::prev(e);
255  }
256  if(b != e)
257  os << *b;
258  return os.str();
259 }
260 
263 template <typename Input, typename Output, typename Value = typename Output::value_type>
264 void split(char delimiter, Output& output, Input const& input) {
265  for(auto cur = std::begin(input), beg = cur;; ++cur) {
266  if(cur == std::end(input) || *cur == delimiter || !*cur) {
267  output.insert(std::end(output), Value(beg, cur));
268  if(cur == std::end(input) || !*cur)
269  break;
270  beg = std::next(cur);
271  }
272  }
273 }
280 inline std::string& ltrim(std::string& str, const std::string& chars = "\t\n\v\f\r ") {
281  str.erase(0, str.find_first_not_of(chars));
282  return str;
283 }
290 inline std::string& rtrim(std::string& str, const std::string& chars = "\t\n\v\f\r ") {
291  str.erase(str.find_last_not_of(chars) + 1);
292  return str;
293 }
300 inline std::string& trim(std::string& str, const std::string& chars = "\t\n\v\f\r ") { return ltrim(rtrim(str, chars), chars); }
306 inline std::string str_tolower(std::string str) {
307  std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::tolower(c); });
308  return str;
309 }
315 inline std::string str_toupper(std::string str) {
316  std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::toupper(c); });
317  return str;
318 }
327 inline bool iequals(const std::string& a, const std::string& b) {
328 #if __cplusplus < 201402L
329  auto sz = a.size();
330  if(b.size() != sz)
331  return false;
332  for(auto i = 0U; i < sz; ++i)
333  if(tolower(static_cast<unsigned>(a[i])) != tolower(static_cast<unsigned>(b[i])))
334  return false;
335  return true;
336 #else
337  return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](unsigned char a, unsigned char b) { return tolower(a) == tolower(b); });
338 #endif
339 }
340 
341 inline bool ends_with(std::string const& value, std::string const& ending) {
342  // if (ending.size() > value.size()) return false;
343  // return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
344  return value.length() >= ending.length() ? !value.compare(value.length() - ending.length(), ending.length(), ending) : false;
345 }
355 inline std::string padded(std::string str, size_t width, bool show_ellipsis = true) {
356  if(width < 7)
357  return str;
358  if(str.length() > width) {
359  if(show_ellipsis) {
360  auto pos = str.size() - (width - 6);
361  return str.substr(0, 3) + "..." + str.substr(pos, str.size() - pos);
362  } else
363  return str.substr(0, width);
364  } else {
365  return str + std::string(width - str.size(), ' ');
366  }
367 }
373 inline bool file_exists(const std::string& name) {
374  struct stat buffer {};
375  return (stat(name.c_str(), &buffer) == 0);
376 }
383 template <class T> inline T dir_name(T const& path, T const& delims = "/\\") {
384  auto pos = path.find_last_of(delims);
385  return pos > path.length() ? "." : path.substr(0, pos);
386 }
393 template <class T> inline T base_name(T const& path, T const& delims = "/\\") {
394  auto pos = path.find_last_of(delims);
395  return pos > path.length() ? path : path.substr(pos + 1);
396 }
402 template <class T> inline T remove_ext(T const& filename) {
403  typename T::size_type const p(filename.find_last_of('.'));
404  return p > 0 && p != T::npos ? filename.substr(0, p) : filename;
405 }
416 inline std::string glob_to_regex(std::string val) {
417  const struct {
418 #ifdef MTI_SYSTEMC
419  const char* question_mark = "[^/]";
420  const char* star = "[^/]*";
421 #else
422  const char* question_mark = "[^.]";
423  const char* star = "[^.]*";
424 #endif
425  const char* double_star = ".*";
426  } subst_table;
427  auto is_regex_meta = [](char c) -> bool {
428  switch(c) {
429  default:
430  return false;
431  case '.':
432  case '(':
433  case ')':
434  case '{':
435  case '}':
436  case '+':
437  case '^':
438  case '$':
439  case '|':
440  return true;
441  }
442  };
443  util::trim(val);
444  std::ostringstream oss;
445  oss << "^";
446  bool in_character_class = false, in_quote = false;
447  for(auto idx = 0U; idx < val.length(); ++idx) {
448  auto c = val[idx];
449  if(in_character_class) {
450  in_character_class = ((c != ']') || (val[idx - 1] == '\\'));
451  oss << c;
452  continue;
453  }
454  if(in_quote) {
455  in_quote = false;
456  oss << c;
457  continue;
458  }
459  if(c == '\\') {
460  in_quote = true;
461  oss << c;
462  continue;
463  } else if(c == '[') {
464  oss << c;
465  in_character_class = true;
466  if(val[idx + 1] == '!') {
467  oss << '^';
468  idx++;
469  }
470  } else if(is_regex_meta(c)) {
471  oss << '\\' << c;
472  } else if(c == '?') {
473  oss << subst_table.question_mark;
474  } else if(c == '*') {
475  if((idx + 1) < val.length() && val[idx + 1] == '*') {
476  idx++;
477  oss << subst_table.double_star;
478  } else
479  oss << subst_table.star;
480  } else {
481  oss << c;
482  }
483  }
484  oss << "$";
485  return oss.str();
486 }
487 
488 } // namespace util
490 #endif /* _UTIL_ITIES_H_ */
CONSTEXPR T signextend(const typename std::make_unsigned< T >::type x)
sign-extend a given value
Definition: ities.h:92
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:111
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:54
R bit_comb(T first, Args... args)
Definition: ities.h:82
SCC common utilities.
Definition: bit_field.h:30
std::string glob_to_regex(std::string val)
Definition: ities.h:416
std::string str_tolower(std::string str)
Definition: ities.h:306
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:355
T remove_ext(T const &filename)
Definition: ities.h:402
CONSTEXPR unsigned ilog2(uint32_t val)
Definition: ities.h:194
std::vector< std::string > split(const std::string &s, char separator)
Definition: ities.h:223
bool iequals(const std::string &a, const std::string &b)
compare two string ignoring case
Definition: ities.h:327
bool file_exists(const std::string &name)
Definition: ities.h:373
std::string join(Range const &elements, char const *const delimiter)
Definition: ities.h:248
T dir_name(T const &path, T const &delims="/\\")
Definition: ities.h:383
std::string & trim(std::string &str, const std::string &chars="\t\n\v\f\r ")
Definition: ities.h:300
std::string & ltrim(std::string &str, const std::string &chars="\t\n\v\f\r ")
Definition: ities.h:280
std::string & rtrim(std::string &str, const std::string &chars="\t\n\v\f\r ")
Definition: ities.h:290
T base_name(T const &path, T const &delims="/\\")
Definition: ities.h:393
std::string str_toupper(std::string str)
Definition: ities.h:315