Spicy
union.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <string>
6 #include <utility>
7 
8 #include <hilti/rt/exception.h>
9 #include <hilti/rt/extension-points.h>
10 #include <hilti/rt/util.h>
11 
12 namespace hilti::rt {
13 
14 namespace trait {
15 struct isUnion {};
16 } // namespace trait
17 
18 namespace union_ {
19 namespace detail {
20 
22 template<int I, typename U>
23 class AssignProxy {
24 public:
25  AssignProxy(U* u) : _u(u) {}
26 
27  template<typename T>
28  AssignProxy& operator=(const T& t) {
29  _u->value.template emplace<I>(t);
30  return *this;
31  }
32 
33  template<typename T>
34  AssignProxy& operator=(T&& t) {
35  _u->value.template emplace<I>(std::forward<T>(t));
36  return *this;
37  }
38 
39 private:
40  U* _u;
41 };
42 
43 } // namespace detail
44 
45 template<int I, class T>
46 inline auto& get(const T& u) {
47  try {
48  return std::get<I>(u.value);
49  } catch ( const std::bad_variant_access& ) {
50  throw UnsetUnionMember("access to union member that does not hold value");
51  }
52 }
53 
54 template<int I, class U>
55 inline auto get_proxy(U& u) {
56  return detail::AssignProxy<I, U>(&u);
57 }
58 
59 } // namespace union_
60 
61 template<typename... T>
62 class Union : public trait::isUnion {
63 public:
64  Union() = default;
65  ~Union() = default;
66  Union(const Union&) = default;
67  Union(Union&&) noexcept = default;
68  Union& operator=(const Union&) = default;
69  Union& operator=(Union&&) noexcept = default;
70 
71  template<typename F>
72  Union(const F& t) : value(t){};
73  template<typename F>
74  Union(const F&& t) : value(t){};
75  template<typename F>
76  Union& operator=(const F& t) {
77  value = t;
78  return *this;
79  }
80 
81  template<typename F>
82  Union& operator=(F&& t) {
83  value = std::forward<F>(t);
84  return *this;
85  }
86 
92  auto index() const { return value.index(); }
93 
94  std::variant<std::monostate, T...> value;
95 };
96 
97 namespace detail::adl {
98 template<typename T, typename std::enable_if_t<std::is_base_of<trait::isUnion, T>::value>* = nullptr>
99 inline std::string to_string(const T& x, adl::tag /*unused*/) {
100  std::string field = "<unset>";
101 
102  auto render_one = [&](auto k, auto v) {
103  if ( v )
104  field = fmt("$%s=%s", k, hilti::rt::to_string(*v));
105  };
106 
107  x.__visit(render_one);
108  return field;
109 }
110 
111 } // namespace detail::adl
112 
113 } // namespace hilti::rt
std::string to_string(T &&x)
Definition: extension-points.h:26
Definition: any.h:7
Definition: union.h:15
Definition: union.h:62
auto index() const
Definition: union.h:92
std::string fmt(const char *fmt, const Args &... args)
Definition: fmt.h:13