1 /* This file is part of the Pangolin Project.
2 * http://github.com/stevenlovegrove/Pangolin
3 *
4 * Copyright (c) 2014 Steven Lovegrove
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following
13 * conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28 #pragma once
29
30 #include <stdexcept>
31 #include <string.h>
32 #include <cmath>
33
34 #include <pangolin/var/varvalue.h>
35 #include <pangolin/var/varwrapper.h>
36 #include <pangolin/var/varstate.h>
37
38 namespace pangolin
39 {
40
41 template<typename T>
InitialiseNewVarMetaGeneric(VarValue<T> & v,const std::string & name)42 inline void InitialiseNewVarMetaGeneric(
43 VarValue<T>& v, const std::string& name
44 ) {
45 // Initialise meta parameters
46 const std::vector<std::string> parts = pangolin::Split(name,'.');
47 v.Meta().full_name = name;
48 v.Meta().friendly = parts.size() > 0 ? parts[parts.size()-1] : "";
49 v.Meta().range[0] = 0.0;
50 v.Meta().range[1] = 0.0;
51 v.Meta().increment = 0.0;
52 v.Meta().flags = META_FLAG_NONE;
53 v.Meta().logscale = false;
54 v.Meta().generic = true;
55
56 VarState::I().NotifyNewVar<T>(name, v);
57 }
58
59 template<typename T>
60 inline void InitialiseNewVarMeta(
61 VarValue<T>& v, const std::string& name,
62 double min = 0, double max = 0, int flags = META_FLAG_TOGGLE,
63 bool logscale = false
64 ) {
65 // Initialise meta parameters
66 const std::vector<std::string> parts = pangolin::Split(name,'.');
67 v.Meta().full_name = name;
68 v.Meta().friendly = parts.size() > 0 ? parts[parts.size()-1] : "";
69 v.Meta().range[0] = min;
70 v.Meta().range[1] = max;
71 if (std::is_integral<T>::value) {
72 v.Meta().increment = 1.0;
73 } else {
74 v.Meta().increment = (max - min) / 100.0;
75 }
76 v.Meta().flags = flags;
77 v.Meta().logscale = logscale;
78 v.Meta().generic = false;
79
80 VarState::I().NotifyNewVar<T>(name, v);
81 }
82
83 template<typename T>
84 class Var
85 {
86 public:
87 static T& Attach(
88 const std::string& name, T& variable,
89 double min, double max, bool logscale = false
90 ) {
91 // Find name in VarStore
92 VarValueGeneric*& v = VarState::I()[name];
93 if(v) {
94 throw std::runtime_error(std::string("Var with the following name already exists: ") + name);
95 }else{
96 // new VarRef<T> (owned by VarStore)
97 VarValue<T&>* nv = new VarValue<T&>(variable);
98 v = nv;
99 if(logscale) {
100 if (min <= 0 || max <= 0) {
101 throw std::runtime_error("LogScale: range of numbers must be positive!");
102 }
103 InitialiseNewVarMeta<T&>(*nv, name, std::log(min), std::log(max), META_FLAG_TOGGLE, logscale);
104 }else{
105 InitialiseNewVarMeta<T&>(*nv, name, min, max, META_FLAG_TOGGLE, logscale);
106 }
107 }
108 return variable;
109 }
110
111 static T& Attach(
112 const std::string& name, T& variable, int flags = META_FLAG_NONE
113 ) {
114 // Find name in VarStore
115 VarValueGeneric*& v = VarState::I()[name];
116 if (v) {
117 throw std::runtime_error(std::string("Var with the following name already exists: ") + name);
118 }
119 else{
120 // new VarRef<T> (owned by VarStore)
121 VarValue<T&>* nv = new VarValue<T&>(variable);
122 v = nv;
123 InitialiseNewVarMeta<T&>(*nv, name, 0.0, 0.0, flags);
124 }
125 return variable;
126 }
127
Attach(const std::string & name,T & variable,bool toggle)128 static T& Attach(
129 const std::string& name, T& variable, bool toggle
130 ) {
131 return Attach(name, variable, toggle ? META_FLAG_TOGGLE : META_FLAG_NONE);
132 }
133
~Var()134 ~Var()
135 {
136 delete ptr;
137 }
138
Var(VarValueGeneric & v)139 Var( VarValueGeneric& v )
140 : ptr(0)
141 {
142 InitialiseFromGeneric(&v);
143 }
144
145
Var(const std::string & name)146 Var( const std::string& name )
147 : ptr(0)
148 {
149 // Find name in VarStore
150 VarValueGeneric*& v = VarState::I()[name];
151 if(v && !v->Meta().generic) {
152 InitialiseFromGeneric(v);
153 }else{
154 // new VarValue<T> (owned by VarStore)
155 VarValue<T>* nv;
156 if(v) {
157 // Specialise generic variable
158 nv = new VarValue<T>( Convert<T,std::string>::Do( v->str->Get() ) );
159 delete v;
160 }else{
161 nv = new VarValue<T>( T() );
162 }
163 v = nv;
164 var = nv;
165 InitialiseNewVarMeta(*nv, name);
166 }
167 }
168
169 Var(const std::string& name, const T& value, int flags = META_FLAG_NONE)
170 : ptr(0)
171 {
172 // Find name in VarStore
173 VarValueGeneric*& v = VarState::I()[name];
174 if(v && !v->Meta().generic) {
175 InitialiseFromGeneric(v);
176 }else{
177 // new VarValue<T> (owned by VarStore)
178 VarValue<T>* nv;
179 if(v) {
180 // Specialise generic variable
181 nv = new VarValue<T>( Convert<T,std::string>::Do( v->str->Get() ) );
182 delete v;
183 }else{
184 nv = new VarValue<T>(value);
185 }
186 v = nv;
187 var = nv;
188 InitialiseNewVarMeta(*nv, name, 0, 1, flags);
189 }
190 }
191
Var(const std::string & name,const T & value,bool toggle)192 Var(const std::string& name, const T& value, bool toggle)
193 : Var(name, value, toggle ? META_FLAG_TOGGLE : META_FLAG_NONE)
194 {
195 }
196
197 Var(
198 const std::string& name, const T& value,
199 double min, double max, bool logscale = false
200 ) : ptr(0)
201 {
202 // Find name in VarStore
203 VarValueGeneric*& v = VarState::I()[name];
204 if(v && !v->Meta().generic) {
205 InitialiseFromGeneric(v);
206 }else{
207 // new VarValue<T> (owned by VarStore)
208 VarValue<T>* nv;
209 if(v) {
210 // Specialise generic variable
211 nv = new VarValue<T>( Convert<T,std::string>::Do( v->str->Get() ) );
212 delete v;
213 }else{
214 nv = new VarValue<T>(value);
215 }
216 var = nv;
217 v = nv;
218 if(logscale) {
219 if (min <= 0 || max <= 0) {
220 throw std::runtime_error("LogScale: range of numbers must be positive!");
221 }
222 InitialiseNewVarMeta(*nv, name, std::log(min), std::log(max), META_FLAG_TOGGLE, true);
223 }else{
224 InitialiseNewVarMeta(*nv, name, min, max);
225 }
226 }
227 }
228
Reset()229 void Reset()
230 {
231 var->Reset();
232 }
233
Get()234 const T& Get() const
235 {
236 try{
237 return var->Get();
238 }catch(const BadInputException&)
239 {
240 const_cast<Var<T> *>(this)->Reset();
241 return var->Get();
242 }
243 }
244
245 operator const T& () const
246 {
247 return Get();
248 }
249
250 const T* operator->()
251 {
252 try{
253 return &(var->Get());
catch(const BadInputException &)254 }catch(const BadInputException&)
255 {
256 Reset();
257 return &(var->Get());
258 }
259 }
260
261 void operator=(const T& val)
262 {
263 var->Set(val);
264 }
265
266 void operator=(const Var<T>& v)
267 {
268 var->Set(v.var->Get());
269 }
270
Meta()271 VarMeta& Meta()
272 {
273 return var->Meta();
274 }
275
GuiChanged()276 bool GuiChanged()
277 {
278 if(var->Meta().gui_changed) {
279 var->Meta().gui_changed = false;
280 return true;
281 }
282 return false;
283 }
284
Ref()285 VarValueT<T>& Ref()
286 {
287 return *var;
288 }
289
290 protected:
291 // Initialise from existing variable, obtain data / accessor
InitialiseFromGeneric(VarValueGeneric * v)292 void InitialiseFromGeneric(VarValueGeneric* v)
293 {
294 if( !strcmp(v->TypeId(), typeid(T).name()) ) {
295 // Same type
296 var = (VarValueT<T>*)(v);
297 }else if( std::is_same<T,std::string>::value ) {
298 // Use types string accessor
299 var = (VarValueT<T>*)(v->str);
300 }else if( !strcmp(v->TypeId(), typeid(bool).name() ) ) {
301 // Wrapper, owned by this object
302 ptr = new VarWrapper<T,bool>( *(VarValueT<bool>*)v );
303 var = ptr;
304 }else if( !strcmp(v->TypeId(), typeid(short).name() ) ) {
305 // Wrapper, owned by this object
306 ptr = new VarWrapper<T,short>( *(VarValueT<short>*)v );
307 var = ptr;
308 }else if( !strcmp(v->TypeId(), typeid(int).name() ) ) {
309 // Wrapper, owned by this object
310 ptr = new VarWrapper<T,int>( *(VarValueT<int>*)v );
311 var = ptr;
312 }else if( !strcmp(v->TypeId(), typeid(long).name() ) ) {
313 // Wrapper, owned by this object
314 ptr = new VarWrapper<T,long>( *(VarValueT<long>*)v );
315 var = ptr;
316 }else if( !strcmp(v->TypeId(), typeid(float).name() ) ) {
317 // Wrapper, owned by this object
318 ptr = new VarWrapper<T,float>( *(VarValueT<float>*)v );
319 var = ptr;
320 }else if( !strcmp(v->TypeId(), typeid(double).name() ) ) {
321 // Wrapper, owned by this object
322 ptr = new VarWrapper<T,double>( *(VarValueT<double>*)v );
323 var = ptr;
324 }else{
325 // other types: have to go via string
326 // Wrapper, owned by this object
327 ptr = new VarWrapper<T,std::string>( *(v->str) );
328 var = ptr;
329 }
330 }
331
332 // Holds reference to stored variable object
333 // N.B. mutable because it is a cached value and Get() is advertised as const.
334 mutable VarValueT<T>* var;
335
336 // ptr is non-zero if this object owns the object variable (a wrapper)
337 VarValueT<T>* ptr;
338 };
339
340 }
341