1. Keyword support
1.1. Introduction
Keywords originally was introduced in gpmi (or actually in
ai_scripts) when we first implemented a text based scripting
language, tcl. We had enums in the c code, but accessing them
from a script language would have been translating them to numbers
by hand. Noone wants to do that. Keyword originally was some array
from which a linear searching algorithm could look up the numbers for
the names.
However, in the current version of gpmi, keyword support is much stronger.
It's a database that contains different tables. Each table has a data
type and varying number of records. Records are name-value pairs, where
name is a string, and value depends on the table type. To speed up
lookups, we store records in a hash table, thus we sometimes call
the name filed the key field.
Each table has a reverse-hash table too, where value-name pairs are
stored. A reverse lookup is when the user supply a value and the
library returns the name.
1.2. Creating a keyword table
There are two ways to create a keyword table. One is importing, the
other is creating.
1.2.1. Importing a keyword table
In most cases a keyword table is set up to provide the translation
between a package's internal data representation and string names.
The easiest way is to define big static arrays in the c code and
then import them. For this, gpmi has gpmi_keyword_import.
Note: when you import an integer array, it won't be checked if
each integer value is unique or not. If you have duplicate
values, reverse lookups will find only one of the names!
It is considered a bug of the array, you must make sure you
don't have duplicate values. gpmi does not check it to save
cpu power - we assume that a package developer should check
imported arrays.
1.2.2. Creating a keyword table
Another way to have a keyword table is to create it using
gpmi_keyword_create. The table is empty after the call.
1.3. Record manipulation
1.3.1. Adding a record
You may use two functions to add records in an existing keyword
table. One is gpmi_keyword_add where you describe the
name-value pair.
The other way, working only for integer type tables, you may use
gpmi_keyword_add_auto. You don't need to supply a value,
only a name, value is filled in using an auto-increment method.
As long as you use only gpmi_keyword_add_auto calls to
fill a keyword table, each name will have an unique number as value.
The first time you use gpmi_keyword_add for this table, it
will be marked and you can't ever use gpmi_keyword_add_auto
again to add new records in it.
Note that adding records in an integer table will force unique values.
It's important to make the reverse lookups work. Also remember that importing
does not force this: a broken array imported may cause value-collisions.
1.3.2. Deleting a record
You may use gpmi_keyword_del to delete records from any
keyword table. Be careful using this routine as you may introduce
memory leaks.
Before you delete a key, you must free the value if, and
only if it was you who allocated it. It's a very simple rule,
but easy to forget about. Some examples when you need to free and
where not:
- imported tables have static data, you won't need to free
- created dynamic integer tables contains integers, no need to free
- EXCEPTION: if you import an integer table and later you add dynamic records yourself, each time you delete a dynamicly added int, sizeof(int) bytes will be leaked. Using the library this way is a misuse, never delete from a mixed (imported and dynamicly extended) tables!
- created dynamic string tables: you need to free your string data before the call
1.3.3. Finding records
1.3.3.1. Finding name->value
You have several routines to find values for a name:
- gpmi_keyword_find_int: resolves a single integer for a name. Works for int tables.
- gpmi_keyword_find_int_numeric: resolves a single integer for a name, or if name is a valid number, returns it. Works for int tables.
- gpmi_keyword_find_string: resolves a string value for a name. Works for string tables.
- gpmi_keyword_find_ptr: resolves a pointer value for a name. Works only for pointer tables.
- gpmi_keyword_find_multi: resolves multiple integer values for a list of names. Works only for int tables, numbers are ORed.
1.3.3.2. Reverse search, find value->name
The general way is to use gpmi_keyword_find_rev which
accepts one value of any type. The parameter's type must match the
keyword table's type.
Only for integer tables, you may user gpmi_keyword_find_rev_multi,
for which you supply an integer built up from bits and gpmi will assemble
a name list where your integer had 1. It's the reverse transformation for
gpmi_keyword_find_multi.
1.4. Table properties
1.4.1. Types
Currently gpmi supports 3 types:
For importing you must use these static array typedefs, respectively:
- gpmi_keyword_static_int
- gpmi_keyword_static_string
- gpmi_keyword_static_ptr
If a call needs to be named in a call, you may use these enum values:
- gpmi_keyword_type_integer
- gpmi_keyword_type_string
- gpmi_keyword_type_pointer
1.4.2. auto-increment
When you create a new integer table (and not import it), by default
auto-increment is enabled. The first time you use gpmi_keyword_add,
it will lose auto-increment state. If you want to keep this property, use
only gpmi_keyword_add_auto to add records in this table. Deleting
records is allowed, but refer section 3.2. for more information about
the potential memory leak it could introduce.
1.4.3. table name
Each table has a name that is a string. This name is supplied by the
user when the table is imported or created. Names are used to build
an keyword table of the keyword tables, which is called gpmi_keywords
and is ptr type.