Spicy
util.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <cxxabi.h>
6 
7 #include <algorithm>
8 #include <climits>
9 #include <cmath>
10 #include <functional>
11 #include <initializer_list>
12 #include <iostream>
13 #include <list>
14 #include <map>
15 #include <memory>
16 #include <optional>
17 #include <set>
18 #include <stdexcept>
19 #include <string>
20 #include <type_traits>
21 #include <unordered_map>
22 #include <utility>
23 #include <vector>
24 
25 #include <hilti/rt/filesystem.h>
26 #include <hilti/rt/unpack.h>
27 #include <hilti/rt/util.h>
28 
29 #include <hilti/autogen/config.h>
30 #include <hilti/base/result.h>
31 
32 namespace hilti::util::detail {
34 void __internal_error(const std::string& s);
35 } // namespace hilti::util::detail
36 
37 #undef TINYFORMAT_ERROR
38 #define TINYFORMAT_ERROR(reason) ::util::detail::__internal_error(reason)
39 #include <hilti/rt/3rdparty/tinyformat/tinyformat.h>
40 
41 namespace hilti {
42 
43 struct Configuration;
44 
50 #define _UNUSED(x) ((void)(x));
51 
53 #define IF_DERIVED_FROM(t, cls) typename std::enable_if_t<std::is_base_of<cls, t>::value>* = nullptr
54 
56 #define IF_NOT_DERIVED_FROM(t, cls) typename std::enable_if_t<! std::is_base_of<cls, t>::value>* = nullptr
57 
59 #define IF_SAME(t, cls) typename std::enable_if_t<std::is_same<cls, t>::value>* = nullptr
60 
62 #define IF_NOT_SAME(t, cls) typename std::enable_if_t<! std::is_same<cls, t>::value>* = nullptr
63 
64 namespace util {
65 
68 
70 extern void cannot_be_reached() __attribute__((noreturn));
71 
73 template<typename T>
74 std::string typename_() {
75  return demangle(typeid(T).name());
76 }
77 
79 template<typename... Args>
80 std::string fmt(const char* fmt, const Args&... args) {
81  return tfm::format(fmt, args...);
82 }
83 
85 template<typename X, typename F>
86 auto transform(const std::vector<X>& x, F f) {
87  using Y = typename std::result_of<F(X&)>::type;
88  std::vector<Y> y;
89  y.reserve(x.size());
90  for ( const auto& i : x )
91  y.emplace_back(f(i));
92  return y;
93 }
94 
96 template<typename X, typename F>
97 auto transform(const std::set<X>& x, F f) {
98  using Y = typename std::result_of<F(X&)>::type;
99  std::set<Y> y;
100  for ( const auto& i : x )
101  y.insert(f(i));
102  return y;
103 }
104 
106 template<typename X, typename F>
107 auto transform(const std::initializer_list<X>& x, F f) {
108  using Y = typename std::result_of<F(X&)>::type;
109  std::vector<Y> y;
110  for ( const auto& i : x )
111  y.emplace_back(f(i));
112  return y;
113 }
114 
116 template<typename X, typename F>
117 auto transform_to_vector(const std::set<X>& x, F f) {
118  using Y = typename std::result_of<F(X&)>::type;
119  std::vector<Y> y;
120  y.reserve(x.size());
121  for ( const auto& i : x )
122  y.push_back(f(i));
123  return y;
124 }
125 
127 template<typename X, typename F>
128 auto filter(const std::vector<X>& x, F f) {
129  std::vector<X> y;
130  y.reserve(x.size());
131  for ( const auto& i : x )
132  if ( f(i) )
133  y.emplace_back(i);
134  return y;
135 }
136 
138 template<typename X, typename F>
139 auto filter(const std::set<X>& x, F f) {
140  std::set<X> y;
141  for ( const auto& i : x )
142  if ( f(i) )
143  y.insert(i);
144  return y;
145 }
146 
151 template<typename T, typename TIter = decltype(std::begin(std::declval<T>())),
152  typename = decltype(std::end(std::declval<T>()))>
153 constexpr auto enumerate(T&& iterable) {
154  struct iterator {
155  size_t i;
156  TIter iter;
157  bool operator!=(const iterator& other) const { return iter != other.iter; }
158  void operator++() {
159  ++i;
160  ++iter;
161  }
162  auto operator*() const { return std::tie(i, *iter); }
163  };
164  struct iterable_wrapper {
165  T iterable;
166  auto begin() { return iterator{0, std::begin(iterable)}; }
167  auto end() { return iterator{0, std::end(iterable)}; }
168  };
169  return iterable_wrapper{std::forward<T>(iterable)};
170 }
171 
173 extern std::vector<std::string> split(std::string s, const std::string& delim = " ");
174 
179 extern std::pair<std::string, std::string> split1(std::string s, const std::string& delim = " ");
180 
185 extern std::pair<std::string, std::string> rsplit1(std::string s, const std::string& delim = " ");
186 
195 template<typename T>
196 std::vector<T> slice(const std::vector<T>& v, int begin, int end = -1) {
197  if ( begin < 0 )
198  begin = v.size() + begin;
199 
200  if ( static_cast<size_t>(begin) > v.size() )
201  return {};
202 
203  if ( end < 0 )
204  end = v.size() + end + 1;
205 
206  if ( begin < 0 )
207  begin = 0;
208 
209  if ( end < 0 )
210  end = 0;
211 
212  if ( static_cast<size_t>(end) > v.size() )
213  end = v.size();
214 
215  return std::vector<T>(v.begin() + begin, v.begin() + end);
216 }
217 
222 template<typename T>
223 std::string join(const T& l, const std::string& delim = "") {
224  std::string result;
225  bool first = true;
226 
227  for ( const auto& i : l ) {
228  if ( not first )
229  result += delim;
230  result += std::string(i);
231  first = false;
232  }
233 
234  return result;
235 }
236 
241 template<typename T>
242 std::string join(const std::initializer_list<T>& l, const std::string& delim = "") {
243  std::string result;
244  bool first = true;
245 
246  for ( const auto& i : l ) {
247  if ( not first )
248  result += delim;
249  result += std::string(i);
250  first = false;
251  }
252 
253  return result;
254 }
255 
260 template<typename iterator>
261 std::string join(const iterator& begin, const iterator& end, const std::string& delim = "") {
262  std::string result;
263  bool first = true;
264 
265  for ( iterator i = begin; i != end; i++ ) {
266  if ( not first )
267  result += delim;
268  result += std::string(*i);
269  first = false;
270  }
271 
272  return result;
273 }
274 
275 
293 extern std::string prefixParts(const std::string& in, const std::string& prefix, const std::string& include_tag = "");
294 
305 extern std::vector<std::string> flattenParts(const std::vector<std::string>& in);
306 
308 extern std::string replace(const std::string& s, const std::string& o, const std::string& n);
309 
311 extern std::string tolower(const std::string& s);
312 
314 extern std::string toupper(const std::string& s);
315 
317 extern std::string trim(const std::string& s);
318 
320 extern std::string rtrim(const std::string& s);
321 
323 extern std::string ltrim(const std::string& s);
324 
326 inline bool startsWith(const std::string& s, const std::string& prefix) { return s.find(prefix) == 0; }
327 
329 extern bool endsWith(const std::string& s, const std::string& suffix);
330 
332 extern uint64_t hash(const std::string& str);
333 
335 extern uint64_t hash(const char* data, size_t len);
336 
341 constexpr std::pair<intmax_t, intmax_t> signed_integer_range(int width) {
342  switch ( width ) {
343  case 8: return std::make_pair(INT8_MIN, INT8_MAX);
344  case 16: return std::make_pair(INT16_MIN, INT16_MAX);
345  case 32: return std::make_pair(INT32_MIN, INT32_MAX);
346  case 64: return std::make_pair(INT64_MIN, INT64_MAX);
347  default: throw std::out_of_range("unsupported integer width");
348  }
349 }
350 
355 constexpr std::pair<uintmax_t, uintmax_t> unsigned_integer_range(int width) {
356  switch ( width ) {
357  case 8: return std::make_pair(0, UINT8_MAX);
358  case 16: return std::make_pair(0, UINT16_MAX);
359  case 32: return std::make_pair(0, UINT32_MAX);
360  case 64: return std::make_pair(0, UINT64_MAX);
361  default: throw std::out_of_range("unsupported integer width");
362  }
363 }
364 
372 template<typename Error>
373 uint64_t chars_to_uint64(const char* dgts, unsigned int base, Error handler) {
374  errno = 0;
375  char* cp;
376  auto u = strtoul(dgts, &cp, base);
377  if ( cp == dgts || *cp != '\0' || (u == ULONG_MAX && errno == ERANGE) ) {
378  errno = 0;
379  handler();
380  }
381  return u;
382 };
383 
390 template<typename Error>
391 double chars_to_double(const char* dgts, Error handler) {
392  errno = 0;
393  char* cp;
394  auto d = strtod(dgts, &cp);
395  if ( cp == dgts || *cp != '\0' || (d == HUGE_VAL && errno == ERANGE) ) {
396  errno = 0;
397  handler();
398  }
399 
400  return d;
401 };
402 
413 extern std::string uitoa_n(uint64_t value, unsigned int base, int n = -1);
414 
415 using hilti::rt::escapeBytes;
416 using hilti::rt::escapeUTF8;
417 using hilti::rt::expandEscapes;
418 
426 inline std::string escapeBytesForCxx(std::string_view s) { return escapeBytes(std::move(s), true, true); }
427 
437 extern std::string toIdentifier(const std::string& s, bool ensure_non_keyword = false);
438 
440 extern double currentTime();
441 
443 extern hilti::Result<hilti::rt::filesystem::path> findInPaths(const hilti::rt::filesystem::path& file,
444  const std::vector<hilti::rt::filesystem::path>& paths);
445 
448 
456 
458 hilti::rt::filesystem::path currentExecutable();
459 
461 [[noreturn]] extern void abort_with_backtrace();
462 
464 template<class Iter, typename Result>
465 inline auto atoi_n(Iter s, Iter e, int base, Result* result) {
466  return hilti::rt::atoi_n(s, e, base, result);
467 }
468 
474 template<typename A, typename B>
475 std::list<std::pair<A, B>> zip2(const std::list<A>& lhs, const std::list<B>& rhs) {
476  std::list<std::pair<A, B>> result;
477  for ( std::pair<typename std::list<A>::const_iterator, typename std::list<B>::const_iterator> iter =
478  std::pair<typename std::list<A>::const_iterator, typename std::list<B>::const_iterator>(lhs.cbegin(),
479  rhs.cbegin());
480  iter.first != lhs.end() and iter.second != rhs.end(); ++iter.first, ++iter.second )
481  result.emplace_back(*iter.first, *iter.second);
482  return result;
483 }
484 
490 template<typename A, typename B>
491 std::vector<std::pair<A, B>> zip2(const std::vector<A>& lhs, const std::vector<B>& rhs) {
492  std::vector<std::pair<A, B>> result;
493  for ( std::pair<typename std::vector<A>::const_iterator, typename std::vector<B>::const_iterator> iter =
494  std::pair<typename std::vector<A>::const_iterator, typename std::vector<B>::const_iterator>(lhs.cbegin(),
495  rhs.cbegin());
496  iter.first != lhs.end() and iter.second != rhs.end(); ++iter.first, ++iter.second )
497  result.emplace_back(*iter.first, *iter.second);
498  return result;
499 }
500 
502 template<typename A, typename B>
503 std::set<A> map_keys(const std::map<A, B>& m) {
504  std::set<A> l;
505 
506  for ( const auto& i : m )
507  l.insert(i.first);
508 
509  return l;
510 }
511 
513 template<typename A, typename B>
514 std::set<B> map_values(const std::map<A, B>& m) {
515  std::set<B> l;
516 
517  for ( const auto& i : m )
518  l.insert(i.second);
519 
520  return l;
521 }
522 
524 template<typename A, typename B>
525 std::set<A> map_keys(const std::unordered_map<A, B>& m) {
526  std::set<A> l;
527 
528  for ( const auto& i : m )
529  l.insert(i.first);
530 
531  return l;
532 }
533 
535 template<typename A, typename B>
536 std::set<B> map_values(const std::unordered_map<A, B>& m) {
537  std::set<B> l;
538 
539  for ( const auto& i : m )
540  l.insert(i.second);
541 
542  return l;
543 }
544 
546 template<typename A, typename Compare = std::less<A>>
547 std::set<A, Compare> set_difference(const std::set<A, Compare>& a, const std::set<A, Compare>& b) {
548  std::set<A, Compare> r;
549  std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::inserter(r, r.end()), Compare());
550  return r;
551 }
552 
554 template<typename A, typename Compare = std::less<A>>
555 std::set<A, Compare> set_intersection(std::set<A, Compare>& a, std::set<A, Compare>& b) {
556  std::set<A, Compare> r;
557  std::set_intersection(a.begin(), a.end(), b.begin(), b.end(), std::inserter(r, r.end()), Compare());
558  return r;
559 }
560 
562 template<typename A, typename Compare = std::less<A>>
563 std::set<A, Compare> set_union(const std::set<A, Compare>& a, const std::set<A, Compare>& b) {
564  std::set<A, Compare> r;
565  std::set_union(a.begin(), a.end(), b.begin(), b.end(), std::inserter(r, r.end()), Compare());
566  return r;
567 }
568 
570 template<typename T>
571 std::vector<T> concat(std::vector<T> v1, const std::vector<T>& v2) {
572  v1.reserve(v1.size() + v2.size());
573  v1.insert(v1.end(), v2.begin(), v2.end());
574  return v1;
575 }
576 
578 template<typename T>
579 std::vector<T>& append(std::vector<T>& v1, const std::vector<T>& v2) {
580  v1.reserve(v1.size() + v2.size());
581  v1.insert(v1.end(), v2.begin(), v2.end());
582  return v1;
583 }
584 
586 template<typename T>
587 std::vector<T> remove_duplicates(std::vector<T> v) {
588  std::set<T> seen;
589  std::vector<T> out;
590 
591  for ( auto&& i : v ) {
592  if ( seen.find(i) != seen.end() )
593  continue;
594 
595  seen.insert(i);
596  out.emplace_back(std::move(i));
597  }
598 
599  return out;
600 }
601 
607 template<typename T>
608 std::string uniqueIndex(const T& c, std::string hint) {
609  if ( c.find(hint) == c.end() )
610  return hint;
611 
612  std::string idx;
613  int cnt = 1;
614 
615  while ( true ) {
616  std::string idx = fmt("%s.%d", hint, ++cnt);
617  if ( c.find(idx) == c.end() )
618  return idx;
619  }
620 }
621 
623 inline bool copyStream(std::istream& in, std::ostream& out) {
624  char buffer[4096];
625  while ( in.good() ) {
626  in.read(buffer, sizeof(buffer));
627  out.write(buffer, sizeof(buffer));
628  }
629 
630  return in.eof();
631 }
632 
633 namespace enum_ {
634 
636 template<typename E>
637 struct Value {
638  E value;
639  const char* name;
640 };
641 
652 template<typename Enum, std::size_t Size>
653 constexpr auto from_string(const std::string_view name, const Value<Enum> (&values)[Size]) {
654  for ( const auto& v : values )
655  if ( v.name == name )
656  return v.value;
657 
658  throw std::out_of_range(name.data());
659 };
660 
671 template<typename Enum, std::size_t Size>
672 constexpr auto to_string(Enum value, const Value<Enum> (&values)[Size]) {
673  for ( const auto& v : values )
674  if ( v.value == value )
675  return v.name;
676 
677  throw std::out_of_range(std::to_string(static_cast<int>(value)));
678 };
679 
680 } // namespace enum_
681 
688 std::optional<hilti::rt::filesystem::path> cacheDirectory(const hilti::Configuration& configuration);
689 
690 } // namespace util
691 
692 } // namespace hilti
std::string replace(const std::string &s, const std::string &o, const std::string &n)
Definition: util.cc:69
std::set< B > map_values(const std::map< A, B > &m)
Definition: util.h:514
auto transform_to_vector(const std::set< X > &x, F f)
Definition: util.h:117
std::string toupper(const std::string &s)
Definition: util.cc:90
std::vector< T > remove_duplicates(std::vector< T > v)
Definition: util.h:587
std::string trim(const std::string &s)
Definition: util.cc:108
std::pair< std::string, std::string > split1(std::string s, const std::string &delim=" ")
Definition: util.cc:55
std::pair< std::string, std::string > rsplit1(std::string s, const std::string &delim=" ")
Definition: util.cc:62
Definition: util.h:637
std::string typename_()
Definition: util.h:74
uint64_t chars_to_uint64(const char *dgts, unsigned int base, Error handler)
Definition: util.h:373
void abort_with_backtrace()
Definition: util.cc:180
constexpr auto enumerate(T &&iterable)
Definition: util.h:153
constexpr std::pair< intmax_t, intmax_t > signed_integer_range(int width)
Definition: util.h:341
Definition: optional.h:79
std::string demangle(const std::string &symbol)
Definition: backtrace.h:39
uint64_t hash(const std::string &str)
Definition: util.cc:110
hilti::rt::filesystem::path normalizePath(const hilti::rt::filesystem::path &p)
Definition: util.cc:102
std::set< A, Compare > set_union(const std::set< A, Compare > &a, const std::set< A, Compare > &b)
Definition: util.h:563
Iter atoi_n(Iter s, Iter e, int base, Result *result)
Definition: util.h:377
std::vector< T > concat(std::vector< T > v1, const std::vector< T > &v2)
Definition: util.h:571
hilti::rt::Result< hilti::rt::filesystem::path > createTemporaryFile(const std::string &prefix="")
Definition: util.cc:84
std::set< A, Compare > set_intersection(std::set< A, Compare > &a, std::set< A, Compare > &b)
Definition: util.h:555
Definition: util.h:32
std::string tolower(const std::string &s)
Definition: util.cc:84
std::list< std::pair< A, B > > zip2(const std::list< A > &lhs, const std::list< B > &rhs)
Definition: util.h:475
std::vector< std::string > split(std::string s, const std::string &delim=" ")
Definition: util.cc:35
std::vector< T > & append(std::vector< T > &v1, const std::vector< T > &v2)
Definition: util.h:579
double chars_to_double(const char *dgts, Error handler)
Definition: util.h:391
void cannot_be_reached() __attribute__((noreturn))
Definition: util.cc:33
std::string prefixParts(const std::string &in, const std::string &prefix, const std::string &include_tag="")
Definition: util.cc:240
double currentTime()
Definition: util.cc:188
std::string fmt(const char *fmt, const Args &... args)
Definition: util.h:80
bool startsWith(const std::string &s, const std::string &prefix)
Definition: util.h:326
std::string join(const T &l, const std::string &delim="")
Definition: util.h:223
bool copyStream(std::istream &in, std::ostream &out)
Definition: util.h:623
std::set< A, Compare > set_difference(const std::set< A, Compare > &a, const std::set< A, Compare > &b)
Definition: util.h:547
std::optional< hilti::rt::filesystem::path > cacheDirectory(const hilti::Configuration &configuration)
Definition: util.cc:283
bool endsWith(const std::string &s, const std::string &suffix)
Definition: util.cc:136
std::vector< std::string > flattenParts(const std::vector< std::string > &in)
Definition: util.cc:267
std::string ltrim(const std::string &s)
Definition: util.cc:102
constexpr std::pair< uintmax_t, uintmax_t > unsigned_integer_range(int width)
Definition: util.h:355
auto atoi_n(Iter s, Iter e, int base, Result *result)
Definition: util.h:465
auto transform(const std::vector< X > &x, F f)
Definition: util.h:86
std::string uniqueIndex(const T &c, std::string hint)
Definition: util.h:608
std::string rtrim(const std::string &s)
Definition: util.cc:96
std::set< A > map_keys(const std::map< A, B > &m)
Definition: util.h:503
std::string uitoa_n(uint64_t value, unsigned int base, int n=-1)
Definition: util.cc:121
std::string escapeBytesForCxx(std::string_view s)
Definition: util.h:426
std::vector< T > slice(const std::vector< T > &v, int begin, int end=-1)
Definition: util.h:196
hilti::rt::filesystem::path currentExecutable()
Definition: util.cc:163
Definition: result.h:67
hilti::Result< hilti::rt::filesystem::path > findInPaths(const hilti::rt::filesystem::path &file, const std::vector< hilti::rt::filesystem::path > &paths)
Definition: util.cc:145
auto filter(const std::vector< X > &x, F f)
Definition: util.h:128
std::string toIdentifier(const std::string &s, bool ensure_non_keyword=false)
Definition: util.cc:194