heterogeneous.hpp 9.09 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
/*******************************************************************************
 * Copyright (c) 2019 UT-Battelle, LLC.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Eclipse Distribution License v1.0 which accompanies this
 * distribution. The Eclipse Public License is available at
 * http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution
 *License is available at https://eclipse.org/org/documents/edl-v10.php
 *
 * Contributors:
 *   Alexander J. McCaskey - initial API and implementation
 *******************************************************************************/
13
14
#ifndef XACC_HETEROGENEOUS_HPP_
#define XACC_HETEROGENEOUS_HPP_
15

16
17
18
19
20
21
22
23
#include <map>
#include <stdexcept>
#include <vector>
#include <unordered_map>
#include <functional>
#include <iostream>
#include <experimental/type_traits>

24
// mpark variant
25
26
27
#include "variant.hpp"

#include "Utils.hpp"
28
#include <complex>
29
#include <any>
30

31
32
namespace xacc {

33
34
35
36
37
38
class HeterogeneousMap;

template <class...> struct is_heterogeneous_map : std::false_type {};

template <> struct is_heterogeneous_map<HeterogeneousMap> : std::true_type {};

39
40
41
42
43
44
45
46
47
48
template <class...> struct type_list {};

template <class... TYPES> struct visitor_base {
  using types = xacc::type_list<TYPES...>;
};

class HeterogeneousMap {
public:
  HeterogeneousMap() = default;
  HeterogeneousMap(const HeterogeneousMap &_other) { *this = _other; }
49
  HeterogeneousMap(HeterogeneousMap &_other) { *this = _other; }
50

51
52
  HeterogeneousMap &operator=(const HeterogeneousMap &_other) {
    clear();
53
    items = _other.items;
54
55
56
    return *this;
  }

57
58
59
60
61
62
63
64
65
66
  template <typename T> void loop_pairs(T value) {
    insert(value.first, value.second);
  }

  template <typename First, typename... Rest>
  void loop_pairs(First firstValue, Rest... rest) {
    loop_pairs(firstValue);
    loop_pairs(rest...);
  }

67
68
69
70
  template <typename... TYPES,
            typename = std::enable_if_t<!is_heterogeneous_map<
                std::remove_cv_t<std::remove_reference_t<TYPES>>...>::value>>
  HeterogeneousMap(TYPES &&... list) {
71
72
73
    loop_pairs(list...);
  }

74
  template <typename... Ts> void print(std::ostream &os) const {
75
76
77
78
    _internal_print_visitor<Ts...> v(os);
    visit(v);
  }

79
  template <class T> void insert(const std::string key, const T &_t) {
80
81
82
83
    if (items.count(key)) {
      items.at(key) = _t;
    } else {
      items.insert({key, _t});
84
85
    }
  }
86

87
88
89
90
91
92
  template <typename T> const T get(const std::string key) const {
    try {
      return std::any_cast<T>(items.at(key));
    } catch (std::exception &e) {
      XACCLogger::instance()->error("HeterogeneousMap::get() error - Invalid type or key (" + key +
                                    ").");
93
    }
94
    return T();
95
96
  }

97
98
  template <class T> const T get_with_throw(const std::string key) const {
    return std::any_cast<T>(items.at(key));
99
100
  }

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  bool stringExists(const std::string key) const {
    if (keyExists<const char *>(key)) {
      return true;
    }
    if (keyExists<std::string>(key)) {
      return true;
    }
    return false;
  }

  const std::string getString(const std::string key) const {
    if (keyExists<const char *>(key)) {
      return get<const char *>(key);
    } else if (keyExists<std::string>(key)) {
      return get<std::string>(key);
    } else {
      XACCLogger::instance()->error("No string-like value at provided key (" +
                                    key + ").");
      print_backtrace();
    }
    return "";
  }

124
125
126
127
128
129
130
131
  template <typename T> bool pointerLikeExists(const std::string key) const {
    if (keyExists<T *>(key)) {
      return true;
    } else if (keyExists<std::shared_ptr<T>>(key)) {
      return true;
    } else {
      return false;
    }
132
  }
133
134
135
136
137
138
139
  template <typename T> T *getPointerLike(const std::string key) const {
    if (keyExists<T *>(key)) {
      return get<T *>(key);
    } else if (keyExists<std::shared_ptr<T>>(key)) {
      return get<std::shared_ptr<T>>(key).get();
    } else {
      XACCLogger::instance()->error("No pointer-like value at provided key (" +
140
                                    key + ").");
141
142
143
      print_backtrace();
    }
    return nullptr;
144
  }
145
  void clear() { items.clear(); }
146
147

  template <class T> size_t number_of() const {
148
149
150
    _internal_number_of_visitor<T> v;
    visit(v);
    return v.count;
151
152
  }

153
  template <typename T> bool keyExists(const std::string key) const {
154
155
156
157
158
159
160
    if (items.count(key)) {
      // we have the key, make sure it is the right type
      try {
        std::any_cast<T>(items.at(key));
      } catch (std::exception &e) {
        return false;
      }
161
162
163
      return true;
    }
    return false;
164
165
  }

166
  size_t size() const { return items.size(); }
167
168
169

  ~HeterogeneousMap() { clear(); }

170
  template <class T> void visit(T &&visitor) const {
171
172
173
174
    visit_impl(visitor, typename std::decay_t<T>::types{});
  }

private:
175
176
177
178
179
180
181
182
183
  std::map<std::string, std::any> items;

  template <typename T>
  class _internal_number_of_visitor : public visitor_base<T> {
  public:
    int count = 0;
    void operator()(const std::string &key, const T &t) { count++; }
  };

184
  template <typename... Ts>
185
  class _internal_print_visitor : public visitor_base<Ts...> {
186
187
188
189
190
191
192
193
194
  private:
    std::ostream &ss;

  public:
    _internal_print_visitor(std::ostream &s) : ss(s) {}

    template <typename T> void operator()(const std::string &key, const T &t) {
      ss << key << ": " << t << "\n";
    }
195
196
  };

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
  template <class T, class HEAD, class... TAIL> struct try_visit {
    template <class U> static void apply(T &visitor, U &&element) {
      try {
        visitor(element.first, std::any_cast<HEAD>(element.second));
      } catch (...) {
        try_visit<T, TAIL...>::apply(visitor, element);
      }
    }
  };
  template <class T, class HEAD> struct try_visit<T, HEAD> {
    template <class U> static void apply(T &visitor, U &&element) {
      try {
        visitor(element.first, std::any_cast<HEAD>(element.second));
      } catch (...) {
      }
    }
  };
  template <class T, class... U>
  void visit_impl(T &&visitor, xacc::type_list<U...>) const {
    for (auto &&element : items) {
      try_visit<std::decay_t<T>, U...>::apply(visitor, element);
218
219
220
221
    }
  }
};

222
// Make sure these basic types are always instantiatied for HeterogeneousMap
223
224
225
template const bool HeterogeneousMap::get<bool>(const std::string key) const;
template const int HeterogeneousMap::get<int>(const std::string key) const;
template const double
226
HeterogeneousMap::get<double>(const std::string key) const;
227
template const std::vector<std::complex<double>>
228
229
HeterogeneousMap::get<std::vector<std::complex<double>>>(
    const std::string key) const;
230
template const std::vector<double>
231
HeterogeneousMap::get<std::vector<double>>(const std::string key) const;
232
template const std::vector<double>
233
234
HeterogeneousMap::get_with_throw<std::vector<double>>(
    const std::string key) const;
235

236
template <typename... Types> class Variant : public mpark::variant<Types...> {
237
238

private:
239
240
  std::string originalExpression = "";

241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
  class ToStringVisitor {
  public:
    template <typename T> std::string operator()(const T &t) const {
      std::stringstream ss;
      ss << t;
      return ss.str();
    }
  };

  class IsArithmeticVisitor {
  public:
    template <typename T> bool operator()(const T &t) const {
      return std::is_arithmetic<T>::value;
    }
  };

257
258
259
  template <typename To, typename From> class CastVisitor {
  public:
    To operator()(const From &t) const { return (To)t; }
260
261
262
  };

public:
263
  Variant() : mpark::variant<Types...>() {}
264
  template <typename T>
265
  Variant(T &element) : mpark::variant<Types...>(element) {}
266
  template <typename T>
267
  Variant(T &&element) : mpark::variant<Types...>(element) {}
268
269
270
  Variant(const Variant &element)
      : mpark::variant<Types...>(element),
        originalExpression(element.originalExpression) {}
271
272
273
274
275
276

  template <typename T> T as() const {
    try {
      // First off just try to get it
      return mpark::get<T>(*this);
    } catch (std::exception &e) {
277
278
279
      std::stringstream s;
      s << "InstructionParameter::this->toString() = " << toString() << "\n";
      s << "This InstructionParameter type id is " << this->which() << "\n";
280
      XACCLogger::instance()->error("Cannot cast Variant: " + s.str());
281
282
      print_backtrace();
      exit(0);
283
284
285
286
287
    }
    return T();
  }

  template <typename T> T as_no_error() const {
288
289
    // First off just try to get it
    return mpark::get<T>(*this);
290
291
  }

292
  int which() const { return this->index(); }
293

294
295
296
297
  bool isNumeric() const {
    IsArithmeticVisitor v;
    return mpark::visit(v, *this);
  }
298
299
300
  void storeOriginalExpression(std::string expr) { originalExpression = expr; }
  void storeOriginalExpression() { originalExpression = toString(); }
  std::string getOriginalExpression() { return originalExpression; }
301
302
303
304
305
306
307
308
309
310
311
312
313
314
  bool isVariable() const {
    try {
      mpark::get<std::string>(*this);
    } catch (std::exception &e) {
      return false;
    }
    return true;
  }

  const std::string toString() const {
    ToStringVisitor vis;
    return mpark::visit(vis, *this);
  }

315
  bool operator==(const Variant<Types...> &v) const {
316
317
318
    return v.toString() == toString();
  }

319
  bool operator!=(const Variant<Types...> &v) const { return !operator==(v); }
320
321
322
};
} // namespace xacc
#endif