cache objects so they can be reused without thrashing malloc() More...
Typedefs | |
typedef typedefCGUL_BEGIN_C struct cgul_cache * | cgul_cache_t |
typedef void *(* | cgul_cache__constructor_t) (cgul_exception_t *cex) |
typedef void(* | cgul_cache__destructor_t) (void *obj) |
typedef void(* | cgul_cache__restructor_t) (void *obj) |
Functions | |
CGUL_EXPORT cgul_cache_t | cgul_cache__get_freer () |
CGUL_EXPORT cgul_cache_t | cgul_cache__new (cgul_exception_t *cex, cgul_cache__constructor_t constructor, cgul_cache__destructor_t destructor, cgul_cache__restructor_t restructor) |
CGUL_EXPORT void | cgul_cache__delete (cgul_cache_t cache) |
CGUL_EXPORT unsigned long int | cgul_cache__get_size (cgul_exception_t *cex, cgul_cache_t cache) |
CGUL_EXPORT void | cgul_cache__set_size (cgul_exception_t *cex, cgul_cache_t cache, unsigned long int size) |
CGUL_EXPORT unsigned long int | cgul_cache__get_reserve (cgul_exception_t *cex, cgul_cache_t cache) |
CGUL_EXPORT void | cgul_cache__set_reserve (cgul_exception_t *cex, cgul_cache_t cache, unsigned long int reserve) |
CGUL_EXPORT void * | cgul_cache__get (cgul_exception_t *cex, cgul_cache_t cache) |
CGUL_EXPORT void | cgul_cache__put (cgul_exception_t *cex, cgul_cache_t cache, void *obj) |
This class allows you to cache objects so that they can be reused without have to reallocate and free the memory. This improves performance because malloc() and free() are relatively expensive. It should also help reduce memory fragmentation.
This class can also be used to reserve objects for future use. This can be used to allow synchronous error reporting in classes like cgul_event_router
which keep a pending event queue. Without reserving an object when cgul_event_router__add_listener()
has to put an event on the pending event queue, that object would have to be allocated later which could cause an asynchronous out-of-memory exception, but by allocating and reserving that object immediately, the client gets synchronous notification of out-of-memory exceptions.
Lastly, this class can be used as an abstraction layer for creating objects. For example, the constructors for cgul_rbtree
set up a cgul_cache
to return different nodes depending on whether the user wants to enable the indexing feature of cgul_rbtree
. This allows the user to save two unsigned int
values per node which can lead to a substantial savings for a large tree. Most of the rest of the code in cgul_rbtree
is written without having to know the exact type of node that is being used and simply calls cgul_cache__get()
and cgul_cache__put()
when appropriate.
This class is used internally by cgul_list
and cgul_rbtree
to cache their nodes. You can use these classes to test this class by, for example, creating a cgul_list
and playing with cgul_list_set_cache_size()
.
typedef typedefCGUL_BEGIN_C struct cgul_cache* cgul_cache_t |
Opaque pointer to a cgul_cache
instance.
typedef void*(* cgul_cache__constructor_t) (cgul_exception_t *cex) |
This function pointer typedef is needed so that the cgul_cache
knows how to create new default instances of the objects you want to cache.
typedef void(* cgul_cache__destructor_t) (void *obj) |
This function pointer typedef is needed so that the cgul_cache
knows how to delete instances of the objects you want to cache. The client's implementation of this function should not throw an exception.
typedef void(* cgul_cache__restructor_t) (void *obj) |
This function pointer typedef is needed so that the cgul_cache
knows how take a fully constructed object and return it to its initial default state. This callback is invoked when objects are put back on the cache to minimize the memory footprint of objects on the cache. If the restructor is set to NULL
, the client is responsible for resetting the object before putting it back on the cgul_cache.
CGUL_EXPORT cgul_cache_t cgul_cache__get_freer | ( | ) |
Static method used to return the cgul_cache
instance that is an adapter for free()
. Because the object returned is statically allocated, the client should not attempt to call cgul_cache__delete()
on the pointer returned. If the client forgets, cgul_cache__delete()
will ignore the request.
The purpose of this static method is to allow clients to use methods (like cgul_rbtree__remove_range()
) that accept cgul_cache
objects for cleaning up keys or values even though the objects are allocated directly using one of the malloc()
family of function calls (instead of through the cgul_cache
interface).
The cgul_cache
object returned only implements the cgul_cache__destructor_t
part of the cgul_cache
interface. Thus, any attempt to use the object returned to construct a new object will result in NULL
being returned.
Because the cgul_cache
object returned is only used in the destruction context, the conventional cgul_exception
object required of most methods is not required of this method.
cgul_cache
adapter for free()
Referenced by cgul_cache_cxx::get_freer().
CGUL_EXPORT cgul_cache_t cgul_cache__new | ( | cgul_exception_t * | cex, |
cgul_cache__constructor_t | constructor, | ||
cgul_cache__destructor_t | destructor, | ||
cgul_cache__restructor_t | restructor | ||
) |
Create a new cgul_cache
instance. If restructor
is set to NULL
, the client is responsible for resetting the object before putting it back on the cgul_cache
. If memory cannot be allocated, NULL
is returned and an exception is thrown.
By default, the maximum cache size is set to 0. This means no objects are cached by default. When you want to enable caching, you can change the maximum cache size by calling cgul_cache__set_size()
.
[in,out] | cex | c-style exception |
[in] | constructor | constructor for the cached objects |
[in] | destructor | destructor for the cached objects |
[in] | restructor | restructor for the cached objects |
cgul_cache
instance Referenced by cgul_cache_cxx::cgul_cache_cxx().
CGUL_EXPORT void cgul_cache__delete | ( | cgul_cache_t | cache | ) |
This method first calls the destructor for each object that is still cached. It then frees all of its internally allocated resources. The client should not use the cache
instance after calling this method.
[in] | cache | cgul_cache instance |
Referenced by cgul_cache_cxx::set_obj(), and cgul_cache_cxx::~cgul_cache_cxx().
CGUL_EXPORT unsigned long int cgul_cache__get_size | ( | cgul_exception_t * | cex, |
cgul_cache_t | cache | ||
) |
Get the maximum number of objects the cache can hold when the reserve is zero. To get the total number of elements the cache can hold, you must add the reserve to the size.
[in] | cex | c-style exception |
[in] | cache | cgul_cache instance |
Referenced by cgul_cache_cxx::get_size().
CGUL_EXPORT void cgul_cache__set_size | ( | cgul_exception_t * | cex, |
cgul_cache_t | cache, | ||
unsigned long int | size | ||
) |
Set the maximum number of objects the cache can hold when the reserve is zero.
Calling this method with size
less than the reserve does not free any of the reserved objects; however, it may free objects that have recently been "moved" from the reserve to the main cache. (See cgul_cache__set_reserve()
.)
You can release all the cached objects and disable caching of objects by setting the cache reserve to 0 and the cache size to 0 (in that order). This is the default.
If an error occurs (while enlarging the cache), an exception is thrown.
[in,out] | cex | c-style exception |
[in] | cache | cgul_cache instance |
[in] | size | maximum size of the cache |
Referenced by cgul_cache_cxx::set_size().
CGUL_EXPORT unsigned long int cgul_cache__get_reserve | ( | cgul_exception_t * | cex, |
cgul_cache_t | cache | ||
) |
Get the reserve limit. This is the number of objects that are guaranteed to be held in reserve by the cache. These objects will not be returned by the cache until the reserve is reduced. The reserve is independent of the size of the cache.
[in] | cex | c-style exception |
[in] | cache | cgul_cache instance |
Referenced by cgul_cache_cxx::get_reserve().
CGUL_EXPORT void cgul_cache__set_reserve | ( | cgul_exception_t * | cex, |
cgul_cache_t | cache, | ||
unsigned long int | reserve | ||
) |
Set the reserve limit. This method causes cache
to reserve objects. The reserved objects are held indefinitely until the reserve is reduced. The reserve is independent of the size of the cache.
It is important to understand that if these reserved objects are not already being held by the cache, the cache will instantiate them. This allows the client to immediately instantiate objects without having to worry about out-of-memory exceptions when the objects are used later.
Note that if you want to get a pointer to one of the reserved object, you first call cgul_cache__set_reserve()
to reduce the number of the reserved objects. This simply "moves" the now unreserved objects to the main cache of objects. You then immediately call cgul_cache__get()
to get an object from the main cache.
It is done like this so that you can code strictly in terms of cgul_cache__get()
. You can then reserve an object now and trigger when it is used later just by calling this method. The code that uses cgul_cache__get()
does not need to know anything about reserved objects. It will just naturally use them.
Objects that are "moved" from the reserve to the main cache are not guaranteed to be available if cgul_cache__set_size()
has since been called.
[in,out] | cex | c-style exception |
[in] | cache | cgul_cache instance |
[in] | reserve | reserve |
Referenced by cgul_cache_cxx::set_reserve().
CGUL_EXPORT void* cgul_cache__get | ( | cgul_exception_t * | cex, |
cgul_cache_t | cache | ||
) |
Try to return a re-initialized object from the cache; if the cache is empty, a newly instantiated object will be returned instead. If an error occurs, NULL
is returned and an exception is thrown.
[in,out] | cex | c-style exception |
[in] | cache | cgul_cache instance |
Referenced by cgul_cache_cxx::get().
CGUL_EXPORT void cgul_cache__put | ( | cgul_exception_t * | cex, |
cgul_cache_t | cache, | ||
void * | obj | ||
) |
Try to put obj
on the cache. If the cache is full, obj
will be delete instead.
[in] | cex | c-style exception |
[in] | cache | cgul_cache instance |
[in] | obj | object to cache or delete |
Referenced by cgul_cache_cxx::put().