Functions | |
KeySet * | ksNew (size_t alloc,...) |
KeySet * | ksDup (const KeySet *source) |
int | ksCopy (KeySet *dest, const KeySet *source) |
int | ksDel (KeySet *ks) |
void | ksSort (KeySet *ks) |
ssize_t | ksGetSize (const KeySet *ks) |
ssize_t | ksAppendKey (KeySet *ks, Key *toAppend) |
ssize_t | ksAppend (KeySet *ks, const KeySet *toAppend) |
Key * | ksPop (KeySet *ks) |
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) |
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) |
A KeySet is a unsorted set of keys.
Terminate with ksNew(0) or ksNew(20, ..., KS_END) This is because there is a list of Key* required and KS_END has the length of (Key*).
It can be implemented in various ways like a linked list or with a dynamically allocated array.
With ksNew() you can create a new KeySet.
You can add keys with ksAppendKey() in the 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:
#include <kdb.h> // create a new keyset with 3 keys // with a hint that about 20 keys will be inside KeySet *myConfig = ksNew(20, keyNew ("user/name1", 0), keyNew ("user/name2", 0), keyNew ("user/name3", 0), KS_END); // append a key in the keyset ksAppendKey(myConfig, keyNew("user/name4", 0)); Key *current; ksRewind(myConfig); while ((current=ksNext(myConfig))!=0) { printf("Key name is %s.\n", keyName (current)); } ksDel (myConfig); // delete keyset and all keys appended
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.
Makes the keyset dirty, see ksSort().
-1 on NULL pointers
ks | the KeySet that will receive the keys | |
toAppend | the KeySet that provides the keys that will be transfered |
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.
The KeySet internal cursor is not moved.
Makes the keyset dirty, see ksSort().
-1 on NULL pointers
ks | KeySet that will receive the key | |
toAppend | Key that will be appended to ks |
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().
int f (KeySet *ks) { KeySet *c = ksNew (20, ..., KS_END); // c receives keys ksCopy (ks, c); // pass the keyset to the caller ksDel (c); } // caller needs to ksDel (ks)
source | has to be an initialized source KeySet or NULL | |
dest | has to be an initialized KeySet where to write the keys |
0 if dest was cleared successfully (source is NULL)
-1 on NULL pointer
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 0 on NULL pointer
kdbMonitorKeys() for a usage example
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 |
-1 on null pointer
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 initializised source KeySet |
0 on NULL pointer
keyDup() for Key :: Basic Methods duplication
cursor_t ksGetCursor | ( | const KeySet * | ks | ) |
Get the KeySet internal cursor.
Use it to get the cursor of the actual position.
cursor_t jump; ksRewind (ks); while ((key = keyNext (ks))!=0) { // now mark this key jump = ksGetCursor(ks); //code.. keyNext (ks); // now browse on // use ksCurrent(ks) to check the keys //code.. // jump back to the position marked before ksSetCursor(ks, jump); }
int f (KeySet *ks) { cursor_t state = ksGetCursor(ks); // work with keyset // now bring the keyset to the state before ksSetCursor (ks, state); }
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 |
an invalid cursor on NULL pointer or after ksRewind()
ssize_t ksGetSize | ( | const KeySet * | ks | ) |
Return the number of keys that ks
contains.
ks | the keyset object to work with |
ks
contains. -1 on NULL pointer
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 |
0 on NULL pointer or empty keyset
ksRewind(), ksCurrent() and ksNext() for iterating over the KeySet :: Class Methods
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.
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/.
if (kdbGet(handle, "user/myapp", myConfig, 0 ) == -1) ErrorHandler ("Could not get Keys"); if (kdbGet(handle, "system/myapp", myConfig, 0 ) == -1) ErrorHandler ("Could not get Keys"); if ((myKey = ksLookup(myConfig, key, 0)) == NULL) ErrorHandler ("Could not Lookup Key");
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 not set the cursor will stay untouched and all keys are considered. A much more efficient binary search will be used then.
So if you change keys, e.g. rename (keySetName()) or remove (keyRemove()) them make sure to sort the keyset with ksSort(). When the keyset is dirty, see ksNeedSort() it will be sorted automatically when needed.
Like in ksPop() the popped key always needs to be keyDel() afterwards, even if it is appended to another keyset.
The more elegant way is to separate the keyset you use for ksLookup() and ksAppendKey():
int f(KeySet *iterator, KeySet *lookup) { KeySet *append = ksNew (ksGetSize(lookup), KS_END); Key *key; Key *current; ksRewind(iterator); while (current=ksNext(iterator)) { key = ksLookup (lookup, current, KDB_O_POP); // do something... ksAppendKey(append, key); // now append it to append, not lookup! keyDel (key); // make sure to ALWAYS delete poped keys. } ksAppend(lookup, append); // now lookup needs to be sorted only once, append never ksDel (append); }
ks | where to look for | |
key | the key object you are looking for | |
options | some KDB_O_* option bits:
|
0 on NULL pointers
ksCurrent(), ksRewind(), ksNext() for iterating over a KeySet :: Class Methods
ksSort() to understand how KeySet :: Class Methods sort themself
Key* ksLookupByName | ( | KeySet * | ks, | |
const char * | name, | |||
option_t | options | |||
) |
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 (kdbGetByName(handle, "/sw/myapp/current", myConfig, 0 ) == -1) ErrorHandler ("Could not get Keys"); if ((myKey = ksLookupByName (myConfig, "/myapp/current/key", 0)) == NULL) ErrorHandler ("Could not Lookup Key");
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 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:
|
0 on NULL pointers
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.
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 14 keys), use:
If you start having 3 keys, and your application needs approximately 200-500 keys, you can use:
KeySet * config = ksNew (500, keyNew ("user/sw/app/fixedConfiguration/key1", KEY_SWITCH_VALUE, "value1", 0), keyNew ("user/sw/app/fixedConfiguration/key2", KEY_SWITCH_VALUE, "value2", 0), keyNew ("user/sw/app/fixedConfiguration/key3", KEY_SWITCH_VALUE, "value3", 0), KS_END); // don't forget the KS_END at the end! // work with it ksDel (config);
The main benefit of taking a list of variant length parameters is to be able to have one C-Statement for any possible KeySet.
Due to ABI compatibility, the KeySet
structure is only declared in kdb.h, and not defined. So you can only declare pointers
to KeySets
in your program. See http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html#AEN135
ksDup() to duplicate an existing KeySet :: Class Methods
alloc | gives a hint for the size how many Keys may be stored initially |
0 on memory error
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. It will set the cursor to the beginning of the KeySet and the next time the first key is returned.
The ks
internal cursor will be changed, so it is not const.
ks | the keyset object to work with |
0 when the end is reached
0 on NULL pointer
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.
ks1=ksNew(0); ks2=ksNew(0); k1=keyNew(0); // ref counter 0 ksAppendKey(ks1, k1); // ref counter 1 ksAppendKey(ks2, k1); // ref counter 2 k1=ksPop (ks1); // ref counter 1 k1=ksPop (ks2); // ref counter 0, like after keyNew() ksAppendKey(ks1, k1); // ref counter 1 ksDel (ks1); // key is deleted too ksDel (ks2); *
ks
NULL if ks
is empty or on NULL pointer
ks | KeySet to work with |
commandList() for an example
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.
ksRewind (ks); while ((key = keyNext (ks))!=0) {}
ks | the keyset object to work with |
-1 on NULL pointer
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.
cursor_t cursor; .. // key now in any position here cursor = ksGetCursor (ks); while ((key = keyNext (ks))!=0) {} ksSetCursor (ks, cursor); // reset state ksCurrent(ks); // in same position as before
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 |
1 otherwise
-1 on NULL pointer
void ksSort | ( | KeySet * | ks | ) |
Sorts a KeySet alphabetically by Key name.
You need ksSort() only in few cases directly.
KeySet *ks = ksNew(0); kdbGet(h, ks, k, 0); // ksPop(), ksAppend() and ksAppendKey() allowed here ksLookup(ks, s, 0); // you dont need to sort ks
This is because the KeySet tracks if it needs to be sorted and ksLookup() will sort when needed.
To achieve that you can pass option_t::KDB_O_SORT to kdbGet() and kdbSet(). Then you will receive a already sorted keyset over which you can iterate.
KeySet *ks = ksNew(0); kdbGet(h, ks, k, KDB_O_SORT); // no changes to keyset allowed ksRewind(ks); // now you can iterate over a sorted keyset
Its of course also possible to use ksLookup() once, because it will sort the keyset too.
manually
sort all
keysets where the key was before using ksLookup() (otherwise ksLookup() won't find that keys), kdbGet() or kdbSet() methods.
It won't be done if you just iterate over the keyset, so you might use a ksLookup() or ksSort() first. ksLookup() will be more efficient in that case, because it will only sort when needed. Don't pass KDB_O_NOALL (it will deactivate the sorting feature), see ksLookup() for more information.
ks | KeySet to be sorted |
keySetName(), keySetBaseName(), keyAddBaseName() and keyRemove() for all methods which change the sorting state where the KeySet :: Class Methods can't track the change.
ksAppend(), ksAppendKey(), ksPop() for all methods which make a KeySet :: Class Methods dirty.
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 |
0 on NULL pointer or empty keyset
ksRewind(), ksCurrent() and ksNext() for iterating over the KeySet :: Class Methods