LIBINT  2.6.0
any.h
1 /*
2  * Copyright (C) 2004-2019 Edward F. Valeev
3  *
4  * This file is part of Libint.
5  *
6  * Libint is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Libint is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with Libint. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #ifndef _libint2_include_libint2_util_any_h_
22 #define _libint2_include_libint2_util_any_h_
23 
24 #include <type_traits>
25 #include <utility>
26 #include <typeinfo>
27 #include <string>
28 #include <cassert>
29 
30 // Include C++17 any header, if available AND functional
31 #if __cplusplus >= 201703L
32 // macos < 10.14 do not have any_cast in their libc++
33 # include <ciso646> // see https://stackoverflow.com/a/31658120
34 # if defined(_LIBCPP_VERSION) && defined(__APPLE__)
35 # include <Availability.h>
36 # ifdef __MAC_OS_X_VERSION_MIN_ALLOWED
37 # if __MAC_OS_X_VERSION_MIN_ALLOWED >= 10140
38 # define LIBINT_HAS_CXX17_ANY
39 # endif // 10.14 or later
40 # endif // have macos version
41 # else // libc++ on macos
42 # define LIBINT_HAS_CXX17_ANY
43 # endif // libc++ on macos
44 #endif // c++17
45 
46 #ifdef LIBINT_HAS_CXX17_ANY
47 # include <any>
48 #endif
49 
50 namespace libint2 {
51 
52 // prefer std::any, if available
53 #ifdef LIBINT_HAS_CXX17_ANY
54 using std::any;
55 using std::any_cast;
56 using std::bad_any_cast;
57 #else
58 
59 namespace detail {
60 // true if decayed T is Base, or is derived from it
61 template <typename Base, typename T>
62 using disable_if_same_or_derived = typename std::enable_if<
63  !std::is_base_of<Base, typename std::decay<T>::type>::value>::type;
64 };
65 
67 class any {
68  public:
69  // this is constexpr in the standard
70  any() : impl_(nullptr) {}
71  any(const any& other) : impl_(other.impl_->clone()) {}
72  any(any&& other) = default;
73  template <typename ValueType,
74  typename = detail::disable_if_same_or_derived<any, ValueType> >
75  any(ValueType&& value)
76  : impl_(new impl<typename std::decay<ValueType>::type>(
77  std::forward<ValueType>(value))) {}
78  ~any() = default;
79 
80  any& operator=( const any& rhs ) {
81  impl_ = decltype(impl_)(rhs.impl_->clone());
82  return *this;
83  }
84  any& operator=( any&& rhs ) {
85  impl_ = std::move(rhs.impl_);
86  return *this;
87  }
88  template <typename ValueType,
89  typename = detail::disable_if_same_or_derived<any, ValueType> >
90  any& operator=(ValueType&& rhs) {
91  impl_ = decltype(impl_)(new impl<typename std::decay<ValueType>::type>(
92  std::forward<ValueType>(rhs)));
93  return *this;
94  }
95 
96  template< class ValueType, class... Args >
97  typename std::decay<ValueType>::type& emplace( Args&&... args ) {
98  reset();
99  impl_ = new impl<typename std::decay<ValueType>::type> (
100  std::forward<Args>(args)...);
101  return (impl_->cast_static<typename std::decay<ValueType>::type>()->value);
102  }
103  template< class ValueType, class U, class... Args >
104  typename std::decay<ValueType>::type& emplace( std::initializer_list<U> il, Args&&... args ) {
105  reset();
106  impl_ = new impl<typename std::decay<ValueType>::type> (il,
107  std::forward<Args>(args)...);
108  return (impl_->cast_static<typename std::decay<ValueType>::type>()->value);
109  }
110 
111  void reset() { impl_.reset(); }
112 
113  void swap(any& other) {
114  std::swap(impl_, other.impl_);
115  }
116 
117  bool has_value() const {
118  return static_cast<bool>(impl_);
119  }
120 
121  const std::type_info& type() const {
122  if (has_value())
123  return impl_->type();
124  else
125  return typeid(void);
126  }
127 
128  private:
129  template <typename T> struct impl;
130 
131  struct impl_base {
132  virtual ~impl_base() {}
133  virtual impl_base* clone() const = 0;
134 
135  virtual const std::type_info& type() const = 0;
136 
137  // static if NDEBUG is defined, dynamic otherwise
138  template <typename T> impl<T>* cast() {
139 #ifndef NDEBUG
140  return this->cast_static<T>();
141 #else
142  return dynamic_cast<impl<T>*>(this);
143 #endif
144  }
145  // static always
146  template <typename T> impl<T>* cast_static() {
147  return static_cast<impl<T>*>(this);
148  }
149  };
150  template <typename T>
151  struct impl : public impl_base {
152  template <typename U> explicit impl(U&& v) : value(std::forward<U>(v)) {}
153  impl_base* clone() const override {
154  return new impl{value};
155  }
156 
157  const std::type_info& type() const override {
158  return typeid(T);
159  }
160 
161  T value;
162  };
163 
164  template<typename ValueType>
165  friend typename std::decay<ValueType>::type* any_cast(any* operand);
166  template<typename ValueType>
167  friend const typename std::decay<ValueType>::type* any_cast(const any* operand);
168 
169  template <typename ValueType>
170  typename std::decay<ValueType>::type* value_ptr() {
171  return &(impl_->cast_static<typename std::decay<ValueType>::type>()->value);
172  }
173 
174  template <typename ValueType>
175  const typename std::decay<ValueType>::type* value_ptr() const {
176  return &(impl_->cast_static<typename std::decay<ValueType>::type>()->value);
177  }
178 
179  std::unique_ptr<impl_base> impl_;
180 };
181 
182 class bad_any_cast : public std::bad_cast {
183  public:
184  bad_any_cast() = default;
185  virtual ~bad_any_cast() {}
186  virtual const char* what() const noexcept {
187  return "Bad any_cast";
188  }
189 };
190 
191 template<typename ValueType>
192 typename std::decay<ValueType>::type* any_cast(any* operand) {
193  if (operand->type() == typeid(typename std::decay<ValueType>::type))
194  return operand->value_ptr<typename std::decay<ValueType>::type>();
195  else
196  return nullptr;
197 }
198 
199 template<typename ValueType>
200 const typename std::decay<ValueType>::type* any_cast(const any* operand) {
201  if (operand->type() == typeid(typename std::decay<ValueType>::type))
202  return operand->value_ptr<typename std::decay<ValueType>::type>();
203  else
204  return nullptr;
205 }
206 
207 template <typename ValueType>
208 ValueType any_cast(const any& operand) {
209  const auto* cast_ptr =
210  any_cast<typename std::decay<ValueType>::type>(&operand);
211  if (cast_ptr != nullptr) return *cast_ptr;
212  throw bad_any_cast();
213 }
214 
215 template <typename ValueType>
216 ValueType any_cast(any& operand) {
217  auto* cast_ptr = any_cast<typename std::decay<ValueType>::type>(&operand);
218  if (cast_ptr != nullptr) return *cast_ptr;
219  throw bad_any_cast();
220 }
221 #endif // C++17
222 
223 } // namespace libint2
224 
225 #endif // header guard
226 
Defaults definitions for various parameters assumed by Libint.
Definition: algebra.cc:24
Definition: any.h:182
a partial C++17 std::any implementation (and less efficient than can be)
Definition: any.h:67