LIBINT 2.7.2
any.h
1/*
2 * Copyright (C) 2004-2021 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
50namespace libint2 {
51
52// prefer std::any, if available
53#ifdef LIBINT_HAS_CXX17_ANY
54using std::any;
55using std::any_cast;
56using std::bad_any_cast;
57#else
58
59namespace detail {
60// true if decayed T is Base, or is derived from it
61template <typename Base, typename T>
62using disable_if_same_or_derived = typename std::enable_if<
63 !std::is_base_of<Base, typename std::decay<T>::type>::value>::type;
64};
65
67class 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
182class 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
191template<typename ValueType>
192typename 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
199template<typename ValueType>
200const 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
207template <typename ValueType>
208ValueType 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
215template <typename ValueType>
216ValueType 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
a partial C++17 std::any implementation (and less efficient than can be)
Definition: any.h:67
Definition: any.h:182
Defaults definitions for various parameters assumed by Libint.
Definition: algebra.cc:24