GLProgramming.com

home :: about :: development guides :: irc :: forums :: search :: paste :: links :: contribute :: code dump

-> Click here to learn how to get live help <-



 
 

Development Guide Library


Resource Management Templates by Dranith

Andy 'Dranith' Fulks Sirdranith@hotmail.com

The Resource Management Templates
V 0.9.0


Overview

These templates were created because I noticed patterns in the way I managed resources in my code, and realized I was duplicating code in the managers for various different resources. Coming up with a reusable set of code took a bit because resources all will have unique needs in terms of acquisition. You may have a texture that needs loading off a disk or a procedural texture created by a random number seed. These templates had to account for all foreseeable forms of resource that a program may need. A direct template would not cleanly allow for the flexibility required for the client programmer to be able to write custom resource acquisition member functions.

The real motivation was to be able to not have to worry about the memory management of resources, so you can think about more important parts of your code. We all know how error prone memory management work is, even after the 100th time. These templates are designed to take care of this for the client programmer. All the following is wrapped in the 'rmt' to help prevent name collisions in the client programmer's code.

Please let me know any questions/comments/complaints/suggestions you have, and if you use these templates in a program, shoot me an email and tell me so I know someone is using this. =)

General Use

Since different resources have different requirements in terms of acquisition and possibly other manipulation functions, these templates can not account for all possible situations. For this reason, you do not directly instantiate these templates, but instead derive your manager from one of the templates available. Once you derive a class from a template instance, you may write your own acquisition functions for your resource. These templates all allow for access to resources via a handle, and some of them allow for access via a resource's name. Accessing via handle provides you with a constant time, inlined function that returns a pointer to the object, where as access via name can be (and in most cases is) an O(n) time function.

The different templates available have varying degrees of efficiency, flexibility and features. You can tell the features available by the name of the template. Vector based templates, which are denoted by 'Vect' in the name, have all of the following, and are also the most efficient at adding and clearing. List based templates, which are denoted by 'List' in the name, have all of the flowing as well as a Delete() member function. Vector based templates don't have a Delete() member because deletion from a vector is extremely slow and if you need this functionality you would be better off using a List anyways. In general they will have the following member functions declared:

ResourceType* Operator[]( unsigned hdl )
Parameters
Hdl
This is the handle to your resource.

Return Value
This function returns a pointer to the resource specified by the handle. If you pass an invalid handle, the results are undefined.

ResourceType* Get( unsigned hdl)
Parameters
Hdl
This is the handle to your resource.

Return Value
This function returns a pointer to the resource specified by the handle. If the handle passed is invalid, the function will return 0.

Remarks
This is a bounds-checking version of Operator[], so it is safer and generally won't crash if you accidentally pass an invalid handle.

void Clear()
Remarks
This destroys all the resources in the manager.

unsigned Add( ResourceType* newRes)
Parameters
newRes
This is a pointer to a heap allocated resource of your type. You must allocate this object yourself, and once you pass the pointer to Add, the resource manager owns the pointer and you do not have to worry about destroying the memory at a later time as it will be done by the manager.

Return Value
The value that is returned is a handle to your resource used for accessing that resource via operator[] or Get();

List derived templates only:
void Delete( unsigned hdl )
Parameters
Hdl
Handle to the resource to destroy. Once removed from the manager and the handle now invalid.

Instantiation
By default, the only type you need to supply to the manager template is the type of your resource as seen in the example below:


// Instantiate from VectMgr

class TextureManager : public VectMgr<MyTextureClass>
{
     // ...
}


Now that the template is instantiated, you need to have a way to add resources, so you need to define a function to acquire your resource. Example :


// Instantiate from VectMgr

class TextureManager : public VectMgr<MyTextureClass> {
public:
     unsigned LoadTexture( std::string textureName ) {
          MyTextureClass* temp = new MyTextureClass;
          // .. code to load texture
          // Add the texture to the manager and
          // return handle.

          return Add( temp );
     }
}


Specific Uses
Each of the managers has a slight little difference in features and performance. These differences are documented in this section.

VectMgr
This is the most basic template, and it is also the most efficient if set up properly. To take full advantage you should have a general idea of how many resources you will be loading as you can set the grow size of the vector through the template instantiation. What this means is when you fill the current vector, it will resize. when it needs more room, by the amount of the grow size. Vector resizing is very slow, so
set your grow size to minimize the number of times it has to resize. If you know you need between 100-200 instances of a specific resource type, set the grow size to somewhere around 100, or even just set it to 200. The grow size is also the initial amount of resources the vector makes room for. The full declaration of the template is :

template<class _RT, int _GSV=5, class _FN=Default<_RT> >

The first parameter is your resource type, the second is the default value for grow size, you can specify any int you want, but the bigger the number the more room the vector reserves, so try to pick a reasonable number. You can set the grow size during runtime if you need to by calling GrowSize( int newSize ) and passing a new grow size. The last template parameter you can ignore for now.

ListMgr
This template is a little less efficient than VectMgr, but has the ability to delete, as mentioned above, specific resources without clearing the whole manager out. This could be useful if you need to load and free resources during runtime. There are no other functions specific to this template.

VectSetMgr
This is similar to VectMgr, except it allows only one instance of a resource to be added to the manager at once. This is done through passing the resources 'name' to the manager when the resource is added. The name by default is an std::string, but it can be anything you need it to be, such as a random number seed or something more complex. The type of the resource name is assumed to have operator==() defined. The following is the template declaration :

template<class _RT, int _GSV=5, class _NT=std::string, class _FN=Default<_RT> >

The first class is your resource type again, and the second is the grow size. The third parameter is the type of your resources name, and as you can see it defaults to std::string. The Add function of this template is a bit different as you have to pass the resources name along with the pointer to the resource. Here is the texture manager example again:


// Instantiate from VectSetMgr

class TextureManager : public VectSetMgr<MyTextureClass> {
public:
     unsigned LoadTexture( std::string textureName ) {
          // Check to make sure resource isn't stored

          if(unsigned h = NameToHdl( textureName ))
              return h;

          MyTextureClass* temp = new MyTextureClass;

          // .. code to load texture
          // Add the texture to the manager and
          // return handle.

          return AddNC( temp, textureName );
     }
}


Note : This is only unsafe if you forget to check ahead of the call to AddNC to make sure the resource is not already stored.

ListSetMgr

This is basically the same as ListVectMgr, except for the ability to use the Delete() member function that are available to the List based managers. There is one new function available only to this manager, and it is a Delete function that is able to delete a resource based in the resource's name instead of handle.

void Delete( const NameType& name)
Parameters
Name
This is the name of the resource that you want to delete. Once removed from the manager and the handle to the resource, and name are now both invalid.

Custom Resource Destruction
By now you probably noticed the last parameter of each of the templates, class _FN=Default<_RT>. This parameter is there more for advanced users who may need custom resource destruction. For instance, your resource may be a handle to textures stored in video ram that won't be freed just by deleting the resource alone. They may need a ->Release() method to be called for instance. By default, the functor Default is passed to the template. This frees resources with the delete command. This means that you can only pass resources allocated by new to the manager if you want memory to be cleaned up properly. If your resource is something more complicated, or needs to be allocated by new[] then this won't do. An Array functor is also provided in the header. This uses delete[] on the resource instead of delete. It is passed to the template as follows :

class TextureManager : public VectMgr<MyTextureClass, 10, rtm::Array<MyTextureClass> >

This will now call delete[] on your resources when they are destroyed. If you need to do something special to free resources, such as textures, then you need to define your own functor as follows (D3D resource release semantics used ) :


Template<class _RT>
class D3Dfree {
public:
     void operator()( _RT* ptr ){
          ptr->Release();
          delete ptr;
     }
}


This can now be used as the destruction function by passing it to the template when instantiated as follows :

class TextureManager : public VectMgr<MyTextureClass, 10, D3Dfree<MyTextureClass> >

That's all for now! More templates and functionality to come if people show interest and give suggestions ! .....

The source code for this DG can be downloaded here.