cmData.h/c: Initial rewrite of cmData to include the concept of homogeneous arrays as containers and leaf nodes.

This commit is contained in:
kpl 2013-11-18 22:35:54 -08:00
parent 691d0ef278
commit b74e24a46b
2 changed files with 1730 additions and 56 deletions

1314
cmData.c

File diff suppressed because it is too large Load Diff

472
cmData.h
View File

@ -5,30 +5,433 @@
extern "C" {
#endif
/*
TODO:
0) Figure out a error handling scheme that does not rely on
a global errno. This is not useful in multi-thread environments.
It might be ok to go with an 'all errors are fatal' model
(except in the var-args functions).
Consider the use of a context object for use with functions
that can have runtime errors or need to allocate memory.
1) Implement the canConvert and willTruncate functions.
2) Make a set of cmDataAllocXXXPtr() functions which take
a flag indicating whether or not to dynamically allocate
the array space. This will allow dynamic allocattion to
occur at runtime. Make var args functions for list and
record objects which also take this flag.
Whereever a function may be implemented using
static/dynamic allocation this flag should be present.
(e.g. string allocation for pair labels)
This choice is common enough that it may be worth
suffixing function names with a capital letter to
be clear what the functions memory policy is.
3) Come up with a var-args format which allows a
hierchy of records to be defined in one line.
4) Implement the serialization functions.
5) Implement an ascii string/parse format for writing/reading.
6) Implement fast lookup of record fields.
7) Allow for user defined types. For example a 'matrix'
data type. This might be as simple as adding an extra 'user_tid'
field to cmData_t.
8) Implement type specific cmDataGetRecordValueXXX() functions.
9) Implement cmDataIsEqual(), cmDataIsLtE(), ...
*/
enum
{
kOkDtRC = cmOkRC,
kAssertErrDtRC,
kConstErrDtRC,
kCvtErrDtRC,
kVarArgErrDtRC,
kMissingFieldDtRC,
kLexFailDtRC,
kParseStackFailDtRC,
kSyntaxErrDtRC,
kInvalidContDtRC,
kInvalidTypeDtRC,
kEolDtRC
};
typedef unsigned cmDtRC_t;
typedef enum
{
kInvalidTypeDtId,// 0
kNullDtId, // 1 the data object exists but it has no data
kUCharDtId, // 2
kCharDtId, // 3
kUShortDtId, // 4
kShortDtId, // 5
kUIntDtId, // 6
kIntDtId, // 7
kULongDtId, // 8
kLongDtId, // 9
kFloatDtId, // 10
kDoubleDtId, // 11
kStrDtId, // 12 zero terminated string
kBlobDtId // 13 application defined raw memory object
} cmDataTypeId_t;
typedef enum
{
kInvalidCntDtId, // 0
kScalarDtId, // 1
kArrayDtId, // 2
kPairDtId, // 3
kListDtId, // 4
kRecordDtId // 5
} cmDataContainerId_t;
enum
{
kInvalidDtChar = 0xff,
kInvalidDtUChar = 0xff,
kInvalidDtShort = 0xffff,
kInvalidDtUShort = 0xffff,
kInvalidDtInt = 0xffffffff,
kInvalidDtUInt = 0xffffffff,
kInvalidDtLong = 0xffffffff,
kInvalidDtULong = 0xffffffff,
kNoFlagsDtFl = 0x00,
// Indicate that the memory used by the data object
// was dynamically allocated and should be released
// by cmDataFree().
kFreeObjDtFl = 0x01,
// Indicate that the memory used by strings, blobs
// and arrays should be freed by cmDataFree().
kFreeValueDtFl = 0x02,
// Indicate that the value of the object cannot be changed.
// (but the object could be reassigned as a new type).
kConstValueDtFl = 0x04,
// Indicate that the type of the object cannot be changed.
// (but the value may be changed).
kConstObjDtFl = 0x08,
// Indicate that the array or string should not be
// internally reallocated but rather the source pointer
// should be taken as the new value of the object.
kNoCopyDtFl = 0x10,
};
typedef struct cmData_str
{
cmDataTypeId_t tid; // data format id
cmDataContainerId_t cid; // container id
unsigned flags; //
struct cmData_str* parent; // this childs parent
struct cmData_str* sibling; // this childs left sibling
unsigned cnt; // byte cnt for strings/blobs and ele count for arrays
union
{
char c;
unsigned char uc;
short s;
unsigned short us;
int i;
unsigned int ui;
long l;
unsigned long ul;
float f;
double d;
cmChar_t* z;
void* vp;
char* cp;
unsigned char* ucp;
short* sp;
unsigned short* usp;
int* ip;
unsigned int* uip;
long* lp;
unsigned long* ulp;
float* fp;
double* dp;
struct cmData_str* child; // first child (list,record,pair)
} u;
} cmData_t;
extern cmData_t cmDataNull;
const cmChar_t* cmDataTypeToLabel( cmDataTypeId_t tid );
cmDataTypeId_t cmDataLabelToType( const cmChar_t* typeLabelStr );
// Returns 1 for kStrDtId.
// Returns cmInvalidCnt if tid is not recognized.
unsigned dmDataByteWidth( cmDataTypeId_t tid );
const cmChar_t* cmDataContainerIdToLabel( cmDataContainerId_t tid );
cmDataContainerId_t cmDataLabelToContainerId( const cmChar_t* contLabelStr );
bool cmDataIsConstObj( const cmData_t* d );
void cmDataEnableConstObj( cmData_t* d, bool enaFl );
bool cmDataIsConstValue( const cmData_t* d );
void cmDataEnableConstValue( cmData_t* d, bool enaFl );
bool cmDataIsFreeValue( const cmData_t* d );
void cmDataEnableFreeValue( cmData_t* d, bool enaFl );
// Returns true if this is a scalar or array node.
bool cmDataIsLeaf( const cmData_t* d);
// Return true if this is NOT a scalar or array node.
bool cmDataIsStruct( const cmData_t* d );
//----------------------------------------------------------------------------
// Scalar related functions
//
// Dynamically allocate a scalar object and set it's value.
// The 'flags' argument may include kConstValueDtFl and kConstObjDtFl.
// The string and blob constructors may also use the
// kNoCopyDtFl and the kFreeValueDtFl.
// Generic:
// 'byteCnt' is ignored for all types other than strings and blobs.
cmDtRC_t cmDataNewScalar( cmData_t* parent, cmDataTypeId_t tid, unsigned flags, void* vp, unsigned byteCnt, cmData_t** ref );
// Type specific
cmDtRC_t cmDataNewNull( cmData_t* parent, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewChar( cmData_t* parent, unsigned flags, char v, cmData_t** ref );
cmDtRC_t cmDataNewUChar( cmData_t* parent, unsigned flags, unsigned char v, cmData_t** ref );
cmDtRC_t cmDataNewShort( cmData_t* parent, unsigned flags, short v, cmData_t** ref );
cmDtRC_t cmDataNewUShort( cmData_t* parent, unsigned flags, unsigned short v, cmData_t** ref );
cmDtRC_t cmDataNewInt( cmData_t* parent, unsigned flags, int v, cmData_t** ref );
cmDtRC_t cmDataNewUInt( cmData_t* parent, unsigned flags, unsigned int v, cmData_t** ref );
cmDtRC_t cmDataNewLong( cmData_t* parent, unsigned flags, long v, cmData_t** ref );
cmDtRC_t cmDataNewULong( cmData_t* parent, unsigned flags, unsigned long v, cmData_t** ref );
cmDtRC_t cmDataNewFloat( cmData_t* parent, unsigned flags, float v, cmData_t** ref );
cmDtRC_t cmDataNewDouble( cmData_t* parent, unsigned flags, double v, cmData_t** ref );
cmDtRC_t cmDataNewStr( cmData_t* parent, unsigned flags, cmChar_t* str, cmData_t** ref );
cmDtRC_t cmDataNewConstStr( cmData_t* parent, unsigned flags, const cmChar_t* str, cmData_t** ref );
cmDtRC_t cmDataNewStrN( cmData_t* parent, unsigned flags, cmChar_t* str, unsigned charCnt, cmData_t** ref );
cmDtRC_t cmDataNewConstStrN(cmData_t* parent, unsigned flags, const cmChar_t* str, unsigned charCnt, cmData_t** ref );
cmDtRC_t cmDataNewBlob( cmData_t* parent, unsigned flags, void* vp, unsigned byteCnt, cmData_t** ref );
cmDtRC_t cmDataNewConstBlob(cmData_t* parent, unsigned flags, const void* vp, unsigned byteCnt, cmData_t** ref );
// Set the value and type of an existing scalar object.
// These functions begin by releasing any resources held by *p
// prior to resetting the type and value of the object.
// The 'flags' argument to cmDataSetStr() and cmDataSetConstStr()
// may use the kNoCopyDtFl and the kFreeValueDtFl
cmDtRC_t cmDataSetScalarValue( cmData_t* d, cmDataTypeId_t tid, void* vp, unsigned byteCnt, unsigned flags );
cmDtRC_t cmDataSetNull( cmData_t* p );
cmDtRC_t cmDataSetChar( cmData_t* p, char v );
cmDtRC_t cmDataSetUChar( cmData_t* p, unsigned char v );
cmDtRC_t cmDataSetShort( cmData_t* p, short v );
cmDtRC_t cmDataSetUShort( cmData_t* p, unsigned short v );
cmDtRC_t cmDataSetInt( cmData_t* p, int v );
cmDtRC_t cmDataSetUInt( cmData_t* p, unsigned int v );
cmDtRC_t cmDataSetLong( cmData_t* p, long v );
cmDtRC_t cmDataSetULong( cmData_t* p, unsigned long v );
cmDtRC_t cmDataSetFloat( cmData_t* p, float v );
cmDtRC_t cmDataSetDouble( cmData_t* p, double v );
cmDtRC_t cmDataSetStr( cmData_t* p, unsigned flags, cmChar_t* s );
cmDtRC_t cmDataSetConstStr( cmData_t* p, unsigned flags, const cmChar_t* s );
cmDtRC_t cmDataSetStrN( cmData_t* p, unsigned flags, cmChar_t* s, unsigned charCnt );
cmDtRC_t cmDataSetConstStrN( cmData_t* p, unsigned flags, const cmChar_t* s, unsigned charCnt );
cmDtRC_t cmDataSetBlob( cmData_t* p, unsigned flags, void* v, unsigned byteCnt );
cmDtRC_t cmDataSetConstBlob( cmData_t* p, unsigned flags, const void* v, unsigned byteCnt );
// Get the value of an object. No conversion is applied the
// type must match exactly or an error is generated.
cmDtRC_t cmDataChar( const cmData_t* p, char* v );
cmDtRC_t cmDataUChar( const cmData_t* p, unsigned char* v );
cmDtRC_t cmDataShort( const cmData_t* p, short* v );
cmDtRC_t cmDataUShort( const cmData_t* p, unsigned short* v );
cmDtRC_t cmDataInt( const cmData_t* p, int* v );
cmDtRC_t cmDataUInt( const cmData_t* p, unsigned int* v );
cmDtRC_t cmDataLong( const cmData_t* p, long* v );
cmDtRC_t cmDataULong( const cmData_t* p, unsigned long* v );
cmDtRC_t cmDataFloat( const cmData_t* p, float* v );
cmDtRC_t cmDataDouble( const cmData_t* p, double* v );
cmDtRC_t cmDataStr( const cmData_t* p, cmChar_t** v );
cmDtRC_t cmDataConstStr( const cmData_t* p, const cmChar_t** v );
cmDtRC_t cmDataBlob( const cmData_t* p, cmChar_t** v, unsigned* byteCntRef );
cmDtRC_t cmDataConstBlob( const cmData_t* p, const cmChar_t** v, unsigned* byteCntRef );
// Get the value of an object with conversion.
cmDtRC_t cmDataGetChar( const cmData_t* p, char* v );
cmDtRC_t cmDataGetUChar( const cmData_t* p, unsigned char* v );
cmDtRC_t cmDataGetShort( const cmData_t* p, short* v );
cmDtRC_t cmDataGetUShort( const cmData_t* p, unsigned short* v );
cmDtRC_t cmDataGetInt( const cmData_t* p, int* v );
cmDtRC_t cmDataGetUInt( const cmData_t* p, unsigned int* v );
cmDtRC_t cmDataGetLong( const cmData_t* p, long* v );
cmDtRC_t cmDataGetULong( const cmData_t* p, unsigned long* v );
cmDtRC_t cmDataGetFloat( const cmData_t* p, float* v );
cmDtRC_t cmDataGetDouble( const cmData_t* p, double* v );
//----------------------------------------------------------------------------
// Array related functions
//
// Notes:
// 1) string arrays are arrays of string pointers.
// 2) blob arrays (array of void pointers) are not supported because
// there is no direct way to determine the length of each blob
// and therefore they cannot be internally duplicated - a special scheme
// could be devised (length goes in first 4 bytes) to make this
// work but we will defer that until the need arises.
//
// Dynamically allocate a new array data object.
//
// eleCnt referes to the number of elements in the array pointed
// to by 'vp'. The number of bytes pointed to by 'vp' is then
// cmDataByteWidth(tid)*eleCnt.
//
// If no flags are set then the array pointed to by 'vp' is reallocated
// and kDataFreeDtFl is set.
//
// If kFreeValueDtFl is set then the object will take responsibility for
// releasing the memory pointed to by 'vp' when the object is destroyed
// or the array is reassigned.
//
// If kNoCopyDtFl is set then 'vp' becomes the internal array
// value (vp[cnt]) is NOT reallocated). In this case the client is
// responsibile for eventually releasing the associated memory - when
// the data object is no longer valid.
cmDtRC_t cmDataNewArray( cmData_t* parent, cmDataTypeId_t tid, void* vp, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewCharArray( cmData_t* parent, char* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewUCharArray( cmData_t* parent, unsigned char* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewShortArray( cmData_t* parent, short* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewUShortArray( cmData_t* parent, unsigned short* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewIntArray( cmData_t* parent, int* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewUIntArray( cmData_t* parent, unsigned int* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewLongArray( cmData_t* parent, long* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewULongArray( cmData_t* parent, unsigned long* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewFloatArray( cmData_t* parent, float* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewDoubleArray( cmData_t* parent, double* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewStrArray( cmData_t* parent, cmChar_t** v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewConstStrArray( cmData_t* parent, const cmChar_t** v,unsigned eleCnt, unsigned flags, cmData_t** ref );
// Set the value and type of an existing scalar object.
//
// These functions begin by releasing any resources held by *p
// prior to resetting the type and value of the object.
// The 'flags' argument may include kConstValueDtFl, kConstObjDtFl,
// kNoCopyDtFl and the kFreeValueDtFl.
// Generic set array functions. 'vp' is assumed to point to an array
// of the type defined by 'tid'.
cmDtRC_t cmDataSetArrayValue( cmData_t* dt, cmDataTypeId_t tid, void* vp, unsigned eleCnt, unsigned flags );
// Type sepctific set array functions.
cmDtRC_t cmDataSetCharArray( cmData_t* d, char* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetUCharArray( cmData_t* d, unsigned char* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetShortArray( cmData_t* d, short* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetUShortArray( cmData_t* d, unsigned short* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetIntArray( cmData_t* d, int* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetUIntArray( cmData_t* d, unsigned int* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetLongArray( cmData_t* d, long* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetULongArray( cmData_t* d, unsigned long* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetFloatArray( cmData_t* d, float* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetDoubleArray( cmData_t* d, double* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetStrArray( cmData_t* d, cmChar_t** v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetConstStrArray(cmData_t* d,const cmChar_t** v,unsigned eleCnt, unsigned flags );
// Return the count of elements in a n array.
unsigned cmDataArrayEleCount( const cmData_t* d );
// Get a pointer to the base of an array.
// The type must match exactly or an error is generated.
// Use cmDataEleCount() to determine the number of elements in the array.
cmDtRC_t cmDataCharArray( const cmData_t* d, char** v );
cmDtRC_t cmDataUCharArray( const cmData_t* d, unsigned char** v );
cmDtRC_t cmDataShortArray( const cmData_t* d, short** v );
cmDtRC_t cmDataUShortArray( const cmData_t* d, unsigned short** v );
cmDtRC_t cmDataIntArray( const cmData_t* d, int** v );
cmDtRC_t cmDataUIntArray( const cmData_t* d, unsigned int** v );
cmDtRC_t cmDataLongArray( const cmData_t* d, long** v );
cmDtRC_t cmDataULongArray( const cmData_t* d, unsigned long** v );
cmDtRC_t cmDataFloatArray( const cmData_t* d, float** v );
cmDtRC_t cmDataDoubleArray( const cmData_t* d, double** v );
cmDtRC_t cmDataStrArray( const cmData_t* d, cmChar_t*** v );
cmDtRC_t cmDataConstStrArray( const cmData_t* d, const cmChar_t*** v );
//----------------------------------------------------------------------------
// Structure related functions
//
// Release an object and any resources held by it.
// Note the this function does not unlink the object
// from it's parent. Use cmDataUnlinkAndFree()
// to remove a object from it's parent list prior
// to releasing it.
void cmDataFree( cmData_t* p );
// Unlink 'p' from its parents and siblings.
// Asserts if parent is not a structure.
// Returns 'p'.
cmData_t* cmDataUnlink( cmData_t* p );
// Wrapper function to cmDataUnlink() and cmDataFree().
void cmDataUnlinkAndFree( cmData_t* p );
// Replace the 'dst' node with the 'src' node and
// return 'src'. This operation does not duplicate
// 'src' it simply links in 'src' at the location of
// 'dst' and then unlinks and free's 'dst'.
cmData_t* cmDataReplace( cmData_t* dst, cmData_t* src );
// Return the count of child nodes.
// 1. Array nodes have one child per array element.
// 2. List nodes have one child pair.
// 3. Pair nodes have two children.
// 4. Leaf nodes have 0 children.
unsigned cmDataChildCount( const cmData_t* p );
// Returns the ith child of 'p'.
// Returns NULL if p has no children or index is invalid.
cmData_t* cmDataChild( cmData_t* p, unsigned index );
// Prepend 'p' to 'parents' child list.
// The source node 'p' is not duplicated it is simply linked in.
// 'p' is automatically unlinked prior to being prepended.
// Returns 'p'.
cmData_t* cmDataPrependChild(cmData_t* parent, cmData_t* p );
// Append 'p' to the end of 'parent' child list.
// The source node 'p' is not duplicated it is simply linked in.
// 'p' is automatically unlinked prior to being appended.
// Returns 'p'.
cmData_t* cmDataAppendChild( cmData_t* parent, cmData_t* p );
// Insert 'p' at index. Index must be in the range:
// 0 to cmDataChildCount(parent).
// The source node 'p' is not duplicated it is simply linked in.
// 'p' is automatically unlinked prior to being inserted.
// Returns 'p'.
cmData_t* cmDataInsertChild( cmData_t* parent, unsigned index, cmData_t* p );
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef NOT_DEF
typedef enum
{
kInvalidDtId,
@ -131,47 +534,6 @@ extern "C" {
bool cmDataIsPtr( const cmData_t* p );
bool cmDataIsStruct( const cmData_t* p ); // is a pair,list or record
/*
TODO:
0) Figure out a error handling scheme that does not rely on
a global errno. This is not useful in multi-thread environments.
It might be ok to go with an 'all errors are fatal' model
(except in the var-args functions).
Consider the use of a context object for use with functions
that can have runtime errors or need to allocate memory.
1) Implement the canConvert and willTruncate functions.
2) Make a set of cmDataAllocXXXPtr() functions which take
a flag indicating whether or not to dynamically allocate
the array space. This will allow dynamic allocattion to
occur at runtime. Make var args functions for list and
record objects which also take this flag.
Where ever a function may be implemented using
static/dynamic allocation this flag should be present.
(e.g. string allocation for pair labels)
This choice is common enough that it may be worth
suffixing function names with a capital letter to
be clear what the functions memory policy is.
3) Come up with a var-args format which allows a
hierchy of records to be defined in one line.
4) Implement the serialization functions.
5) Implement an ascii string/parse format for writing/reading.
6) Implement fast lookup of record fields.
7) Allow for user defined types. For example a 'matrix'
data type. This might be as simple as adding an extra 'user_tid'
field to cmData_t.
8) Implement type specific cmDataGetRecordValueXXX() functions.
9) Implement cmDataIsEqual(), cmDataIsLtE(), ...
*/
bool canConvertType( cmDataFmtId_t srcId, cmDataFmtId_t dstId );
bool willTruncate( cmDataFmtId_t srcId, cmDataFmtId_t dstId );
@ -556,7 +918,7 @@ extern "C" {
void cmDataPrint( const cmData_t* p, cmRpt_t* rpt );
void cmDataTest( cmCtx_t* ctx );
#endif
#ifdef __cplusplus