Fix issue in Rocket.lua script.
[Cafu-Engine.git] / Libs / Variables.hpp
blob362bc637fa5d50519e7c22730f782b9f415decd9
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
7 #ifndef CAFU_TYPESYS_VARIABLES_HPP_INCLUDED
8 #define CAFU_TYPESYS_VARIABLES_HPP_INCLUDED
10 #include "Templates/Array.hpp"
11 #include "Math3D/Vector2.hpp"
12 #include "Math3D/Vector3.hpp"
13 #include "Math3D/BoundingBox.hpp"
15 #if defined(_WIN32) && _MSC_VER<1600
16 #include "pstdint.h" // Paul Hsieh's portable implementation of the stdint.h header.
17 #else
18 #include <stdint.h>
19 #endif
21 #include <cstring>
22 #include <map>
25 /**
26 @page OverviewVariables TypeSys Variables Overview
28 The "variable" classes in cf::TypeSys are supposed to turn a "normal" member
29 variable of a class into something "more" that also other code can work with.
31 Problem and Motivation
32 ======================
34 In Cafu we use "components" to compose map entities and GUI windows, see the
35 cf::GuiSys::ComponentBaseT hierarchy for an example.
36 Components are classes like any other, but their member variables should be:
38 - editable in our graphical map and GUI editor CaWE,
39 - accessible via scripting, and
40 - easy to serialize and deserialize (maps, GUIs, prefabs).
42 However, none of these features should impact the component in its actual,
43 inherent purpose, being a component. The cf::GuiSys::ComponentBaseT classes
44 should not be hindered in their performance, and their interfaces and
45 implementations should not be cluttered with the details of the above
46 requirements.
47 In fact, it would be desireable to separate these issues from the components,
48 so that the way in which the editors let users edit the variables or the
49 details in which variables are bound to scripts can be varied without ever
50 affecting the components themselves.
52 How it works
53 ============
55 Consider the typical code structure of a component that has a member variable `x`:
57 ~~~~~~~~~~~~~~~~{cpp}
58 class SomeComponentT
60 public:
62 // [ other methods ... ]
63 void SetX(int newX);
64 int GetX() const;
67 private:
69 int x;
71 ~~~~~~~~~~~~~~~~
73 A member variable usually implies three items: the variable itself, a "Get"
74 function and a "Set" function.
75 The implementations of the two functions are often trivial and `inline`, but
76 it is not unusual that especially the "Set" function has side-effects, such as
77 updating a graphical resource if a new filename has been set, etc.
79 Now, the key idea is to replace the variable and its Get/Set functions with a
80 "wrapper" class.
81 This is what the cf::TypeSys::VarT classes in this file are for.
83 As we also need a list of all cf::TypeSys::VarT instances in the class that
84 contains them (the component), the cf::TypeSys::VarT classes all must derive
85 from a common base class, cf::TypeSys::VarBaseT.
86 As the list of variables should actually have more features than a plain array
87 or list, we manage them in a cf::TypeSys::VarManT instance.
89 Finally, we apply the [Visitor pattern](http://en.wikipedia.org/wiki/Visitor_pattern)
90 to the cf::TypeSys::VarBaseT hierarchy: It allows user code to add arbitrary
91 operations to the cf::TypeSys::VarBaseT instances without modifying them.
95 namespace cf
97 namespace Network { class InStreamT; }
98 namespace Network { class OutStreamT; }
101 namespace TypeSys
103 class VisitorT;
104 class VisitorConstT;
107 /// This is the common base class for the VarT classes.
109 /// It allows other code to work with VarT%s without having to know their concrete type.
110 /// For example, VarManT is a container for pointers to VarBaseT%s.
112 /// @see \ref OverviewVariables
113 class VarBaseT
115 public:
117 VarBaseT(const char* Name, const char* Flags[])
118 : m_Name(Name), m_Flags(Flags) { }
120 const char* GetName() const { return m_Name; }
122 const char** GetFlags() const { return m_Flags; }
123 bool HasFlag(const char* Flag) const;
124 const char* GetFlag(const char* Flag, unsigned int Nr, const char* Default=NULL) const;
126 /// Sometimes actions on variables generate extra messages that are relevant to the user.
127 /// For example, setting a string that is interpreted as a filename can generate an extra
128 /// message with details if the related resource could not be opened.
129 /// This function returns the last extra message for this variable.
130 /// However, note that a proper logging system would be a better solution to this problem,
131 /// and we should probably replace this method with logging in the future.
132 virtual std::string GetExtraMessage() const { return ""; }
134 /// Stores the value of this variable in the given Stream.
135 /// An implementation may also store additional data, so that Deserialize() is able to recover from side-
136 /// effects where restoring the value of the variable alone does not suffice.
137 /// For example, consider the side-effects of setting a new model name in a ComponentModelT as described
138 /// at VarT::Set(): restoring the previous model name will properly restore the internal model resource,
139 /// but not undo any clamps or resets that setting the new name caused for the animation and skin numbers.
140 /// Thus, the implementation of this method for the model name would also store the values of the affected
141 /// sibling variables, so that Deserialize() can implement a proper restore / "undo".
142 virtual void Serialize(Network::OutStreamT& Stream) const = 0;
144 /// Restores the value of this variable from the given Stream.
145 /// See Serialize() for additional details.
146 virtual void Deserialize(Network::InStreamT& Stream) = 0;
148 virtual void accept(VisitorT& Visitor) = 0;
149 virtual void accept(VisitorConstT& Visitor) const = 0;
152 private:
154 const char* m_Name; ///< The name of the variable.
155 const char** m_Flags; ///< An optional list of context-dependent flags.
159 // template<class T> Network::InStreamT& operator >> (Network::InStreamT& Stream, VarBaseT& Var) { Var.Deserialize(Stream); return Stream; }
160 // template<class T> Network::OutStreamT& operator << (Network::OutStreamT& Stream, const VarBaseT& Var) { Var.Serialize(Stream); return Stream; }
163 /// This is a "wrapper" around a normal C++ variable.
165 /// It can be used in place of a normal variable whenever the functionality
166 /// described in \ref OverviewVariables is desired, for example in the member
167 /// variables of component classes of game entities and GUI windows.
169 /// User code can derive from this class and override the Set() method in
170 /// order to customize the behaviour.
172 /// @see \ref OverviewVariables
173 template<class T> class VarT : public VarBaseT
175 public:
177 /// The constructor.
178 VarT(const char* Name, const T& Value, const char* Flags[]=NULL)
179 : VarBaseT(Name, Flags), m_Value(Value) { }
181 /// Returns the value of this variable.
182 const T& Get() const { return m_Value; }
184 /// Sets the value of this variable to the given value `v`.
185 /// Derived classes can override this method to add "side-effects", such as updating graphical resources.
186 /// In some cases, side-effects can even affect *other* variables (siblings). For example, setting a new
187 /// model name in ComponentModelT not only updates the internal (private) model resource, but it can also
188 /// imply updates (resets or clamps) to the animation and skin number variables.
189 virtual void Set(const T& v) { m_Value = v; }
191 /// This method returns a list of acceptable input values for this variable, along with a string
192 /// representation of each.
193 /// The relevancy of the returned tuples is limited: They are intended to create helpful user interfaces
194 /// in our graphical editors and to provide extra information in scripts, but if Set() is called with a
195 /// value that is not in `Values`, it will work and is not an error.
196 /// If the method returns no tuples at all, it means that user input is free and any value is acceptable.
197 virtual void GetChoices(ArrayT<std::string>& Strings, ArrayT<T>& Values) const { }
199 void Serialize(Network::OutStreamT& Stream) const /*override*/;
200 void Deserialize(Network::InStreamT& Stream) /*override*/;
202 void accept(VisitorT& Visitor) /*override*/;
203 void accept(VisitorConstT& Visitor) const /*override*/;
206 private:
208 T m_Value; ///< The actual variable that is wrapped by this class.
212 /// This is a "wrapper" around a normal C++ variable specifically of type ArrayT<T>.
214 /// This class is similar to VarT< ArrayT<T> >, but was invented because working with VarT< ArrayT<T> >s
215 /// is actually difficult in practice:
217 /// - Setting individual elements of the array or modifying the array itself (e.g. pushing back another
218 /// element) via the VarT::Set() method is cumbersome.
219 /// - Adding a non-const Get() method to VarT< ArrayT<T> > was not desired, because it would break the
220 /// accounting for side-effects that is guaranteed by the VarT::Set() method.
221 /// - (Arrays seem to need side-effects as little as lists of pre-made choices.)
223 /// Therefore, VarArrayT<T> was made to have an interface that is easier to use and more efficient when
224 /// working with arrays, and consciously omits the "possible side-effects" feature that VarT::Set() has.
226 /// It can be used in place of a normal ArrayT variable whenever the functionality described in
227 /// \ref OverviewVariables is desired, for example in the member variables of component classes of game
228 /// entities and GUI windows.
230 /// @see \ref OverviewVariables
231 template<class T> class VarArrayT : public VarBaseT
233 public:
235 /// The constructor.
236 VarArrayT(const char* Name, unsigned int InitSize, const T& InitValue, const char* Flags[]=NULL);
238 const ArrayT<T>& Get() const { return m_Array; }
239 unsigned int Size() const { return m_Array.Size(); }
240 void Clear() { m_Array.Clear(); }
241 void Overwrite() { m_Array.Overwrite(); }
242 void PushBack(const T Element) { m_Array.PushBack(Element); }
244 const T& operator [] (unsigned int i) const { return m_Array[i]; }
245 T& operator [] (unsigned int i) { return m_Array[i]; }
247 void Serialize(Network::OutStreamT& Stream) const /*override*/;
248 void Deserialize(Network::InStreamT& Stream) /*override*/;
250 void accept(VisitorT& Visitor) /*override*/;
251 void accept(VisitorConstT& Visitor) const /*override*/;
254 private:
256 ArrayT<T> m_Array; ///< The actual array that is wrapped by this class.
260 /// This is the base class for the visitors of VarT%s.
262 /// With the Visitor pattern, the data structure being used is independent
263 /// of the uses to which it is being put.
265 /// @see \ref OverviewVariables
266 class VisitorT
268 public:
270 virtual ~VisitorT() { }
272 virtual void visit(VarT<float>& Var) = 0;
273 virtual void visit(VarT<double>& Var) = 0;
274 virtual void visit(VarT<int>& Var) = 0;
275 virtual void visit(VarT<unsigned int>& Var) = 0;
276 virtual void visit(VarT<uint16_t>& Var) = 0;
277 virtual void visit(VarT<uint8_t>& Var) = 0;
278 virtual void visit(VarT<bool>& Var) = 0;
279 virtual void visit(VarT<std::string>& Var) = 0;
280 virtual void visit(VarT<Vector2fT>& Var) = 0;
281 virtual void visit(VarT<Vector3fT>& Var) = 0;
282 virtual void visit(VarT<Vector3dT>& Var) = 0;
283 virtual void visit(VarT<BoundingBox3dT>& Var) = 0;
284 virtual void visit(VarArrayT<uint32_t>& Var) = 0;
285 virtual void visit(VarArrayT<uint16_t>& Var) = 0;
286 virtual void visit(VarArrayT<uint8_t>& Var) = 0;
287 virtual void visit(VarArrayT<std::string>& Var) = 0;
291 /// Like VisitorT, but for `const` VarT%s.
293 /// @see \ref OverviewVariables.
294 class VisitorConstT
296 public:
298 virtual ~VisitorConstT() { }
300 virtual void visit(const VarT<float>& Var) = 0;
301 virtual void visit(const VarT<double>& Var) = 0;
302 virtual void visit(const VarT<int>& Var) = 0;
303 virtual void visit(const VarT<unsigned int>& Var) = 0;
304 virtual void visit(const VarT<uint16_t>& Var) = 0;
305 virtual void visit(const VarT<uint8_t>& Var) = 0;
306 virtual void visit(const VarT<bool>& Var) = 0;
307 virtual void visit(const VarT<std::string>& Var) = 0;
308 virtual void visit(const VarT<Vector2fT>& Var) = 0;
309 virtual void visit(const VarT<Vector3fT>& Var) = 0;
310 virtual void visit(const VarT<Vector3dT>& Var) = 0;
311 virtual void visit(const VarT<BoundingBox3dT>& Var) = 0;
312 virtual void visit(const VarArrayT<uint32_t>& Var) = 0;
313 virtual void visit(const VarArrayT<uint16_t>& Var) = 0;
314 virtual void visit(const VarArrayT<uint8_t>& Var) = 0;
315 virtual void visit(const VarArrayT<std::string>& Var) = 0;
319 /// This class is a simple container for pointers to VarBaseTs.
321 /// Together with the VarT classes, it provides a very simple kind of
322 /// "reflection" or "type introspection" feature.
323 /// See class ComponentBaseT for an example use.
325 /// @see \ref OverviewVariables
326 class VarManT
328 public:
330 struct CompareCStr
332 // See "Die C++ Programmiersprache" by Bjarne Stroustrup pages 498 and 510 and
333 // Scott Meyers "Effective STL" Item 21 for more information about this struct.
334 bool operator () (const char* a, const char* b) const { return std::strcmp(a, b) < 0; }
337 typedef std::map<const char*, VarBaseT*, CompareCStr> MapVarBaseT;
340 void Add(VarBaseT* Var);
342 /// Adds an alias name for the given variable so that a call to Find() will also find the variable
343 /// under the alias name.
344 /// The purpose of this method is to provide backwards-compatibility if variables must be renamed
345 /// after they have been introduced and became widely used, e.g. in custom user scripts.
346 void AddAlias(const char* Alias, VarBaseT* Var);
348 const ArrayT<VarBaseT*>& GetArray() const { return m_VarsArray; }
350 VarBaseT* Find(const char* Name) const
352 const MapVarBaseT::const_iterator It = m_VarsMap.find(Name);
354 return It != m_VarsMap.end() ? It->second : NULL;
358 private:
360 ArrayT<VarBaseT*> m_VarsArray; ///< Keeps the variables in the order they were added.
361 MapVarBaseT m_VarsMap; ///< Keeps the variables by name (for find by name and lexicographical traversal).
366 #endif