fixed some resource management bugs
[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 "config.h"
21
22 #include <cstdio>
23 #include <map>
24 #include <stdexcept>
25 #include <string>
26 #include <vector>
27
28 #include <boost/shared_ptr.hpp>
29 #include <boost/function.hpp>
30
31 #include <moof/debug.hh>
32
33
34 namespace moof {
35
36
37 class resource;
38 typedef boost::shared_ptr<resource> resource_ptr;
39
40
41 /**
42 * Generic resource class capable of containing any type of resource,
43 * providing a type-safe interface.
44 */
45 class resource
46 {
47 public:
48
49 // XXX: this won't be necessary once the existing code is modified to
50 // use the resource handles
51 resource() {}
52
53 /**
54 * Add a directory to search when looking for resource files.
55 * \param paths A colon-separated list of directory paths.
56 */
57 static void add_search_paths(const std::string& paths);
58
59
60 /**
61 * Get the path to a resource of a given name.
62 * \param path The name of the resource to find. Upon successful
63 * return, this is changed to an absolute path to the resource.
64 * \return True if a path to a resource was found, false otherwise.
65 * XXX this is legacy
66 */
67 static bool find(const std::string& file);
68
69 static std::string find_file(const std::string& name);
70
71 static std::string find_file(const std::string& name,
72 const std::string& ext);
73
74 /**
75 * Get the path to a resource of a given name and open it if a resource
76 * was found.
77 * \param path The name of the resource to find. Upon successful
78 * return, this is changed to an absolute path to the resource.
79 * \param mode The open mode.
80 * \return The FILE* if the resource was found, 0 otherwise.
81 * XXX deprecated
82 */
83 static FILE* open_file(const std::string& path,
84 const std::string& mode = "rb");
85
86
87 /**
88 * Register a type with the extension of files which this type can
89 * load. If any type has already been registered with the given file
90 * extension, it will be replaced.
91 * \param extension The file extension.
92 */
93 template <class T>
94 static void register_type(const std::string& extension,
95 const std::string& prefix = "")
96 {
97 loader_ptr loader(new specific_loader<T>(prefix));
98 printf("registered type with prefix %s", loader->prefix().c_str());
99 call_registry(extension, loader, set);
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 loader_ptr loader;
111 call_registry(extension, loader, set);
112 }
113
114
115 static resource_ptr load(const std::string& name);
116 static resource_ptr load(const std::string& name,
117 const std::string& ext);
118
119 static resource_ptr reload(std::string& path);
120
121
122 /**
123 * Construct a resource container.
124 * \param ptr A pointer to the underlying resource data.
125 */
126 template <class T>
127 explicit resource(T* ptr) :
128 resource_(ptr),
129 typeinfo_(const_cast<std::type_info*>(&typeid(T))),
130 unloader_(new specific_unloader<T>(ptr)) {}
131
132 /**
133 * Deconstruct a resource container.
134 */
135 virtual ~resource();
136
137
138 /**
139 * Reload the resource data. This will cause the resource file to be
140 * reread, and the underlying resource data will change.
141 */
142 void reload();
143
144
145 /**
146 * Get whether or not the type of the underlying resource data matches
147 * an expected type.
148 * \return True if the types match, false otherwise.
149 */
150 template <class T>
151 bool check() const
152 {
153 return *typeinfo_ == typeid(T);
154 }
155
156 /**
157 * Get a pointer to the underlying resource data as long as the type of
158 * the resource data matches the expected type.
159 * \return The resource data, or null if there is a type mismatch.
160 */
161 template <class T>
162 T* get() const
163 {
164 if (check<T>()) return (T*)resource_;
165 return 0;
166 }
167
168
169 /**
170 * Reloads some resources which have been modified on disk since they
171 * were loaded. Hotloading must have been enabled at compile-time.
172 * \return The number of resources reloaded.
173 */
174 static int reload_as_needed();
175
176
177 private:
178
179 static resource_ptr load_with_path(const std::string& path);
180
181 class loader
182 {
183 public:
184
185 //loader() {}
186 loader(const std::string& prefix) :
187 prefix_(prefix) {}
188
189 virtual ~loader() {}
190
191 virtual resource* load(const std::string& path)
192 {
193 return 0;
194 }
195
196 const std::string& prefix() const
197 {
198 return prefix_;
199 }
200
201
202 private:
203
204 std::string prefix_;
205 };
206
207 typedef boost::shared_ptr<loader> loader_ptr;
208
209 template <class T>
210 class specific_loader : public loader
211 {
212 public:
213
214 //specific_loader() {}
215 specific_loader(const std::string& prefix) :
216 loader(prefix) {}
217
218 virtual resource* load(const std::string& path)
219 {
220 log_info("loading resource of type ", typeid(T).name());
221 return new resource(new T(path));
222 }
223 };
224
225
226 class unloader
227 {
228 public:
229
230 virtual ~unloader() {};
231 };
232
233 typedef boost::shared_ptr<unloader> unloader_ptr;
234
235 template <class T>
236 class specific_unloader : public unloader
237 {
238 public:
239
240 specific_unloader(T* object = 0) :
241 object_(object) {}
242
243 virtual ~specific_unloader()
244 {
245 log_info("unloading resource of type ", typeid(T).name());
246 delete object_;
247 }
248
249
250 private:
251
252 T* object_;
253 };
254
255
256 void set_loader(const std::string& path, loader_ptr loader)
257 {
258 path_ = path;
259 loader_ = loader;
260 }
261
262
263 void* resource_;
264 std::type_info* typeinfo_;
265 unloader_ptr unloader_;
266
267 std::string path_;
268 loader_ptr loader_;
269
270 typedef std::map<std::string,loader_ptr> type_lookup;
271 //typedef boost::shared_ptr<type_lookup> type_lookup_ptr;
272 //static type_lookup_ptr type_lookup_;
273 //static type_lookup type_lookup_;
274
275 enum registry_action
276 {
277 lookup,
278 set
279 };
280
281 static bool call_registry(const std::string& extension,
282 loader_ptr& loader,
283 registry_action action);
284
285 #ifdef USE_HOTLOADING
286 int wd_;
287
288 void set_watch_descriptor(int wd)
289 {
290 wd_ = wd;
291 }
292 #endif
293 };
294
295
296 /**
297 * The resource handle class provides a nicer way to work with resources.
298 * It allows you to work with a resource pointer as if you already know the
299 * type of the resource.
300 */
301 template <class T>
302 class resource_handle
303 {
304 public:
305
306 /**
307 * Construct a null resource handle.
308 */
309 resource_handle() {}
310
311 /**
312 * Construct a resource handle.
313 * \param ptr The resource pointer to reference.
314 */
315 resource_handle(resource_ptr ptr) :
316 resource_(ptr) {}
317
318 explicit resource_handle(const std::string& name) :
319 resource_(resource::load(name)) {}
320
321 resource_handle(const std::string& name, const std::string& ext) :
322 resource_(resource::load(name, ext)) {}
323
324
325
326 /**
327 * Get whether or not the handle is dereferenceable to the type of this
328 * handle. A resource handle is dereferenceable if it is not a null
329 * handle and if its underlying resource is in fact the same type as is
330 * expected by the handle.
331 * \return True if the handle is dereferenceable, false otherwise.
332 */
333 operator bool () const
334 {
335 if (!resource_) return false;
336 return resource_->check<T>();
337 }
338
339
340 /**
341 * Get a pointer to the underlying resource.
342 * \return The pointer, or null if this handle is not dereferenceable.
343 */
344 T* get() const
345 {
346 if (!*this) return 0;
347 return resource_->get<T>();
348 }
349
350 /**
351 * Dereference the handle all the way to the underlying resource.
352 * \return A reference to the resource.
353 * \throws std::runtime_error If this is a null handle.
354 */
355 T& get_reference() const
356 {
357 if (!*this) throw std::runtime_error("dereference null handle");
358 return *(resource_->get<T>());
359 }
360
361
362 /**
363 * Same as get() for getting a pointer to the underlying resources.
364 * \return The pointer, or null if this handle is not dereferenceable.
365 */
366 T* operator -> () const
367 {
368 return get();
369 }
370
371 /**
372 * Same a get_reference() for dereferencing the handle.
373 * \return A reference to the resource.
374 * \throws std::runtime_error If this is a null handle.
375 */
376 T& operator * () const
377 {
378 return get_reference();
379 }
380
381
382 /**
383 * Unload the resource associated with this handle.
384 */
385 void unload()
386 {
387 resource_ = resource_ptr();
388 }
389
390
391 private:
392
393 resource_ptr resource_;
394 };
395
396
397 } // namespace moof
398
399 #endif // _MOOF_RESOURCE_HH_
400
This page took 0.046727 seconds and 4 git commands to generate.