1 #pragma once
2 
3 /// \file Dynamic.h
4 /// \brief Object holding a single values of various types
5 /// \author Pavel Sevecek (sevecek at sirrah.troja.mff.cuni.cz)
6 /// \date 2016-2021
7 
8 #include "math/Means.h"
9 #include "objects/containers/String.h"
10 #include "objects/geometry/Tensor.h"
11 #include "objects/geometry/TracelessTensor.h"
12 #include "objects/wrappers/Variant.h"
13 
14 NAMESPACE_SPH_BEGIN
15 
16 /// \brief Enum representing a value type stored in a Value object.
17 ///
18 /// Has to be kept in sync with ValueVariant defined below.
19 enum class DynamicId {
20     SIZE = 1,
21     FLOAT,
22     VECTOR,
23     TENSOR,
24     SYMMETRIC_TENSOR,
25     TRACELESS_TENSOR,
26     MIN_MAX_MEAN,
27     STRING,
28 };
29 
30 /// \brief Convenient object for storing a single value of different types
31 ///
32 /// Object can currently store scalar, vector, tensor, unsigned integer and \ref MinMaxMean.
33 /// This is intended mainly for logging and output routines, as the object provides generic way to store
34 /// different types and print stored values. There is no need to pass types as template arguments, so the
35 /// object Value is a suitable return value or parameter of virtual functions (that cannot be templated).
36 class Dynamic {
37 private:
38     /// \note If bool is added into the variant, it will probably clash with operator bool().
39     using DynamicVariant = Variant<NothingType,
40         Size,
41         Float,
42         Vector,
43         Tensor,
44         SymmetricTensor,
45         TracelessTensor,
46         MinMaxMean,
47         String>;
48 
49     DynamicVariant storage;
50 
51 public:
52     /// Construct an uninitialized value
53     Dynamic();
54 
55     ~Dynamic();
56 
57     /// Contruct value from one of possible value types
58     template <typename T, typename = std::enable_if_t<DynamicVariant::canHold<T>()>>
Dynamic(T && value)59     Dynamic(T&& value)
60         : storage(std::forward<T>(value)) {}
61 
Dynamic(const Dynamic & other)62     Dynamic(const Dynamic& other)
63         : storage(other.storage) {}
64 
Dynamic(Dynamic && other)65     Dynamic(Dynamic&& other)
66         : storage(std::move(other.storage)) {}
67 
68     /// Assign one of possible value types into the value
69     template <typename T, typename = std::enable_if_t<DynamicVariant::canHold<T>()>>
70     Dynamic& operator=(T&& rhs) {
71         storage = std::forward<T>(rhs);
72         return *this;
73     }
74 
75     Dynamic& operator=(const Dynamic& other) {
76         storage = other.storage;
77         return *this;
78     }
79 
80     Dynamic& operator=(Dynamic&& other) {
81         storage = std::move(other.storage);
82         return *this;
83     }
84 
85     /// \brief Returns the reference to the stored value given its type.
86     ///
87     /// The stored value must indeed have a type T, checked by assert.
88     template <typename T, typename = std::enable_if_t<DynamicVariant::canHold<T>()>>
get()89     INLINE T& get() {
90         return storage.get<T>();
91     }
92 
93     /// Returns the const reference to the stored value given its type.
94     template <typename T, typename = std::enable_if_t<DynamicVariant::canHold<T>()>>
get()95     const T& get() const {
96         return storage.get<T>();
97     }
98 
99     /// Conversion operator to one of stored types
100     template <typename T, typename = std::enable_if_t<DynamicVariant::canHold<T>()>>
101     operator T&() {
102         return this->get<T>();
103     }
104 
105     /// Coversion operator to one of stored types, const version
106     template <typename T, typename = std::enable_if_t<DynamicVariant::canHold<T>()>>
107     operator const T&() const {
108         return this->get<T>();
109     }
110 
111     /// Converts the stored value into a single number, using one of possible conversions
112     Float getScalar() const;
113 
getType()114     DynamicId getType() const {
115         return DynamicId(storage.getTypeIdx());
116     }
117 
118     /// Checks if the value has been initialized.
empty()119     bool empty() const {
120         return storage.getTypeIdx() == 0;
121     }
122 
123     explicit operator bool() const {
124         return !this->empty();
125     }
126 
127     bool operator!() const {
128         return this->empty();
129     }
130 
131     /// Equality operator with one of stored types.
132     template <typename T, typename = std::enable_if_t<DynamicVariant::canHold<T>()>>
133     bool operator==(const T& value) const {
134         return this->get<T>() == value;
135     }
136 
137     /// Prints the currently stored value into the stream, using << operator of its type.
138     template <typename TStream>
139     friend TStream& operator<<(TStream& stream, const Dynamic& value) {
140         forValue(value.storage, [&stream](const auto& v) { stream << std::setw(20) << v; });
141         return stream;
142     }
143 };
144 
145 NAMESPACE_SPH_END
146