January 27, 2011

Homeward Developer Diary #1: The templated ResourceManager

After building a TextureManager and MaterialManager classes, and about to embark on an AnimationManager class, I paused for a second and realized I was being rather thick, rewriting nearly the same class for the third time (and likely many more times in the future for sounds, music, shaders, entities, etc.)

So I'm rather thankful for templates today, which allowed me to replace the 2 existing, distinct Manager classes with one set of code and a few typedefs.

In essence, the ResourceManager class is internally composed as follows:

template<Key, ResourceType>
class ResourceManager {
  ResourceManager() : m_resources() { ... }
  ResourceManager(const ResourceManager<Key, ResourceType*>&) : m_resources() { ... }
  virtual ~ResourceManager() { ... }
  ResourceManager& operator=(const ResourceManager<Key, ResourceType*>&) { ... }
  Resource* get(Key name) const { ... }  // Gets the named resource
  void add(Key name, ResourceType* pResource) { ... }  // Adds the named resource
  void remove(Key name) { ... }  // Removes the named resource
  void removeAll() { ... }  // Removes all resources
  map<Key, ResourceType*> m_resources; // Holds all of the resources

Note that Key is a string 99% of the time, but could probably be an int or other data if necessary. Also, ResourceType is the type of resource being stored). 1

The ResourceManager assumes ownership over the resources themselves, which means that the destructor deletes each resource, so the rest of the application should behave accordingly and not delete resources. 2

Insofar as public methods are concerned, a spartan set is provided until I find a reason to add more. At the moment, I'm not dealing with collisions when inserting, and I'm internally catching exceptions in the remove() and get() methods if the specified resources aren't found rather than letting said exceptions bubble up.

In the rare case where different behaviour is required for a certain resource, I can always write a specialized implementation of the ResourceManager class, but thus far, all I've needed to do for a new type of resource is set a typedef.

typedef ResourceManager<string, Shader> ShaderManager;

So that's it! A few lines of code and I've now got a generic resource-manager that is much more extensible and maintainable than writing separate classes for each type of resource.

And, since I've only usually got an hour or two a day on the subway to develop this stuff, it cuts out a whole bunch of extra coding that I'd otherwise have to do.

Rock and roll.

1: I should be using boost::shared_ptr and return weak_ptrs when requested, but I haven't gotten boost running on iOS yet (which is to say I haven't tried) and this is supposed to be portable between the two platforms. I don't want to commit to it on Windows and then discover it's not. It should be a straightforward rewrite, if necessary.

2: Note to me: Seriously, boost::weak_ptr. Quit being lazy and make this happen