RDKit
Open-source cheminformatics and machine learning.
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 
43 #include <boost/cstdint.hpp>
44 #include <boost/any.hpp>
45 #include <boost/utility.hpp>
46 #include <boost/lexical_cast.hpp>
47 #include <boost/type_traits/is_floating_point.hpp>
49 #include "LocaleSwitcher.h"
50 
51 #define RDVALUE_HASBOOL
52 
53 namespace RDKit {
54 
55 // RDValue does not dynamically create POD types (kind of like
56 // cdiggins::any) However, it doesn't use RTTI type info
57 // directly, it uses a companion short valued type
58 // to determine what to do.
59 // For unregistered types, it falls back to boost::any.
60 // The Size of an RDAny is (sizeof(double) + sizeof(short) == 10 bytes
61 // (aligned to actually 16 so hard to pass as value type)
62 //
63 // For the sake of compatibility, errors throw boost::bad_any_cast
64 //
65 // Examples:
66 //
67 // RDAny v(2.);
68 // v = 1;
69 // std::vector<double> d;
70 // v == d;
71 // v.asDoubleVect().push_back(4.)
72 // rdany_cast<std::vector<double>(v).push_back(4.)
73 //
74 // Falls back to boost::any for non registered types
75 // v = boost::shared_ptr<ROMol>(new ROMol(m));
76 //
77 
78 // RDValue does not manange memory of non-pod data
79 // this must be done externally (string, Any, vector...)
80 // Tagged union
81 
82 namespace RDTypeTag {
83 const short EmptyTag = 0;
84 const short IntTag = 1;
85 const short DoubleTag = 2;
86 const short StringTag = 3;
87 const short FloatTag = 4;
88 const short BoolTag = 5;
89 const short UnsignedIntTag = 6;
90 const short AnyTag = 7;
91 const short VecDoubleTag = 8;
92 const short VecFloatTag = 9;
93 const short VecIntTag = 10;
94 const short VecUnsignedIntTag = 11;
95 const short VecStringTag = 12;
96 template <class T>
97 inline short GetTag() {
98  return AnyTag;
99 }
100 template <>
101 inline short GetTag<double>() {
102  return DoubleTag;
103 }
104 template <>
105 inline short GetTag<float>() {
106  return FloatTag;
107 }
108 template <>
109 inline short GetTag<int>() {
110  return IntTag;
111 }
112 template <>
113 inline short GetTag<unsigned int>() {
114  return UnsignedIntTag;
115 }
116 template <>
117 inline short GetTag<bool>() {
118  return BoolTag;
119 }
120 template <>
121 inline short GetTag<std::string>() {
122  return StringTag;
123 }
124 template <>
125 inline short GetTag<std::vector<double> >() {
126  return VecDoubleTag;
127 }
128 template <>
129 inline short GetTag<std::vector<float> >() {
130  return VecFloatTag;
131 }
132 template <>
133 inline short GetTag<std::vector<int> >() {
134  return VecIntTag;
135 }
136 template <>
137 inline short GetTag<std::vector<unsigned int> >() {
138  return VecUnsignedIntTag;
139 }
140 template <>
141 inline short GetTag<std::vector<std::string> >() {
142  return VecStringTag;
143 }
144 template <>
145 inline short GetTag<boost::any>() {
146  return AnyTag;
147 }
148 
149 namespace detail {
150 union Value {
151  double d;
152  float f;
153  int i;
154  unsigned u;
155  bool b;
156  std::string *s;
157  boost::any *a;
158  std::vector<double> *vd;
159  std::vector<float> *vf;
160  std::vector<int> *vi;
161  std::vector<unsigned int> *vu;
162  std::vector<std::string> *vs;
163 
164  inline Value() {}
165  inline Value(double v) : d(v) {}
166  inline Value(float v) : f(v) {}
167  inline Value(int v) : i(v) {}
168  inline Value(unsigned int v) : u(v) {}
169  inline Value(bool v) : b(v) {}
170  inline Value(std::string *v) : s(v) {}
171  inline Value(boost::any *v) : a(v) {}
172  inline Value(std::vector<double> *v) : vd(v) {}
173  inline Value(std::vector<float> *v) : vf(v) {}
174  inline Value(std::vector<int> *v) : vi(v) {}
175  inline Value(std::vector<unsigned int> *v) : vu(v) {}
176  inline Value(std::vector<std::string> *v) : vs(v) {}
177 };
178 
179 template <class T>
180 inline T *valuePtrCast(Value value) {
181  return boost::any_cast<T *>(*value.a);
182 }
183 template <>
184 inline boost::any *valuePtrCast<boost::any>(Value value) {
185  return value.a;
186 }
187 
188 template <>
189 inline std::string *valuePtrCast<std::string>(Value value) {
190  return value.s;
191 }
192 template <>
193 inline std::vector<double> *valuePtrCast<std::vector<double> >(Value value) {
194  return value.vd;
195 }
196 template <>
197 inline std::vector<float> *valuePtrCast<std::vector<float> >(Value value) {
198  return value.vf;
199 }
200 template <>
201 inline std::vector<int> *valuePtrCast<std::vector<int> >(Value value) {
202  return value.vi;
203 }
204 template <>
205 inline std::vector<unsigned int> *valuePtrCast<std::vector<unsigned int> >(
206  Value value) {
207  return value.vu;
208 }
209 template <>
210 inline std::vector<std::string> *valuePtrCast<std::vector<std::string> >(
211  Value value) {
212  return value.vs;
213 }
214 }
215 }
216 
217 struct RDValue {
219  short type;
220  short reserved_tag; // 16 bit alignment
221 
222  inline RDValue() : value(0.0), type(RDTypeTag::EmptyTag) {}
223  // Pod Style (Direct storage)
224  inline RDValue(double v) : value(v), type(RDTypeTag::DoubleTag) {}
225  inline RDValue(float v) : value(v), type(RDTypeTag::FloatTag) {}
226  inline RDValue(int v) : value(v), type(RDTypeTag::IntTag) {}
227  inline RDValue(unsigned v) : value(v), type(RDTypeTag::UnsignedIntTag) {}
228  inline RDValue(bool v) : value(v), type(RDTypeTag::BoolTag) {}
229 
230  inline RDValue(boost::any *v) : value(v), type(RDTypeTag::AnyTag) {}
231 
232  // Copies passed in pointers
233  inline RDValue(const boost::any &v)
234  : value(new boost::any(v)), type(RDTypeTag::AnyTag) {}
235  inline RDValue(const std::string &v)
236  : value(new std::string(v)), type(RDTypeTag::StringTag){};
237  template <class T>
238  inline RDValue(const T &v)
239  : value(new boost::any(v)), type(RDTypeTag::AnyTag) {}
240 
241  inline RDValue(const std::vector<double> &v)
242  : value(new std::vector<double>(v)), type(RDTypeTag::VecDoubleTag) {}
243  inline RDValue(const std::vector<float> &v)
244  : value(new std::vector<float>(v)), type(RDTypeTag::VecFloatTag) {}
245  inline RDValue(const std::vector<int> &v)
246  : value(new std::vector<int>(v)), type(RDTypeTag::VecIntTag) {}
247  inline RDValue(const std::vector<unsigned int> &v)
248  : value(new std::vector<unsigned int>(v)),
249  type(RDTypeTag::VecUnsignedIntTag) {}
250  inline RDValue(const std::vector<std::string> &v)
251  : value(new std::vector<std::string>(v)), type(RDTypeTag::VecStringTag) {}
252 
253  short getTag() const { return type; }
254 
255  // ptrCast - unsafe, use rdvalue_cast instead.
256  template <class T>
257  inline T *ptrCast() const {
258  return RDTypeTag::detail::valuePtrCast<T>(value);
259  }
260 
261  // RDValue doesn't have an explicit destructor, it must
262  // be wrapped in a container.
263  // The idea is that POD types don't need to be destroyed
264  // and this allows the container optimization possibilities.
265  void destroy() {
266  switch (type) {
268  delete value.s;
269  break;
270  case RDTypeTag::AnyTag:
271  delete value.a;
272  break;
274  delete value.vd;
275  break;
277  delete value.vf;
278  break;
280  delete value.vi;
281  break;
283  delete value.vu;
284  break;
286  delete value.vs;
287  break;
288  default:
289  break;
290  }
291  type = RDTypeTag::EmptyTag;
292  }
293 
294  static // Given a type and an RDAnyValue - delete the appropriate structure
295  inline void
297  rdvalue.destroy();
298  }
299 };
300 
301 /////////////////////////////////////////////////////////////////////////////////////
302 // Given two RDValue::Values - copy the appropriate structure
303 // RDValue doesn't have a copy constructor, the default
304 // copy act's like a move for better value semantics.
305 // Containers may need to copy though.
306 inline void copy_rdvalue(RDValue &dest, const RDValue &src) {
307  if (&dest == &src) // don't copy over yourself
308  return;
309  dest.destroy();
310  dest.type = src.type;
311  switch (src.type) {
313  dest.value.s = new std::string(*src.value.s);
314  break;
315  case RDTypeTag::AnyTag:
316  dest.value.a = new boost::any(*src.value.a);
317  break;
319  dest.value.vd = new std::vector<double>(*src.value.vd);
320  break;
322  dest.value.vf = new std::vector<float>(*src.value.vf);
323  break;
325  dest.value.vi = new std::vector<int>(*src.value.vi);
326  break;
328  dest.value.vu = new std::vector<unsigned int>(*src.value.vu);
329  break;
331  dest.value.vs = new std::vector<std::string>(*src.value.vs);
332  break;
333  default:
334  dest = src;
335  }
336 }
337 
338 /////////////////////////////////////////////////////////////////////////////////////
339 // rdvalue_is<T>
340 
341 template <class T>
342 inline bool rdvalue_is(RDValue v) {
343  return v.getTag() ==
344  RDTypeTag::GetTag<typename boost::remove_reference<T>::type>();
345 }
346 
347 /////////////////////////////////////////////////////////////////////////////////////
348 // rdvalue_cast<T>
349 //
350 // POD types do not support reference semantics. Other types do.
351 // rdvalue_cast<const std::vector<double> &>(RDValue); // ok
352 // rdvalue_cast<const float &>(RDValue); // bad_any_cast
353 
354 #ifdef RDK_32BIT_BUILD
355 // avoid register pressure and spilling on 32 bit systems
356 typedef const RDValue &RDValue_cast_t;
357 #else
358 typedef RDValue RDValue_cast_t;
359 #endif
360 
361 // Get stuff stored in boost any
362 template <class T>
363 inline T rdvalue_cast(RDValue_cast_t v) {
364  // Disable reference and pointer casts to POD data.
365  BOOST_STATIC_ASSERT(!(
366  (boost::is_pointer<T>::value &&
367  (boost::is_integral<typename boost::remove_pointer<T>::type>::value ||
368  boost::is_floating_point<
369  typename boost::remove_pointer<T>::type>::value)) ||
370  (boost::is_reference<T>::value &&
371  (boost::is_integral<typename boost::remove_reference<T>::type>::value ||
372  boost::is_floating_point<
373  typename boost::remove_reference<T>::type>::value))));
374 
375  if (rdvalue_is<boost::any>(v)) {
376  return boost::any_cast<T>(*v.ptrCast<boost::any>());
377  }
378  throw boost::bad_any_cast();
379 }
380 
381 // POD casts
382 template <>
383 inline double rdvalue_cast<double>(RDValue_cast_t v) {
384  if (rdvalue_is<double>(v)) return v.value.d;
385  throw boost::bad_any_cast();
386 }
387 
388 template <>
389 inline float rdvalue_cast<float>(RDValue_cast_t v) {
390  if (rdvalue_is<float>(v)) return v.value.f;
391  throw boost::bad_any_cast();
392 }
393 
394 template <>
395 inline int rdvalue_cast<int>(RDValue_cast_t v) {
396  if (rdvalue_is<int>(v)) return v.value.i;
397  throw boost::bad_any_cast();
398 }
399 template <>
400 inline unsigned int rdvalue_cast<unsigned int>(RDValue_cast_t v) {
401  if (rdvalue_is<unsigned int>(v)) return v.value.u;
402  throw boost::bad_any_cast();
403 }
404 
405 template <>
406 inline bool rdvalue_cast<bool>(RDValue_cast_t v) {
407  if (rdvalue_is<bool>(v)) return v.value.b;
408  throw boost::bad_any_cast();
409 }
410 
411 } // namespace rdkit
412 #endif
bool rdvalue_is< double >(RDValue v)
RDValue(const std::vector< unsigned int > &v)
boost::uint64_t GetTag< float >()
Definition: RDLog.h:21
void copy_rdvalue(RDValue &dest, const RDValue &src)
static const boost::uint64_t VecDoubleTag
boost::uint64_t GetTag< int >()
short getTag() const
static const boost::uint64_t UnsignedIntTag
T rdvalue_cast(RDValue v)
static const boost::uint64_t AnyTag
static const boost::uint64_t DoubleTag
STL namespace.
RDValue(const std::vector< float > &v)
static const boost::uint64_t FloatTag
std::vector< unsigned int > * vu
static const boost::uint64_t StringTag
bool rdvalue_is(RDValue v)
RDValue(const std::vector< std::string > &v)
static void cleanup_rdvalue(RDValue &rdvalue)
static const boost::uint64_t VecIntTag
static const boost::uint64_t VecUnsignedIntTag
Std stuff.
Definition: Atom.h:30
static const boost::uint64_t VecStringTag
boost::uint64_t GetTag()
Value(std::vector< float > *v)
static const boost::uint64_t IntTag
Value(std::vector< std::string > *v)
RDValue(const boost::any &v)
boost::uint64_t GetTag< unsigned int >()
Value(std::vector< unsigned int > *v)
RDValue RDValue_cast_t
Value(std::vector< double > *v)
static const boost::uint64_t BoolTag
boost::uint64_t getTag() const
static const boost::uint64_t VecFloatTag
RDValue(const std::vector< double > &v)
boost::uint64_t GetTag< double >()
RDValue(boost::any *v)
std::vector< std::string > * vs
RDTypeTag::detail::Value value
boost::uint64_t GetTag< bool >()
RDValue(const std::vector< int > &v)
RDValue(const std::string &v)