RDKit
Open-source cheminformatics and machine learning.
Loading...
Searching...
No Matches
RDValue-taggedunion.h
Go to the documentation of this file.
1// Copyright (c) 2015, Novartis Institutes for BioMedical Research Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following
12// disclaimer in the documentation and/or other materials provided
13// with the distribution.
14// * Neither the name of Novartis Institutes for BioMedical Research Inc.
15// nor the names of its contributors may be used to endorse or promote
16// products derived from this software without specific prior written
17// permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30//
31#include <RDGeneral/export.h>
32#ifndef RDKIT_RDVALUE_TAGGED_UNION_H
33#define RDKIT_RDVALUE_TAGGED_UNION_H
34
35#include <cassert>
36#include "Invariant.h"
37#include <iostream>
38#include <iomanip>
39#include <sstream>
40#include <vector>
41#include <cstdint>
43#include <cstdint>
44#include <any>
45#include <boost/utility.hpp>
46#include <boost/lexical_cast.hpp>
47#include <boost/numeric/conversion/cast.hpp>
48#include <boost/type_traits/is_floating_point.hpp>
50#include "LocaleSwitcher.h"
51
52#define RDVALUE_HASBOOL
53
54namespace RDKit {
55
56// RDValue does not dynamically create POD types (kind of like
57// cdiggins::any) However, it doesn't use RTTI type info
58// directly, it uses a companion short valued type
59// to determine what to do.
60// For unregistered types, it falls back to std::any.
61// The Size of an RDAny is (sizeof(double) + sizeof(short) == 10 bytes
62// (aligned to actually 16 so hard to pass as value type)
63//
64// For the sake of compatibility, errors throw std::bad_any_cast
65//
66// Examples:
67//
68// RDAny v(2.);
69// v = 1;
70// std::vector<double> d;
71// v == d;
72// v.asDoubleVect().push_back(4.)
73// rdany_cast<std::vector<double>(v).push_back(4.)
74//
75// Falls back to std::any for non registered types
76// v = boost::shared_ptr<ROMol>(new ROMol(m));
77//
78
79// RDValue does not manange memory of non-pod data
80// this must be done externally (string, Any, vector...)
81// Tagged union
82
83namespace RDTypeTag {
84const short EmptyTag = 0;
85const short IntTag = 1;
86const short DoubleTag = 2;
87const short StringTag = 3;
88const short FloatTag = 4;
89const short BoolTag = 5;
90const short UnsignedIntTag = 6;
91const short AnyTag = 7;
92const short VecDoubleTag = 8;
93const short VecFloatTag = 9;
94const short VecIntTag = 10;
95const short VecUnsignedIntTag = 11;
96const short VecStringTag = 12;
97template <class T>
98inline short GetTag() {
99 return AnyTag;
100}
101template <>
102inline short GetTag<double>() {
103 return DoubleTag;
104}
105template <>
106inline short GetTag<float>() {
107 return FloatTag;
108}
109template <>
110inline short GetTag<int>() {
111 return IntTag;
112}
113template <>
114inline short GetTag<unsigned int>() {
115 return UnsignedIntTag;
116}
117template <>
118inline short GetTag<bool>() {
119 return BoolTag;
120}
121template <>
122inline short GetTag<std::string>() {
123 return StringTag;
124}
125template <>
127 return VecDoubleTag;
128}
129template <>
131 return VecFloatTag;
132}
133template <>
134inline short GetTag<std::vector<int>>() {
135 return VecIntTag;
136}
137template <>
139 return VecUnsignedIntTag;
140}
141template <>
143 return VecStringTag;
144}
145template <>
146inline short GetTag<std::any>() {
147 return AnyTag;
148}
149
150namespace detail {
151union Value {
152 double d;
153 float f;
154 int i;
155 unsigned u;
156 bool b;
157 std::string *s;
158 std::any *a;
159 std::vector<double> *vd;
160 std::vector<float> *vf;
161 std::vector<int> *vi;
162 std::vector<unsigned int> *vu;
163 std::vector<std::string> *vs;
164
165 inline Value() {}
166 inline Value(double v) : d(v) {}
167 inline Value(float v) : f(v) {}
168 inline Value(int v) : i(v) {}
169 inline Value(unsigned int v) : u(v) {}
170 inline Value(bool v) : b(v) {}
171 inline Value(std::string *v) : s(v) {}
172 inline Value(std::any *v) : a(v) {}
173 inline Value(std::vector<double> *v) : vd(v) {}
174 inline Value(std::vector<float> *v) : vf(v) {}
175 inline Value(std::vector<int> *v) : vi(v) {}
176 inline Value(std::vector<unsigned int> *v) : vu(v) {}
177 inline Value(std::vector<std::string> *v) : vs(v) {}
178};
179
180template <class T>
181inline T *valuePtrCast(Value value) {
182 return std::any_cast<T *>(*value.a);
183}
184template <>
185inline std::any *valuePtrCast<std::any>(Value value) {
186 return value.a;
187}
188
189template <>
190inline std::string *valuePtrCast<std::string>(Value value) {
191 return value.s;
192}
193template <>
194inline std::vector<double> *valuePtrCast<std::vector<double>>(Value value) {
195 return value.vd;
196}
197template <>
198inline std::vector<float> *valuePtrCast<std::vector<float>>(Value value) {
199 return value.vf;
200}
201template <>
202inline std::vector<int> *valuePtrCast<std::vector<int>>(Value value) {
203 return value.vi;
204}
205template <>
206inline std::vector<unsigned int> *valuePtrCast<std::vector<unsigned int>>(
207 Value value) {
208 return value.vu;
209}
210template <>
211inline std::vector<std::string> *valuePtrCast<std::vector<std::string>>(
212 Value value) {
213 return value.vs;
214}
215} // namespace detail
216} // namespace RDTypeTag
217
218struct RDValue {
220 short type;
221 short reserved_tag = 0; // 16 bit alignment
222
223 inline RDValue() : value(0.0), type(RDTypeTag::EmptyTag) {}
224 // Pod Style (Direct storage)
225 inline RDValue(double v) : value(v), type(RDTypeTag::DoubleTag) {}
226 inline RDValue(float v) : value(v), type(RDTypeTag::FloatTag) {}
227 inline RDValue(int v) : value(v), type(RDTypeTag::IntTag) {}
228 inline RDValue(unsigned v) : value(v), type(RDTypeTag::UnsignedIntTag) {}
229 inline RDValue(bool v) : value(v), type(RDTypeTag::BoolTag) {}
230
231 inline RDValue(std::any *v) : value(v), type(RDTypeTag::AnyTag) {}
232
233 // Copies passed in pointers
234 inline RDValue(const std::any &v)
235 : value(new std::any(v)), type(RDTypeTag::AnyTag) {}
236 inline RDValue(const std::string &v)
237 : value(new std::string(v)), type(RDTypeTag::StringTag) {}
238 template <class T>
239 inline RDValue(const T &v)
240 : value(new std::any(v)), type(RDTypeTag::AnyTag) {}
241
242 inline RDValue(const std::vector<double> &v)
243 : value(new std::vector<double>(v)), type(RDTypeTag::VecDoubleTag) {}
244 inline RDValue(const std::vector<float> &v)
245 : value(new std::vector<float>(v)), type(RDTypeTag::VecFloatTag) {}
246 inline RDValue(const std::vector<int> &v)
247 : value(new std::vector<int>(v)), type(RDTypeTag::VecIntTag) {}
248 inline RDValue(const std::vector<unsigned int> &v)
249 : value(new std::vector<unsigned int>(v)),
250 type(RDTypeTag::VecUnsignedIntTag) {}
251 inline RDValue(const std::vector<std::string> &v)
252 : value(new std::vector<std::string>(v)), type(RDTypeTag::VecStringTag) {}
253
254 short getTag() const { return type; }
255
256 // ptrCast - unsafe, use rdvalue_cast instead.
257 template <class T>
258 inline T *ptrCast() const {
259 return RDTypeTag::detail::valuePtrCast<T>(value);
260 }
261
262 // RDValue doesn't have an explicit destructor, it must
263 // be wrapped in a container.
264 // The idea is that POD types don't need to be destroyed
265 // and this allows the container optimization possibilities.
266 void destroy() {
267 switch (type) {
269 delete value.s;
270 break;
272 delete value.a;
273 break;
275 delete value.vd;
276 break;
278 delete value.vf;
279 break;
281 delete value.vi;
282 break;
284 delete value.vu;
285 break;
287 delete value.vs;
288 break;
289 default:
290 break;
291 }
293 }
294
295 static // Given a type and an RDAnyValue - delete the appropriate structure
296 inline void
298 rdvalue.destroy();
299 }
300};
301
302/////////////////////////////////////////////////////////////////////////////////////
303// Given two RDValue::Values - copy the appropriate structure
304// RDValue doesn't have a copy constructor, the default
305// copy act's like a move for better value semantics.
306// Containers may need to copy though.
307inline void copy_rdvalue(RDValue &dest, const RDValue &src) {
308 if (&dest == &src) { // don't copy over yourself
309 return;
310 }
311 dest.destroy();
312 dest.type = src.type;
313 switch (src.type) {
315 dest.value.s = new std::string(*src.value.s);
316 break;
318 dest.value.a = new std::any(*src.value.a);
319 break;
321 dest.value.vd = new std::vector<double>(*src.value.vd);
322 break;
324 dest.value.vf = new std::vector<float>(*src.value.vf);
325 break;
327 dest.value.vi = new std::vector<int>(*src.value.vi);
328 break;
330 dest.value.vu = new std::vector<unsigned int>(*src.value.vu);
331 break;
333 dest.value.vs = new std::vector<std::string>(*src.value.vs);
334 break;
335 default:
336 dest = src;
337 }
338}
339
340#ifdef RDK_32BIT_BUILD
341// avoid register pressure and spilling on 32 bit systems
342typedef const RDValue &RDValue_cast_t;
343#else
344typedef RDValue RDValue_cast_t;
345#endif
346
347/////////////////////////////////////////////////////////////////////////////////////
348// rdvalue_is<T>
349
350template <class T>
351inline bool rdvalue_is(RDValue_cast_t v) {
352 const short tag =
353 RDTypeTag::GetTag<typename boost::remove_reference<T>::type>();
354
355 // If we are an Any tag, check the any type info
356 // see the template specialization below if we are
357 // looking for a boost any directly
358 if (v.getTag() == RDTypeTag::AnyTag) {
359 return v.value.a->type() == typeid(T);
360 }
361
362 if (v.getTag() == tag) {
363 return true;
364 }
365
366 return false;
367}
368
369template <>
371 // If we are explicitly looking for a std::any
372 // then just check the top level tag
373 const short tag = RDTypeTag::GetTag<std::any>();
374 return v.getTag() == tag;
375}
376/////////////////////////////////////////////////////////////////////////////////////
377// rdvalue_cast<T>
378//
379// POD types do not support reference semantics. Other types do.
380// rdvalue_cast<const std::vector<double> &>(RDValue); // ok
381// rdvalue_cast<const float &>(RDValue); // bad_any_cast
382
383// Get stuff stored in boost any
384template <class T>
385inline T rdvalue_cast(RDValue_cast_t v) {
386 // Disable reference and pointer casts to POD data.
388 (boost::is_pointer<T>::value &&
389 (boost::is_integral<typename boost::remove_pointer<T>::type>::value ||
390 boost::is_floating_point<
391 typename boost::remove_pointer<T>::type>::value)) ||
392 (boost::is_reference<T>::value &&
393 (boost::is_integral<typename boost::remove_reference<T>::type>::value ||
394 boost::is_floating_point<
395 typename boost::remove_reference<T>::type>::value))));
396
397 if (rdvalue_is<std::any>(v)) {
398 return std::any_cast<T>(*v.ptrCast<std::any>());
399 }
400 throw std::bad_any_cast();
401}
402
403// POD casts
404template <>
406 if (rdvalue_is<double>(v)) {
407 return v.value.d;
408 }
409 if (rdvalue_is<float>(v)) {
410 return v.value.f;
411 }
412 throw std::bad_any_cast();
413}
414
415template <>
417 if (rdvalue_is<float>(v)) {
418 return v.value.f;
419 }
420 if (rdvalue_is<double>(v)) {
421 return boost::numeric_cast<float>(v.value.d);
422 }
423 throw std::bad_any_cast();
424}
425
426template <>
428 if (rdvalue_is<int>(v)) {
429 return v.value.i;
430 }
432 return boost::numeric_cast<int>(v.value.u);
433 }
434 throw std::bad_any_cast();
435}
436
437template <>
439 if (rdvalue_is<int>(v)) {
440 return boost::numeric_cast<std::int8_t>(v.value.i);
441 }
443 return boost::numeric_cast<std::int8_t>(v.value.u);
444 }
445 throw std::bad_any_cast();
446}
447
448template <>
450 if (rdvalue_is<int>(v)) {
451 return boost::numeric_cast<std::int16_t>(v.value.i);
452 }
454 return boost::numeric_cast<std::int16_t>(v.value.u);
455 }
456 throw std::bad_any_cast();
457}
458
459template <>
461 if (rdvalue_is<int>(v)) {
462 return static_cast<std::int64_t>(v.value.i);
463 }
465 return static_cast<std::int64_t>(v.value.u);
466 }
467 if (rdvalue_is<std::any>(v)) {
468 return std::any_cast<std::int64_t>(*v.ptrCast<std::any>());
469 }
470 throw std::bad_any_cast();
471}
472
473template <>
476 return v.value.u;
477 }
478 if (rdvalue_is<int>(v)) {
479 return boost::numeric_cast<unsigned int>(v.value.i);
480 }
481 throw std::bad_any_cast();
482}
483
484template <>
486 if (rdvalue_is<int>(v)) {
487 return boost::numeric_cast<std::uint8_t>(v.value.i);
488 }
490 return boost::numeric_cast<std::uint8_t>(v.value.u);
491 }
492 throw std::bad_any_cast();
493}
494
495template <>
497 if (rdvalue_is<int>(v)) {
498 return boost::numeric_cast<std::uint16_t>(v.value.i);
499 }
501 return boost::numeric_cast<std::uint16_t>(v.value.u);
502 }
503 throw std::bad_any_cast();
504}
505
506template <>
509 return static_cast<std::uint64_t>(v.value.u);
510 }
511 if (rdvalue_is<int>(v)) {
512 return boost::numeric_cast<std::uint64_t>(v.value.i);
513 }
514 if (rdvalue_is<std::any>(v)) {
515 return std::any_cast<std::uint64_t>(*v.ptrCast<std::any>());
516 }
517 throw std::bad_any_cast();
518}
519
520template <>
522 if (rdvalue_is<bool>(v)) {
523 return v.value.b;
524 }
525 throw std::bad_any_cast();
526}
527
528} // namespace RDKit
529#endif
std::any * valuePtrCast< std::any >(Value value)
std::string * valuePtrCast< std::string >(Value value)
boost::uint64_t GetTag< int >()
static const boost::uint64_t UnsignedIntTag
static const boost::uint64_t StringTag
boost::uint64_t GetTag< std::string >()
boost::uint64_t GetTag< bool >()
boost::uint64_t GetTag< unsigned int >()
boost::uint64_t GetTag()
static const boost::uint64_t VecStringTag
boost::uint64_t GetTag< std::any >()
static const boost::uint64_t VecIntTag
static const boost::uint64_t FloatTag
static const boost::uint64_t VecUnsignedIntTag
static const boost::uint64_t DoubleTag
boost::uint64_t GetTag< double >()
static const boost::uint64_t IntTag
boost::uint64_t GetTag< float >()
static const boost::uint64_t AnyTag
static const boost::uint64_t VecFloatTag
static const boost::uint64_t VecDoubleTag
static const boost::uint64_t BoolTag
Std stuff.
std::int16_t rdvalue_cast< std::int16_t >(RDValue_cast_t v)
int rdvalue_cast< int >(RDValue_cast_t v)
unsigned int rdvalue_cast< unsigned int >(RDValue_cast_t v)
std::uint8_t rdvalue_cast< std::uint8_t >(RDValue_cast_t v)
bool rdvalue_is(const RDValue_cast_t)
std::int64_t rdvalue_cast< std::int64_t >(RDValue_cast_t v)
std::uint64_t rdvalue_cast< std::uint64_t >(RDValue_cast_t v)
double rdvalue_cast< double >(RDValue_cast_t v)
void copy_rdvalue(RDValue &dest, const RDValue &src)
T rdvalue_cast(RDValue_cast_t v)
std::int8_t rdvalue_cast< std::int8_t >(RDValue_cast_t v)
std::uint16_t rdvalue_cast< std::uint16_t >(RDValue_cast_t v)
bool rdvalue_is< double >(const RDValue_cast_t)
RDValue RDValue_cast_t
bool rdvalue_cast< bool >(RDValue_cast_t v)
float rdvalue_cast< float >(RDValue_cast_t v)
bool rdvalue_is< std::any >(RDValue_cast_t v)
RDValue(const std::vector< int > &v)
RDValue(const std::vector< std::string > &v)
RDValue(const std::vector< double > &v)
RDValue(const std::vector< unsigned int > &v)
boost::uint64_t getTag() const
RDTypeTag::detail::Value value
RDValue(const std::string &v)
RDValue(const std::vector< float > &v)
RDValue(const std::any &v)
static void cleanup_rdvalue(RDValue &rdvalue)
Value(std::vector< std::string > *v)
std::vector< std::string > * vs
Value(std::vector< unsigned int > *v)
Value(std::vector< double > *v)
std::vector< unsigned int > * vu