1 #pragma once
2
3 #include <boost/dynamic_bitset.hpp>
4 #include <cassert>
5 #include <cstring>
6 #include <map>
7 #include <stdexcept>
8 #include <string>
9
10 #include "MaeParserConfig.hpp"
11
12 namespace schrodinger
13 {
14 namespace mae
15 {
16 typedef uint8_t BoolProperty;
17
18 template <typename T>
get_property(const std::map<std::string,T> & map,const std::string & name)19 inline const T& get_property(const std::map<std::string, T>& map,
20 const std::string& name)
21 {
22 auto iter = map.find(name);
23 if (iter == map.end()) {
24 throw std::out_of_range("Key not found: " + name);
25 } else {
26 return iter->second;
27 }
28 }
29
30 // Forward declaration.
31 class IndexedBlockBuffer;
32 class IndexedBlock;
33
34 class EXPORT_MAEPARSER IndexedBlockMapI
35 {
36 public:
37 virtual ~IndexedBlockMapI() = default;
38
39 virtual bool hasIndexedBlock(const std::string& name) const = 0;
40
41 virtual std::shared_ptr<const IndexedBlock>
42 getIndexedBlock(const std::string& name) const = 0;
43
44 virtual std::vector<std::string> getBlockNames() const = 0;
45 bool operator==(const IndexedBlockMapI& rhs);
46 };
47
48 class EXPORT_MAEPARSER IndexedBlockMap : public IndexedBlockMapI
49 {
50 std::map<std::string, std::shared_ptr<IndexedBlock>> m_indexed_block;
51
52 public:
53 virtual bool hasIndexedBlock(const std::string& name) const;
54
55 virtual std::shared_ptr<const IndexedBlock>
56 getIndexedBlock(const std::string& name) const;
57
getBlockNames() const58 virtual std::vector<std::string> getBlockNames() const
59 {
60 std::vector<std::string> rval;
61 for (const auto& p : m_indexed_block) {
62 rval.push_back(p.first);
63 }
64
65 return rval;
66 }
67
68 /**
69 * Add an IndexedBlock to the map.
70 */
addIndexedBlock(const std::string & name,std::shared_ptr<IndexedBlock> indexed_block)71 void addIndexedBlock(const std::string& name,
72 std::shared_ptr<IndexedBlock> indexed_block)
73 {
74 m_indexed_block[name] = indexed_block;
75 }
76 };
77
78 class EXPORT_MAEPARSER BufferedIndexedBlockMap : public IndexedBlockMapI
79 {
80 private:
81 std::map<std::string, std::shared_ptr<IndexedBlock>> m_indexed_block;
82 std::map<std::string, std::shared_ptr<IndexedBlockBuffer>> m_indexed_buffer;
83
84 public:
85 virtual bool hasIndexedBlock(const std::string& name) const;
86
87 virtual std::shared_ptr<const IndexedBlock>
88 getIndexedBlock(const std::string& name) const;
89
getBlockNames() const90 virtual std::vector<std::string> getBlockNames() const
91 {
92 std::vector<std::string> rval;
93 for (const auto& p : m_indexed_buffer) {
94 rval.push_back(p.first);
95 }
96
97 return rval;
98 }
99
100 /**
101 * Add an IndexedBlockBuffer to the map, which can be used to retrieve an
102 * IndexedBlock.
103 */
addIndexedBlockBuffer(const std::string & name,std::shared_ptr<IndexedBlockBuffer> block_buffer)104 void addIndexedBlockBuffer(const std::string& name,
105 std::shared_ptr<IndexedBlockBuffer> block_buffer)
106 {
107 m_indexed_buffer[name] = block_buffer;
108 }
109 };
110
111 class EXPORT_MAEPARSER Block
112 {
113 private:
114 const std::string m_name;
115
116 std::map<std::string, BoolProperty> m_bmap;
117 std::map<std::string, double> m_rmap;
118 std::map<std::string, int> m_imap;
119 std::map<std::string, std::string> m_smap;
120 std::map<std::string, std::shared_ptr<Block>> m_sub_block;
121 std::shared_ptr<IndexedBlockMapI> m_indexed_block_map;
122
123 // Prevent copying.
124 Block(const Block&) = delete;
125 Block& operator=(const Block&) = delete;
126
127 public:
Block(std::string name)128 Block(std::string name)
129 : m_name(std::move(name)), m_bmap(), m_rmap(), m_imap(), m_smap(),
130 m_indexed_block_map(nullptr)
131 {
132 }
133
getName() const134 const std::string& getName() const { return m_name; }
135
136 std::string toString() const;
137
138 void write(std::ostream& out, unsigned int current_indentation = 0) const;
139
setIndexedBlockMap(std::shared_ptr<IndexedBlockMapI> indexed_block_map)140 void setIndexedBlockMap(std::shared_ptr<IndexedBlockMapI> indexed_block_map)
141 {
142 m_indexed_block_map = indexed_block_map;
143 }
144
hasIndexedBlockData() const145 bool hasIndexedBlockData() const { return m_indexed_block_map != nullptr; }
hasIndexedBlock(const std::string & name)146 bool hasIndexedBlock(const std::string& name)
147 {
148 return hasIndexedBlockData() &&
149 m_indexed_block_map->hasIndexedBlock(name);
150 }
151
152 std::shared_ptr<const IndexedBlock>
153 getIndexedBlock(const std::string& name);
154
addBlock(std::shared_ptr<Block> b)155 void addBlock(std::shared_ptr<Block> b) { m_sub_block[b->getName()] = b; }
156
157 /**
158 * Check whether this block has a sub-block of the provided name.
159 */
hasBlock(const std::string & name)160 bool hasBlock(const std::string& name)
161 {
162 std::map<std::string, std::shared_ptr<Block>>::const_iterator iter =
163 m_sub_block.find(name);
164 return (iter != m_sub_block.end());
165 }
166
167 /**
168 * Retrieve a shared pointer to the named sub-block.
169 */
getBlock(const std::string & name)170 std::shared_ptr<Block> getBlock(const std::string& name)
171 {
172 std::map<std::string, std::shared_ptr<Block>>::const_iterator iter =
173 m_sub_block.find(name);
174 if (iter == m_sub_block.end()) {
175 throw std::out_of_range("Sub-block not found: " + name);
176 } else {
177 return iter->second;
178 }
179 }
180
181 bool operator==(const Block& rhs) const;
182
hasRealProperty(const std::string & name) const183 bool hasRealProperty(const std::string& name) const
184 {
185 return (m_rmap.find(name) != m_rmap.end());
186 }
187
getRealProperty(const std::string & name) const188 double getRealProperty(const std::string& name) const
189 {
190 return get_property<double>(m_rmap, name);
191 }
192
setRealProperty(const std::string & name,double value)193 void setRealProperty(const std::string& name, double value)
194 {
195 m_rmap[name] = value;
196 }
197
hasIntProperty(const std::string & name) const198 bool hasIntProperty(const std::string& name) const
199 {
200 return (m_imap.find(name) != m_imap.end());
201 }
202
getIntProperty(const std::string & name) const203 int getIntProperty(const std::string& name) const
204 {
205 return get_property<int>(m_imap, name);
206 }
207
setIntProperty(const std::string & name,int value)208 void setIntProperty(const std::string& name, int value)
209 {
210 m_imap[name] = value;
211 }
212
hasBoolProperty(const std::string & name) const213 bool hasBoolProperty(const std::string& name) const
214 {
215 return (m_bmap.find(name) != m_bmap.end());
216 }
217
getBoolProperty(const std::string & name) const218 bool getBoolProperty(const std::string& name) const
219 {
220 return 1u == get_property<BoolProperty>(m_bmap, name);
221 }
222
setBoolProperty(const std::string & name,bool value)223 void setBoolProperty(const std::string& name, bool value)
224 {
225 m_bmap[name] = static_cast<BoolProperty>(value);
226 }
227
hasStringProperty(const std::string & name) const228 bool hasStringProperty(const std::string& name) const
229 {
230 return (m_smap.find(name) != m_smap.end());
231 }
232
getStringProperty(const std::string & name) const233 const std::string& getStringProperty(const std::string& name) const
234 {
235 return get_property<std::string>(m_smap, name);
236 }
237
setStringProperty(const std::string & name,std::string value)238 void setStringProperty(const std::string& name, std::string value)
239 {
240 m_smap[name] = std::move(value);
241 }
242
243 template <typename T> const std::map<std::string, T>& getProperties() const;
244 };
245
246 template <typename T> class IndexedProperty
247 {
248 private:
249 std::vector<T> m_data;
250 boost::dynamic_bitset<>* m_is_null;
251
252 // Prevent copying.
253 IndexedProperty<T>(const IndexedProperty<T>&) = delete;
254 IndexedProperty<T>& operator=(const IndexedProperty<T>&) = delete;
255
256 public:
257 typedef typename std::vector<T>::size_type size_type;
258
259 /**
260 * Construct an IndexedProperty from a reference to a vector of data.
261 * This swaps out the data of the input vector.
262 *
263 * The optional boost::dynamic_bitset is owned by the created object.
264 */
265 explicit IndexedProperty<T>(std::vector<T>& data,
266 boost::dynamic_bitset<>* is_null = nullptr)
267 : m_data(), m_is_null(is_null)
268 {
269 m_data.swap(data);
270 }
271
272 ~IndexedProperty<T>()
273 {
274 if (m_is_null != nullptr) {
275 delete m_is_null;
276 }
277 }
278
279 bool operator==(const IndexedProperty<T>& rhs) const;
280
size() const281 size_type size() const { return m_data.size(); }
282
hasUndefinedValues() const283 bool hasUndefinedValues() const
284 {
285 return (m_is_null != NULL && m_is_null->any());
286 }
287
isDefined(size_type index) const288 bool isDefined(size_type index) const
289 {
290 if (m_is_null == nullptr) {
291 // Use of assert matches out-of-bounds behavior for dynamic_bitset.
292 assert(index < m_data.size());
293 return true;
294 } else {
295 return !m_is_null->test(index);
296 }
297 }
298
undefine(size_type index)299 void undefine(size_type index)
300 {
301 if (m_is_null == NULL) {
302 m_is_null = new boost::dynamic_bitset<>(m_data.size());
303 }
304 m_is_null->set(index);
305 }
306
operator [](size_type index)307 inline T& operator[](size_type index)
308 {
309 if (m_is_null && m_is_null->test(index)) {
310 throw std::runtime_error("Indexed property value undefined.");
311 }
312 return m_data[index];
313 }
314
operator [](size_type index) const315 inline const T& operator[](size_type index) const
316 {
317 if (m_is_null && m_is_null->test(index)) {
318 throw std::runtime_error("Indexed property value undefined.");
319 }
320 return m_data[index];
321 }
322
at(size_type index)323 inline T& at(size_type index) { return operator[](index); }
324
at(size_type index) const325 inline const T& at(size_type index) const { return operator[](index); }
326
at(size_type index,const T & default_) const327 inline const T& at(size_type index, const T& default_) const
328 {
329 if (m_is_null && m_is_null->test(index)) {
330 return default_;
331 }
332 return m_data[index];
333 }
334
set(size_type index,const T & value)335 void set(size_type index, const T& value)
336 {
337 m_data[index] = value;
338 if (m_is_null != NULL && m_is_null->test(index)) {
339 m_is_null->reset(index);
340 }
341 }
342
data() const343 const std::vector<T>& data() const { return m_data; }
nullIndices() const344 const boost::dynamic_bitset<>* nullIndices() const { return m_is_null; }
345 };
346
347 typedef IndexedProperty<double> IndexedRealProperty;
348 typedef IndexedProperty<int> IndexedIntProperty;
349 typedef IndexedProperty<BoolProperty> IndexedBoolProperty;
350 typedef IndexedProperty<std::string> IndexedStringProperty;
351
352 template <typename T>
353 inline std::shared_ptr<T>
get_indexed_property(const std::map<std::string,std::shared_ptr<T>> & map,const std::string & name)354 get_indexed_property(const std::map<std::string, std::shared_ptr<T>>& map,
355 const std::string& name)
356 {
357 auto iter = map.find(name);
358 if (iter == map.end()) {
359 return std::shared_ptr<T>(nullptr);
360 } else {
361 return iter->second;
362 }
363 }
364
365 template <typename T>
set_indexed_property(std::map<std::string,std::shared_ptr<T>> & map,const std::string & name,std::shared_ptr<T> value)366 inline void set_indexed_property(std::map<std::string, std::shared_ptr<T>>& map,
367 const std::string& name,
368 std::shared_ptr<T> value)
369
370 {
371 map[name] = std::move(value);
372 }
373
374 class EXPORT_MAEPARSER IndexedBlock
375 {
376 private:
377 const std::string m_name;
378
379 std::map<std::string, std::shared_ptr<IndexedBoolProperty>> m_bmap;
380 std::map<std::string, std::shared_ptr<IndexedIntProperty>> m_imap;
381 std::map<std::string, std::shared_ptr<IndexedRealProperty>> m_rmap;
382 std::map<std::string, std::shared_ptr<IndexedStringProperty>> m_smap;
383
384 // Prevent copying.
385 IndexedBlock(const IndexedBlock&) = delete;
386 IndexedBlock& operator=(const IndexedBlock&) = delete;
387
388 public:
389 /**
390 * Create an indexed block.
391 */
IndexedBlock(std::string name)392 IndexedBlock(std::string name)
393 : m_name(std::move(name)), m_bmap(), m_imap(), m_rmap(), m_smap()
394 {
395 }
396
397 size_t size() const;
398
getName() const399 const std::string& getName() const { return m_name; }
400
401 std::string toString() const;
402
403 void write(std::ostream& out, unsigned int current_indentation = 0) const;
404
405 bool operator==(const IndexedBlock& rhs) const;
406
operator !=(const IndexedBlock & rhs) const407 bool operator!=(const IndexedBlock& rhs) const
408 {
409 return !(operator==(rhs));
410 }
411
412 template <typename T>
413 void setProperty(const std::string& name,
414 std::shared_ptr<IndexedProperty<T>> value);
415
hasBoolProperty(const std::string & name) const416 bool hasBoolProperty(const std::string& name) const
417 {
418 return (m_bmap.find(name) != m_bmap.end());
419 }
420
421 std::shared_ptr<IndexedBoolProperty>
getBoolProperty(const std::string & name) const422 getBoolProperty(const std::string& name) const
423 {
424 return get_indexed_property<IndexedBoolProperty>(m_bmap, name);
425 }
426
setBoolProperty(const std::string & name,std::shared_ptr<IndexedBoolProperty> value)427 void setBoolProperty(const std::string& name,
428 std::shared_ptr<IndexedBoolProperty> value)
429 {
430 set_indexed_property<IndexedBoolProperty>(m_bmap, name, value);
431 }
432
hasIntProperty(const std::string & name) const433 bool hasIntProperty(const std::string& name) const
434 {
435 return (m_imap.find(name) != m_imap.end());
436 }
437
438 std::shared_ptr<IndexedIntProperty>
getIntProperty(const std::string & name) const439 getIntProperty(const std::string& name) const
440 {
441 return get_indexed_property<IndexedIntProperty>(m_imap, name);
442 }
443
setIntProperty(const std::string & name,std::shared_ptr<IndexedIntProperty> value)444 void setIntProperty(const std::string& name,
445 std::shared_ptr<IndexedIntProperty> value)
446 {
447 set_indexed_property<IndexedIntProperty>(m_imap, name, value);
448 }
449
hasRealProperty(const std::string & name) const450 bool hasRealProperty(const std::string& name) const
451 {
452 return (m_rmap.find(name) != m_rmap.end());
453 }
454
455 std::shared_ptr<IndexedRealProperty>
getRealProperty(const std::string & name) const456 getRealProperty(const std::string& name) const
457 {
458 return get_indexed_property<IndexedRealProperty>(m_rmap, name);
459 }
460
setRealProperty(const std::string & name,std::shared_ptr<IndexedRealProperty> value)461 void setRealProperty(const std::string& name,
462 std::shared_ptr<IndexedRealProperty> value)
463 {
464 set_indexed_property<IndexedRealProperty>(m_rmap, name, value);
465 }
466
hasStringProperty(const std::string & name) const467 bool hasStringProperty(const std::string& name) const
468 {
469 return (m_smap.find(name) != m_smap.end());
470 }
471
472 std::shared_ptr<IndexedStringProperty>
getStringProperty(const std::string & name) const473 getStringProperty(const std::string& name) const
474 {
475 return get_indexed_property<IndexedStringProperty>(m_smap, name);
476 }
477
setStringProperty(const std::string & name,std::shared_ptr<IndexedStringProperty> value)478 void setStringProperty(const std::string& name,
479 std::shared_ptr<IndexedStringProperty> value)
480 {
481 set_indexed_property<IndexedStringProperty>(m_smap, name, value);
482 }
483
484 template <typename T>
485 const std::map<std::string, std::shared_ptr<IndexedProperty<T>>>&
486 getProperties() const;
487 };
488
489 // Template specializations
490
491 template <>
492 inline const std::map<std::string, BoolProperty>&
getProperties() const493 Block::getProperties<BoolProperty>() const
494 {
495 return m_bmap;
496 }
497
498 template <>
getProperties() const499 inline const std::map<std::string, int>& Block::getProperties<int>() const
500 {
501 return m_imap;
502 }
503
504 template <>
getProperties() const505 inline const std::map<std::string, double>& Block::getProperties<double>() const
506 {
507 return m_rmap;
508 }
509
510 template <>
511 inline const std::map<std::string, std::string>&
getProperties() const512 Block::getProperties<std::string>() const
513 {
514 return m_smap;
515 }
516
517 template <>
518 inline const std::map<std::string,
519 std::shared_ptr<IndexedProperty<BoolProperty>>>&
getProperties() const520 IndexedBlock::getProperties() const
521 {
522 return m_bmap;
523 }
524
525 template <>
526 inline const std::map<std::string, std::shared_ptr<IndexedProperty<int>>>&
getProperties() const527 IndexedBlock::getProperties() const
528 {
529 return m_imap;
530 }
531
532 template <>
533 inline const std::map<std::string, std::shared_ptr<IndexedProperty<double>>>&
getProperties() const534 IndexedBlock::getProperties() const
535 {
536 return m_rmap;
537 }
538
539 template <>
540 inline const std::map<std::string,
541 std::shared_ptr<IndexedProperty<std::string>>>&
getProperties() const542 IndexedBlock::getProperties() const
543 {
544 return m_smap;
545 }
546
547 } // namespace mae
548 } // namespace schrodinger
549