C++ bindings for cgul_hash
More...
#include <cgul_hash_cxx.h>
Public Types | |
typedef cgul_hash__hash_t | hash_t |
typedef cgul_hash__compare_t | compare_t |
typedef int(* | fold_key_t) (const void *key, void *data) |
typedef int(* | fold_value_t) (void *value, void *data) |
typedef int(* | fold_pair_t) (const void *key, void *value, void *data) |
typedef int(* | traverse_t) (cgul_hash_cxx *h, cgul_hash_node_cxx *n, void *data) |
Public Member Functions | |
cgul_hash_cxx () | |
cgul_hash_cxx (hash_t hf, void *hf_data, compare_t cf) | |
virtual | ~cgul_hash_cxx () |
virtual void | free_keys () |
virtual void | free_values () |
virtual float | get_load_factor () const |
virtual void | set_load_factor (float load_factor) |
virtual void | swap (cgul_hash_cxx &rhs) |
virtual int | is_empty () const |
virtual const void ** | get_keys (size_t *key_count) const |
virtual const void ** | get_sorted_keys (size_t *key_count) const |
virtual cgul_hash_node_cxx * | get_front () const |
virtual cgul_hash_node_cxx * | get_back () const |
virtual cgul_hash_node_cxx * | get_oldest () const |
virtual void | set_oldest (cgul_hash_node_cxx *n) |
virtual cgul_hash_node_cxx * | get_youngest () const |
virtual void | set_youngest (cgul_hash_node_cxx *n) |
virtual int | insert (const void *key, cgul_hash_node_cxx **n) |
virtual cgul_hash_node_cxx * | find (const void *key) |
virtual int | remove (const void *key_in, void **key_out, void **value_out) |
virtual void | remove_node (cgul_hash_node_cxx *n) |
virtual int | remove_front (void **key_out, void **value_out) |
virtual int | remove_back (void **key_out, void **value_out) |
virtual int | remove_oldest (void **key_out, void **value_out) |
virtual int | remove_youngest (void **key_out, void **value_out) |
virtual void | clear () |
virtual size_t | get_size () const |
virtual unsigned int | hash_block (void *block, size_t block_size) |
virtual char * | get_stats () const |
virtual void | foldl_keys (fold_key_t f, void *data) |
virtual void | foldr_keys (fold_key_t f, void *data) |
virtual void | foldl_values (fold_value_t f, void *data) |
virtual void | foldr_values (fold_value_t f, void *data) |
virtual void | foldl_pairs (fold_pair_t f, void *data) |
virtual void | foldr_pairs (fold_pair_t f, void *data) |
virtual void | traverse (traverse_t f, void *data) |
virtual void | traverse_range (cgul_hash_node_cxx *first, cgul_hash_node_cxx *last, traverse_t f, void *data) |
virtual cgul_hash_t | get_obj () const |
virtual cgul_hash_t | take_obj () |
virtual void | set_obj (cgul_hash_t rhs) |
This class provides the C++ bindings for C cgul_hash
objects. The main purpose of this class is to convert the C-style function calls and exception handling in cgul_hash
into C++-style function calls and exception handling.
This typedef defines the interface for hash functions that can be used with custom cgul_hash_cxx
objects. The hash function returns the hash of key
which should be in the range of [0 - UINT_MAX]. The cgul_hash_cxx
object will then use the hash value to map to the correct bucket.
It may not be necessary to write your own hash function as hash_block()
is a good choice, but you will still need to write an adaptor because hash_block()
needs to know the size of the key which is not something intrinsically stored in the hash itself.
The data
pointer is just a copy of the same pointer that was registered when the custom cgul_hash_cxx
object was instantiated.
This typedef defines the interface for comparison functions that can be used with custom cgul_hash_cxx
objects. After the hash function selects a bucket, the comparison function is used to compare keys within the same bucket in order to determine if a key exists in the hash.
When you define your comparison function, you should compare key1
to key2
and return less than zero, zero, or greater than zero if key1
is less than, equal to, or greater than key2
. The reason the comparison function needs to be complete is so get_sorted_keys()
can work.
typedef int(* cgul_hash_cxx::fold_key_t) (const void *key, void *data) |
This typedef is the interface for the combining function used by the following methods:
foldl_keys()
foldr_keys()
[in] | key | key |
[in] | data | client data |
typedef int(* cgul_hash_cxx::fold_value_t) (void *value, void *data) |
This typedef is the interface for the combining function used by the following methods:
foldl_values()
foldr_values()
[in] | value | value |
[in] | data | client data |
typedef int(* cgul_hash_cxx::fold_pair_t) (const void *key, void *value, void *data) |
This typedef is the interface for the combining function used by the following methods:
foldl_pairs()
foldr_pairs()
[in] | key | key |
[in] | value | value |
[in] | data | client data |
typedef int(* cgul_hash_cxx::traverse_t) (cgul_hash_cxx *h, cgul_hash_node_cxx *n, void *data) |
This typedef is the interface for the callback function used by the following methods:
traverse()
traverse_range()
[in] | h | hash |
[in] | n | node |
[in] | data | client data |
|
inline |
Create a new default cgul_hash_cxx
object that is already configured to use C-style strings as keys. If memory cannot be allocated, an exception is thrown.
References cgul_hash__new().
Referenced by set_obj().
Create a new custom cgul_hash_cxx
object that uses hf
as the hash function and cf
as the comparison function. With the help of an adaptor, the hash_block()
function is a good choice for hf
. If memory cannot be allocated, an exception is thrown.
[in] | hf | hash function |
[in] | hf_data | hash function client data |
[in] | cf | comparison function |
References cgul_hash__new_custom().
|
inlinevirtual |
The method frees all internally allocated memory.
References cgul_hash__delete().
|
inlinevirtual |
This method calls free()
on all the keys in the hash. Because this is such a common operation, it is an exception to the rule that cgul containers never free keys. This method should only ever be called immediately before calling delete
because it otherwise invalidates the hash.
References cgul_hash__free_keys().
|
inlinevirtual |
This method calls free()
on all the values in the hash. Because this is such a common operation, it is an exception to the rule that cgul containers never free values. This method should only ever be called immediately before calling delete
because it otherwise invalidates the hash.
References cgul_hash__free_values().
|
inlinevirtual |
Get the load factor.
References cgul_hash__get_load_factor().
|
inlinevirtual |
The load_factor
is the main parameter that governs the speed/space tradeoff. It is the ratio of the number of keys to buckets.
This is an important value because each key hashes to a particular bucket. Then the hash has to perform a linear search of the keys in the bucket. Because the load factor limits the average number of keys per bucket, it controls how deep the linear search is allowed to get (on average).
The default load factor is 0.75.
[in] | load_factor | load factor |
References cgul_hash__set_load_factor().
|
inlinevirtual |
Swap the internal data for this
and rhs
. This is much faster in general than trying to do the same thing by iterating over the hash elements.
[in] | rhs | righ-hand side |
References cgul_hash__swap().
|
inlinevirtual |
Return true if the hash is empty.
References cgul_hash__is_empty().
|
inlinevirtual |
Return an array of keys in insertion order. A NULL
pointer is appended to the array that is returned and can be used as a sentinel.
If key_count
is not NULL
, *key_count
is set to the number of keys returned in the array.
The caller is responsible for calling free()
on the array that is returned but must not attempt to free the keys themselves.
The main reason for calling this method is because you want to sort the keys in the hash. If you need the keys sorted using the comparison function, as a convenience, you can call get_sorted_keys()
instead. If you need to sort by some other criteria, you can use cgul_merge_sort_pointers()
directly on the array returned by this method.
It is wasteful to use this method if all you want to do is iterate over the keys in insertion order. Use get_oldest()
and cgul_hash_node::get_younger()
to do this instead.
If possible, cgul_rbtree_cxx
should be used instead of cgul_hash_cxx
if the caller needs frequent access to the keys in sorted order.
[out] | key_count | number of keys returned in the array |
References cgul_hash__get_keys().
|
inlinevirtual |
Return an array of keys sorted using the comparison function. A NULL
pointer is appended to the array that is returned and can be used as a sentinel.
If key_count
is not NULL
, *key_count
is set to the number of keys returned in the array.
The caller is responsible for calling free()
on the array that is returned but must not attempt to free the keys themselves.
If possible, cgul_rbtree_cxx
should be used instead of cgul_hash_cxx
if the caller needs frequent access to the keys in sorted order.
[out] | key_count | number of keys returned in the array |
strcmp()
References cgul_hash__get_sorted_keys().
|
inlinevirtual |
Return the front node or NULL
if the hash is empty. The "front" node is just a synonym for the "oldest" node. You can use the return value to iterate over all the nodes in the hash by calling cgul_hash_node::get_next()
.
References cgul_hash__get_front().
|
inlinevirtual |
Return the back node or NULL
if the hash is empty. The "back" node is just a synonym for the "youngest" node. You can use the return value to iterate over all the nodes in the hash by calling cgul_hash_node::get_prev()
.
References cgul_hash__get_back().
|
inlinevirtual |
Get the oldest node. This operation is O(1). If the hash is empty, NULL
is returned. This class does not have to search the hash in order to find the oldest node because it efficiently keeps a direct pointer to the oldest node up to date.
The following example shows how to iterate over the entire hash in insertion order:
cgul_hash_node_cxx* n = h->get_oldest(); for ( ; n ; n = n->get_younger()) { ... }
References cgul_hash__get_oldest().
|
inlinevirtual |
Set the oldest node in the hash to be n
. Calling this method has the potential to confuse iterators and should be handled with roughly the same level of caution as calling remove_node()
.
This method could be used, for example, if your code expires the oldest node in the hash and you want to force n
to be the next node to expire.
[in] | n | node |
References cgul_hash__set_oldest().
|
inlinevirtual |
Get the youngest node. This operation is O(1). If the hash is empty, NULL
is returned. This class does not have to search the hash in order to find the youngest node because it efficiently keeps a direct pointer to the youngest node up to date.
The following example shows how to iterate over the entire hash in reverse insertion order:
cgul_hash_node_cxx* n = h->get_youngest(); for ( ; n ; n = n->get_older()) { ... }
References cgul_hash__get_youngest().
|
inlinevirtual |
Set the youngest node in the hash to be n
. Calling this method has the potential to confuse iterators and should be handled with roughly the same level of caution as calling remove_node()
.
This method could be used, for example, if your code expires the least-recently used (LRU) node. By calling set_youngest()
each time a node is used, the least-recently used node will be the oldest node in the hash.
[in] | n | node |
References cgul_hash__set_youngest().
|
inlinevirtual |
Return the new cgul_hash_node_cxx
object created by inserting key
into the hash. If key
already exists, another node with the same key is not created. The new or pre-existing node is returned in n
if it is not NULL
.
An important thing to notice is that there is no way to pass in the value
pointer that makes up the key/value pair. This is by design. The reason is that find()
and insert()
share the same basic code to search to see if the key already exists. Thus, if you want to see if a key already exists before inserting a new key (which is very common), you could call find()
followed by insert()
, but this inefficiently causes hash to do the same lookup twice.
By not allowing insert()
to set the value
pointer, it allows you to easily use this method in those places where you want find()
to fail before you call insert()
; instead, you just call insert()
and check the return value. Here is an example:
int insert_rv = 0; cgul_hash_node_cxx* n = NULL;
key = s->get_value(); insert_rv = h->insert(key, &n); if (insert_rv) { s->take_value(); . . . } else { . . . }
As with all the cgul containers, the client is responsible for deallocating both key
and value
. If before inserting the new node the hash detects that the load factor has been exceeded, the hash will be resized.
key
continues to exist until it is removed from the hash. [in] | key | key |
[out] | n | newly inserted node if successful; otherwise, unaltered |
References cgul_hash__insert().
|
inlinevirtual |
Return the hash node associated with key
. You can use cgul_hash_node::get_value()
and cgul_hash_node::set_value()
to get and set the value associated with the node. If no node is found, NULL
is returned.
[in] | key | key |
key
References cgul_hash__find().
|
inlinevirtual |
Remove the node associated with the key key_in
from the hash. If key_out
is not NULL
, the key that is currently stored in the node to be removed will be returned. If value_out
is not NULL
, the value stored in the node to be removed will be returned. The return value is 1
if the node for key_in
was removed; otherwise, it is 0
.
[in] | key_in | key to find |
[out] | key_out | actual key stored in node |
[out] | value_out | actual value stored in node |
key
was removed References cgul_hash__remove().
|
inlinevirtual |
Remove the node n
from the hash. Calling this method has the potential to invalidate iterators. If you need to remove nodes while simultaneously iterating over the tree, you must call get_next()
(or the equivalent) before removing the current node because, once the node is removed, you cannot use it safely.
[in] | n | node |
References cgul_hash__remove_node().
|
inlinevirtual |
This method removes the front node from the hash. The "front" node is just a synonym for the "oldest" node. The key and value pointers stored in the node that is to be removed will be returned in key_out
and value_out
if you pass in pointers that are not NULL
. If the hash is not empty, the front node will be removed, and 1
will be returned; otherwise, 0
will be returned.
[out] | key_out | pointer for the key stored in the node |
[out] | value_out | pointer for the value stored in the node |
References cgul_hash__remove_front().
|
inlinevirtual |
This method removes the back node from the hash. The "back" node is just a synonym for the "youngest" node. The key and value pointers stored in the node that is to be removed will be returned in key_out
and value_out
if you pass in pointers that are not NULL
. If the hash is not empty, the back node will be removed, and 1
will be returned; otherwise, 0
will be returned.
[out] | key_out | pointer for the key stored in the node |
[out] | value_out | pointer for the value stored in the node |
References cgul_hash__remove_back().
|
inlinevirtual |
This method removes the oldest node from the hash. The key and value pointers stored in the node that is to be removed will be returned in key_out
and value_out
if you pass in pointers that are not NULL
. If the hash is not empty, the oldest node will be removed and 1
will be returned; otherwise, 0
will be returned.
[out] | key_out | pointer for the key stored in the node |
[out] | value_out | pointer for the value stored in the node |
References cgul_hash__remove_oldest().
|
inlinevirtual |
This method removes the youngest node from the hash. The key and value pointers stored in the node that is to be removed will be returned in key_out
and value_out
if you pass in pointers that are not NULL
. If the hash is not empty, the youngest node will be removed and 1
will be returned; otherwise, 0
will be returned.
[out] | key_out | pointer for the key stored in the node |
[out] | value_out | pointer for the value stored in the node |
References cgul_hash__remove_youngest().
|
inlinevirtual |
Remove all elements from the hash. You should be careful to deallocate the key/value pairs (if necessary) before calling this method.
References cgul_hash__clear().
|
inlinevirtual |
Return the total number of elements stored in the hash.
References cgul_hash__get_size().
|
inlinevirtual |
This function computes the hash for block
which can be any arbitrary data extending for block_size
bytes.
With the help of an adaptor, this function can be used as the hash function for custom cgul_hash_cxx
objects. An adaptor is needed because the block size is not a value that is intrinsically stored in cgul_hash_cxx
objects.
[in] | block | block |
[in] | block_size | block size |
block
References cgul_hash__hash_block().
|
inlinevirtual |
Return a string with statistics for the hash. The caller is responsible for freeing the string by calling free()
. If an error occurs while generating the stats, an exception is thrown.
References cgul_hash__get_stats().
|
inlinevirtual |
This method performs a left fold of the hash with the combining function f
. f
is called once for each key in the hash starting at the front of the hash and iterating forward to the end of the hash.
The first parameter passed into f
is the current key. The second parameter passed into f
is the client data which is where the result of the fold should be accumulated.
f
must return true after each iteration in order for iteration to continue.
[in] | f | combining function |
[in] | data | client data passed to f |
References cgul_hash__get_front(), cgul_hash_node__get_key(), and cgul_hash_node__get_next().
|
inlinevirtual |
This method performs a right fold of the hash with the combining function f
. f
is called once for each key in the hash starting at the back of the hash and iterating backward to the front of the hash.
The first parameter passed into f
is the current key. The second parameter passed into f
is the client data which is where the result of the fold should be accumulated.
f
must return true after each iteration in order for iteration to continue.
[in] | f | combining function |
[in] | data | client data passed to f |
References cgul_hash__get_back(), cgul_hash_node__get_key(), and cgul_hash_node__get_prev().
|
inlinevirtual |
This method performs a left fold of the hash with the combining function f
. f
is called once for each value in the hash starting at the front of the hash and iterating forward to the end of the hash.
The first parameter passed into f
is the current value. The second parameter passed into f
is the client data which is where the result of the fold should be accumulated.
f
must return true after each iteration in order for iteration to continue.
[in] | f | combining function |
[in] | data | client data passed to f |
References cgul_hash__get_front(), cgul_hash_node__get_next(), and cgul_hash_node__get_value().
|
inlinevirtual |
This method performs a right fold of the hash with the combining function f
. f
is called once for each value in the hash starting at the back of the hash and iterating backward to the front of the hash.
The first parameter passed into f
is the current value. The second parameter passed into f
is the client data which is where the result of the fold should be accumulated.
f
must return true after each iteration in order for iteration to continue.
[in] | f | combining function |
[in] | data | client data passed to f |
References cgul_hash__get_back(), cgul_hash_node__get_prev(), and cgul_hash_node__get_value().
|
inlinevirtual |
This method performs a left fold of the hash with the combining function f
. f
is called once for each key/value pair in the hash starting at the front of the hash and iterating forward to the end of the hash.
The first parameter passed into f
is the current key. The second parameter passed into f
is the current value. The third parameter passed into f
is the client data which is where the result of the fold should be accumulated.
f
must return true after each iteration in order for iteration to continue.
[in] | f | combining function |
[in] | data | client data passed to f |
References cgul_hash__get_front(), cgul_hash_node__get_key(), cgul_hash_node__get_next(), and cgul_hash_node__get_value().
|
inlinevirtual |
This method performs a right fold of the hash with the combining function f
. f
is called once for each key/value pair in the hash starting at the back of the hash and iterating backward to the front of the hash.
The first parameter passed into f
is the current key. The second parameter passed into f
is the current value. The third parameter passed into f
is the client data which is where the result of the fold should be accumulated.
f
must return true after each iteration in order for iteration to continue.
[in] | f | combining function |
[in] | data | client data passed to f |
References cgul_hash__get_back(), cgul_hash_node__get_key(), cgul_hash_node__get_prev(), and cgul_hash_node__get_value().
|
inlinevirtual |
Traverse all nodes passing each node to the function f
.
The first parameter passed into f
is the hash this
. The second paramenter passed into f
is the node for this iteration. The third parameter passed into f
is the client data data
.
f
is provided with a safe context in which it can remove the node that is passed into f
by calling remove_node()
.
f
must return true after each iteration in order for the traversal to continue.
NOTE: It is not strictly necessary that you use traverse()
or traverse_range()
in order to iterate over the hash elements. In fact, I would recommend that you use cgul_hash_node_cxx::get_next()
for most of your iteration needs. If you need to remove nodes though, you should probably use this method. If you look at this method's source however, you will see that the cgul_hash_node_cxx
class provides all the public methods you need to safely remove nodes while you are iterating over the hash, but you do have to be careful.
[in] | f | traversal callback function |
[in] | data | client data passed to f |
References traverse_range().
|
inlinevirtual |
Traverse all nodes starting with first
(inclusive) and ending with last
(inclusive) passing each node to the function f
. If you know the first node, but are not sure of the last node, just use NULL
as the last node. This will cause this method to iterate until it reaches the end of the hash. You can than have f
return 0 when it determines that the last node has been reached.
The first parameter passed into f
is the hash this
. The second paramenter passed into f
is the node for this iteration. The third parameter passed into f
is the client data data
.
f
is provided with a safe context in which it can remove the node that is passed into f
by calling remove_node()
.
f
must return true after each iteration in order for the traversal to continue.
If first
is NULL
, iteration starts at the beginning of the hash. If last
is NULL
, iteration stops at the end of the hash.
NOTE: It is not strictly necessary that you use traverse()
or traverse_range()
in order to iterate over the hash elements. In fact, I would recommend that you use cgul_hash_node_cxx::get_next()
for most of your iteration needs. If you need to remove nodes though, you should probably use this method. If you look at this method's source however, you will see that the cgul_hash_node_cxx
class provides all the public methods you need to safely remove nodes while you are iterating over the hash, but you do have to be careful.
[in] | first | first node in range |
[in] | last | last node in range |
[in] | f | traversal callback function |
[in] | data | client data passed to f |
References cgul_hash__get_back(), cgul_hash__get_front(), and cgul_hash_node__get_next().
Referenced by traverse().
|
inlinevirtual |
Get the underlying cgul_hash
object.
|
inlinevirtual |
Take the underlying cgul_hash
object. This means the underlying object will not be deleted when the wrapper goes out of scope. Also, because you have taken the underlying object, no other methods should be called on this wrapper's instance. Lastly, after taking the underlying object, it is the caller's responsibility to delete the underlying object by calling cgul_hash__delete()
.
|
inlinevirtual |
Set the new underlying object to rhs
. This causes the old underlying object to be deleted which invalidates any outstanding pointers to or iterators for the old underlying object.
This instance takes ownership of rhs
which means rhs
will be automatically deleted when the C++ wrapper is deleted. To prevent automatic deletion of rhs
, call take_obj()
when the C++ wrapper is no longer needed.
[in] | rhs | right-hand side |
References cgul_hash__delete(), and cgul_hash_cxx().