begin cleaning up resource management
[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 // FIXME: 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 */
66 static bool find(const std::string& file);
67
68 /**
69 * Get the path to a resource of a given name and open it if a resource
70 * was found.
71 * \param path The name of the resource to find. Upon successful
72 * return, this is changed to an absolute path to the resource.
73 * \param mode The open mode.
74 * \return The FILE* if the resource was found, 0 otherwise.
75 */
76 static FILE* open_file(const std::string& path,
77 const std::string& mode = "rb");
78
79
80 /**
81 * Register a type with the extension of files which this type can
82 * load. If any type has already been registered with the given file
83 * extension, it will be replaced.
84 * \param extension The file extension.
85 */
86 template <class T>
87 static void register_type(const std::string& extension)
88 {
89 if (!type_lookup_) type_lookup_ = type_lookup_ptr(new type_lookup);
90 loader_ptr loader(new specific_loader<T>);
91 (*type_lookup_)[extension] = loader;
92 }
93
94 /**
95 * Unregister the type associated with a file extension. Resources of
96 * this type will no longer be loadable, although resources which are
97 * already loaded will remain loaded.
98 * \param extension The file extension
99 */
100 static void unregister_type(const std::string& extension)
101 {
102 type_lookup_->erase(extension);
103 }
104
105
106 static resource_ptr load(const std::string& path);
107
108 static resource_ptr reload(std::string& path);
109
110
111 /**
112 * Construct a resource container.
113 * \param ptr A pointer to the underlying resource data.
114 */
115 template <class T>
116 explicit resource(T* ptr) :
117 resource_(ptr),
118 typeinfo_(const_cast<std::type_info*>(&typeid(T))),
119 unloader_(new specific_unloader<T>(ptr)) {}
120
121 /**
122 * Deconstruct a resource container.
123 */
124 virtual ~resource();
125
126
127 /**
128 * Reload the resource data. This will cause the resource file to be
129 * reread, and the underlying resource data will change.
130 */
131 void reload();
132
133
134 /**
135 * Get whether or not the type of the underlying resource data matches
136 * an expected type.
137 * \return True if the types match, false otherwise.
138 */
139 template <class T>
140 bool check() const
141 {
142 return *typeinfo_ == typeid(T);
143 }
144
145 /**
146 * Get a pointer to the underlying resource data as long as the type of
147 * the resource data matches the expected type.
148 * \return The resource data, or null if there is a type mismatch.
149 */
150 template <class T>
151 T* get() const
152 {
153 if (check<T>()) return (T*)resource_;
154 return 0;
155 }
156
157
158 /**
159 * Reloads some resources which have been modified on disk since they
160 * were loaded. Hotloading must have been enabled at compile-time.
161 * \return The number of resources reloaded.
162 */
163 static int reload_as_needed();
164
165
166 private:
167
168 class loader
169 {
170 public:
171
172 virtual ~loader() {}
173
174 virtual resource* load(const std::string& path)
175 {
176 return 0;
177 }
178 };
179
180 typedef boost::shared_ptr<loader> loader_ptr;
181
182 template <class T>
183 class specific_loader : public loader
184 {
185 public:
186
187 virtual resource* load(const std::string& path)
188 {
189 return new resource(new T(path));
190 }
191 };
192
193
194 class unloader
195 {
196 public:
197
198 virtual ~unloader() {};
199 };
200
201 typedef boost::shared_ptr<unloader> unloader_ptr;
202
203 template <class T>
204 class specific_unloader : public unloader
205 {
206 public:
207
208 specific_unloader(T* object = 0) :
209 object_(object) {}
210
211 virtual ~specific_unloader()
212 {
213 log_warning("unloading resource of type ", typeid(T).name());
214 delete object_;
215 }
216
217
218 private:
219
220 T* object_;
221 };
222
223
224 void set_loader(const std::string& path, loader_ptr loader)
225 {
226 path_ = path;
227 loader_ = loader;
228 }
229
230
231 void* resource_;
232 std::type_info* typeinfo_;
233 unloader_ptr unloader_;
234
235 std::string path_;
236 loader_ptr loader_;
237
238 typedef std::map<std::string,loader_ptr> type_lookup;
239 typedef boost::shared_ptr<type_lookup> type_lookup_ptr;
240 static type_lookup_ptr type_lookup_;
241
242 #ifdef USE_HOTLOADING
243 int wd_;
244
245 void set_watch_descriptor(int wd)
246 {
247 wd_ = wd;
248 }
249 #endif
250 };
251
252
253 /**
254 * The resource handle class provides a nicer way to work with resources.
255 * It allows you to work with a resource pointer as if you already know the
256 * type of the resource.
257 */
258 template <class T>
259 class resource_handle
260 {
261 public:
262
263 /**
264 * Construct a null resource handle.
265 */
266 resource_handle() {}
267
268 /**
269 * Construct a resource handle.
270 * \param ptr The resource pointer to reference.
271 */
272 resource_handle(resource_ptr ptr) :
273 resource_(ptr) {}
274
275
276 /**
277 * Get whether or not the handle is dereferenceable to the type of this
278 * handle. A resource handle is dereferenceable if it is not a null
279 * handle and if its underlying resource is in fact the same type as is
280 * expected by the handle.
281 * \return True if the handle is dereferenceable, false otherwise.
282 */
283 operator bool () const
284 {
285 if (!resource_) return false;
286 return resource_->check<T>();
287 }
288
289
290 /**
291 * Get a pointer to the underlying resource.
292 * \return The pointer, or null if this handle is not dereferenceable.
293 */
294 T* get() const
295 {
296 if (!*this) return 0;
297 return resource_->get<T>();
298 }
299
300 /**
301 * Dereference the handle all the way to the underlying resource.
302 * \return A reference to the resource.
303 * \throws std::runtime_error If this is a null handle.
304 */
305 T& get_reference() const
306 {
307 if (!*this) throw std::runtime_error("dereference null handle");
308 return *(resource_->get<T>());
309 }
310
311
312 /**
313 * Same as get() for getting a pointer to the underlying resources.
314 * \return The pointer, or null if this handle is not dereferenceable.
315 */
316 T* operator -> () const
317 {
318 return get();
319 }
320
321 /**
322 * Same a get_reference() for dereferencing the handle.
323 * \return A reference to the resource.
324 * \throws std::runtime_error If this is a null handle.
325 */
326 T& operator * () const
327 {
328 return get_reference();
329 }
330
331
332 private:
333
334 resource_ptr resource_;
335 };
336
337
338 } // namespace moof
339
340 #endif // _MOOF_RESOURCE_HH_
341
This page took 0.04523 seconds and 5 git commands to generate.