Coverage Report

Created: 2026-09-28 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rdkit/Code/RDGeneral/RDValue.h
Line
Count
Source
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_H
33
#define RDKIT_RDVALUE_H
34
35
// #define UNSAFE_RDVALUE
36
#ifdef UNSAFE_RDVALUE
37
#include "RDValue-doublemagic.h"
38
#else
39
#include "RDValue-taggedunion.h"
40
#endif
41
42
#include <boost/algorithm/string.hpp>
43
44
namespace RDKit {
45
//  Common Casts (POD Casts are implementation dependent)
46
// string casts
47
template <>
48
98.5k
inline std::string rdvalue_cast<std::string>(RDValue_cast_t v) {
49
98.5k
  if (rdvalue_is<std::string>(v)) {
50
98.5k
    return *v.ptrCast<std::string>();
51
98.5k
  }
52
0
  throw std::bad_any_cast();
53
98.5k
}
54
55
template <>
56
0
inline std::string &rdvalue_cast<std::string &>(RDValue_cast_t v) {
57
0
  if (rdvalue_is<std::string>(v)) {
58
0
    return *v.ptrCast<std::string>();
59
0
  }
60
0
  throw std::bad_any_cast();
61
0
}
62
63
// Special Vecor Casts
64
template <>
65
0
inline std::vector<double> rdvalue_cast<std::vector<double>>(RDValue_cast_t v) {
66
0
  if (rdvalue_is<std::vector<double>>(v)) {
67
0
    return *v.ptrCast<std::vector<double>>();
68
0
  }
69
0
  throw std::bad_any_cast();
70
0
}
71
72
template <>
73
inline std::vector<double> &rdvalue_cast<std::vector<double> &>(
74
0
    RDValue_cast_t v) {
75
0
  if (rdvalue_is<std::vector<double>>(v)) {
76
0
    return *v.ptrCast<std::vector<double>>();
77
0
  }
78
0
  throw std::bad_any_cast();
79
0
}
80
81
template <>
82
0
inline std::vector<float> rdvalue_cast<std::vector<float>>(RDValue_cast_t v) {
83
0
  if (rdvalue_is<std::vector<float>>(v)) {
84
0
    return *v.ptrCast<std::vector<float>>();
85
0
  }
86
0
  throw std::bad_any_cast();
87
0
}
88
89
template <>
90
inline std::vector<float> &rdvalue_cast<std::vector<float> &>(
91
0
    RDValue_cast_t v) {
92
0
  if (rdvalue_is<std::vector<float>>(v)) {
93
0
    return *v.ptrCast<std::vector<float>>();
94
0
  }
95
0
  throw std::bad_any_cast();
96
0
}
97
98
template <>
99
inline std::vector<std::string> rdvalue_cast<std::vector<std::string>>(
100
3.92M
    RDValue_cast_t v) {
101
3.92M
  if (rdvalue_is<std::vector<std::string>>(v)) {
102
3.92M
    return *v.ptrCast<std::vector<std::string>>();
103
3.92M
  }
104
0
  throw std::bad_any_cast();
105
3.92M
}
106
107
template <>
108
inline std::vector<std::string> &rdvalue_cast<std::vector<std::string> &>(
109
0
    RDValue_cast_t v) {
110
0
  if (rdvalue_is<std::vector<std::string>>(v)) {
111
0
    return *v.ptrCast<std::vector<std::string>>();
112
0
  }
113
0
  throw std::bad_any_cast();
114
0
}
115
116
template <>
117
134k
inline std::vector<int> rdvalue_cast<std::vector<int>>(RDValue_cast_t v) {
118
134k
  if (rdvalue_is<std::vector<int>>(v)) {
119
134k
    return *v.ptrCast<std::vector<int>>();
120
134k
  }
121
0
  throw std::bad_any_cast();
122
134k
}
123
124
template <>
125
0
inline std::vector<int> &rdvalue_cast<std::vector<int> &>(RDValue_cast_t v) {
126
0
  if (rdvalue_is<std::vector<int>>(v)) {
127
0
    return *v.ptrCast<std::vector<int>>();
128
0
  }
129
0
  throw std::bad_any_cast();
130
0
}
131
132
template <>
133
inline std::vector<unsigned int> rdvalue_cast<std::vector<unsigned int>>(
134
16.4k
    RDValue_cast_t v) {
135
16.4k
  if (rdvalue_is<std::vector<unsigned int>>(v)) {
136
16.4k
    return *v.ptrCast<std::vector<unsigned int>>();
137
16.4k
  }
138
0
  throw std::bad_any_cast();
139
16.4k
}
140
141
template <>
142
inline std::vector<unsigned int> &rdvalue_cast<std::vector<unsigned int> &>(
143
0
    RDValue_cast_t v) {
144
0
  if (rdvalue_is<std::vector<unsigned int>>(v)) {
145
0
    return *v.ptrCast<std::vector<unsigned int>>();
146
0
  }
147
0
  throw std::bad_any_cast();
148
0
}
149
150
// Get boost any
151
template <>
152
0
inline std::any rdvalue_cast<std::any>(RDValue_cast_t v) {
153
0
  if (rdvalue_is<std::any>(v)) {
154
0
    return *v.ptrCast<std::any>();
155
0
  }
156
0
  throw std::bad_any_cast();
157
0
}
158
159
template <>
160
0
inline std::any &rdvalue_cast<std::any &>(RDValue_cast_t v) {
161
0
  if (rdvalue_is<std::any>(v)) {
162
0
    return *v.ptrCast<std::any>();
163
0
  }
164
0
  throw std::bad_any_cast();
165
0
}
166
167
template <>
168
0
inline const std::any &rdvalue_cast<const std::any &>(RDValue_cast_t v) {
169
0
  if (rdvalue_is<std::any>(v)) {
170
0
    return *v.ptrCast<std::any>();
171
0
  }
172
0
  throw std::bad_any_cast();
173
0
}
174
175
/////////////////////////////////////////////////////////////////////////////////////
176
// lexical casts...
177
template <class T>
178
0
std::string vectToString(RDValue val) {
179
0
  const std::vector<T> &tv = rdvalue_cast<std::vector<T> &>(val);
180
0
  std::ostringstream sstr;
181
0
  sstr.imbue(std::locale("C"));
182
0
  sstr << std::setprecision(17);
183
0
  sstr << "[";
184
0
  if (!tv.empty()) {
185
0
    std::copy(tv.begin(), tv.end() - 1, std::ostream_iterator<T>(sstr, ","));
186
0
    sstr << tv.back();
187
0
  }
188
0
  sstr << "]";
189
0
  return sstr.str();
190
0
}
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > RDKit::vectToString<double>(RDKit::RDValue)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > RDKit::vectToString<float>(RDKit::RDValue)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > RDKit::vectToString<int>(RDKit::RDValue)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > RDKit::vectToString<unsigned int>(RDKit::RDValue)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > RDKit::vectToString<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(RDKit::RDValue)
191
192
98.5k
inline bool rdvalue_tostring(RDValue_cast_t val, std::string &res) {
193
98.5k
  switch (val.getTag()) {
194
98.5k
    case RDTypeTag::StringTag:
195
98.5k
      res = rdvalue_cast<std::string>(val);
196
98.5k
      break;
197
0
    case RDTypeTag::IntTag:
198
0
      res = boost::lexical_cast<std::string>(rdvalue_cast<int>(val));
199
0
      break;
200
0
    case RDTypeTag::DoubleTag: {
201
0
      Utils::LocaleSwitcher ls;  // for lexical cast...
202
0
      res = boost::lexical_cast<std::string>(rdvalue_cast<double>(val));
203
0
      break;
204
0
    }
205
0
    case RDTypeTag::UnsignedIntTag:
206
0
      res = boost::lexical_cast<std::string>(rdvalue_cast<unsigned int>(val));
207
0
      break;
208
0
#ifdef RDVALUE_HASBOOL
209
0
    case RDTypeTag::BoolTag:
210
0
      res = boost::lexical_cast<std::string>(rdvalue_cast<bool>(val));
211
0
      break;
212
0
#endif
213
0
    case RDTypeTag::FloatTag: {
214
0
      Utils::LocaleSwitcher ls;  // for lexical cast...
215
0
      res = boost::lexical_cast<std::string>(rdvalue_cast<float>(val));
216
0
      break;
217
0
    }
218
0
    case RDTypeTag::VecDoubleTag: {
219
      // vectToString uses std::imbue for locale
220
0
      res = vectToString<double>(val);
221
0
      break;
222
0
    }
223
0
    case RDTypeTag::VecFloatTag: {
224
      // vectToString uses std::imbue for locale
225
0
      res = vectToString<float>(val);
226
0
      break;
227
0
    }
228
0
    case RDTypeTag::VecIntTag:
229
0
      res = vectToString<int>(val);
230
0
      break;
231
0
    case RDTypeTag::VecUnsignedIntTag:
232
0
      res = vectToString<unsigned int>(val);
233
0
      break;
234
0
    case RDTypeTag::VecStringTag:
235
0
      res = vectToString<std::string>(val);
236
0
      break;
237
0
    case RDTypeTag::AnyTag: {
238
0
      Utils::LocaleSwitcher ls;  // for lexical cast...
239
0
      try {
240
0
        res = std::any_cast<std::string>(rdvalue_cast<std::any &>(val));
241
0
      } catch (const std::bad_any_cast &) {
242
0
        auto &rdtype = rdvalue_cast<std::any &>(val).type();
243
0
        if (rdtype == typeid(long)) {
244
0
          res = boost::lexical_cast<std::string>(
245
0
              std::any_cast<long>(rdvalue_cast<std::any &>(val)));
246
0
        } else if (rdtype == typeid(int64_t)) {
247
0
          res = boost::lexical_cast<std::string>(
248
0
              std::any_cast<int64_t>(rdvalue_cast<std::any &>(val)));
249
0
        } else if (rdtype == typeid(uint64_t)) {
250
0
          res = boost::lexical_cast<std::string>(
251
0
              std::any_cast<uint64_t>(rdvalue_cast<std::any &>(val)));
252
0
        } else if (rdtype == typeid(unsigned long)) {
253
0
          res = boost::lexical_cast<std::string>(
254
0
              std::any_cast<unsigned long>(rdvalue_cast<std::any &>(val)));
255
0
        } else {
256
0
          throw;
257
0
          return false;
258
0
        }
259
0
      }
260
0
      break;
261
0
    }
262
0
    default:
263
0
      res = "";
264
98.5k
  }
265
98.5k
  return true;
266
98.5k
}
267
268
// from_rdvalue -> converts string values to appropriate types
269
template <class T>
270
typename boost::enable_if<boost::is_arithmetic<T>, T>::type from_rdvalue(
271
31.6M
    RDValue_cast_t arg) {
272
31.6M
  T res;
273
31.6M
  if (arg.getTag() == RDTypeTag::StringTag) {
274
6
    Utils::LocaleSwitcher ls;
275
6
    try {
276
6
      res = rdvalue_cast<T>(arg);
277
6
    } catch (const std::bad_any_cast &exc) {
278
6
      try {
279
6
  std::string val = rdvalue_cast<std::string>(arg);
280
  // trim only the right characters, this mimics how SD values
281
  //  work on read, they will be trimmed by the MolFile parser
282
6
  boost::trim_right(val);
283
6
        res = boost::lexical_cast<T>(val);
284
6
      } catch (...) {
285
0
        throw exc;
286
0
      }
287
6
    }
288
31.6M
  } else {
289
31.6M
    res = rdvalue_cast<T>(arg);
290
31.6M
  }
291
31.6M
  return res;
292
31.6M
}
boost::enable_if<boost::is_arithmetic<int>, int>::type RDKit::from_rdvalue<int>(RDKit::RDValue)
Line
Count
Source
271
180k
    RDValue_cast_t arg) {
272
180k
  T res;
273
180k
  if (arg.getTag() == RDTypeTag::StringTag) {
274
6
    Utils::LocaleSwitcher ls;
275
6
    try {
276
6
      res = rdvalue_cast<T>(arg);
277
6
    } catch (const std::bad_any_cast &exc) {
278
6
      try {
279
6
  std::string val = rdvalue_cast<std::string>(arg);
280
  // trim only the right characters, this mimics how SD values
281
  //  work on read, they will be trimmed by the MolFile parser
282
6
  boost::trim_right(val);
283
6
        res = boost::lexical_cast<T>(val);
284
6
      } catch (...) {
285
0
        throw exc;
286
0
      }
287
6
    }
288
180k
  } else {
289
180k
    res = rdvalue_cast<T>(arg);
290
180k
  }
291
180k
  return res;
292
180k
}
Unexecuted instantiation: boost::enable_if<boost::is_arithmetic<short>, short>::type RDKit::from_rdvalue<short>(RDKit::RDValue)
Unexecuted instantiation: boost::enable_if<boost::is_arithmetic<signed char>, signed char>::type RDKit::from_rdvalue<signed char>(RDKit::RDValue)
boost::enable_if<boost::is_arithmetic<unsigned int>, unsigned int>::type RDKit::from_rdvalue<unsigned int>(RDKit::RDValue)
Line
Count
Source
271
31.4M
    RDValue_cast_t arg) {
272
31.4M
  T res;
273
31.4M
  if (arg.getTag() == RDTypeTag::StringTag) {
274
0
    Utils::LocaleSwitcher ls;
275
0
    try {
276
0
      res = rdvalue_cast<T>(arg);
277
0
    } catch (const std::bad_any_cast &exc) {
278
0
      try {
279
0
  std::string val = rdvalue_cast<std::string>(arg);
280
  // trim only the right characters, this mimics how SD values
281
  //  work on read, they will be trimmed by the MolFile parser
282
0
  boost::trim_right(val);
283
0
        res = boost::lexical_cast<T>(val);
284
0
      } catch (...) {
285
0
        throw exc;
286
0
      }
287
0
    }
288
31.4M
  } else {
289
31.4M
    res = rdvalue_cast<T>(arg);
290
31.4M
  }
291
31.4M
  return res;
292
31.4M
}
boost::enable_if<boost::is_arithmetic<bool>, bool>::type RDKit::from_rdvalue<bool>(RDKit::RDValue)
Line
Count
Source
271
43
    RDValue_cast_t arg) {
272
43
  T res;
273
43
  if (arg.getTag() == RDTypeTag::StringTag) {
274
0
    Utils::LocaleSwitcher ls;
275
0
    try {
276
0
      res = rdvalue_cast<T>(arg);
277
0
    } catch (const std::bad_any_cast &exc) {
278
0
      try {
279
0
  std::string val = rdvalue_cast<std::string>(arg);
280
  // trim only the right characters, this mimics how SD values
281
  //  work on read, they will be trimmed by the MolFile parser
282
0
  boost::trim_right(val);
283
0
        res = boost::lexical_cast<T>(val);
284
0
      } catch (...) {
285
0
        throw exc;
286
0
      }
287
0
    }
288
43
  } else {
289
43
    res = rdvalue_cast<T>(arg);
290
43
  }
291
43
  return res;
292
43
}
Unexecuted instantiation: boost::enable_if<boost::is_arithmetic<float>, float>::type RDKit::from_rdvalue<float>(RDKit::RDValue)
Unexecuted instantiation: boost::enable_if<boost::is_arithmetic<double>, double>::type RDKit::from_rdvalue<double>(RDKit::RDValue)
Unexecuted instantiation: boost::enable_if<boost::is_arithmetic<unsigned long>, unsigned long>::type RDKit::from_rdvalue<unsigned long>(RDKit::RDValue)
293
294
template <class T>
295
typename boost::disable_if<boost::is_arithmetic<T>, T>::type from_rdvalue(
296
4.07M
    RDValue_cast_t arg) {
297
4.07M
  return rdvalue_cast<T>(arg);
298
4.07M
}
boost::disable_if<boost::is_arithmetic<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >::type RDKit::from_rdvalue<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(RDKit::RDValue)
Line
Count
Source
296
3.92M
    RDValue_cast_t arg) {
297
3.92M
  return rdvalue_cast<T>(arg);
298
3.92M
}
Unexecuted instantiation: boost::disable_if<boost::is_arithmetic<ExplicitBitVect const&>, ExplicitBitVect const&>::type RDKit::from_rdvalue<ExplicitBitVect const&>(RDKit::RDValue)
boost::disable_if<boost::is_arithmetic<std::__1::vector<int, std::__1::allocator<int> > >, std::__1::vector<int, std::__1::allocator<int> > >::type RDKit::from_rdvalue<std::__1::vector<int, std::__1::allocator<int> > >(RDKit::RDValue)
Line
Count
Source
296
134k
    RDValue_cast_t arg) {
297
134k
  return rdvalue_cast<T>(arg);
298
134k
}
boost::disable_if<boost::is_arithmetic<std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > >, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > >::type RDKit::from_rdvalue<std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > >(RDKit::RDValue)
Line
Count
Source
296
16.4k
    RDValue_cast_t arg) {
297
16.4k
  return rdvalue_cast<T>(arg);
298
16.4k
}
299
}  // namespace RDKit
300
#endif