|
DS API
REFERENCE
DQUESTIONS/PROBLEMS/BUGS:
michaelcollins@ivorycity.com
DOWNLOAD:
xwspc-0.0.2.tar.gz
FUNCTION SUMMARY:
dsany general functions
Setting dsany
variable type
|
Longhand |
Shorthand |
| void |
dsany_setchar( dsany ds, char chr) |
dsetC( dsany ds, char chr) |
| void |
dsany_setuchar( dsany ds, unsigned char uchr ) |
dsetUC( dsany ds, unsigned char uchr ) |
| void |
dsany_setuint( dsany ds, unsigned int
uint ) |
dsetUI( dsany ds, unsigned int uint ) |
| void |
dsany_setint( dsany ds, int sint ) |
dsetI( dsany ds, int sint ) |
| void |
dsany_setfloat( dsany ds, float flt ) |
dsetF( dsany ds, float flt ) |
| void |
dsany_setstring( dsany ds, char* string ) |
dsetS( dsany ds, char* string ) |
| void |
dsany_setvoid( dsany ds, void* vptr ) |
dsetV( dsany ds, void* vptr ) |
| void |
dsany_setdsarray( dsany ds, dsarray* lowlevelarr ) *Low
Level |
dsetLLA( dsany ds, dsarray* lowlevelarr ) |
| void |
dsany_setdsanyarray( dsany ds,
dsanyarray* dsanyarr ) |
dsetA( dsany ds, dsanyarray* dsanyarr ) |
| void |
dsany_setdstable( dsany ds, dstable* dsanytable ) |
dsetT( dsany ds, dstable* dsanytable ) |
Testing dsany
variable type
Getting the
value of a dsany variable
dsarray
functions (Low Level -- You usually won't use this.)
|
|
| dsarray* |
dsarray_new( int nElements, int elementSize ) |
| int |
dsarray_delete(
dsarray* a ) |
| int |
dsarray_clear ( dsarray* a ) |
| int |
dsarray_push ( dsarray* a, void* ptrToYourData ) |
| int |
dsarray_pop ( dsarray* a, void* ptrToYourContainer
) |
| int |
dsarray_unshift ( dsarray* a, void*
ptrToYourData ) |
| int |
dsarray_set (
dsarray* a, int index, void*
ptrToYourData ) |
| int |
dsarray_get ( dsarray* a, int index, void*
ptrToYourContainer ) |
| int |
dsarray_getIndexOf ( dsarray* a, void*
pDataToMatch,
int startAtIndex ) |
| int |
dsarray_spliceOut ( dsarray* a, int
startIndex, int
endIndex ) |
| int |
dsarray_foreachcall ( dsarray* a,
dsarray_callback
yourCallback, void* yourUserData ) |
| int |
dsarray_getLength ( dsarray* a ) |
dsanyarray
functions (Arrays of dsany type variables)
|
|
| dsanyarray* |
dsanyarray_new ( int nElements) |
| int |
dsanyarray_delete ( dsanyarray* a, int
deleteChildren ) |
| int |
dsanyarray_clear ( dsanyarray* a ) |
| int |
dsanyarray_push ( dsanyarray* a, dsany ds ) |
| int |
dsanyarray_pop ( dsanyarray* a, dsany* ds ) |
| int |
dsanyarray_unshift ( dsanyarray* a, dsany*
ds ) |
| int |
dsanyarray_set ( dsanyarray* a, int index,
dsany ds ) |
| int |
dsanyarray_get ( dsanyarray* a, int index,
dsany* ds ) |
| int |
dsanyarray_getIndexOf ( dsanyarray* a,
dsany dsanyToMatch, int startAtIndex ) |
| int |
dsanyarray_spliceOut ( dsanyarray* a, int
startIndex,
int endIndex ) |
| int |
dsanyarray_foreachcall ( dsanyarray* a,
dsarray_callback
yourCallback, void* yourUserData ) |
| int |
dsanyarray_getLength ( dsanyarray* a ) |
dstable
functions (key-value storage for dsany type variables)
|
|
| dstable* |
dstable_new (int approxEntries ) |
| int |
dstable_add ( dstable* t, const char* key, dsany
value ) |
| int |
dstable_set ( dstable* t, const char* key, dsany
value ) |
| int |
dstable_get ( dstable* t, const char* key, dsany*
value
) |
| int |
dstable_foreach ( dstable* t,
dstable_iterator* iter,
char** key, dsany* value ) |
| int |
dstable_clear ( dstable* t, int destroy_values ) |
| int |
dstable_delete ( dstable* t, int destroy_values
) |
| int |
dstable_getlength ( dstable* t ) |
| void |
dstable_setnocasekeys ( dstable* t ) |
| void |
dstable_iterator_init ( struct
dstable_iterator*
iterator ) |
OVERVIEW:
So what do we have
here? The data structures (ds) API is the C interface for dynamic data
structures used with mod_perlservice. Of course Perl uses dynamic data
structures, so we need to have a way to deal with them in C too!
The dsany type can
be any type of data structure, makes sense huh? A dsany type is
basically equivalent to the Perl scalar type, ie a number, string, or
reference (arrays, and tables).
FUNCTION
DOCUMENTATION
dsany
dsmake( const char* dsdescription )
|
Allocate and populate a new dsany variable. This is the highest level
way to create a very complex data structure. It basically compiles the
description into the corresponding entry. Don't be fooled though, this
is very fast at runtime! It's hardly slower than constructing it by
hand and much more readable!
USAGE
dsany mydsany = dsmake("[ { mystr:'hello',myint:8192},123.321,'some
text']");
ARGUMENTS
| char* dsdescription |
The dsdescription argument constructs, allocates, and
populates a dynamic data structure described by the string. For
instance, the above example creates a dsanyarray with 3 elements: a
table, a number, and a string. The table has 2 key value pairs. mystr
keys for the string 'hello' and myint keys for 8192.
You may nest these data structures as deeply as you
wish. The below table describes the format for each type.
| Integer Type |
8192 |
| Float Type |
11.110 |
| String Type |
'hello' (enclosed by single quote ) |
| Array Type |
[item1, item2, item3,...] |
| Table Type |
{ key1: item1, key2: item2, key3, item3, ...} |
Of course table and array items may be any of the above
types including arrays and tables for nesting.
|
| int
dsquery( dsany
toquery, const char* query, dsany* returnval ) |
This function is the highest level and easiest way to retrieve a
variable in a complex data structure. It is dsmake's counterpart.
Again, it's very fast, so to you performance mongers: don't be afraid
to use it! It queries the 'dsany toquery' and stores the return value
in retval. It returns 1 if the variable can be found, 0 if it cannot.
USAGE
dsany myvar;
dsany myds = dsmake( "{ keyofmyarray: [ { keyofmyvar:200, blah:'hi' }
], someotherkey:18 }" );
if( dsquery( myds, "thekeyofmyarray.[0].thekeyofmyvar", &myvar) ){
printf("myvar %d",dsI(myvar); }
else { printf("not found\n"); }
if( dsquery( myds, "thekeyofmyarray.[0].blah", &myvar) ){
printf("myvar %s",dsS(myvar); }
else { printf("not found\n"); }
if( dsquery( myds, "someotherkey", &myvar) ){ printf("myvar
%d",dsI(myvar); }
else { printf("not found\n"); }
dsdelete(myds,1);
ARGUMENTS
| dsany toquery |
The dsany you want to query. This will be a dstable or
dsanyarray, otherwise why would you want to query it? |
| const char* query |
The query string. Queries are constructed as follows:
Arrays are queried using [elementid]
Tables are queried using the key of your element
Put them all with '.' (period) in between and you've got yourself a
query.
So, "[8].foo" queries a dsanyarray's element 8, which is a table with a
key 'foo'. We've stored foo's value in returnval.
|
| dsany* returnval |
The variable where the result is stored. Remember to
pass the POINTER to it! |
| void
dsdump( dsany
dumpme ) |
Recursively prints the data structure to stdout. Good for debugging.
USAGE
dsdump( mydsany );
ARGUMENTS
| dsany dumpme |
The dsany you want to print out. |
| void
dsdelete( dsany
delme, int freechildren ) |
dstables, dsanyarrays and dsarrays are all dynamically allocated. This
function frees their dynamic memory and sends them to that heap in data
structure heaven. Optionally, you may request it to delete the children
recursively. You will usually want to do that. Be careful though not to
delete variables that are not dynamically allocated! Don't attempt to
delete constant strings for instance, that would be bad.
USAGE
dsdelete( myComplexDs, 1);
dsdelete( mySingleLevelDs, 0);
ARGUMENTS
| dsany delme |
The datastructure you want scrubbed from existence. |
| int freechildren |
Whether it should recursively commit datastructuricide. |
| void
dsglobal_setdestructor( int usertype, dsdestructor fcn ) |
This is an advanced user feature. You can extend the dsapi to your own
data structures by defining your own user types. Internally the dsapi
uses negative numbers for dsany types, so you can use positive numbers
greater than 0 for your custom types. However, you may need to have
automatic destruction of your custom type via dsdelete. Here just tell
the dsapi what number your custom type is and pass your destructor
function and it will automatically call your custom destructor when
it's elimination time.
USAGE
#define MYTYPE 1
struct mytype
{
int a;
int b;
};
void mytype_destroy(void* yourtype, int freechildren )
{
free(yourtype);
}
int main()
{
struct mytype* m = malloc( sizeof(struct mytype) );
dsany d;
dsglobal_setdestructor( MYTYPE, mytype_destroy);
d.type = MYTYPE;
d.any.voidptr = m;
dsdelete( d, 0 ); /* your destructor will be called */
}
ARGUMENTS
| int
usertype |
Your user defined type
number. Anything > 0 is okay to define.
|
dsdestructor fcn
|
Your custom destructor
function in the format: void mydestructor( void* mytype, int destroy
children )
|
| void
dsany_set*(dsany d, X ) or
dset*(dsany d, X ) |
Set
the dsany to a specified value and type. This does not allocate
anything! What you pass is what you store. The dsany is not passed by
pointer.
USAGE
dsany myds;
char* str = "Hello!";
dsetI(myds,
1492 ); /*myds is an int type and contains 1492 */
dsetS(myds, str ); /*myds is a string type and contains the
pointer to "Hello!". Beware, 'str' is local!! */
ARGUMENTS
dsany d
|
The dsany you want to set.
|
X
|
The thing you want to set
it to.
|
| int
dsany_is*( dsany ds ) |
Test to see if a dsany is of a specific type. Returns true if so, false
if not.
USAGE
if( dsisI(myds) ) {.. do int
stuff ..}
else if ( dsisS( myds ) ) { .. do string stuff .. }
else if ( dsisT( myds ) ) { .. do table stuff .. }
ARGUMENTS
dsany ds
The dsany you want to test
|
This set of functions retrieves the value stored in the dsany.
USAGE
int myi = dsI(mydsany1);
dstable* t = dsT(mydsany2);
| dsarray* dsarray_new( int nElements, int
elementSize ) |
The dsarray* functions are a lower lever array interface, you will
usually want to use dsanyarray* which are arrays of dsany type
variables. dsarray's can be arrays of any SIZE object as opposed to
dsany arrays which can be any type of object. They grow automatically
to any size, though they are not implemented using linked lists -- an
actual data buffer is used. This means that your array will
indeed be the size of your greatest element index. This approach makes
setting and getting elements very fast, but operations like splicing
are slow. Initialize the size of your array to the number
elements you think you're going to need to maximize performance.
When you set an element in the array, you're actually copying all the
data into the array, not a pointer. So the array allocates all the
storage you need.
USAGE
dsarray* a1 = dsarray_new( 1024, sizeof(int) ); /* creates a 1024
element dynamic array of integers */
dsarray* a2 = dsarray_new( 24, sizeof( struct mystruct ) ); /* creates
a 24 element dynamic array of 'struct mystruct' */
ARGUMENTS
int nElements
|
The number of initial
elements you want in your array. The array can grow beyond this, but
its your best guess.
|
int elementSize
|
The size of each element
in your array. So if you wanted to store structures that are 18 bites
wide, you would say 18 here. An array with 10 elements would take up
180 bytes of space.
|
| int dsarray_delete( dsarray* a ) |
Free all resources associated with this array. Returns 1 if okay, else
0.
| int dsarray_clear ( dsarray* a ) |
This function zero's out the array, deleting all the data. It's a born
again array. The array length is set to 0. Returns 1 if okay else 0.
| int dsarray_push ( dsarray* a, void*
ptrToYourData ) |
Append and copy the data pointed to by ptrToYourData to
the end of the array. Remember, the size of your data must
be the element SIZE you specified when you created the array. Returns 1 if okay else 0.
USAGE
dsarray* a1 = dsarray_new( 8, sizeof(int) );
int myint = 3;
dsarray_push( a1, &myint );
| int dsarray_pop ( dsarray* a,
void* ptrToYourContainer ) |
Pop the last element off the end of the array and copy it into
ptrToYourContainer. Make sure your container is big enough! Returns 1 if okay else 0.
USAGE
dsarray* a1 = dsarray_new( 8, sizeof(double) );
double d1 = 3.14;
double d2;
dsarray_push( a1, &d1 );
dsarray_pop( a1, &d2 );
| int dsarray_unshift ( dsarray* a, void*
ptrToYourData ) |
Remove the first element from the front of the array and copy it into
ptrToYourData. This operation may be slow on large arrays. Returns 1 if okay
else 0.
| int dsarray_set ( dsarray* a, int index, void*
ptrToYourData ) |
Copies the contents of ptrToYourData to the 'index' in array
'a'. Returns 1 if okay else 0.
USAGE
double md = 32.221
dsarray_set(mya, 32, &md ); /* sets element 32 to 32.221 */
| int dsarray_get ( dsarray* a, int index, void*
ptrToYourContainer ) |
Copies the contents of the data at the specified index into
ptrToYourContainer. Returns 1 if okay
else 0.
USAGE
double md;
dsarray_get(mya, 32, &md ); /* sets md to the double at index 32 */
| int dsarray_getIndexOf ( dsarray* a,
void* pDataToMatch,
int startAtIndex ) |
Returns the index in the array
of first intstance of the contents pointed to by pDataToMatch. It
starts searching at index 'startAtIndex'. If there is no match, it
returns -1.
| int dsarray_spliceOut ( dsarray* a, int
startIndex, int
endIndex ) |
Removes elements from the
array. It removes elements from startIndex up to and including
endIndex, and the remaining elements are spliced together.
Returns 1 if okay
else 0.
| int dsarray_foreachcall ( dsarray* a,
dsarray_callback
yourCallback, void* yourUserData ) |
This is one way to interate
through every element of the array.
For every element in the array, 'yourCallback' function of the form:
int mycallback(dsarray*
a, void* yourUserData, void* ptrToElement)
is called. Your callback must
return either DSARRAY_CALLBACK_STOP, if you want to stop iterating or
DSARRAY_CALLBACK_CONTINUE if otherwise. You may place anything you want
in 'yourUserData' for use in the callback.
USAGE
int
onElement(dsarray* a, void*
yourUserData, void* ptrToElement)
{
int* pcount = (int*) yourUserData;
char** ppchar = (char**) ptrToElement;
if( *pcount>10
) return DSARRAY_CALLBACK_STOP;
printf(*ppchar);
*pcount++;
return DSARRAY_CALLBACK_CONTINUE;
}
.
.
.
int count = 0;
dsarray_foreachcall( mycharptrarr, onElement, &count );
| int dsarray_getLength ( dsarray* a ) |
Returns the number of items in
the array.
| dsanyarray* dsanyarray_new ( int
nElements ) |
The dsany array is an array of
dsany type variables. This is the array you will most often use. For
instance, the arrays created with dsmake are dsany arrays. This
function creates a new dsany array with a projected length of
nElements. This entire set of functions inherits from dsarray, but
provides a convenience interface for specifically dealing with dsany's.
| int dsanyarray_delete ( dsanyarray* a,
int deleteChildren ) |
Free all resources associated
with this array. If deleteChildren is 1, call the appropriate dsany
destructor recursively for all the child dsany's. Returns 1 if okay,
else 0.
| int dsanyarray_clear ( dsarray* a ) |
This function zero's out the
array, deleting all the data. It's a born again array. The array length
is reset to 0. Returns 1 if okay else 0.
| int dsanyarray_push ( dsanyarray*
a, dsany ds ) |
Append and copy the dsany to the end of the
array. Notice the dsany is passed by
VALUE. Returns 1 if okay else 0.
USAGE
dsany da = dsmake("[1,2,3,4]");
dsany di;
dsetI(di,5 );
dsanyarray_push( dsA(a1), di ); /* the array now reads [1,2,3,4,5] */
| int dsanyarray_pop ( dsanyarray* a, dsany*
ds ) |
Pop the last element off the end of the array and copy it into
ds. Make sure you pass the pointer to the dsany! Returns 1 if okay else 0.
USAGE
dsany da = dsmake("[ 1.1, 2.2, 3.3, 4.4 ]");
dsany f1;
dsanyarray_pop( a1, &f1 ); /* f1 is a float of value 4.4 and
the array is [ 1.1, 2.2, 3.3 ] */
| int dsanyarray_unshift ( dsanyarray* a,
dsany* ds ) |
Remove the first element from the front of the array and copy
it into ds. Its just like the pop, but from the front of the array.
This operation may be slow on large arrays. Returns 1 if
okay else 0.
| int dsanyarray_set ( dsanyarray* a, int
index, dsany ds ) |
Sets the index 'index' to ds. Pass by VALUE! Returns 1 if okay else 0.
USAGE
dsany md;
dsany mi;
dsetF(md, 32.221 );
dsetI( mi, 200 );
dsanyarray_set(mya, 32, md ); /* sets element 32 to md */
dsanyarray_set(mya, 33, mi
); /* sets element 32 to mi */
| int dsanyarray_get ( dsanyarray* a, int
index, dsany* ds ) |
Copies the dsany at 'index' into 'ds' . Returns 1 if okay else 0.
USAGE
dsany md;
dsetF(32.221);
dsanyarray_set(mya, 32, &md ); /* sets element 32 to 32.221 */
| int dsanyarray_getIndexOf (
dsanyarray* a, dsany dsanyToMatch, int startAtIndex ) |
Returns the index in the
array of first
intstance of the contents that match 'dsanyToMatch'. It starts
searching at index 'startAtIndex'. If there is no match, it returns -1.
| int dsanyarray_spliceOut ( dsanyarray*
a, int startIndex,
int endIndex ) |
Removes elements from the array.
It
removes elements from startIndex up to and including endIndex, and the
remaining elements are spliced together.
Returns 1 if okay
else 0.
int dsanyarray_foreachcall (
dsanyarray* a, dsarray_callback
yourCallback, void* yourUserData )
|
This is one way to interate
through every element of the array.
For every element in the array, 'yourCallback' function of the form:
int mycallback(dsarray*
a, void* yourUserData, void* ptrToElement)
is called. Your callback must
return
either DSARRAY_CALLBACK_STOP, if you want to stop iterating or
DSARRAY_CALLBACK_CONTINUE if otherwise. You may place anything you want
in 'yourUserData' for use in the callback.
USAGE
int
onElement(dsarray* a, void*
yourUserData, dsany* ptrToDsAny)
{
int* pcount = (int*) yourUserData;
dsany d = *ptrToDsAny;
if( *pcount>10
) return DSARRAY_CALLBACK_STOP;
printf( dsS(d) );
*pcount++;
return DSARRAY_CALLBACK_CONTINUE;
}
.
.
.
int count = 0;
dsanyarray_foreachcall( mycharptrarr, onElement, &count );
| int dsanyarray_getLength (
dsanyarray* a ) |
Returns the number of items in
the array.
| dstable* dstable_new (int approxEntries ) |
Creates a new key-value table of dsany type variables.
'approxEntries' is your best guess of how many key-value pairs you will
need in your table: this is done for efficiency reasons and you may
safely have more or fewer pairs.
| int
dstable_add ( dstable* t, const char* key,
dsany value ) |
Adds a new key-value pair to the table. Returns 1 if OK, else
0.
USAGE:
dstable* t = dstable_new(8);
dsany n;
dsetI( 12 );
dstable_add( t, "mykey", n ); /* adds a dsany value 12 to the
table */
| int dstable_set (
dstable* t, const char* key, dsany value ) |
This changes the value of the
dsany. If the key-value pair doesn't exist, this behaves exactly as
dstable_add. Returns 1 if OK, else 0.
| int dstable_get ( dstable* t, const char* key,
dsany* value
) |
Gets the dsany value associated with 'key'. Returns 0 if key
doesn't exist, else 1 means OK.
USAGE:
dsany dt = dsmake("{ hello: 'world' , foo: 'bar', left:
'right' }");
dsany dstr;
dstable_get( dsT(dt), "foo", &dstr );
printf( dsS(dstr) ); /* prints bar */
| int dstable_foreach ( dstable* t,
dstable_iterator* iter,
char** key, dsany* value ) |
This function iterates through
each key-value pair in the table one by one. Once you initialize the
dstable_iterator, call this function each time you want to get a new
key-value pair. It returns 0 if you have seen all the pairs, 1 if some
remain.
USAGE:
dsany dt = dsmake("{ hello: 'world' , foo: 'bar', left:
'right' }");
char* key;
dsany value;
dstable_iterator it;
dstable_iterator_init ( &it
);
while( dstable_foreach(
dsT(dt), &it, &key, &value ) )
{
printf("key %s value %s\n", key, dsS(value) );
}
|
int
dstable_clear ( dstable* t, int destroy_children )
|
This function clears out all
the existing key-value pairs in the table though it does not free the
table itself. You would want to use this when you want a clean, fresh
table but don't want to deallocate an old table and reallocate a new
one. Pass a '1' for destroy values if you want to call the destructors
(if any) of the values in the table.
| int dstable_delete ( dstable* t, int
destroy_children ) |
Deletes and frees the table's
resources. Optionally recursively calls the destructors of the dsany
values contained in the table.
| int dstable_getlength ( dstable* t ) |
Returns the number of key-value
pairs stored in the table.
| int dstable_setnocasekeys ( dstable*
t ) |
Tells the dstable to ignore
case in the table keys.
USAGE:
dsany dstr;
dsany dt = dsmake("{ hello: 'world' , foo: 'bar', left: 'right'
}");
dstable_setnocasekeys( dsT( dt ) );
dstable_get( dsT(dt), "foo", &dstr );
printf( dsS(dstr) ); /* prints bar */
dstable_get( dsT(dt), "FOo", &dstr );
printf( dsS(dstr) ); /* prints bar */
|