Cafu Engine
Variables.hpp
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 */
6 
7 #ifndef CAFU_TYPESYS_VARIABLES_HPP_INCLUDED
8 #define CAFU_TYPESYS_VARIABLES_HPP_INCLUDED
9 
10 #include "Templates/Array.hpp"
11 #include "Math3D/Vector2.hpp"
12 #include "Math3D/Vector3.hpp"
13 #include "Math3D/BoundingBox.hpp"
14 
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
20 
21 #include <cstring>
22 #include <map>
23 
24 
25 /**
26 @page OverviewVariables TypeSys Variables Overview
27 
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.
30 
31 Problem and Motivation
32 ======================
33 
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:
37 
38  - editable in our graphical map and GUI editor CaWE,
39  - accessible via scripting, and
40  - easy to serialize and deserialize (maps, GUIs, prefabs).
41 
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.
51 
52 How it works
53 ============
54 
55 Consider the typical code structure of a component that has a member variable `x`:
56 
57 ~~~~~~~~~~~~~~~~{cpp}
58 class SomeComponentT
59 {
60  public:
61 
62  // [ other methods ... ]
63  void SetX(int newX);
64  int GetX() const;
65 
66 
67  private:
68 
69  int x;
70 };
71 ~~~~~~~~~~~~~~~~
72 
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.
78 
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.
82 
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.
88 
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.
92 */
93 
94 
95 namespace cf
96 {
97  namespace Network { class InStreamT; }
98  namespace Network { class OutStreamT; }
99 
100 
101  namespace TypeSys
102  {
103  class VisitorT;
104  class VisitorConstT;
105 
106 
107  /// This is the common base class for the VarT classes.
108  ///
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.
111  ///
112  /// @see \ref OverviewVariables
113  class VarBaseT
114  {
115  public:
116 
117  VarBaseT(const char* Name, const char* Flags[])
118  : m_Name(Name), m_Flags(Flags) { }
119 
120  const char* GetName() const { return m_Name; }
121 
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;
125 
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 ""; }
133 
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;
143 
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;
147 
148  virtual void accept(VisitorT& Visitor) = 0;
149  virtual void accept(VisitorConstT& Visitor) const = 0;
150 
151 
152  private:
153 
154  const char* m_Name; ///< The name of the variable.
155  const char** m_Flags; ///< An optional list of context-dependent flags.
156  };
157 
158 
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; }
161 
162 
163  /// This is a "wrapper" around a normal C++ variable.
164  ///
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.
168  ///
169  /// User code can derive from this class and override the Set() method in
170  /// order to customize the behaviour.
171  ///
172  /// @see \ref OverviewVariables
173  template<class T> class VarT : public VarBaseT
174  {
175  public:
176 
177  /// The constructor.
178  VarT(const char* Name, const T& Value, const char* Flags[]=NULL)
179  : VarBaseT(Name, Flags), m_Value(Value) { }
180 
181  /// Returns the value of this variable.
182  const T& Get() const { return m_Value; }
183 
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; }
190 
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 { }
198 
199  void Serialize(Network::OutStreamT& Stream) const /*override*/;
200  void Deserialize(Network::InStreamT& Stream) /*override*/;
201 
202  void accept(VisitorT& Visitor) /*override*/;
203  void accept(VisitorConstT& Visitor) const /*override*/;
204 
205 
206  private:
207 
208  T m_Value; ///< The actual variable that is wrapped by this class.
209  };
210 
211 
212  /// This is a "wrapper" around a normal C++ variable specifically of type ArrayT<T>.
213  ///
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:
216  ///
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.)
222  ///
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.
225  ///
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.
229  ///
230  /// @see \ref OverviewVariables
231  template<class T> class VarArrayT : public VarBaseT
232  {
233  public:
234 
235  /// The constructor.
236  VarArrayT(const char* Name, unsigned int InitSize, const T& InitValue, const char* Flags[]=NULL);
237 
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); }
243 
244  const T& operator [] (unsigned int i) const { return m_Array[i]; }
245  T& operator [] (unsigned int i) { return m_Array[i]; }
246 
247  void Serialize(Network::OutStreamT& Stream) const /*override*/;
248  void Deserialize(Network::InStreamT& Stream) /*override*/;
249 
250  void accept(VisitorT& Visitor) /*override*/;
251  void accept(VisitorConstT& Visitor) const /*override*/;
252 
253 
254  private:
255 
256  ArrayT<T> m_Array; ///< The actual array that is wrapped by this class.
257  };
258 
259 
260  /// This is the base class for the visitors of VarT%s.
261  ///
262  /// With the Visitor pattern, the data structure being used is independent
263  /// of the uses to which it is being put.
264  ///
265  /// @see \ref OverviewVariables
266  class VisitorT
267  {
268  public:
269 
270  virtual ~VisitorT() { }
271 
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;
288  };
289 
290 
291  /// Like VisitorT, but for `const` VarT%s.
292  ///
293  /// @see \ref OverviewVariables.
295  {
296  public:
297 
298  virtual ~VisitorConstT() { }
299 
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;
316  };
317 
318 
319  /// This class is a simple container for pointers to VarBaseTs.
320  ///
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.
324  ///
325  /// @see \ref OverviewVariables
326  class VarManT
327  {
328  public:
329 
330  struct CompareCStr
331  {
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; }
335  };
336 
337  typedef std::map<const char*, VarBaseT*, CompareCStr> MapVarBaseT;
338 
339 
340  void Add(VarBaseT* Var);
341 
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);
347 
348  const ArrayT<VarBaseT*>& GetArray() const { return m_VarsArray; }
349 
350  VarBaseT* Find(const char* Name) const
351  {
352  const MapVarBaseT::const_iterator It = m_VarsMap.find(Name);
353 
354  return It != m_VarsMap.end() ? It->second : NULL;
355  }
356 
357 
358  private:
359 
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).
362  };
363  }
364 }
365 
366 #endif
This is the base class for the visitors of VarTs.
Definition: Variables.hpp:266
Like VisitorT, but for const VarTs.
Definition: Variables.hpp:294
void Serialize(Network::OutStreamT &Stream) const
Stores the value of this variable in the given Stream.
Definition: Variables.cpp:50
This class is a simple container for pointers to VarBaseTs.
Definition: Variables.hpp:326
This is a "wrapper" around a normal C++ variable specifically of type ArrayT<T>.
Definition: SetCompVar.hpp:16
void Serialize(Network::OutStreamT &Stream) const
Stores the value of this variable in the given Stream.
Definition: Variables.cpp:211
virtual void Deserialize(Network::InStreamT &Stream)=0
Restores the value of this variable from the given Stream.
virtual void Serialize(Network::OutStreamT &Stream) const =0
Stores the value of this variable in the given Stream.
Definition: Variables.hpp:330
This class is used for reading data from a StateT instance (deserialization).
Definition: State.hpp:207
VarT(const char *Name, const T &Value, const char *Flags[]=NULL)
The constructor.
Definition: Variables.hpp:178
virtual std::string GetExtraMessage() const
Sometimes actions on variables generate extra messages that are relevant to the user.
Definition: Variables.hpp:132
This class is used for writing data into a StateT instance (serialization).
Definition: State.hpp:81
virtual void GetChoices(ArrayT< std::string > &Strings, ArrayT< T > &Values) const
This method returns a list of acceptable input values for this variable, along with a string represen...
Definition: Variables.hpp:197
This is the common base class for the VarT classes.
Definition: Variables.hpp:113
void AddAlias(const char *Alias, VarBaseT *Var)
Adds an alias name for the given variable so that a call to Find() will also find the variable under ...
Definition: Variables.cpp:252
virtual void Set(const T &v)
Sets the value of this variable to the given value v.
Definition: Variables.hpp:189
void Deserialize(Network::InStreamT &Stream)
Restores the value of this variable from the given Stream.
Definition: Variables.cpp:101
void Deserialize(Network::InStreamT &Stream)
Restores the value of this variable from the given Stream.
Definition: Variables.cpp:218
const T & Get() const
Returns the value of this variable.
Definition: Variables.hpp:182
VarArrayT(const char *Name, unsigned int InitSize, const T &InitValue, const char *Flags[]=NULL)
The constructor.
Definition: Variables.cpp:200