moving some non-portable code to stlplus
[chaz/yoink] / src / moof / resource.hh
1
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
4 *
5 * vi:ts=4 sw=4 tw=75
6 *
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
9 *
10 **************************************************************************/
11
12 #ifndef _MOOF_RESOURCE_HH_
13 #define _MOOF_RESOURCE_HH_
14
15 /**
16 * \file resource.hh
17 * Interface for textures, sounds, and other types of resources.
18 */
19
20 #include <cstdio>
21 #include <map>
22 #include <stdexcept>
23 #include <string>
24 #include <vector>
25
26 #include <boost/shared_ptr.hpp>
27 #include <boost/function.hpp>
28
29 #include <moof/debug.hh>
30
31 #if HAVE_CONFIG_H
32 #include "../config.h"
33 #endif
34
35
36 namespace moof {
37
38
39 class resource;
40 typedef boost::shared_ptr<resource> resource_ptr;
41
42
43 /**
44 * Generic resource class capable of containing any type of resource,
45 * providing a type-safe interface.
46 */
47 class resource
48 {
49 public:
50
51 // FIXME: this won't be necessary once the existing code is modified to
52 // use the resource handles
53 resource() {}
54
55 /**
56 * Add a directory to search when looking for resource files.
57 * \param paths A colon-separated list of directory paths.
58 */
59 static void add_search_paths(const std::string& paths);
60
61 /**
62 * Add directories to search when looking for resource files.
63 * \param pathList The list of directory paths.
64 */
65 static void add_search_paths(const std::vector<std::string>& pathList);
66
67
68 /**
69 * Get the path to a resource of a given name.
70 * \param path The name of the resource to find. Upon successful
71 * return, this is changed to an absolute path to the resource.
72 * \return True if a path to a resource was found, false otherwise.
73 */
74 static bool find(const std::string& file);
75
76 /**
77 * Get the path to a resource of a given name and open it if a resource
78 * was found.
79 * \param path The name of the resource to find. Upon successful
80 * return, this is changed to an absolute path to the resource.
81 * \param mode The open mode.
82 * \return The FILE* if the resource was found, 0 otherwise.
83 */
84 static FILE* open_file(const std::string& path,
85 const std::string& mode = "rb");
86
87
88 /**
89 * Register a type with the extension of files which this type can
90 * load. If any type has already been registered with the given file
91 * extension, it will be replaced.
92 * \param extension The file extension.
93 */
94 template <class T>
95 static void register_type(const std::string& extension)
96 {
97 if (!type_lookup_) type_lookup_ = type_lookup_ptr(new type_lookup);
98 loader_ptr loader(new specific_loader<T>);
99 (*type_lookup_)[extension] = loader;
100 }
101
102 /**
103 * Unregister the type associated with a file extension. Resources of
104 * this type will no longer be loadable, although resources which are
105 * already loaded will remain loaded.
106 * \param extension The file extension
107 */
108 static void unregister_type(const std::string& extension)
109 {
110 type_lookup_->erase(extension);
111 }
112
113
114 static resource_ptr load(const std::string& path);
115
116 static resource_ptr reload(std::string& path);
117
118
119 /**
120 * Construct a resource container.
121 * \param ptr A pointer to the underlying resource data.
122 */
123 template <class T>
124 explicit resource(T* ptr) :
125 resource_(ptr),
126 typeinfo_(const_cast<std::type_info*>(&typeid(T))),
127 unloader_(new specific_unloader<T>(ptr)) {}
128
129 /**
130 * Deconstruct a resource container.
131 */
132 virtual ~resource();
133
134
135 /**
136 * Reload the resource data. This will cause the resource file to be
137 * reread, and the underlying resource data will change.
138 */
139 void reload();
140
141
142 /**
143 * Get whether or not the type of the underlying resource data matches
144 * an expected type.
145 * \return True if the types match, false otherwise.
146 */
147 template <class T>
148 bool check() const
149 {
150 return *typeinfo_ == typeid(T);
151 }
152
153 /**
154 * Get a pointer to the underlying resource data as long as the type of
155 * the resource data matches the expected type.
156 * \return The resource data, or null if there is a type mismatch.
157 */
158 template <class T>
159 T* get() const
160 {
161 if (check<T>()) return (T*)resource_;
162 return 0;
163 }
164
165
166 /**
167 * Reloads some resources which have been modified on disk since they
168 * were loaded. Hotloading must have been enabled at compile-time.
169 * \return The number of resources reloaded.
170 */
171 static int reload_as_needed();
172
173
174 private:
175
176 class loader
177 {
178 public:
179
180 virtual ~loader() {}
181
182 virtual resource* load(const std::string& path)
183 {
184 return 0;
185 }
186 };
187
188 typedef boost::shared_ptr<loader> loader_ptr;
189
190 template <class T>
191 class specific_loader : public loader
192 {
193 public:
194
195 virtual resource* load(const std::string& path)
196 {
197 return new resource(new T(path));
198 }
199 };
200
201
202 class unloader
203 {
204 public:
205
206 virtual ~unloader() {};
207 };
208
209 typedef boost::shared_ptr<unloader> unloader_ptr;
210
211 template <class T>
212 class specific_unloader : public unloader
213 {
214 public:
215
216 specific_unloader(T* object = 0) :
217 object_(object) {}
218
219 virtual ~specific_unloader()
220 {
221 log_warning("unloading resource of type ", typeid(T).name());
222 delete object_;
223 }
224
225
226 private:
227
228 T* object_;
229 };
230
231
232 void set_loader(const std::string& path, loader_ptr loader)
233 {
234 path_ = path;
235 loader_ = loader;
236 }
237
238
239 void* resource_;
240 std::type_info* typeinfo_;
241 unloader_ptr unloader_;
242
243 std::string path_;
244 loader_ptr loader_;
245
246 typedef std::map<std::string,loader_ptr> type_lookup;
247 typedef boost::shared_ptr<type_lookup> type_lookup_ptr;
248 static type_lookup_ptr type_lookup_;
249
250 #ifdef USE_HOTLOADING
251 int wd_;
252
253 void set_watch_descriptor(int wd)
254 {
255 wd_ = wd;
256 }
257 #endif
258 };
259
260
261 /**
262 * The resource handle class provides a nicer way to work with resources.
263 * It allows you to work with a resource pointer as if you already know the
264 * type of the resource.
265 */
266 template <class T>
267 class resource_handle
268 {
269 public:
270
271 /**
272 * Construct a null resource handle.
273 */
274 resource_handle() {}
275
276 /**
277 * Construct a resource handle.
278 * \param ptr The resource pointer to reference.
279 */
280 resource_handle(resource_ptr ptr) :
281 resource_(ptr) {}
282
283
284 /**
285 * Get whether or not the handle is dereferenceable to the type of this
286 * handle. A resource handle is dereferenceable if it is not a null
287 * handle and if its underlying resource is in fact the same type as is
288 * expected by the handle.
289 * \return True if the handle is dereferenceable, false otherwise.
290 */
291 operator bool () const
292 {
293 if (!resource_) return false;
294 return resource_->check<T>();
295 }
296
297
298 /**
299 * Get a pointer to the underlying resource.
300 * \return The pointer, or null if this handle is not dereferenceable.
301 */
302 T* get() const
303 {
304 if (!*this) return 0;
305 return resource_->get<T>();
306 }
307
308 /**
309 * Dereference the handle all the way to the underlying resource.
310 * \return A reference to the resource.
311 * \throws std::runtime_error If this is a null handle.
312 */
313 T& get_reference() const
314 {
315 if (!*this) throw std::runtime_error("dereference null handle");
316 return *(resource_->get<T>());
317 }
318
319
320 /**
321 * Same as get() for getting a pointer to the underlying resources.
322 * \return The pointer, or null if this handle is not dereferenceable.
323 */
324 T* operator -> () const
325 {
326 return get();
327 }
328
329 /**
330 * Same a get_reference() for dereferencing the handle.
331 * \return A reference to the resource.
332 * \throws std::runtime_error If this is a null handle.
333 */
334 T& operator * () const
335 {
336 return get_reference();
337 }
338
339
340 private:
341
342 resource_ptr resource_;
343 };
344
345
346 } // namespace moof
347
348 #endif // _MOOF_RESOURCE_HH_
349
This page took 0.045577 seconds and 5 git commands to generate.