aboutsummaryrefslogtreecommitdiff
path: root/src/FbTk
diff options
context:
space:
mode:
Diffstat (limited to 'src/FbTk')
-rw-r--r--src/FbTk/ResTraits.hh208
-rw-r--r--src/FbTk/Resource.hh60
2 files changed, 244 insertions, 24 deletions
diff --git a/src/FbTk/ResTraits.hh b/src/FbTk/ResTraits.hh
new file mode 100644
index 0000000..32be48d
--- /dev/null
+++ b/src/FbTk/ResTraits.hh
@@ -0,0 +1,208 @@
1// ResTraits.hh
2// Copyright (c) 2011 Pavel Labath (pavelo at centrum dot sk)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22#ifndef FBTK_RESTRAITS_HH
23#define FBTK_RESTRAITS_HH
24
25#include <stdexcept>
26#include <vector>
27
28#include "Luamm.hh"
29#include "StringUtil.hh"
30
31namespace FbTk {
32
33struct ConversionError: public std::runtime_error {
34 ConversionError(const std::string &msg) : std::runtime_error(msg) {}
35};
36
37/* Classes that "know" how to convert from string and lua representations
38 * into corresponding C++ types
39 */
40
41template<typename T>
42struct IntTraits {
43 typedef T Type;
44 static std::string toString(T x) { return StringUtil::number2String(x); }
45 static void toLua(T x, lua::state &l) { l.pushnumber(x); }
46
47 static T fromString(const std::string &x) {
48 T t;
49 if(StringUtil::extractNumber(x, t))
50 return t;
51 throw ConversionError("Cannot convert to integer from '" + x + "'");
52 }
53
54 static T fromLua(lua::state &l) {
55 lua::stack_sentry s(l, -1);
56
57 if(l.isnumber(-1))
58 return l.tonumber(-1);
59 else if(l.isstring(-1))
60 return fromString(l.tostring(-1));
61 throw ConversionError( std::string("Cannot convert to integer from lua type ")
62 + l.type_name(l.type(-1)) );
63 }
64};
65
66struct StringTraits {
67 typedef std::string Type;
68 static std::string toString(const std::string &x) { return x; }
69 static void toLua(const std::string &x, lua::state &l) { l.pushstring(x); }
70 static std::string fromString(const std::string &x) { return x; }
71
72 static std::string fromLua(lua::state &l) {
73 lua::stack_sentry s(l, -1);
74
75 if(l.isstring(-1) || l.isnumber(-1))
76 return fromString(l.tostring(-1));
77 throw ConversionError( std::string("Cannot convert to string from lua type ")
78 + l.type_name(l.type(-1)) );
79 }
80};
81
82struct BoolTraits {
83 typedef bool Type;
84 static std::string toString(bool x) { return x ? "true" : "false"; }
85 static void toLua(bool x, lua::state &l) { l.pushboolean(x); }
86 static bool fromString(const std::string &x) {
87 return strcasecmp(x.c_str(), "true") == 0;
88 }
89
90 static bool fromLua(lua::state &l) {
91 lua::stack_sentry s(l, -1);
92
93 if(l.isstring(-1))
94 return fromString(l.tostring(-1));
95 else if(l.isnumber(-1))
96 return l.tointeger(-1) != 0;
97 else
98 return l.toboolean(-1);
99 }
100};
101
102/**
103 * To use this class, one must first define a mapping between enum values and their names using
104 * the s_map array. A NULL value for name signals the end of the array. E.g.,
105 *
106 * template<>
107 * EnumTraits<Foo>::Pair EnumTraits<Foo>::s_map[] = { {"Bar", Bar}, {"Baz", Baz} {NULL, Baz} };
108 */
109template<typename T>
110struct EnumTraits {
111 typedef T Type;
112 struct Pair {
113 const char *name;
114 T value;
115 };
116 static const Pair s_map[];
117
118 static std::string toString(T x) {
119 for(const Pair *p = s_map; p->name; ++p) {
120 if(p->value == x)
121 return p->name;
122 }
123 throw ConversionError("Unknown value for enum");
124 }
125
126 static void toLua(T x, lua::state &l) { l.pushstring(toString(x)); }
127
128 static T fromString(const std::string &x) {
129 for(const Pair *p = s_map; p->name; ++p) {
130 if(strcasecmp(p->name, x.c_str()) == 0)
131 return p->value;
132 }
133 throw ConversionError("Cannot convert to enum from '" + x + "'");
134 }
135
136 static T fromLua(lua::state &l) {
137 lua::stack_sentry s(l, -1);
138
139 if(l.isstring(-1) || l.isnumber(-1))
140 return fromString(l.tostring(-1));
141 throw ConversionError( std::string("Cannot convert to enum from lua type ")
142 + l.type_name(l.type(-1)) );
143 }
144};
145
146template<typename Traits>
147struct VectorTraits {
148 typedef std::vector<typename Traits::Type> Type;
149 static std::string toString(const Type &x) {
150 std::string retval;
151 for(size_t i = 0; i < x.size(); ++i) {
152 retval.append(Traits::toString(x[i]));
153 retval.append(" ");
154 }
155
156 return retval;
157 }
158
159 static void toLua(const Type &x, lua::state &l) {
160 l.checkstack(2);
161 l.createtable(x.size());
162 lua::stack_sentry s(l);
163
164 for(size_t i = 0; i < x.size(); ++i) {
165 Traits::toLua(x[i], l);
166 l.rawseti(-2, i);
167 }
168 }
169
170 static Type fromString(const std::string &x) {
171 std::vector<std::string> val;
172 StringUtil::stringtok(val, x);
173 Type retval;
174
175 for(size_t i = 0; i < val.size(); i++) {
176 try {
177 retval.push_back(Traits::fromString(val[i]));
178 }
179 catch(std::runtime_error &) {
180 }
181 }
182
183 return retval;
184 }
185
186 static Type fromLua(lua::state &l) {
187 l.checkstack(1);
188 lua::stack_sentry s(l, -1);
189 Type retval;
190
191 if(l.type(-1) == lua::TTABLE) {
192 for(size_t i = 0; l.rawgeti(-1, i), !l.isnil(-1); ++i) {
193 try {
194 retval.push_back(Traits::fromLua(l));
195 }
196 catch(std::runtime_error &) {
197 }
198 }
199 return retval;
200 }
201 throw ConversionError( std::string("Cannot convert to vector from lua type ")
202 + l.type_name(l.type(-1)) );
203 }
204};
205
206} // end namespace FbTk
207
208#endif // FBTK_RESTRAITS_HH
diff --git a/src/FbTk/Resource.hh b/src/FbTk/Resource.hh
index 1c53bff..fb05426 100644
--- a/src/FbTk/Resource.hh
+++ b/src/FbTk/Resource.hh
@@ -31,12 +31,9 @@
31 31
32#include <exception> 32#include <exception>
33#include <typeinfo> 33#include <typeinfo>
34#include "ResTraits.hh"
34#include "XrmDatabaseHelper.hh" 35#include "XrmDatabaseHelper.hh"
35 36
36namespace lua {
37 class state;
38}
39
40namespace FbTk { 37namespace FbTk {
41 38
42class ResourceException: public std::exception { 39class ResourceException: public std::exception {
@@ -82,7 +79,7 @@ private:
82 std::string m_altname; ///< alternative name 79 std::string m_altname; ///< alternative name
83}; 80};
84 81
85template <typename T> 82template <typename T, typename Traits>
86class Resource; 83class Resource;
87 84
88class ResourceManager_base 85class ResourceManager_base
@@ -119,8 +116,8 @@ public:
119 * it will throw exception if it fails 116 * it will throw exception if it fails
120 * @return reference to resource type 117 * @return reference to resource type
121 */ 118 */
122 template <typename ResourceType> 119 template <typename ResourceType, typename Traits>
123 Resource<ResourceType> &getResource(const std::string &resource); 120 Resource<ResourceType, Traits> &getResource(const std::string &resource);
124}; 121};
125 122
126class ResourceManager: public ResourceManager_base 123class ResourceManager: public ResourceManager_base
@@ -189,15 +186,10 @@ private:
189 186
190/// Real resource class 187/// Real resource class
191/** 188/**
192 * usage: Resource<int> someresource(resourcemanager, 10, "someresourcename", "somealternativename"); 189 * usage: Resource<int, IntTraits<int> > someresource(resourcemanager, 10, "someresourcename", "somealternativename");
193 * and then implement setFromString and getString 190 * If there is no traits class for your type, you have to implement one.
194 * example:
195 * template <>
196 * void Resource<int>::setFromString(const char *str) {
197 * *(*this) = atoi(str);
198 * }
199 */ 191 */
200template <typename T> 192template <typename T, typename Traits>
201class Resource:public Resource_base, public Accessor<T> { 193class Resource:public Resource_base, public Accessor<T> {
202public: 194public:
203 typedef T Type; 195 typedef T Type;
@@ -211,14 +203,30 @@ public:
211 203
212 void setDefaultValue() { m_value = m_defaultval; } 204 void setDefaultValue() { m_value = m_defaultval; }
213 /// sets resource from string, specialized, must be implemented 205 /// sets resource from string, specialized, must be implemented
214 void setFromString(const char *strval); 206 void setFromString(const char *strval) {
207 try {
208 m_value = Traits::fromString(strval);
209 }
210 catch(ConversionError &e) {
211 std::cerr << name() << ": " << e.what() << std::endl;
212 setDefaultValue();
213 }
214 }
215 Accessor<T> &operator =(const T& newvalue) { m_value = newvalue; return *this;} 215 Accessor<T> &operator =(const T& newvalue) { m_value = newvalue; return *this;}
216 /// specialized, must be implemented 216 /// specialized, must be implemented
217 /// @return string value of resource 217 /// @return string value of resource
218 std::string getString() const; 218 std::string getString() const { return Traits::toString(m_value); }
219 219
220 virtual void setFromLua(lua::state &l); 220 virtual void setFromLua(lua::state &l) {
221 virtual void pushToLua(lua::state &l) const; 221 try {
222 m_value = Traits::fromLua(l);
223 }
224 catch(ConversionError &e) {
225 std::cerr << name() << ": " << e.what() << std::endl;
226 setDefaultValue();
227 }
228 }
229 virtual void pushToLua(lua::state &l) const { Traits::toLua(m_value, l); }
222 230
223 operator T() const { return m_value; } 231 operator T() const { return m_value; }
224 T& get() { return m_value; } 232 T& get() { return m_value; }
@@ -232,17 +240,16 @@ private:
232}; 240};
233 241
234 242
235 243template <typename ResourceType, typename Traits>
236template <typename ResourceType> 244Resource<ResourceType, Traits> &ResourceManager_base::getResource(const std::string &resname) {
237Resource<ResourceType> &ResourceManager_base::getResource(const std::string &resname) {
238 Resource_base *res = findResource(resname); 245 Resource_base *res = findResource(resname);
239 if (res == 0) { 246 if (res == 0) {
240 throw ResourceException("Could not find resource \"" + 247 throw ResourceException("Could not find resource \"" +
241 resname + "\""); 248 resname + "\"");
242 } 249 }
243 250
244 Resource<ResourceType> *res_type = 251 Resource<ResourceType, Traits> *res_type =
245 dynamic_cast<Resource<ResourceType> *>(res); 252 dynamic_cast<Resource<ResourceType, Traits> *>(res);
246 if (res_type == 0) { 253 if (res_type == 0) {
247 throw ResourceException("Could not convert resource \"" + 254 throw ResourceException("Could not convert resource \"" +
248 resname + 255 resname +
@@ -252,6 +259,11 @@ Resource<ResourceType> &ResourceManager_base::getResource(const std::string &res
252 return *res_type; 259 return *res_type;
253} 260}
254 261
262typedef Resource<bool, BoolTraits> BoolResource;
263typedef Resource<int, IntTraits<int> > IntResource;
264typedef Resource<unsigned int, IntTraits<unsigned int> > UIntResource;
265typedef Resource<std::string, StringTraits> StringResource;
266
255} // end namespace FbTk 267} // end namespace FbTk
256 268
257#endif // FBTK_RESOURCE_HH 269#endif // FBTK_RESOURCE_HH