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