[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Some of GM's internal modules may be useful to GM developers, so their APIs are exposed. These modules include the following:
13.1 CRC Functions 13.2 Hash Table 13.3 Lookaside List 13.4 Marks 13.5 Page Allocation
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
GM provides the following functions, which compute 32-bit CRCs on the contents of memory. These functions are not guaranteed to perform any particular variant of the CRC-32, but these functions are useful for creating robust hashing functions.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
13.2.1 Introduction 13.2.2 Hash Table API
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
GM implements a generic hash table with a flexible interface. This module can automatically manage storage of fixed-size keys and/or data, or can allow the client to manage storage for keys and/or data. It allows the client to specify arbitrary hashing and comparison functions.
For example,
hash = gm_create_hash (gm_hash_compare_strings, gm_hash_hash_string, 0, 0, 0, 0); |
As another example,
hash = gm_create_hash (gm_hash_compare_ints, gm_hash_hash_int, sizeof (int), sizeof (struct my_big_struct), 100, 0); |
ints
as keys and returns
pointers to copies of the inserted structures. All storage
for the keys and data is automatically managed by the hash table. In
this case, all pointers to hash keys and data passed by GM to the client
will point to GM-managed buffers. This function also preallocates
enough storage for 100 hash entries, guaranteeing that at least
100 key/data pairs can be inserted in the table if the hash table
creation succeeds.
The automatic storage management option of GM not only is convenient, but also is extremely space efficient for keys and data no larger than a pointer, because when keys and data are no larger than a pointer, GM automatically stores them in the space reserved for the pointer to the key or data, rather than allocating a separate buffer.
Note that all keys and data buffers are referred to by pointers, not by value. This allows keys and data buffers of arbitrary size to be used. As a special (but common) case, however, one may wish to use pointers as keys directly, rather than use what they point to. In this special case, use the following initialization, and pass the keys (pointers) directly to the API, rather than the usual references to the keys.
hash = gm_create_hash (gm_hash_compare_ptrs, gm_hash_hash_ptr, 0, data_len, min_cnt, flags); |
sizeof (void
*)
during initialization and treat pointer keys just like any other
keys, the API above is more efficient, more convenient, and completely
architecture independent.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Some day the GM hash table API may be extended, but the current API is as follows:
gm_hash
structure or 0
if the
hash table could not be created. The parameters are as follows:
gm_hash_compare_ints
gm_hash_compare_longs
gm_hash_compare_ptrs
gm_hash_compare_strings
or may be a client-defined function.
gm_hash_hash_int
gm_hash_hash_long
gm_hash_hash_ptr
gm_hash_hash_string
or may be a client-defined function.
0
if the keys should not be copied into GM-managed buffers.
0
if the data should not be copied into GM-managed buffers.
0
because no flags are currently defined.
0
if no match exists. If the data resides in a GM-managed
buffer, it is only guaranteed to be valid until the next operation on
the hash table.
0
if no match exists.
*
key (or data *
data) is
copied into the hash table unless the table was initialized with a
key_len (or data_len) of 0.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
GM implements a lookaside list, which may be used to manage small
fixed-length blocks more efficiently than gm_malloc()
and
gm_free()
. Lookaside lists can also be used to ensure that at
least a minimum number of blocks are available for allocation at all
times.
GM lookaside lists have the following API:
0
if the buffer could not be allocated.
gm_lookaside_alloc()
. The contents of the block of memory
are guaranteed to be unchanged until the next operation is performed
on the lookaside list.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The GM "mark" API is new to GM-1.4. It allows the creation and destruction of mark sets, which allow mark addition, mark removal, and test for mark in mark set operations to be performed in constant time. Marks may be members of only one mark set at a time. Marks have the very unusual property that they need not be initialized before use.
All operations on marks are extremely efficient. Mark initialization
requires zero time. Removing a mark from a mark set and testing for
mark inclusion in a mark set take constant time. Addition of a mark to
a mark set takes O(constant) time, assuming the marks set was created
with support for a sufficient number of marks; otherwise, it requires
O(constant) average time. Finally, creation and destruction of a mark
set take time comperable to the time required for a single call to
malloc()
and free()
, respectively.
Because marks need not be initialized before use, they can actually be used to determine if other objects have been initialized. This is done by putting a mark in the object, and adding the mark to a "mark set of marks in initialized objects" once the object has been initialized. This is similar to one common use of "magic numbers" for debugging purposes, except that it is immune to the possibility that the uninitialized magic number contained the magic number before initialization, so such marks can be used for non-debugging purposes. Therefore, marks can be used in ways that magic numbers cannot. For example, they may be used to solve the following exercise:
Marks have a nice set of properties that each mark in a mark set has a unique value and if this value is corrupted, then the mark is implicitly removed from the mark set. This makes marks useful for detecting memory corruption, and are less prone to false negatives than are magic numbers, which proliferate copies of a single value.
Finally, marks are location-dependent. This means that if a mark is copied, the copy will not be a member of the mark set.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
GM_SUCCESS
on success.
Requires time comperable to malloc()
.
*set
.
Requires time comperable to free()
.
*mark
to set. Requires O(constant) time if
the mark set has preallocated resources for the mark. Otherwise, requires
O(constant) average time.
*mark
is in set. Requires O(constant) time.
*mark
from set.
Requires O(constant) time.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The following GM API allows pages to be allocated and freed.
GM_PAGE_LEN
.
gm_page_alloc()
.
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |