Some of GM's internal modules may be useful to GM developers, so their APIs are exposed. These modules include the following:
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.
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.
hash = gm_create_hash (gm_hash_compare_strings, gm_hash_hash_string, 0, 0, 0, 0);
creates a hash table that uses null-terminated character string keys residing in client-managed storage, and returns pointers to data in client-managed storage. In this case, all pointers to hash keys and data passed by GM to the client will be the same as the pointers passed by the client to GM.
As another example,
hash = gm_create_hash (gm_hash_compare_ints, gm_hash_hash_int, sizeof (int), sizeof (struct my_big_struct), 100, 0);
creates a hash table that uses
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
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);
While it is possible to specify a key_len of
*) during initialization and treat pointer keys just like any other
keys, the API above is more efficient, more convenient, and completely
Some day the GM hash table API may be extended, but the current API is as follows:
0if the hash table could not be created. The parameters are as follows:
0if the keys should not be copied into GM-managed buffers.
0if the data should not be copied into GM-managed buffers.
0because no flags are currently defined.
0if 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.
0if 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.
GM implements a lookaside list, which may be used to manage small
fixed-length blocks more efficiently than
gm_free(). Lookaside lists can also be used to ensure that at
least a minimum number of blocks are available for allocation at all
GM lookaside lists have the following API:
0if 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.
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
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.
GM_SUCCESSon success. Requires time comperable to
*set. Requires time comperable to
*markto set. Requires O(constant) time if the mark set has preallocated resources for the mark. Otherwise, requires O(constant) average time.
*markis in set. Requires O(constant) time.
*markfrom set. Requires O(constant) time.
The following GM API allows pages to be allocated and freed.
Go to the first, previous, next, last section, table of contents.