scc  2022.4.0
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 }
76 template <typename T, unsigned B> CONSTEXPR T signextend(const typename std::make_unsigned<T>::type x) {
77  struct X {
78  T x : B;
79  X(T x_)
80  : x(x_) {}
81  } s(x);
82  return s.x;
83 }
84 
85 // according to http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend
95 template <unsigned int bit, unsigned int width, typename T> inline constexpr typename std::make_signed<T>::type signed_bit_sub(T v) {
96 #if __cplusplus < 201402L
97  return ((v << (sizeof(T) * 8 - bit - width)) >> (sizeof(T) * 8 - width));
98 #else
99  typename std::make_signed<T>::type r = v << (sizeof(T) * 8 - bit - width);
100  typename std::make_signed<T>::type ret = (r >> (sizeof(T) * 8 - width));
101  return ret;
102 #endif
103 }
104 
106 namespace util {
107 template <typename T, typename... Args> std::unique_ptr<T> make_unique(Args&&... args) {
108 #if __cplusplus < 201402L
109  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
110 #else
111  return std::make_unique<T>(std::forward<Args>(args)...);
112 #endif
113 }
114 
115 // according to
116 // http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup
117 static std::array<const int, 32> MultiplyDeBruijnBitPosition = {
118  {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}};
119 template <size_t N> constexpr size_t find_first(std::bitset<N>& bits) {
120  static_assert(N <= 32, "find_first only supports bitsets smaller than 33");
121  return MultiplyDeBruijnBitPosition[static_cast<uint32_t>((bits.to_ulong() & -bits.to_ulong()) * 0x077CB531U) >> 27];
122 }
123 template <typename T> T leftmost_one(T n) {
124  for(T mask = 1; mask < sizeof(T) * 8; mask <<= 1)
125  n |= (n >> mask);
126  return n - (n >> 1);
127 }
128 
129 // according to
130 // https://stackoverflow.com/questions/8871204/count-number-of-1s-in-binary-representation
131 #if defined(__GNUG__)
132 constexpr inline size_t bit_count(uint32_t u) { return __builtin_popcount(u); }
133 constexpr inline size_t bit_count(uint64_t u) { return __builtin_popcountl(u); }
134 #elif __cplusplus < 201402L
135 constexpr inline size_t uCount(uint32_t u) { return u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111); }
136 constexpr inline size_t bit_count(uint32_t u) { return ((uCount(u) + (uCount(u) >> 3)) & 030707070707) % 63; }
137 #else
138 constexpr inline size_t bit_count(uint32_t u) {
139  size_t uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
140  return ((uCount + (uCount >> 3)) & 030707070707) % 63;
141 }
142 #endif
143 
144 template <typename T> CONSTEXPR typename std::enable_if<std::is_integral<T>::value, T>::type rotl(T n, unsigned int c) {
145  const unsigned int mask = (CHAR_BIT * sizeof(n) - 1); // assumes width is a power of 2.
146  assert((c <= mask) && "left rotate by type width or more");
147  c &= mask;
148  return (n << c) | (n >> ((-c) & mask));
149 }
150 
151 template <typename T> CONSTEXPR typename std::enable_if<std::is_integral<T>::value, T>::type rotr(T n, unsigned int c) {
152  const unsigned int mask = (CHAR_BIT * sizeof(n) - 1);
153  assert((c <= mask) && "left rotate by type width or more");
154  c &= mask;
155  return (n >> c) | (n << ((-c) & mask));
156 }
163 CONSTEXPR inline unsigned ilog2(uint32_t val) {
164 #ifdef __GNUG__
165  return sizeof(uint32_t) * 8 - 1 - __builtin_clz(static_cast<unsigned>(val));
166 #else
167  if(val == 0)
168  return std::numeric_limits<uint32_t>::max();
169  if(val == 1)
170  return 0;
171  auto ret = 0U;
172  while(val > 1) {
173  val >>= 1;
174  ++ret;
175  }
176  return ret;
177 #endif
178 } // namespace util
179 
180 #if defined(__GNUG__)
181 constexpr inline bool hasOddParity(uint32_t u) { return bit_count(u) % 2; }
182 #else
183 CONSTEXPR inline bool hasOddParity(uint32_t u) { return bit_count(u) % 2; }
184 #endif
192 inline std::vector<std::string> split(const std::string& s, char separator) {
193  std::vector<std::string> output;
194  std::string::size_type prev_pos = 0;
195  std::string::size_type pos = 0;
196  while((pos = s.find(separator, pos)) != std::string::npos) {
197  std::string substring(s.substr(prev_pos, pos - prev_pos));
198  output.push_back(substring);
199  prev_pos = ++pos;
200  }
201  output.push_back(s.substr(prev_pos, pos - prev_pos)); // Last word
202  return output;
203  /* could also be done similar to this
204  // construct a stream from the string
205  std::stringstream ss(str);
206  // use stream iterators to copy the stream to the vector as whitespace separated strings
207  std::istream_iterator<std::string> it(ss);
208  std::istream_iterator<std::string> end;
209  std::vector<std::string> results(it, end);
210  return results;
211  */
212 }
213 
216 template <typename Range, typename Value = typename Range::value_type>
217 std::string join(Range const& elements, char const* const delimiter) {
218  std::ostringstream os;
219  auto b = std::begin(elements);
220  auto e = std::end(elements);
221  if(b != e) {
222  std::copy(b, std::prev(e), std::ostream_iterator<Value>(os, delimiter));
223  b = std::prev(e);
224  }
225  if(b != e)
226  os << *b;
227  return os.str();
228 }
229 
232 template <typename Input, typename Output, typename Value = typename Output::value_type>
233 void split(char delimiter, Output& output, Input const& input) {
234  for(auto cur = std::begin(input), beg = cur;; ++cur) {
235  if(cur == std::end(input) || *cur == delimiter || !*cur) {
236  output.insert(std::end(output), Value(beg, cur));
237  if(cur == std::end(input) || !*cur)
238  break;
239  beg = std::next(cur);
240  }
241  }
242 }
249 inline std::string& ltrim(std::string& str, const std::string& chars = "\t\n\v\f\r ") {
250  str.erase(0, str.find_first_not_of(chars));
251  return str;
252 }
259 inline std::string& rtrim(std::string& str, const std::string& chars = "\t\n\v\f\r ") {
260  str.erase(str.find_last_not_of(chars) + 1);
261  return str;
262 }
269 inline std::string& trim(std::string& str, const std::string& chars = "\t\n\v\f\r ") { return ltrim(rtrim(str, chars), chars); }
275 inline std::string str_tolower(std::string str) {
276  std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::tolower(c); });
277  return str;
278 }
284 inline std::string str_toupper(std::string str) {
285  std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::toupper(c); });
286  return str;
287 }
296 inline bool iequals(const std::string& a, const std::string& b) {
297 #if __cplusplus < 201402L
298  auto sz = a.size();
299  if(b.size() != sz)
300  return false;
301  for(auto i = 0U; i < sz; ++i)
302  if(tolower(static_cast<unsigned>(a[i])) != tolower(static_cast<unsigned>(b[i])))
303  return false;
304  return true;
305 #else
306  return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](unsigned char a, unsigned char b) { return tolower(a) == tolower(b); });
307 #endif
308 }
309 
310 inline bool ends_with(std::string const& value, std::string const& ending) {
311  // if (ending.size() > value.size()) return false;
312  // return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
313  return value.length() >= ending.length() ? !value.compare(value.length() - ending.length(), ending.length(), ending) : false;
314 }
324 inline std::string padded(std::string str, size_t width, bool show_ellipsis = true) {
325  if(width < 7)
326  return str;
327  if(str.length() > width) {
328  if(show_ellipsis) {
329  auto pos = str.size() - (width - 6);
330  return str.substr(0, 3) + "..." + str.substr(pos, str.size() - pos);
331  } else
332  return str.substr(0, width);
333  } else {
334  return str + std::string(width - str.size(), ' ');
335  }
336 }
342 inline bool file_exists(const std::string& name) {
343  struct stat buffer {};
344  return (stat(name.c_str(), &buffer) == 0);
345 }
352 template <class T> inline T dir_name(T const& path, T const& delims = "/\\") {
353  auto pos = path.find_last_of(delims);
354  return pos > path.length() ? "." : path.substr(0, pos);
355 }
362 template <class T> inline T base_name(T const& path, T const& delims = "/\\") {
363  auto pos = path.find_last_of(delims);
364  return pos > path.length() ? path : path.substr(pos + 1);
365 }
371 template <class T> inline T remove_ext(T const& filename) {
372  typename T::size_type const p(filename.find_last_of('.'));
373  return p > 0 && p != T::npos ? filename.substr(0, p) : filename;
374 }
385 inline std::string glob_to_regex(std::string val) {
386  const struct {
387 #ifdef MTI_SYSTEMC
388  const char* question_mark = "[^/]";
389  const char* star = "[^/]*";
390 #else
391  const char* question_mark = "[^.]";
392  const char* star = "[^.]*";
393 #endif
394  const char* double_star = ".*";
395  } subst_table;
396  auto is_regex_meta = [](char c) -> bool {
397  switch(c) {
398  default:
399  return false;
400  case '.':
401  case '(':
402  case ')':
403  case '{':
404  case '}':
405  case '+':
406  case '^':
407  case '$':
408  case '|':
409  return true;
410  }
411  };
412  util::trim(val);
413  std::ostringstream oss;
414  oss << "^";
415  bool in_character_class = false, in_quote = false;
416  for(auto idx = 0U; idx < val.length(); ++idx) {
417  auto c = val[idx];
418  if(in_character_class) {
419  in_character_class = ((c != ']') || (val[idx - 1] == '\\'));
420  oss << c;
421  continue;
422  }
423  if(in_quote) {
424  in_quote = false;
425  oss << c;
426  continue;
427  }
428  if(c == '\\') {
429  in_quote = true;
430  oss << c;
431  continue;
432  } else if(c == '[') {
433  oss << c;
434  in_character_class = true;
435  if(val[idx + 1] == '!') {
436  oss << '^';
437  idx++;
438  }
439  } else if(is_regex_meta(c)) {
440  oss << '\\' << c;
441  } else if(c == '?') {
442  oss << subst_table.question_mark;
443  } else if(c == '*') {
444  if((idx + 1) < val.length() && val[idx + 1] == '*') {
445  idx++;
446  oss << subst_table.double_star;
447  } else
448  oss << subst_table.star;
449  } else {
450  oss << c;
451  }
452  }
453  oss << "$";
454  return oss.str();
455 }
456 
457 } // namespace util
459 #endif /* _UTIL_ITIES_H_ */
CONSTEXPR T signextend(const typename std::make_unsigned< T >::type x)
sign-extend a given value
Definition: ities.h:76
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:95
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
SCC common utilities.
Definition: bit_field.h:30
std::string glob_to_regex(std::string val)
Definition: ities.h:385
std::string str_tolower(std::string str)
Definition: ities.h:275
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:324
T remove_ext(T const &filename)
Definition: ities.h:371
CONSTEXPR unsigned ilog2(uint32_t val)
Definition: ities.h:163
std::vector< std::string > split(const std::string &s, char separator)
Definition: ities.h:192
bool iequals(const std::string &a, const std::string &b)
compare two string ignoring case
Definition: ities.h:296
bool file_exists(const std::string &name)
Definition: ities.h:342
std::string join(Range const &elements, char const *const delimiter)
Definition: ities.h:217
T dir_name(T const &path, T const &delims="/\\")
Definition: ities.h:352
std::string & trim(std::string &str, const std::string &chars="\t\n\v\f\r ")
Definition: ities.h:269
std::string & ltrim(std::string &str, const std::string &chars="\t\n\v\f\r ")
Definition: ities.h:249
std::string & rtrim(std::string &str, const std::string &chars="\t\n\v\f\r ")
Definition: ities.h:259
T base_name(T const &path, T const &delims="/\\")
Definition: ities.h:362
std::string str_toupper(std::string str)
Definition: ities.h:284