Remove dynamic exceptions
[anna.git] / source / core / util / Variable.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #include <anna/core/functions.hpp>
10 #include <anna/core/util/Variable.hpp>
11
12 using namespace std;
13 using namespace anna;
14
15 anna_assign_enum(Variable::Type) =  {
16   "Unused0", "String", "Integer", "Unused1", "Boolean", "Integer64", "Block", "Float", "Double", "Custom", NULL
17 };
18
19 Variable::Variable(const char* name, const Type::_v type) :
20   a_name(name),
21   a_isNull(true),
22   a_type(type),
23   a_isOwner(true) {
24   anna_memset(&a_value, 0, sizeof(a_value));
25
26   switch(type) {
27   case Type::String: a_value.a_string = new std::string; break;
28   case Type::Integer: a_value.a_integer = &a_aux.integer; break;
29   case Type::Integer64: a_value.a_longInteger = &a_aux.longInteger; break;
30   case Type::Boolean: a_value.a_boolean = &a_aux.boolean; break;
31   case Type::Block: a_value.a_dataBlock = new DataBlock(true); break;
32   case Type::Float: a_value.a_float = &a_aux.theFloat; break;
33   case Type::Double: a_value.a_double = &a_aux.theDouble; break;
34   case Type::Custom: a_value.a_custom = NULL; break;
35   default: break;
36   }
37 }
38
39 Variable::~Variable() {
40   if(a_isOwner == false)
41     return;
42
43   switch(a_type) {
44   case Type::String:
45     delete a_value.a_string;
46     a_value.a_string = NULL;
47     break;
48   case Type::Block:
49     delete a_value.a_dataBlock;
50     a_value.a_dataBlock = NULL;
51     break;
52   default: break;
53   }
54 }
55
56 void Variable::setValue(const char* value)
57 noexcept(false) {
58   verifyMatchType(Type::String, ANNA_FILE_LOCATION);
59   a_isNull = false;
60   *a_value.a_string = value;
61 }
62
63 void Variable::setValue(const int value)
64 noexcept(false) {
65   verifyMatchType(Type::Integer, ANNA_FILE_LOCATION);
66   a_isNull = false;
67   *a_value.a_integer = value;
68 }
69
70 void Variable::setValue(const S64 value)
71 noexcept(false) {
72   verifyMatchType(Type::Integer64, ANNA_FILE_LOCATION);
73   a_isNull = false;
74   *a_value.a_longInteger = value;
75 }
76
77 void Variable::setValue(const bool value)
78 noexcept(false) {
79   verifyMatchType(Type::Boolean, ANNA_FILE_LOCATION);
80   a_isNull = false;
81   *a_value.a_boolean = value;
82 }
83
84 void Variable::setValue(const DataBlock& value)
85 noexcept(false) {
86   verifyMatchType(Type::Block, ANNA_FILE_LOCATION);
87
88   if(a_value.a_dataBlock->deepCopy() == false) {
89     string msg("Variable: ");
90     msg += a_name;
91     msg += " | Datablock requires deep copy";
92     throw RuntimeException(msg, ANNA_FILE_LOCATION);
93   }
94
95   a_isNull = false;
96   *a_value.a_dataBlock = value;
97 }
98
99 void Variable::setValue(const float value)
100 noexcept(false) {
101   verifyMatchSomeType(Type::Float, Type::Double, ANNA_FILE_LOCATION);
102
103   if(a_type == Type::Float) {
104     a_isNull = false;
105     *a_value.a_float = value;
106   } else if(a_type == Type::Double) {
107     a_isNull = false;
108     *a_value.a_double = value;
109   }
110 }
111
112 void Variable::setValue(const double value)
113 noexcept(false) {
114   verifyMatchSomeType(Type::Float, Type::Double, ANNA_FILE_LOCATION);
115
116   if(a_type == Type::Float) {
117     a_isNull = false;
118     *a_value.a_float = value;
119   } else if(a_type == Type::Double) {
120     a_isNull = false;
121     *a_value.a_double = value;
122   }
123 }
124
125 const char* Variable::getStringValue() const
126 noexcept(false) {
127   verifyIsNotNull(ANNA_FILE_LOCATION);
128   verifyMatchType(Type::String, ANNA_FILE_LOCATION);
129   return a_value.a_string->c_str();
130 }
131
132 int Variable::getIntegerValue() const
133 noexcept(false) {
134   verifyIsNotNull(ANNA_FILE_LOCATION);
135   verifyMatchType(Type::Integer, ANNA_FILE_LOCATION);
136   return *a_value.a_integer;
137 }
138
139 S64 Variable::getInteger64Value() const
140 noexcept(false) {
141   int result(0);
142   verifyIsNotNull(ANNA_FILE_LOCATION);
143   verifyMatchSomeType(Type::Integer, Type::Integer64, ANNA_FILE_LOCATION);
144
145   switch(a_type) {
146   case Type::Integer: result = *a_value.a_integer; break;
147   case Type::Integer64: result = *a_value.a_longInteger; break;
148   default: break;
149   }
150
151   return result;
152 }
153
154 bool Variable::getBooleanValue() const
155 noexcept(false) {
156   verifyIsNotNull(ANNA_FILE_LOCATION);
157   verifyMatchType(Type::Boolean, ANNA_FILE_LOCATION);
158   return *a_value.a_boolean;
159 }
160
161 const DataBlock& Variable::getDataBlockValue() const
162 noexcept(false) {
163   verifyIsNotNull(ANNA_FILE_LOCATION);
164   verifyMatchType(Type::Block, ANNA_FILE_LOCATION);
165   return *a_value.a_dataBlock;
166 }
167
168 float Variable::getFloatValue() const
169 noexcept(false) {
170   float result(0.0);
171   verifyIsNotNull(ANNA_FILE_LOCATION);
172   verifyMatchSomeType(Type::Float, Type::Double, ANNA_FILE_LOCATION);
173
174   switch(a_type) {
175   case Type::Float: result = *a_value.a_float; break;
176   case Type::Double: result = (float) *a_value.a_double; break;
177   default: break;
178   }
179
180   return result;
181 }
182
183 double Variable::getDoubleValue() const
184 noexcept(false) {
185   double result(0.0);
186   verifyIsNotNull(ANNA_FILE_LOCATION);
187   verifyMatchSomeType(Type::Float, Type::Double, ANNA_FILE_LOCATION);
188
189   switch(a_type) {
190   case Type::Float: result = (double) *a_value.a_float; break;
191   case Type::Double: result = *a_value.a_double; break;
192   default: break;
193   }
194
195   return result;
196 }
197
198 String Variable::asString() const
199 {
200   String result("anna::Variable { Name: ");
201   result << a_name;
202   result << " | Type: " << Type::asNotNullCString(a_type);
203   result += " | Value: ";
204
205   if(a_isNull == true)
206     result += "<null>";
207   else {
208     switch(a_type) {
209     case Type::String: result += a_value.a_string->c_str(); break;
210     case Type::Integer: result += functions::asString(*a_value.a_integer); break;
211     case Type::Integer64: result += functions::asString(*a_value.a_longInteger); break;
212     case Type::Boolean: result += functions::asString(*a_value.a_boolean); break;
213     case Type::Block: result += functions::asString(*a_value.a_dataBlock); break;
214     case Type::Float: result += functions::asString("%f", *a_value.a_float); break;
215     case Type::Double: result += functions::asString("%g", *a_value.a_double); break;
216     case Type::Custom: result += functions::asHexString(anna_ptrnumber_cast(a_value.a_custom)); break;
217     default: break;
218     }
219   }
220
221   return result += " }";
222 }
223
224 void* Variable::buffer() const
225 {
226   void* result(NULL);
227
228   switch(a_type) {
229   case Type::String: result = const_cast <char*>(a_value.a_string->data()); break;
230   case Type::Integer: result = a_value.a_integer; break;
231   case Type::Integer64: result = a_value.a_longInteger; break;
232   case Type::Boolean: result = a_value.a_boolean; break;
233   case Type::Block: result = const_cast <char*>(a_value.a_dataBlock->getData()); break;
234   case Type::Float: result = a_value.a_float; break;
235   case Type::Double: result = a_value.a_double; break;
236   case Type::Custom: result = a_value.a_custom; break;
237   default: break;
238   }
239
240   return result;
241 }
242
243 void* Variable::getReference() const
244 {
245   void* result(NULL);
246
247   switch(a_type) {
248   case Type::String: result = a_value.a_string; break;
249   case Type::Integer: result = a_value.a_integer; break;
250   case Type::Integer64: result = a_value.a_longInteger; break;
251   case Type::Boolean: result = a_value.a_boolean; break;
252   case Type::Block: result = a_value.a_dataBlock; break;
253   case Type::Float: result = a_value.a_float; break;
254   case Type::Double: result = a_value.a_double; break;
255   case Type::Custom: result = a_value.a_custom; break;
256   default: break;
257   }
258
259   return result;
260 }
261
262 void Variable::verifyMatchType(const Type::_v type, const char* file, const int lineno) const
263 noexcept(false) {
264   if(a_type != type) {
265     String msg("Variable: ");
266     msg << a_name << " | " << Type::asNotNullCString(type) << " mismatch data type";
267     throw RuntimeException(msg, file, lineno);
268   }
269 }
270
271 void Variable::verifyMatchSomeType(const Type::_v firstType, const Type::_v secondType, const char* file, const int lineno) const
272 noexcept(false) {
273   if(a_type != firstType && a_type != secondType) {
274     String msg("Variable: ");
275     msg << a_name << " | Neihter " << Type::asNotNullCString(firstType);
276     msg << " nor " << Type::asNotNullCString(secondType) << " matches with data type";
277     throw RuntimeException(msg, file, lineno);
278   }
279 }
280
281 void Variable::verifyIsNotNull(const char* file, const int lineno) const
282 noexcept(false) {
283   if(a_isNull == true) {
284     String msg("Variable: ");
285     msg << a_name << " | Variable does not have assigned value";
286     throw RuntimeException(msg, file, lineno);
287   }
288 }