LIBINT 2.9.0
any.h
1/*
2 * Copyright (C) 2004-2024 Edward F. Valeev
3 *
4 * This file is part of Libint library.
5 *
6 * Libint library 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 library 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 library. 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 <cassert>
25#include <string>
26#include <type_traits>
27#include <typeinfo>
28#include <utility>
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}; // namespace detail
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,
105 Args&&... args) {
106 reset();
107 impl_ = new impl<typename std::decay<ValueType>::type>(
108 il, std::forward<Args>(args)...);
109 return (impl_->cast_static<typename std::decay<ValueType>::type>()->value);
110 }
111
112 void reset() { impl_.reset(); }
113
114 void swap(any& other) { std::swap(impl_, other.impl_); }
115
116 bool has_value() const { return static_cast<bool>(impl_); }
117
118 const std::type_info& type() const {
119 if (has_value())
120 return impl_->type();
121 else
122 return typeid(void);
123 }
124
125 private:
126 template <typename T>
127 struct impl;
128
129 struct impl_base {
130 virtual ~impl_base() {}
131 virtual impl_base* clone() const = 0;
132
133 virtual const std::type_info& type() const = 0;
134
135 // static if NDEBUG is defined, dynamic otherwise
136 template <typename T>
137 impl<T>* cast() {
138#ifndef NDEBUG
139 return this->cast_static<T>();
140#else
141 return dynamic_cast<impl<T>*>(this);
142#endif
143 }
144 // static always
145 template <typename T>
146 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>
153 explicit impl(U&& v) : value(std::forward<U>(v)) {}
154 impl_base* clone() const override { return new impl{value}; }
155
156 const std::type_info& type() const override { return typeid(T); }
157
158 T value;
159 };
160
161 template <typename ValueType>
162 friend typename std::decay<ValueType>::type* any_cast(any* operand);
163 template <typename ValueType>
164 friend const typename std::decay<ValueType>::type* any_cast(
165 const any* operand);
166
167 template <typename ValueType>
168 typename std::decay<ValueType>::type* value_ptr() {
169 return &(impl_->cast_static<typename std::decay<ValueType>::type>()->value);
170 }
171
172 template <typename ValueType>
173 const typename std::decay<ValueType>::type* value_ptr() const {
174 return &(impl_->cast_static<typename std::decay<ValueType>::type>()->value);
175 }
176
177 std::unique_ptr<impl_base> impl_;
178};
179
180class bad_any_cast : public std::bad_cast {
181 public:
182 bad_any_cast() = default;
183 virtual ~bad_any_cast() {}
184 virtual const char* what() const noexcept { return "Bad any_cast"; }
185};
186
187template <typename ValueType>
188typename std::decay<ValueType>::type* any_cast(any* operand) {
189 if (operand->type() == typeid(typename std::decay<ValueType>::type))
190 return operand->value_ptr<typename std::decay<ValueType>::type>();
191 else
192 return nullptr;
193}
194
195template <typename ValueType>
196const typename std::decay<ValueType>::type* any_cast(const any* operand) {
197 if (operand->type() == typeid(typename std::decay<ValueType>::type))
198 return operand->value_ptr<typename std::decay<ValueType>::type>();
199 else
200 return nullptr;
201}
202
203template <typename ValueType>
204ValueType any_cast(const any& operand) {
205 const auto* cast_ptr =
206 any_cast<typename std::decay<ValueType>::type>(&operand);
207 if (cast_ptr != nullptr) return *cast_ptr;
208 throw bad_any_cast();
209}
210
211template <typename ValueType>
212ValueType any_cast(any& operand) {
213 auto* cast_ptr = any_cast<typename std::decay<ValueType>::type>(&operand);
214 if (cast_ptr != nullptr) return *cast_ptr;
215 throw bad_any_cast();
216}
217#endif // C++17
218
219} // namespace libint2
220
221#endif // header guard
a partial C++17 std::any implementation (and less efficient than can be)
Definition any.h:67
Definition any.h:180
Defaults definitions for various parameters assumed by Libint.
Definition algebra.cc:24