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