Elektra
0.8.10
|
Methods to manipulate KeySets. More...
Enumerations | |
enum | option_t { KDB_O_NONE =0, KDB_O_DEL =1, KDB_O_POP =1<<1, KDB_O_NODIR =1<<2, KDB_O_DIRONLY =1<<3, KDB_O_NOREMOVE =1<<6, KDB_O_REMOVEONLY =1<<7, KDB_O_INACTIVE =1<<8, KDB_O_SYNC =1<<9, KDB_O_SORT =1<<10, KDB_O_NORECURSIVE =1<<11, KDB_O_NOCASE =1<<12, KDB_O_WITHOWNER =1<<13, KDB_O_NOALL =1<<14 } |
Functions | |
KeySet * | ksNew (size_t alloc,...) |
KeySet * | ksVNew (size_t alloc, va_list va) |
| |
KeySet * | ksDup (const KeySet *source) |
int | ksCopy (KeySet *dest, const KeySet *source) |
| |
int | ksDel (KeySet *ks) |
int | elektraKeyCmpOrder (const Key *ka, const Key *kb) |
ssize_t | ksGetSize (const KeySet *ks) |
ssize_t | ksAppendKey (KeySet *ks, Key *toAppend) |
| |
ssize_t | ksAppend (KeySet *ks, const KeySet *toAppend) |
| |
KeySet * | ksCut (KeySet *ks, const Key *cutpoint) |
Key * | ksPop (KeySet *ks) |
int | elektraKsToMemArray (KeySet *ks, Key **buffer) |
int | ksRewind (KeySet *ks) |
Key * | ksNext (KeySet *ks) |
Key * | ksCurrent (const KeySet *ks) |
Key * | ksHead (const KeySet *ks) |
Key * | ksTail (const KeySet *ks) |
cursor_t | ksGetCursor (const KeySet *ks) |
Key * | ksAtCursor (KeySet *ks, cursor_t pos) |
return key at given cursor position | |
int | elektraKsFilter (KeySet *result, KeySet *input, int(*filter)(const Key *k, void *argument), void *argument) |
return only those keys from the given keyset that pass the supplied filter function with the supplied argument | |
int | ksSetCursor (KeySet *ks, cursor_t cursor) |
Key * | ksLookup (KeySet *ks, Key *key, option_t options) |
Key * | ksLookupByName (KeySet *ks, const char *name, option_t options) |
Methods to manipulate KeySets.
A KeySet is a sorted set of keys. So the correct name actually would be KeyMap.
With ksNew() you can create a new KeySet.
You can add keys with ksAppendKey() in the keyset. Using ksAppend() you can append a whole keyset.
ksGetSize() tells you the current size of the keyset.
With ksRewind() and ksNext() you can navigate through the keyset. Don't expect any particular order, but it is assured that you will get every key of the set.
KeySets have an internal cursor . This is used for ksLookup() and kdbSet().
KeySet has a fundamental meaning inside elektra. It makes it possible to get and store many keys at once inside the database. In addition to that the class can be used as high level datastructure in applications. With ksLookupByName() it is possible to fetch easily specific keys out of the list of keys.
You can easily create and iterate keys:
enum option_t |
Options to change the default behavior of ksLookup() functions.
These options can be ORed. That is the |-Operator in C.
KDB_O_NONE |
No Option set. Will be recursive with no inactive keys.
|
KDB_O_DEL |
Delete parentKey key in kdbGet(), kdbSet() or ksLookup(). |
KDB_O_POP |
Pop Parent out of keyset key in kdbGet().
|
KDB_O_NODIR |
Exclude keys containing other keys in result. Only return leaves.
|
KDB_O_DIRONLY |
Retrieve only directory keys (keys containing other keys). This will give you an skeleton without leaves. This must not be used together with KDB_O_NODIR.
|
KDB_O_NOREMOVE |
Don't remove any keys. This must not be used together with KDB_O_REMOVEONLY. |
KDB_O_REMOVEONLY |
Only remove keys. This must not be used together with KDB_O_NOREMOVE. |
KDB_O_INACTIVE |
Do not ignore inactive keys (that name begins with .).
|
KDB_O_SYNC |
Set keys independent of sync status.
|
KDB_O_SORT |
This option has no effect. KeySets are always sorted.
|
KDB_O_NORECURSIVE |
Do not call kdbGet() for every key containing other keys (keyIsDir()). |
KDB_O_NOCASE |
Ignore case. |
KDB_O_WITHOWNER |
Search with owner. |
KDB_O_NOALL |
Only search from start -> cursor to cursor -> end. |
int elektraKeyCmpOrder | ( | const Key * | ka, |
const Key * | kb | ||
) |
Compare the order metadata of two keys.
ka | key to compare with |
kb | other key to compare with |
int elektraKsFilter | ( | KeySet * | result, |
KeySet * | input, | ||
int(*)(const Key *k, void *argument) | filter, | ||
void * | argument | ||
) |
return only those keys from the given keyset that pass the supplied filter function with the supplied argument
result | the keyset that should contain the filtered keys |
input | the keyset whose keys should be filtered |
filter | a function pointer to a function that will be used to filter the keyset. A key will be taken if the function returns a value greater than 0. |
argument | an argument that will be passed to the filter function each time it is called |
NULL | on NULL pointer |
int elektraKsToMemArray | ( | KeySet * | ks, |
Key ** | buffer | ||
) |
Builds an array of pointers to the keys in the supplied keyset. The keys are not copied, calling keyDel may remove them from the keyset.
The size of the buffer can be easily allocated via ksGetSize. Example:
ks | the keyset object to work with |
buffer | the buffer to put the result into |
ssize_t ksAppend | ( | KeySet * | ks, |
const KeySet * | toAppend | ||
) |
Append all toAppend
contained keys to the end of the ks
.
toAppend
KeySet will be left unchanged.
If a key is both in toAppend and ks, the Key in ks will be overridden.
ks | the KeySet that will receive the keys |
toAppend | the KeySet that provides the keys that will be transferred |
ssize_t ksAppendKey | ( | KeySet * | ks, |
Key * | toAppend | ||
) |
Appends a Key to the end of ks
.
A pointer to the key will be stored, and not a private copy. So a future ksDel() on ks
may keyDel() the toAppend
object, see keyGetRef().
The reference counter of the key will be incremented, and thus toAppend is not const.
If the keyname already existed, it will be replaced with the new key.
The KeySet internal cursor will be set to the new key.
It is save to use ksAppendKey(ks, keyNew(..)).
ks | KeySet that will receive the key |
toAppend | Key that will be appended to ks or deleted |
Key* ksAtCursor | ( | KeySet * | ks, |
cursor_t | pos | ||
) |
return key at given cursor position
ks | the keyset to pop key from |
pos | where to get |
NULL | on NULL pointer, negative cursor position or a position that does not lie within the keyset |
int ksCopy | ( | KeySet * | dest, |
const KeySet * | source | ||
) |
Copy a keyset.
Most often you may want a duplicate of a keyset, see ksDup() or append keys, see ksAppend(). But in some situations you need to copy a keyset to a existing keyset, for that this function exists.
You can also use it to clear a keyset when you pass a NULL pointer as source
.
Note that all keys in dest
will be deleted. Afterwards the content of the source will be added to the destination and the ksCurrent() is set properly in dest
.
A flat copy is made, so the keys will not be duplicated, but there reference counter is updated, so both keysets need to be ksDel().
source | has to be an initialized source KeySet or NULL |
dest | has to be an initialized KeySet where to write the keys |
Key* ksCurrent | ( | const KeySet * | ks | ) |
Return the current Key.
The pointer is NULL if you reached the end or after ksRewind().
ks | the keyset object to work with |
ks's
cursor KeySet* ksCut | ( | KeySet * | ks, |
const Key * | cutpoint | ||
) |
Cuts out a keyset at the cutpoint.
Searches for the cutpoint inside the KeySet ks. If found it cuts out everything which is below (see keyIsBelow()) this key. These keys will be missing in the keyset ks
. Instead, they will be moved to the returned keyset. If cutpoint
is not found an empty keyset is returned and ks
is not changed.
The cursor will stay at the same key as it was before. If the cursor was inside the region of cut (moved) keys, the cursor will be set to the key before the cutpoint.
If you use ksCut() on a keyset you got from kdbGet() and plan to make a kdbSet() later, make sure that you keep all keys that should not be removed permanently. You have to keep the KeySet that was returned and the KeySet ks
.
You have the keyset ks:
system/mountpoint/interest
system/mountpoint/interest/folder
system/mountpoint/interest/folder/key1
system/mountpoint/interest/folder/key2
system/mountpoint/other/key1
When you use
Then in returned
are:
system/mountpoint/interest
system/mountpoint/interest/folder
system/mountpoint/interest/folder/key1
system/mountpoint/interest/folder/key2
And in ks
are:
system/mountpoint/other/key1
So kdbSet() permanently removes all keys below system/mountpoint/interest
.
0 | on null pointers, no key name or allocation problems |
ks | the keyset to cut. It will be modified by removing all keys below the cutpoint. The cutpoint itself will also be removed. |
cutpoint | the point where to cut out the keyset |
int ksDel | ( | KeySet * | ks | ) |
A destructor for KeySet objects.
Cleans all internal dynamic attributes, decrement all reference pointers to all keys and then keyDel() all contained Keys, and free()s the release the KeySet object memory (that was previously allocated by ksNew()).
ks | the keyset object to work with |
KeySet* ksDup | ( | const KeySet * | source | ) |
Return a duplicate of a keyset.
Objects created with ksDup() must be destroyed with ksDel().
Memory will be allocated as needed for dynamic properties, so you need to ksDel() the returned pointer.
A flat copy is made, so the keys will not be duplicated, but there reference counter is updated, so both keysets need ksDel().
source | has to be an initialized source KeySet |
cursor_t ksGetCursor | ( | const KeySet * | ks | ) |
Get the KeySet internal cursor.
Use it to get the cursor of the actual position.
With the cursors it is possible to read ahead in a keyset:
It can also be used to restore the state of a keyset in a function
It is of course possible to make the KeySet const and cast its const away to set the cursor. Another way to achieve the same is to ksDup() the keyset, but it is not as efficient.
An invalid cursor will be returned directly after ksRewind(). When you set an invalid cursor ksCurrent() is 0 and ksNext() == ksHead().
ks | the keyset object to work with |
ssize_t ksGetSize | ( | const KeySet * | ks | ) |
Return the number of keys that ks
contains.
ks | the keyset object to work with |
ks
contains. Key* ksHead | ( | const KeySet * | ks | ) |
Return the first key in the KeySet.
The KeySets cursor will not be effected.
If ksCurrent()==ksHead() you know you are on the first key.
ks | the keyset object to work with |
Key* ksLookup | ( | KeySet * | ks, |
Key * | key, | ||
option_t | options | ||
) |
Look for a Key contained in ks
that matches the name of the key
.
ksLookup()
is designed to let you work with entirely pre-loaded KeySets, so instead of kdbGetKey(), key by key, the idea is to fully kdbGet() for your application root key and process it all at once with ksLookup()
.
This function is very efficient by using binary search. Together with kdbGet() which can you load the whole configuration with only some communication to backends you can write very effective but short code for configuration.
If found, ks
internal cursor will be positioned in the matched key (also accessible by ksCurrent()), and a pointer to the Key is returned. If not found, ks
internal cursor will not move, and a NULL pointer is returned.
Cascading is done if the first character is a /. This leads to ignoring the prefix like system/ and user/.
This is the way multi user Programs should get there configuration and search after the values. It is guaranteed that more namespaces can be added easily and that all values can be set by admin and user.
When KDB_O_NOALL is set the keyset will be only searched from ksCurrent() to ksTail(). You need to ksRewind() the keyset yourself. ksCurrent() is always set properly after searching a key, so you can go on searching another key after the found key.
When KDB_O_NOALL is not set the cursor will stay untouched and all keys are considered. A much more efficient binary search will be used then.
When KDB_O_POP is set the key which was found will be ksPop()ed. ksCurrent() will not be changed, only iff ksCurrent() is the searched key, then the keyset will be ksRewind()ed.
You can solve this problem by using KDB_O_NOALL, risking you have to iterate n^2 instead of n.
The more elegant way is to separate the keyset you use for ksLookup() and ksAppendKey():
ks | where to look for |
key | the key object you are looking for |
options | some KDB_O_* option bits:
|
Key* ksLookupByName | ( | KeySet * | ks, |
const char * | name, | ||
option_t | options | ||
) |
Convenience method to look for a Key contained in ks
that matches name
.
ksLookupByName()
is designed to let you work with entirely pre-loaded KeySets, so instead of kdbGetKey(), key by key, the idea is to fully kdbGetByName() for your application root key and process it all at once with ksLookupByName()
.
This function is very efficient by using binary search. Together with kdbGetByName() which can you load the whole configuration with only some communication to backends you can write very effective but short code for configuration.
If found, ks
internal cursor will be positioned in the matched key (also accessible by ksCurrent()), and a pointer to the Key is returned. If not found, ks
internal cursor will not move, and a NULL pointer is returned. If requested to pop the key, the cursor will be rewinded.
Cascading is done if the first character is a /. This leads to ignoring the prefix like system/ and user/.
This is the way multi user Programs should get there configuration and search after the values. It is guaranteed that more namespaces can be added easily and that all values can be set by admin and user.
It is up to the application to implement a sophisticated cascading algorithm, for e.g. a list of profiles (specific, group and fallback):
Note that for every profile both the user and the system key are searched. The first key found will be used.
When KDB_O_NOALL is set the keyset will be only searched from ksCurrent() to ksTail(). You need to ksRewind() the keyset yourself. ksCurrent() is always set properly after searching a key, so you can go on searching another key after the found key.
When KDB_O_NOALL is not set the cursor will stay untouched and all keys are considered. A much more efficient binary search will be used then.
ks | where to look for |
name | key name you are looking for |
options | some KDB_O_* option bits:
|
Currently no options supported.
KeySet* ksNew | ( | size_t | alloc, |
... | |||
) |
Allocate, initialize and return a new KeySet object.
Objects created with ksNew() must be destroyed with ksDel().
You can use a various long list of parameters to preload the keyset with a list of keys. Either your first and only parameter is 0 or your last parameter must be KEY_END.
So, terminate with ksNew(0, KS_END) or ksNew(20, ..., KS_END)
For most uses
goes ok, the alloc size will be 16, defined in kdbprivate.h. The alloc size will be doubled whenever size reaches alloc size, so it also performs out large keysets.
But if you have any clue how large your keyset may be you should read the next statements.
If you want a keyset with length 15 (because you know of your application that you normally need about 12 up to 15 keys), use:
If you start having 3 keys, and your application needs approximately 200-500 keys, you can use:
Alloc size is 500, the size of the keyset will be 3 after ksNew. This means the keyset will reallocate when appending more than 497 keys.
The main benefit of taking a list of variant length parameters is to be able to have one C-Statement for any possible KeySet.
alloc | gives a hint for the size how many Keys may be stored initially |
Key* ksNext | ( | KeySet * | ks | ) |
Returns the next Key in a KeySet.
KeySets have an internal cursor that can be reset with ksRewind(). Every time ksNext() is called the cursor is incremented and the new current Key is returned.
You'll get a NULL pointer if the key after the end of the KeySet was reached. On subsequent calls of ksNext() it will still return the NULL pointer.
The ks
internal cursor will be changed, so it is not const.
ks | the keyset object to work with |
Key* ksPop | ( | KeySet * | ks | ) |
Remove and return the last key of ks
.
The reference counter will be decremented by one.
The KeySets cursor will not be effected if it did not point to the popped key.
ks
ks
is empty or on NULL pointer ks | KeySet to work with |
int ksRewind | ( | KeySet * | ks | ) |
Rewinds the KeySet internal cursor.
Use it to set the cursor to the beginning of the KeySet. ksCurrent() will then always return NULL afterwards. So you want to ksNext() first.
ks | the keyset object to work with |
int ksSetCursor | ( | KeySet * | ks, |
cursor_t | cursor | ||
) |
Set the KeySet internal cursor.
Use it to set the cursor to a stored position. ksCurrent() will then be the position which you got with.
An invalid cursor will set the keyset to its beginning like ksRewind(). When you set an invalid cursor ksCurrent() is 0 and ksNext() == ksHead().
cursor | the cursor to use |
ks | the keyset object to work with |
Key* ksTail | ( | const KeySet * | ks | ) |
Return the last key in the KeySet.
The KeySets cursor will not be effected.
If ksCurrent()==ksTail() you know you are on the last key. ksNext() will return a NULL pointer afterwards.
ks | the keyset object to work with |
KeySet* ksVNew | ( | size_t | alloc, |
va_list | va | ||
) |
Allocate, initialize and return a new KeySet object.Objects created with ksNew() must be destroyed with ksDel().You can use a various long list of parameters to preload the keyset with a list of keys. Either your first and only parameter is 0 or your last parameter must be KEY_END.So, terminate with ksNew(0, KS_END) or ksNew(20, ..., KS_END)For most uses
goes ok, the alloc size will be 16, defined in kdbprivate.h. The alloc size will be doubled whenever size reaches alloc size, so it also performs out large keysets.But if you have any clue how large your keyset may be you should read the next statements.If you want a keyset with length 15 (because you know of your application that you normally need about 12 up to 15 keys), use:
If you start having 3 keys, and your application needs approximately 200-500 keys, you can use:Alloc size is 500, the size of the keyset will be 3 after ksNew. This means the keyset will reallocate when appending more than 497 keys.The main benefit of taking a list of variant length parameters is to be able to have one C-Statement for any possible KeySet.
alloc | gives a hint for the size how many Keys may be stored initially |
alloc | the allocation size |
va | the list of variable arguments |