Files
sics/hipadaba.c
koennecke a5c2da6acf - Switched motor to hdb
- Changes to Hipadaba
- Added project to histogram memory code
- Started regression testing code
- Added hill climbing as optimization method to optimise
2006-08-16 14:13:05 +00:00

821 lines
23 KiB
C

/*-------------------------------------------------------------------------
The hierarchical parameter database code. For more information, see
hipadaba.h
copyright: GPL
Mark Koennecke, June 2006
---------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#include "hipadaba.h"
#define ABS(x) (x < 0 ? -(x) : (x))
#define HDBMAGICK 77119900
/*================== internal functions ===================================*/
void DeleteCallbackChain(pHdbCallback root){
pHdbCallback current = NULL, thisEntry;
current = root;
while(current != NULL){
if(current->killFunc != NULL){
current->killFunc(current->userData);
}
thisEntry = current;
current = (pHdbCallback)current->next;
free(thisEntry);
}
}
/*-----------------------------------------------------------------------*/
static void DeleteNodeData(pHdb node){
pHdb tmp = NULL;
if(node == NULL){
return;
}
DeleteCallbackChain(node->writeCallbacks);
DeleteCallbackChain(node->updateCallbacks);
DeleteCallbackChain(node->readCallbacks);
if(node->name != NULL){
free(node->name);
}
ReleaseHdbValue(&node->value);
node->magic = 000000;
while(node->child != NULL){
tmp = node->child;
node->child = node->child->next;
DeleteNodeData(tmp);
}
free(node);
}
/*------------------------------------------------------------------------*/
void RemoveHdbNodeFromParent(pHdb node){
pHdb parent = NULL;
pHdb current = NULL;
parent = node->mama;
if(parent != NULL){
if(parent->child == node){
parent->child = node->next;
return;
}
current = parent->child;
while(current->next != node){
current = current->next;
}
current->next = current->next->next;
}
}
/*-----------------------------------------------------------------------*/
static void RemoveCallbackNode(pHdbCallback victim){
if(victim->previous != NULL) {
victim->previous->next = victim->next;
}
if(victim->next != NULL){
victim->next->previous = victim->previous;
}
if(victim->killFunc != NULL){
victim->killFunc(victim->userData);
}
free(victim);
}
/*-----------------------------------------------------------------------
* This code is ugly: the problem is fixing up the start of the chain.
* Think about it and improve
* ----------------------------------------------------------------------*/
static pHdbCallback DeleteForID(pHdbCallback root, int id){
pHdbCallback current = root;
pHdbCallback tmp = NULL;
pHdbCallback result = NULL;
if(root == NULL){
return NULL;
}
/*
* delete at the start of the chain
*/
result = root;
while(result->id == id){
tmp = result;
result = result->next;
RemoveCallbackNode(tmp);
if(result == NULL){
return NULL;
}
}
/*
* delete nodes in the middle of the chain
*/
current = result;
while(current != NULL){
if(current->id == id){
tmp = current;
current = (pHdbCallback)current->next;
RemoveCallbackNode(tmp);
} else {
current = (pHdbCallback)current->next;
}
}
return result;
}
/*-----------------------------------------------------------------------*/
static pHdbCallback DeleteForInternalID(pHdbCallback root, int id){
pHdbCallback current = root;
pHdbCallback tmp = NULL;
pHdbCallback result = NULL;
if(root == NULL){
return NULL;
}
/*
* delete at the start of the chain
*/
result = root;
while(result->internalID == id){
tmp = result;
result = result->next;
if(tmp->killFunc != NULL){
tmp->killFunc(tmp->userData);
}
free(tmp);
if(result == NULL){
return NULL;
}
}
/*
* delete nodes in the middle of the chain
*/
current = result;
while(current != NULL){
if(current->internalID == id){
if(current->next != NULL){
current->next->previous = current->previous;
}
if(current->previous != NULL){
current->previous->next = current->next;
}
tmp = current;
current = (pHdbCallback)current->next;
if(tmp->killFunc != NULL){
tmp->killFunc(tmp->userData);
}
free(tmp);
} else {
current = (pHdbCallback)current->next;
}
}
return result;
}
/*-------------------------------------------------------------------------*/
static int InvokeCallbackChain(pHdbCallback root, pHdb node,
void *callData, hdbValue v){
pHdbCallback current = root;
int status;
while(current != NULL){
status = current->userCallback(current->userData,callData,
node,v);
if(status != 1){
return status;
}
current = current->next;
}
return 1;
}
/*----------------------------------------------------------------------*/
char *hdbTrim(char *str)
{
char *ibuf = str, *obuf = str;
int i = 0, cnt = 0;
/*
** Trap NULL
*/
if (str)
{
/*
** Remove leading spaces (from RMLEAD.C)
*/
for (ibuf = str; *ibuf && isspace(*ibuf); ++ibuf)
;
if (str != ibuf)
memmove(str, ibuf, ibuf - str);
/*
** Collapse embedded spaces (from LV1WS.C)
*/
while (*ibuf)
{
if (isspace(*ibuf) && cnt)
ibuf++;
else
{
if (!isspace(*ibuf))
cnt = 0;
else
{
*ibuf = ' ';
cnt = 1;
}
obuf[i++] = *ibuf++;
}
}
obuf[i] = '\0';
/*
** Remove trailing spaces (from RMTRAIL.C)
*/
while (--i >= 0)
{
if (!isspace(obuf[i]))
break;
}
obuf[++i] = '\0';
}
return str;
}
/*------------------------------------------------------------------------*/
static pHdb locateChild(pHdb root, char *name){
pHdb current = NULL;
current = root->child;
while(current != NULL){
if(strcmp(current->name,name) == 0){
return current;
}
current = current->next;
}
return NULL;
}
/*================= data functions ========================================*/
hdbValue makeHdbValue(int datatype, int length){
hdbValue val;
memset(&val,0,sizeof(hdbValue));
val.dataType = datatype;
switch(datatype){
case HIPINTAR:
case HIPINTVARAR:
val.arrayLength = length;
val.v.intArray = malloc(length*sizeof(int));
if(val.v.intArray != NULL){
memset(val.v.intArray,0,length*sizeof(int));
}
break;
case HIPFLOATAR:
case HIPFLOATVARAR:
val.arrayLength = length;
val.v.floatArray = malloc(length*sizeof(double));
if(val.v.floatArray != NULL){
memset(val.v.floatArray,0,length*sizeof(double));
}
break;
case HIPTEXT:
val.v.text = strdup("UNKNOWN");
val.arrayLength = length;
break;
}
return val;
}
/*-------------------------------------------------------------------------*/
hdbValue MakeHdbInt(int initValue){
hdbValue result;
result.dataType = HIPINT;
result.v.intValue = initValue;
return result;
}
/*-------------------------------------------------------------------------*/
hdbValue MakeHdbFloat(double initValue){
hdbValue result;
result.dataType = HIPFLOAT;
result.v.doubleValue = initValue;
return result;
}
/*-------------------------------------------------------------------------*/
hdbValue MakeHdbText(char *initText){
hdbValue result;
result.dataType = HIPTEXT;
result.v.text = initText;
result.arrayLength = strlen(initText);
return result;
}
/*-------------------------------------------------------------------------*/
hdbValue MakeHdbIntArray(int length, int *data){
hdbValue result;
result.dataType = HIPINTAR;
result.arrayLength = length;
result.v.intArray = data;
return result;
}
/*-------------------------------------------------------------------------*/
hdbValue MakeHdbFloatArrray(int length, double *data){
hdbValue result;
result.dataType = HIPFLOATAR;
result.arrayLength = length;
result.v.floatArray = data;
return result;
}
/*-------------------------------------------------------------------------*/
void ReleaseHdbValue(hdbValue *v){
switch(v->dataType){
case HIPTEXT:
if(v->v.text != NULL){
free(v->v.text);
}
break;
case HIPINTAR:
case HIPINTVARAR:
if(v->v.intArray != NULL){
free(v->v.intArray);
}
break;
case HIPFLOATAR:
case HIPFLOATVARAR:
if(v->v.floatArray != NULL){
free(v->v.floatArray);
}
break;
}
}
/*------------------------------------------------------------------------*/
int compareHdbValue(hdbValue v1, hdbValue v2){
int i;
if(v1.dataType != v2.dataType){
return 0;
}
switch(v1.dataType){
case HIPNONE:
return 0;
break;
case HIPINT:
if(v1.v.intValue == v2.v.intValue){
return 1;
} else {
return 0;
}
break;
case HIPFLOAT:
if(ABS(v1.v.doubleValue - v2.v.doubleValue) < .01){
return 1;
} else {
return 0;
}
break;
case HIPTEXT:
if(strcmp(v1.v.text,v2.v.text) == 0){
return 1;
} else {
return 0;
}
break;
case HIPINTAR:
case HIPINTVARAR:
if(v1.arrayLength != v2.arrayLength){
return 0;
}
for(i = 0; i < v1.arrayLength; i++){
if(v1.v.intArray[i] != v2.v.intArray[i]){
return 0;
}
}
return 1;
break;
case HIPFLOATAR:
case HIPFLOATVARAR:
if(v1.arrayLength != v2.arrayLength){
return 0;
}
for(i = 0; i < v1.arrayLength; i++){
if(ABS(v1.v.floatArray[i] - v2.v.floatArray[i]) > .01){
return 0;
}
}
return 1;
break;
default:
assert(0);
break;
}
return 0;
}
/*-------------------------------------------------------------------------*/
int cloneHdbValue(hdbValue *source, hdbValue *clone){
memset(clone,0,sizeof(hdbValue));
clone->dataType = source->dataType;
return copyHdbValue(source, clone);
}
/*================= node functions ========================================*/
pHdb MakeHipadabaNode(char *name, int datatype, int length){
pHdb pNew = NULL;
pNew = malloc(sizeof(Hdb));
if(pNew == NULL){
return NULL;
}
memset(pNew,0,sizeof(Hdb));
pNew->magic = HDBMAGICK;
pNew->name = strdup(name);
pNew->value.dataType = datatype;
switch(datatype){
case HIPINTAR:
case HIPINTVARAR:
pNew->value.arrayLength = length;
pNew->value.v.intArray = malloc(length*sizeof(int));
if(pNew->value.v.intArray == NULL){
return NULL;
}
memset(pNew->value.v.intArray,0,length*sizeof(int));
break;
case HIPFLOATAR:
case HIPFLOATVARAR:
pNew->value.arrayLength = length;
pNew->value.v.floatArray = malloc(length*sizeof(double));
if(pNew->value.v.floatArray == NULL){
return NULL;
}
memset(pNew->value.v.floatArray,0,length*sizeof(double));
break;
case HIPTEXT:
pNew->value.arrayLength = length;
pNew->value.v.text = strdup("UNKNOWN");
break;
}
return pNew;
}
/*-------------------------------------------------------------------------*/
void AddHipadabaChild(pHdb parent, pHdb child){
pHdb current = NULL, prev = NULL;
assert(parent != NULL);
if(child == NULL){
return;
}
current = parent->child;
child->mama = parent;
if(current == NULL){
parent->child = child;
child->next = NULL;
} else {
/*
* step to end of child chain
*/
while(current != NULL){
prev = current;
current = current->next;
}
child->next = NULL;
prev->next = child;
}
}
/*--------------------------------------------------------------------------*/
void DeleteHipadabaNode(pHdb node){
pHdb current = NULL, tmp = NULL;
if(node == NULL){
return;
}
RemoveHdbNodeFromParent(node);
DeleteNodeData(node);
}
/*--------------------------------------------------------------------------*/
int isHdbNodeValid(pHdb node){
if(node == NULL){
return 0;
}
if(node->magic == HDBMAGICK){
return 1;
} else {
return 0;
}
}
/*--------------------------------------------------------------------------*/
pHdb GetHipadabaNode(pHdb root, char *puth){
pHdb resultNode = NULL;
char *separator = NULL;
char *path = NULL, *pathData;
/*
* I need to make a copy in order to get the path in writable memory.
* Otherwise we SEGFAULT in hdbTrim when this function is called with
* a string constant in puth
*/
pathData = strdup(puth);
path = pathData;
if(path == NULL){
return NULL;
}
path = hdbTrim(path);
if(strcmp(path,"/") == 0 || strlen(path) == 0){
free(pathData);
return root;
}
if(path[0] == '/'){
path++;
}
separator = strchr(path,'/');
if(separator == NULL){
resultNode = locateChild(root,path);
free(pathData);
return resultNode;
} else {
*separator = '\0';
resultNode = locateChild(root, path);
if(resultNode == NULL){
free(pathData);
return NULL;
} else {
separator++;
resultNode = GetHipadabaNode(resultNode,separator);
free(pathData);
return resultNode;
}
}
}
/*--------------------------------------------------------------------------*/
char *GetHipadabaPath(pHdb node){
pHdb nodeStack[64];
int depth = 0, length = 0, i;
pHdb current = NULL;
char *pPtr = NULL;
/**
* build a nodestack and find out required string length for path
*/
current = node;
while(current != NULL){
length += strlen(current->name) + 1;
nodeStack[depth] = current;
depth++;
assert(depth < 64);
current = current->mama;
}
pPtr = malloc(length*sizeof(char));
if(pPtr == NULL){
return NULL;
}
memset(pPtr,0,length*sizeof(char));
/*
* we wish to decremement by one because above loop
* increments one to many and we wish to ignore the
* root node
*/
for(i = depth - 2; i >= 0; i--){
strcat(pPtr,"/");
strcat(pPtr,nodeStack[i]->name);
}
return pPtr;
}
/*==================== Callback Functions ==================================*/
pHdbCallback MakeHipadabaCallback(hdbCallbackFunction func,
void *userData, killUserData killFunc,
int id, int internalID){
pHdbCallback pNew = NULL;
assert(func != NULL);
pNew = malloc(sizeof(hdbCallback));
if(pNew == NULL){
return NULL;
}
memset(pNew,0,sizeof(hdbCallback));
pNew->userCallback = func;
pNew->userData = userData;
pNew->killFunc = killFunc;
pNew->id = id;
pNew->internalID = internalID;
return pNew;
}
/*-------------------------------------------------------------------*/
void AppendHipadabaCallback(pHdb node, int type, pHdbCallback newCB){
pHdbCallback current = NULL;
switch(type){
case HCBSET:
if(node->writeCallbacks == NULL){
node->writeCallbacks = newCB;
return;
} else {
current = node->writeCallbacks;
}
break;
case HCBUPDATE:
if(node->updateCallbacks == NULL){
node->updateCallbacks = newCB;
return;
} else {
current = node->updateCallbacks;
}
break;
case HCBREAD:
if(node->readCallbacks == NULL){
node->readCallbacks = newCB;
return;
} else {
current = node->readCallbacks;
}
break;
default:
assert(0);
break;
}
if(current != NULL){
while(current->next != NULL){
current = (pHdbCallback)current->next;
}
current->next= newCB;
newCB->previous = current;
}
}
/*-------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void PrependHipadabaCallback(pHdb node, int type, pHdbCallback newCB){
switch(type){
case HCBSET:
if(node->writeCallbacks == NULL){
node->writeCallbacks = newCB;
return;
} else {
newCB->next = node->writeCallbacks;
node->writeCallbacks->previous = newCB;
node->writeCallbacks = newCB;
}
break;
case HCBUPDATE:
if(node->updateCallbacks == NULL){
node->updateCallbacks = newCB;
return;
} else {
newCB->next = node->updateCallbacks;
node->updateCallbacks->previous = newCB;
node->updateCallbacks = newCB;
}
break;
case HCBREAD:
if(node->readCallbacks == NULL){
node->readCallbacks = newCB;
return;
} else {
newCB->next = node->readCallbacks;
node->readCallbacks->previous = newCB;
node->readCallbacks = newCB;
}
break;
default:
assert(0);
break;
}
}
/*----------------------------------------------------------------------------*/
void RemoveHipadabaCallback(pHdb root, int id){
pHdb current = NULL;
root->writeCallbacks = DeleteForID(root->writeCallbacks,id);
root->updateCallbacks = DeleteForID(root->updateCallbacks,id);
root->readCallbacks = DeleteForID(root->readCallbacks,id);
current = root->child;
while(current != NULL){
RemoveHipadabaCallback(current,id);
current = current->next;
}
}
/*----------------------------------------------------------------------------*/
void InternalRemoveHipadabaCallback(pHdb root, int internalID){
pHdb current = NULL;
root->writeCallbacks = DeleteForInternalID(root->writeCallbacks,internalID);
root->updateCallbacks = DeleteForInternalID(root->updateCallbacks,internalID);
root->readCallbacks = DeleteForInternalID(root->readCallbacks,internalID);
current = root->child;
while(current != NULL){
InternalRemoveHipadabaCallback(current,internalID);
current = current->next;
}
}
/*=================== parameter interface ====================================*/
int copyHdbValue(hdbValue *source, hdbValue *target){
int i;
if(source->dataType != target->dataType){
return 0;
}
switch(source->dataType){
case HIPNONE:
break;
case HIPINT:
target->v.intValue = source->v.intValue;
break;
case HIPFLOAT:
target->v.doubleValue = source->v.doubleValue;
break;
case HIPTEXT:
if(target->v.text != NULL){
free(target->v.text);
}
target->v.text = strdup(source->v.text);
break;
case HIPINTAR:
case HIPINTVARAR:
if(target->arrayLength != source->arrayLength){
if(target->v.intArray != NULL){
free(target->v.intArray);
}
target->v.intArray = malloc(source->arrayLength * sizeof(int));
if(target->v.intArray == NULL){
return 0;
}
memset(target->v.intArray,0,source->arrayLength * sizeof(int));
target->arrayLength = source->arrayLength;
}
for(i = 0; i < source->arrayLength; i++){
target->v.intArray[i] = source->v.intArray[i];
}
break;
case HIPFLOATAR:
case HIPFLOATVARAR:
if(target->arrayLength != source->arrayLength){
if(target->v.floatArray != NULL){
free(target->v.floatArray);
}
target->v.floatArray = malloc(source->arrayLength * sizeof(double));
if(target->v.floatArray == NULL){
return 0;
}
memset(target->v.floatArray,0,source->arrayLength * sizeof(double));
target->arrayLength = source->arrayLength;
}
for(i = 0; i < source->arrayLength; i++){
target->v.floatArray[i] = source->v.floatArray[i];
}
break;
default:
/*
* unknown data type
*/
assert(0);
break;
}
return 1;
}
/*----------------------------------------------------------------------------*/
int SetHipadabaPar(pHdb node, hdbValue v, void *callData){
int status;
status = InvokeCallbackChain(node->writeCallbacks, node, callData, v);
return status;
}
/*-----------------------------------------------------------------------------*/
int UpdateHipadabaPar(pHdb node, hdbValue v, void *callData){
int status;
status = InvokeCallbackChain(node->updateCallbacks, node, callData, v);
if(status != 1 ){
return status;
}
copyHdbValue(&v,&node->value);
return 1;
}
/*-----------------------------------------------------------------------------*/
int GetHipadabaPar(pHdb node, hdbValue *v, void *callData){
int status;
status = InvokeCallbackChain(node->readCallbacks, node, callData, *v);
if(status != 1 ){
return status;
}
v->dataType = node->value.dataType;
copyHdbValue(&node->value,v);
return 1;
}