X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fmoof%2Fresource.hh;fp=src%2Fmoof%2Fresource.hh;h=0f797571c3e1266f493f148b098e06594b32cbc2;hp=ed8a7d06f8fd9a8c420d9fab59c0c54de60a0658;hb=6b0a0d0efafe34d48ab344fca3b479553bd4e62c;hpb=85783316365181491a3e3c0c63659972477cebba diff --git a/src/moof/resource.hh b/src/moof/resource.hh index ed8a7d0..0f79757 100644 --- a/src/moof/resource.hh +++ b/src/moof/resource.hh @@ -18,23 +18,39 @@ */ #include +#include +#include #include #include +#include +#include + +#include + +#if HAVE_CONFIG_H +#include "../config.h" +#endif + namespace moof { +class resource; +typedef boost::shared_ptr resource_ptr; + + /** - * Generic resource class. + * Generic resource class capable of containing any type of resource, + * providing a type-safe interface. */ - class resource { public: - virtual ~resource() {} - + // FIXME: this won't be necessary once the existing code is modified to + // use the resource handles + resource() {} /** * Add a directory to search when looking for resource files. @@ -53,33 +69,277 @@ public: * Get the path to a resource of a given name. * \param path The name of the resource to find. Upon successful * return, this is changed to an absolute path to the resource. - * \param prefix A colon-separated list of subdirectories to search. - * \param extension A colon-separated list of possible extensions. * \return True if a path to a resource was found, false otherwise. */ - static bool find_path(std::string& path, - const std::string& prefix = "", - const std::string& extension = ""); + static bool find(const std::string& file); /** * Get the path to a resource of a given name and open it if a resource * was found. * \param path The name of the resource to find. Upon successful * return, this is changed to an absolute path to the resource. - * \param prefix A colon-separated list of subdirectories to search. - * \param extension A colon-separated list of possible extensions. * \param mode The open mode. * \return The FILE* if the resource was found, 0 otherwise. */ - static FILE* open_file(std::string& path, - const std::string& prefix = "", - const std::string& extension = "", + static FILE* open_file(const std::string& path, const std::string& mode = "rb"); + /** + * Register a type with the extension of files which this type can + * load. If any type has already been registered with the given file + * extension, it will be replaced. + * \param extension The file extension. + */ + template + static void register_type(const std::string& extension) + { + if (!type_lookup_) type_lookup_ = type_lookup_ptr(new type_lookup); + loader_ptr loader(new specific_loader); + (*type_lookup_)[extension] = loader; + } + + /** + * Unregister the type associated with a file extension. Resources of + * this type will no longer be loadable, although resources which are + * already loaded will remain loaded. + * \param extension The file extension + */ + static void unregister_type(const std::string& extension) + { + type_lookup_->erase(extension); + } + + + static resource_ptr load(const std::string& path); + + static resource_ptr reload(std::string& path); + + + /** + * Construct a resource container. + * \param ptr A pointer to the underlying resource data. + */ + template + explicit resource(T* ptr) : + resource_(ptr), + typeinfo_(const_cast(&typeid(T))), + unloader_(new specific_unloader(ptr)) {} + + /** + * Deconstruct a resource container. + */ + virtual ~resource(); + + + /** + * Reload the resource data. This will cause the resource file to be + * reread, and the underlying resource data will change. + */ + void reload(); + + + /** + * Get whether or not the type of the underlying resource data matches + * an expected type. + * \return True if the types match, false otherwise. + */ + template + bool check() const + { + return *typeinfo_ == typeid(T); + } + + /** + * Get a pointer to the underlying resource data as long as the type of + * the resource data matches the expected type. + * \return The resource data, or null if there is a type mismatch. + */ + template + T* get() const + { + if (check()) return (T*)resource_; + return 0; + } + + + /** + * Reloads some resources which have been modified on disk since they + * were loaded. Hotloading must have been enabled at compile-time. + * \return The number of resources reloaded. + */ + static int reload_as_needed(); + + +private: + + class loader + { + public: + + virtual ~loader() {} + + virtual resource* load(const std::string& path) + { + return 0; + } + }; + + typedef boost::shared_ptr loader_ptr; + + template + class specific_loader : public loader + { + public: + + virtual resource* load(const std::string& path) + { + return new resource(new T(path)); + } + }; + + + class unloader + { + public: + + virtual ~unloader() {}; + }; + + typedef boost::shared_ptr unloader_ptr; + + template + class specific_unloader : public unloader + { + public: + + specific_unloader(T* object = 0) : + object_(object) {} + + virtual ~specific_unloader() + { + log_warning("unloading resource of type ", typeid(T).name()); + delete object_; + } + + + private: + + T* object_; + }; + + + void set_loader(const std::string& path, loader_ptr loader) + { + path_ = path; + loader_ = loader; + } + + + void* resource_; + std::type_info* typeinfo_; + unloader_ptr unloader_; + + std::string path_; + loader_ptr loader_; + + typedef std::map type_lookup; + typedef boost::shared_ptr type_lookup_ptr; + static type_lookup_ptr type_lookup_; + +#if USE_HOTLOADING + int wd_; + + void set_watch_descriptor(int wd) + { + wd_ = wd; + } +#endif +}; + + +/** + * The resource handle class provides a nicer way to work with resources. + * It allows you to work with a resource pointer as if you already know the + * type of the resource. + */ +template +class resource_handle +{ +public: + + /** + * Construct a null resource handle. + */ + resource_handle() {} + + /** + * Construct a resource handle. + * \param ptr The resource pointer to reference. + */ + resource_handle(resource_ptr ptr) : + resource_(ptr) {} + + + /** + * Get whether or not the handle is dereferenceable to the type of this + * handle. A resource handle is dereferenceable if it is not a null + * handle and if its underlying resource is in fact the same type as is + * expected by the handle. + * \return True if the handle is dereferenceable, false otherwise. + */ + operator bool () const + { + if (!resource_) return false; + return resource_->check(); + } + + + /** + * Get a pointer to the underlying resource. + * \return The pointer, or null if this handle is not dereferenceable. + */ + T* get() const + { + if (!*this) return 0; + return resource_->get(); + } + + /** + * Dereference the handle all the way to the underlying resource. + * \return A reference to the resource. + * \throws std::runtime_error If this is a null handle. + */ + T& get_reference() const + { + if (!*this) throw std::runtime_error("dereference null handle"); + return *(resource_->get()); + } + + + /** + * Same as get() for getting a pointer to the underlying resources. + * \return The pointer, or null if this handle is not dereferenceable. + */ + T* operator -> () const + { + return get(); + } + + /** + * Same a get_reference() for dereferencing the handle. + * \return A reference to the resource. + * \throws std::runtime_error If this is a null handle. + */ + T& operator * () const + { + return get_reference(); + } + + private: - static std::vector search_paths_; + resource_ptr resource_; };