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