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 
87 template<typename X, typename F>
88 auto transform_to_vector(const std::set<X>& x, F f) {
89  using Y = typename std::result_of<F(X&)>::type;
90  std::vector<Y> y;
91  y.reserve(x.size());
92  for ( const auto& i : x )
93  y.push_back(f(i));
94  return y;
95 }
96 
98 template<typename C, typename F>
99 auto filter(const C& x, F f) {
100  C y;
101  std::copy_if(std::begin(x), std::end(x), std::inserter(y, std::end(y)), f);
102  return y;
103 }
104 
109 template<typename T, typename TIter = decltype(std::begin(std::declval<T>())),
110  typename = decltype(std::end(std::declval<T>()))>
111 constexpr auto enumerate(T&& iterable) {
112  struct iterator {
113  size_t i;
114  TIter iter;
115  bool operator!=(const iterator& other) const { return iter != other.iter; }
116  void operator++() {
117  ++i;
118  ++iter;
119  }
120  auto operator*() const { return std::tie(i, *iter); }
121  };
122  struct iterable_wrapper {
123  T iterable;
124  auto begin() { return iterator{0, std::begin(iterable)}; }
125  auto end() { return iterator{0, std::end(iterable)}; }
126  };
127  return iterable_wrapper{std::forward<T>(iterable)};
128 }
129 
131 extern std::vector<std::string> split(std::string s, const std::string& delim = " ");
132 
137 extern std::pair<std::string, std::string> split1(std::string s, const std::string& delim = " ");
138 
143 extern std::pair<std::string, std::string> rsplit1(std::string s, const std::string& delim = " ");
144 
153 template<typename T>
154 std::vector<T> slice(const std::vector<T>& v, int begin, int end = -1) {
155  if ( begin < 0 )
156  begin = v.size() + begin;
157 
158  if ( static_cast<size_t>(begin) > v.size() )
159  return {};
160 
161  if ( end < 0 )
162  end = v.size() + end + 1;
163 
164  if ( begin < 0 )
165  begin = 0;
166 
167  if ( end < 0 )
168  end = 0;
169 
170  if ( static_cast<size_t>(end) > v.size() )
171  end = v.size();
172 
173  return std::vector<T>(v.begin() + begin, v.begin() + end);
174 }
175 
180 template<typename T>
181 std::string join(const T& l, const std::string& delim = "") {
182  std::string result;
183  bool first = true;
184 
185  for ( const auto& i : l ) {
186  if ( not first )
187  result += delim;
188 
189  result += std::string(i);
190  first = false;
191  }
192 
193  return result;
194 }
195 
200 template<typename T>
201 std::string join(const std::initializer_list<T>& l, const std::string& delim = "") {
202  std::string result;
203  bool first = true;
204 
205  for ( const auto& i : l ) {
206  if ( not first )
207  result += delim;
208  result += std::string(i);
209  first = false;
210  }
211 
212  return result;
213 }
214 
219 template<typename iterator>
220 std::string join(const iterator& begin, const iterator& end, const std::string& delim = "") {
221  std::string result;
222  bool first = true;
223 
224  for ( iterator i = begin; i != end; i++ ) {
225  if ( not first )
226  result += delim;
227  result += std::string(*i);
228  first = false;
229  }
230 
231  return result;
232 }
233 
234 
252 extern std::string prefixParts(const std::string& in, const std::string& prefix, const std::string& include_tag = "");
253 
264 extern std::vector<std::string> flattenParts(const std::vector<std::string>& in);
265 
267 extern std::string replace(const std::string& s, const std::string& o, const std::string& n);
268 
270 extern std::string tolower(const std::string& s);
271 
273 extern std::string toupper(const std::string& s);
274 
276 extern std::string trim(const std::string& s);
277 
279 extern std::string rtrim(const std::string& s);
280 
282 extern std::string ltrim(const std::string& s);
283 
285 inline bool startsWith(const std::string& s, const std::string& prefix) { return s.find(prefix) == 0; }
286 
288 extern bool endsWith(const std::string& s, const std::string& suffix);
289 
291 extern uint64_t hash(const std::string& str);
292 
294 extern uint64_t hash(const char* data, size_t len);
295 
300 constexpr std::pair<intmax_t, intmax_t> signed_integer_range(int width) {
301  switch ( width ) {
302  case 8: return std::make_pair(INT8_MIN, INT8_MAX);
303  case 16: return std::make_pair(INT16_MIN, INT16_MAX);
304  case 32: return std::make_pair(INT32_MIN, INT32_MAX);
305  case 64: return std::make_pair(INT64_MIN, INT64_MAX);
306  default: throw std::out_of_range("unsupported integer width");
307  }
308 }
309 
314 constexpr std::pair<uintmax_t, uintmax_t> unsigned_integer_range(int width) {
315  switch ( width ) {
316  case 8: return std::make_pair(0, UINT8_MAX);
317  case 16: return std::make_pair(0, UINT16_MAX);
318  case 32: return std::make_pair(0, UINT32_MAX);
319  case 64: return std::make_pair(0, UINT64_MAX);
320  default: throw std::out_of_range("unsupported integer width");
321  }
322 }
323 
331 template<typename Error>
332 uint64_t chars_to_uint64(const char* dgts, unsigned int base, Error handler) {
333  errno = 0;
334  char* cp;
335  auto u = strtoul(dgts, &cp, base);
336  if ( cp == dgts || *cp != '\0' || (u == ULONG_MAX && errno == ERANGE) ) {
337  errno = 0;
338  handler();
339  }
340  return u;
341 };
342 
349 template<typename Error>
350 double chars_to_double(const char* dgts, Error handler) {
351  errno = 0;
352  char* cp;
353  auto d = strtod(dgts, &cp);
354  if ( cp == dgts || *cp != '\0' || (d == HUGE_VAL && errno == ERANGE) ) {
355  errno = 0;
356  handler();
357  }
358 
359  return d;
360 };
361 
372 extern std::string uitoa_n(uint64_t value, unsigned int base, int n = -1);
373 
374 using hilti::rt::escapeBytes;
375 using hilti::rt::escapeUTF8;
376 using hilti::rt::expandEscapes;
377 
385 inline std::string escapeBytesForCxx(std::string_view s) { return escapeBytes(std::move(s), true, true); }
386 
396 extern std::string toIdentifier(const std::string& s, bool ensure_non_keyword = false);
397 
399 extern double currentTime();
400 
402 extern hilti::Result<hilti::rt::filesystem::path> findInPaths(const hilti::rt::filesystem::path& file,
403  const std::vector<hilti::rt::filesystem::path>& paths);
404 
407 
415 
417 hilti::rt::filesystem::path currentExecutable();
418 
420 [[noreturn]] extern void abort_with_backtrace();
421 
423 template<class Iter, typename Result>
424 inline auto atoi_n(Iter s, Iter e, int base, Result* result) {
425  return hilti::rt::atoi_n(s, e, base, result);
426 }
427 
433 template<typename A, typename B>
434 std::list<std::pair<A, B>> zip2(const std::list<A>& lhs, const std::list<B>& rhs) {
435  std::list<std::pair<A, B>> result;
436  for ( std::pair<typename std::list<A>::const_iterator, typename std::list<B>::const_iterator> iter =
437  std::pair<typename std::list<A>::const_iterator, typename std::list<B>::const_iterator>(lhs.cbegin(),
438  rhs.cbegin());
439  iter.first != lhs.end() and iter.second != rhs.end(); ++iter.first, ++iter.second )
440  result.emplace_back(*iter.first, *iter.second);
441  return result;
442 }
443 
449 template<typename A, typename B>
450 std::vector<std::pair<A, B>> zip2(const std::vector<A>& lhs, const std::vector<B>& rhs) {
451  std::vector<std::pair<A, B>> result;
452  for ( std::pair<typename std::vector<A>::const_iterator, typename std::vector<B>::const_iterator> iter =
453  std::pair<typename std::vector<A>::const_iterator, typename std::vector<B>::const_iterator>(lhs.cbegin(),
454  rhs.cbegin());
455  iter.first != lhs.end() and iter.second != rhs.end(); ++iter.first, ++iter.second )
456  result.emplace_back(*iter.first, *iter.second);
457  return result;
458 }
459 
461 template<typename A, typename B>
462 std::set<A> map_keys(const std::map<A, B>& m) {
463  std::set<A> l;
464 
465  for ( const auto& i : m )
466  l.insert(i.first);
467 
468  return l;
469 }
470 
472 template<typename A, typename B>
473 std::set<B> map_values(const std::map<A, B>& m) {
474  std::set<B> l;
475 
476  for ( const auto& i : m )
477  l.insert(i.second);
478 
479  return l;
480 }
481 
483 template<typename A, typename B>
484 std::set<A> map_keys(const std::unordered_map<A, B>& m) {
485  std::set<A> l;
486 
487  for ( const auto& i : m )
488  l.insert(i.first);
489 
490  return l;
491 }
492 
494 template<typename A, typename B>
495 std::set<B> map_values(const std::unordered_map<A, B>& m) {
496  std::set<B> l;
497 
498  for ( const auto& i : m )
499  l.insert(i.second);
500 
501  return l;
502 }
503 
505 template<typename A, typename Compare = std::less<A>>
506 std::set<A, Compare> set_difference(const std::set<A, Compare>& a, const std::set<A, Compare>& b) {
507  std::set<A, Compare> r;
508  std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::inserter(r, r.end()), Compare());
509  return r;
510 }
511 
513 template<typename A, typename Compare = std::less<A>>
514 std::set<A, Compare> set_intersection(std::set<A, Compare>& a, std::set<A, Compare>& b) {
515  std::set<A, Compare> r;
516  std::set_intersection(a.begin(), a.end(), b.begin(), b.end(), std::inserter(r, r.end()), Compare());
517  return r;
518 }
519 
521 template<typename A, typename Compare = std::less<A>>
522 std::set<A, Compare> set_union(const std::set<A, Compare>& a, const std::set<A, Compare>& b) {
523  std::set<A, Compare> r;
524  std::set_union(a.begin(), a.end(), b.begin(), b.end(), std::inserter(r, r.end()), Compare());
525  return r;
526 }
527 
529 template<typename T>
530 std::vector<T> concat(std::vector<T> v1, const std::vector<T>& v2) {
531  v1.reserve(v1.size() + v2.size());
532  v1.insert(v1.end(), v2.begin(), v2.end());
533  return v1;
534 }
535 
537 template<typename T>
538 std::vector<T>& append(std::vector<T>& v1, const std::vector<T>& v2) {
539  v1.reserve(v1.size() + v2.size());
540  v1.insert(v1.end(), v2.begin(), v2.end());
541  return v1;
542 }
543 
545 template<typename T>
546 std::vector<T> remove_duplicates(std::vector<T> v) {
547  std::set<T> seen;
548  std::vector<T> out;
549 
550  for ( auto&& i : v ) {
551  if ( seen.find(i) != seen.end() )
552  continue;
553 
554  seen.insert(i);
555  out.emplace_back(std::move(i));
556  }
557 
558  return out;
559 }
560 
566 template<typename T>
567 std::string uniqueIndex(const T& c, std::string hint) {
568  if ( c.find(hint) == c.end() )
569  return hint;
570 
571  std::string idx;
572  int cnt = 1;
573 
574  while ( true ) {
575  std::string idx = fmt("%s.%d", hint, ++cnt);
576  if ( c.find(idx) == c.end() )
577  return idx;
578  }
579 }
580 
582 inline bool copyStream(std::istream& in, std::ostream& out) {
583  char buffer[4096];
584  while ( in.good() ) {
585  in.read(buffer, sizeof(buffer));
586  out.write(buffer, sizeof(buffer));
587  }
588 
589  return in.eof();
590 }
591 
592 namespace enum_ {
593 
595 template<typename E>
596 struct Value {
597  E value;
598  const char* name;
599 };
600 
611 template<typename Enum, std::size_t Size>
612 constexpr auto from_string(const std::string_view name, const Value<Enum> (&values)[Size]) {
613  for ( const auto& v : values )
614  if ( v.name == name )
615  return v.value;
616 
617  throw std::out_of_range(name.data());
618 };
619 
630 template<typename Enum, std::size_t Size>
631 constexpr auto to_string(Enum value, const Value<Enum> (&values)[Size]) {
632  for ( const auto& v : values )
633  if ( v.value == value )
634  return v.name;
635 
636  throw std::out_of_range(std::to_string(static_cast<int>(value)));
637 };
638 
639 } // namespace enum_
640 
647 std::optional<hilti::rt::filesystem::path> cacheDirectory(const hilti::Configuration& configuration);
648 
649 } // namespace util
650 
651 } // 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:473
auto transform_to_vector(const std::set< X > &x, F f)
Definition: util.h:88
std::string toupper(const std::string &s)
Definition: util.cc:90
std::vector< T > remove_duplicates(std::vector< T > v)
Definition: util.h:546
std::string trim(const std::string &s)
Definition: util.cc:108
auto transform(const C &x, F f)
Definition: util.h:332
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:596
std::string typename_()
Definition: util.h:74
uint64_t chars_to_uint64(const char *dgts, unsigned int base, Error handler)
Definition: util.h:332
void abort_with_backtrace()
Definition: util.cc:180
constexpr auto enumerate(T &&iterable)
Definition: util.h:111
constexpr std::pair< intmax_t, intmax_t > signed_integer_range(int width)
Definition: util.h:300
Definition: optional.h:79
std::string demangle(const std::string &symbol)
Definition: backtrace.h:40
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:522
std::vector< T > concat(std::vector< T > v1, const std::vector< T > &v2)
Definition: util.h:530
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:514
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:434
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:538
double chars_to_double(const char *dgts, Error handler)
Definition: util.h:350
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:285
std::string join(const T &l, const std::string &delim="")
Definition: util.h:181
bool copyStream(std::istream &in, std::ostream &out)
Definition: util.h:582
auto filter(const C &x, F f)
Definition: util.h:99
std::set< A, Compare > set_difference(const std::set< A, Compare > &a, const std::set< A, Compare > &b)
Definition: util.h:506
std::optional< hilti::rt::filesystem::path > cacheDirectory(const hilti::Configuration &configuration)
Definition: util.cc:283
Iter atoi_n(Iter s, Iter e, uint8_t base, Result *result)
Definition: util.h:366
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:314
auto atoi_n(Iter s, Iter e, int base, Result *result)
Definition: util.h:424
std::string uniqueIndex(const T &c, std::string hint)
Definition: util.h:567
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:462
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:385
std::vector< T > slice(const std::vector< T > &v, int begin, int end=-1)
Definition: util.h:154
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
std::string toIdentifier(const std::string &s, bool ensure_non_keyword=false)
Definition: util.cc:194