From e3423e775e4b6b50ff2485a00296b50543f84e3d Mon Sep 17 00:00:00 2001 From: kevin Date: Mon, 25 Nov 2024 09:55:05 -0500 Subject: [PATCH] cwFlowValue.h/cpp : Implemented recd_fmt_t to alloc spec. of 'record' in class desc. Implemented recd_get()/set() for multiple fields at once. Moved value_from_value() and value_from_cfg() into cwFlowValue from cwFlowType --- cwFlowValue.cpp | 673 ++++++++++++++++++++++++++++++++++-------------- cwFlowValue.h | 182 +++++++++---- 2 files changed, 621 insertions(+), 234 deletions(-) diff --git a/cwFlowValue.cpp b/cwFlowValue.cpp index 2a0b223..e3342ea 100644 --- a/cwFlowValue.cpp +++ b/cwFlowValue.cpp @@ -70,124 +70,187 @@ namespace cw if( f->group_fl ) _recd_type_destroy_field_list(f->u.group_fieldL); + mem::release(f->doc); mem::release(f->label); mem::release(f); f = f0; } } - - rc_t _recd_type_add_field( recd_field_t*& fieldL_ref, const char* field_label, recd_field_t*& new_field_ref ) + + unsigned _recd_field_list_set_index( recd_field_t* fld, unsigned index ) { - rc_t rc = kOkRC; - recd_field_t* f = nullptr; - recd_field_t* new_field = nullptr; + for(recd_field_t* f=fld; f!=nullptr; f=f->link) + if( f->group_fl ) + index = _recd_field_list_set_index(f->u.group_fieldL,index); + else + f->u.index = index++; + return index; + } + + + const char* _recd_field_index_to_label(const recd_field_t* fld, unsigned field_idx) + { + const char* label = nullptr; - new_field_ref = nullptr; - - if( textLength(field_label) == 0 ) - { - rc = cwLogError(kInvalidArgRC,"A blank msg field was encountered."); - goto errLabel; - } - - for(f=fieldL_ref; f!=nullptr; f=f->link) - { - if( textIsEqual(field_label,f->label)) + for(const recd_field_t* f=fld; f!=nullptr; f=f->link) + if( f->group_fl ) + label = _recd_field_index_to_label(f->u.group_fieldL,field_idx); + else { - rc = cwLogError(kInvalidArgRC,"A duplicate msg field '%s' has been encountered.", field_label); - goto errLabel; + if(f->u.index == field_idx ) + label = f->label; } - - // add the new field to the end of the list - if( f->link == nullptr ) - break; - } - - new_field = mem::allocZ(); - new_field->label = mem::duplStr(field_label); - if( f == nullptr ) - fieldL_ref = new_field; - else - f->link = new_field; - - new_field_ref = new_field; - - - errLabel: - return rc; - } - - - rc_t _recd_type_add_value_field( recd_field_t*& fieldL_ref, const char* field_label, unsigned index ) - { - rc_t rc; - - recd_field_t* new_field = nullptr; - - if((rc = _recd_type_add_field( fieldL_ref, field_label, new_field )) != kOkRC ) - { - rc = cwLogError(rc,"Record add value field '%s' failed.",cwStringNullGuard(field_label)); - goto errLabel; - } - - new_field->group_fl = false; - new_field->u.index = index; - - errLabel: - return rc; - } - - rc_t _recd_type_add_group_field( recd_field_t*& fieldL_ref, const char* field_label, recd_field_t*& new_field_ref ) - { - rc_t rc; - - if((rc = _recd_type_add_field( fieldL_ref, field_label, new_field_ref )) != kOkRC ) - { - rc = cwLogError(rc,"Record add group field '%s' failed.",cwStringNullGuard(field_label)); - goto errLabel; - } - - new_field_ref->group_fl = true; - - errLabel: - return rc; + return label; } - rc_t _recd_type_add_value_fields( recd_type_t* recd_type, recd_field_t*& fieldL_ref, const char* field_labels ) + rc_t _recd_field_list_from_cfg( recd_field_t*& field_list_ref, const object_t* field_dict_cfg ) { rc_t rc = kOkRC; - const char* s0 = field_labels; - while(s0 != nullptr) + if( !field_dict_cfg->is_dict() ) { - s0 = nextNonWhiteChar(s0); - - const char* s1 = nextWhiteChar(s0); - - unsigned sn = s1==nullptr ? textLength(s0) : s1-s0; - char s[sn+1]; - strncpy(s,s0,sn); - s[sn] = 0; - - if((rc = _recd_type_add_value_field(fieldL_ref, s, recd_type->fieldN)) != kOkRC ) - { - goto errLabel; - } - - recd_type->fieldN += 1; - - s0 = s1; + rc = cwLogError(kSyntaxErrorRC,"The field cfg. is not a dictionary."); + goto errLabel; } + else + { + unsigned row_cnt = field_dict_cfg->child_count(); - errLabel: + for(unsigned i=0; ichild_ele(i); + recd_field_t* field = nullptr; + const char* type_label = nullptr; + const char* doc_string = nullptr; + const object_t* val_cfg = nullptr; + + // parse the required fields + if((rc = pair->pair_value()->getv("type",type_label, + "doc",doc_string)) != kOkRC ) + { + rc = cwLogError(rc,"Error parsing the field '%s'.",cwStringNullGuard(pair->pair_label())); + goto errLabel; + } + + // allocate the field record + field = mem::allocZ(); + // add the new field to the end of the field list + if( field_list_ref == nullptr ) + field_list_ref = field; + else + { + recd_field_t* f = field_list_ref; + while( f->link != nullptr ) + f = f->link; + + assert(f!=nullptr); + f->link = field; + } + + field->label = mem::duplStr(pair->pair_label()); + field->doc = mem::duplStr(doc_string); + + if( textIsEqual(type_label,"group") ) + { + const object_t* field_dict; + + field->group_fl = true; + + // get the group 'fields' dictionary + if((rc = pair->pair_value()->getv("fields",field_dict)) != kOkRC ) + { + rc = cwLogError(rc,"The field group '%s' does not have a field list.",pair->pair_label()); + goto errLabel; + } + + // recursively read the group field list + if((rc = _recd_field_list_from_cfg(field->u.group_fieldL,field_dict)) != kOkRC ) + { + rc = cwLogError(rc,"The creation of field group '%s' failed.",pair->pair_label()); + goto errLabel; + } + + + } + else + { + + // validate the value type flag + if((field->value.tflag = value_type_label_to_flag( type_label )) == kInvalidTFl ) + { + rc = cwLogError(kSyntaxErrorRC,"The value type label '%s' is not valid on the field specifier '%s'.",cwStringNullGuard(type_label),cwStringNullGuard(pair->pair_label())); + goto errLabel; + } + + // get the optional default value + if((val_cfg = pair->pair_value()->find("value")) != nullptr ) + { + value_t v; + v.tflag = kInvalidTFl; + + // parse the value into 'v' + if((rc = value_from_cfg(val_cfg,v)) != kOkRC ) + { + rc = cwLogError(rc,"The default value parse failed for the field '%s'.",cwStringNullGuard(pair->pair_label())); + goto errLabel; + } + + // convert the value from 'v' into field->value + if((rc = value_from_value(v,field->value)) != kOkRC ) + { + rc = cwLogError(rc,"The default value assignment failed for the field '%s'.",cwStringNullGuard(pair->pair_label())); + goto errLabel; + } + } + } + } + + } + errLabel: return rc; } + void _recd_set_value_type( recd_field_t* fieldL, recd_t* r ) + { + recd_field_t* f = fieldL; + for(; f!=nullptr; f=f->link) + if( f->group_fl ) + _recd_set_value_type( f->u.group_fieldL, r ); + else + r->valA[ f->u.index ].tflag = f->value.tflag; + } + rc_t _recd_set_default_value( recd_field_t* fieldL, recd_t* r ) + { + rc_t rc = kOkRC; + recd_field_t* f = fieldL; + + for(; f!=nullptr; f=f->link) + { + if( f->group_fl ) + _recd_set_default_value( f->u.group_fieldL, r ); + else + { + if(f->value.tflag != kInvalidTFl) + { + if((rc = value_from_value( f->value, r->valA[f->u.index] )) != kOkRC ) + { + rc = cwLogError(rc,"Set default value failed on the field '%s'.",cwStringNullGuard(f->label)); + goto errLabel; + } + } + } + } + + errLabel: + return rc; + } + + const recd_field_t* _find_field( const recd_field_t* fieldL, const char* label, unsigned label_charN, bool group_fl ) { for(const recd_field_t* f = fieldL; f!=nullptr; f=f->link) @@ -779,7 +842,137 @@ void cw::flow::value_duplicate( value_t& dst, const value_t& src ) } } + + +cw::rc_t cw::flow::value_from_cfg( const object_t* cfg, value_t& value_ref ) +{ + rc_t rc = kOkRC; + + switch( cfg->type->id ) + { + case kCharTId: + case kUInt8TId: + case kUInt16TId: + case kUInt32TId: + value_ref.tflag = kUIntTFl; + if((rc = cfg->value(value_ref.u.u)) != kOkRC ) + rc = cwLogError(rc,"Conversion to uint failed."); + break; + + case kInt8TId: + case kInt16TId: + case kInt32TId: + value_ref.tflag = kIntTFl; + if((rc = cfg->value(value_ref.u.i)) != kOkRC ) + rc = cwLogError(rc,"Conversion to int failed."); + break; + + case kInt64TId: + case kUInt64TId: + rc = cwLogError(kInvalidArgRC,"The flow system does not currently implement 64bit integers."); + goto errLabel; + break; + + case kFloatTId: + value_ref.tflag = kFloatTFl; + if((rc = cfg->value(value_ref.u.f)) != kOkRC ) + rc = cwLogError(rc,"Conversion to float failed."); + break; + + case kDoubleTId: + value_ref.tflag = kDoubleTFl; + if((rc = cfg->value(value_ref.u.d)) != kOkRC ) + rc = cwLogError(rc,"Conversion to double failed."); + break; + + case kBoolTId: + value_ref.tflag = kBoolTFl; + if((rc = cfg->value(value_ref.u.b)) != kOkRC ) + rc = cwLogError(rc,"Conversion to bool failed."); + break; + + case kStringTId: + case kCStringTId: + value_ref.tflag = kStringTFl; + if((rc = cfg->value(value_ref.u.s)) != kOkRC ) + rc = cwLogError(rc,"Conversion to string failed."); + break; + + default: + value_ref.tflag = kCfgTFl; + value_ref.u.cfg = cfg; + + } +errLabel: + + return rc; +} + +cw::rc_t cw::flow::value_from_value( const value_t& src, value_t& dst ) +{ + rc_t rc = kOkRC; + + if( dst.tflag == kInvalidTFl || dst.tflag & src.tflag) + { + dst = src; + return kOkRC; + } + + // we only get here if conversion is necessary + + switch( src.tflag ) + { + case kInvalidTFl: + rc = cwLogError(kInvalidStateRC,"The src operand does not have a valid type."); + break; + + case kBoolTFl: + rc = value_set(&dst,src.u.b); + break; + + case kUIntTFl: + rc = value_set(&dst,src.u.u); + break; + + case kIntTFl: + rc = value_set(&dst,src.u.i); + break; + + case kFloatTFl: + rc = value_set(&dst,src.u.f); + break; + + case kDoubleTFl: + rc = value_set(&dst,src.u.d); + break; + + case kBoolMtxTFl: + case kUIntMtxTFl: + case kIntMtxTFl: + case kFloatMtxTFl: + case kDoubleMtxTFl: + rc = cwLogError(kNotImplementedRC,"Matrix conversion is not implemented for value to value conversion."); + break; + + case kABufTFl: + case kFBufTFl: + case kMBufTFl: + case kRBufTFl: + case kStringTFl: + case kTimeTFl: + case kCfgTFl: + case kMidiTFl: + rc = cwLogError(kOpFailRC,"Value conversion failed during value to value assignement."); + break; + + default: + rc = cwLogError(kInvalidArgRC,"An unknown source operand data type 0x%x was encountered.",src.tflag); + } + return rc; +} + + void cw::flow::value_print( const value_t* v, bool info_fl ) { if( v == nullptr ) @@ -1394,6 +1587,21 @@ cw::rc_t cw::flow::value_get( const value_t* val, midi::ch_msg_t*& valRef ) return rc; } +cw::rc_t cw::flow::value_get( const value_t* val, const midi::ch_msg_t*& valRef ) +{ + rc_t rc = kOkRC; + + if( cwIsFlag(val->tflag & kTypeMask, kMidiTFl) ) + valRef = val->u.midi; + else + { + valRef = nullptr; + rc = cwLogError(kTypeMismatchRC,"The type %s (0x%x) could not be converted to a MIDI record.",_typeFlagToLabel(val->tflag),val->tflag); + + } + return rc; +} + cw::rc_t cw::flow::value_set(value_t* val, midi::ch_msg_t* v ) { rc_t rc = kOkRC; @@ -1406,7 +1614,7 @@ cw::rc_t cw::flow::value_set(value_t* val, midi::ch_msg_t* v ) case kInvalidTFl: val->u.midi=v; - val->tflag = kCfgTFl; + val->tflag = kMidiTFl; break; default: @@ -1417,17 +1625,74 @@ cw::rc_t cw::flow::value_set(value_t* val, midi::ch_msg_t* v ) } -cw::rc_t cw::flow::recd_type_create( recd_type_t*& recd_type_ref, const recd_type_t* base, const char* fields_str ) -{ - rc_t rc = kOkRC; - recd_type_t* recd_type = mem::allocZ(); +//------------------------------------------------------------------------------------------------------------------------ +// +// Record +// + +cw::rc_t cw::flow::recd_format_create( recd_fmt_t*& recd_fmt_ref, const object_t* cfg ) +{ + rc_t rc = kOkRC; + recd_fmt_t* recd_fmt = nullptr; + + recd_fmt_ref = nullptr; + + recd_fmt = mem::allocZ(); + + if((rc = recd_type_create(recd_fmt->recd_type,nullptr,cfg)) != kOkRC ) + goto errLabel; + + recd_fmt->alloc_cnt = 32; // TODO: this should not be hard coded + + if((rc =cfg->getv_opt("alloc_cnt",recd_fmt->alloc_cnt)) != kOkRC ) + { + rc = cwLogError(rc,"Error parsing record format 'alloc_cnt'."); + goto errLabel; + } + + recd_fmt_ref = recd_fmt; + +errLabel: + if(rc != kOkRC ) + rc = cwLogError(rc,"Record format creation failed."); + return rc; +} + +void cw::flow::recd_format_destroy( recd_fmt_t*& recd_fmt_ref ) +{ + if( recd_fmt_ref != nullptr ) + { + recd_type_destroy(recd_fmt_ref->recd_type); + mem::release(recd_fmt_ref); + } +} + + +cw::rc_t cw::flow::recd_type_create( recd_type_t*& recd_type_ref, const recd_type_t* base, const object_t* cfg ) +{ + rc_t rc = kOkRC; + const object_t* fields_dict = nullptr;; + + recd_type_t* recd_type = mem::allocZ(); + recd_type_ref = nullptr; - if((rc = recd_type_add_value_fields( recd_type, fields_str )) != kOkRC ) + // get the fields list + if((rc = cfg->getv("fields",fields_dict)) != kOkRC ) + { + rc = cwLogError(rc,"The 'fields' dictionary was not found in the record 'fmt' specifier."); + goto errLabel; + } + + // load the fields list + if((rc = _recd_field_list_from_cfg(recd_type->fieldL,fields_dict)) != kOkRC ) { goto errLabel; } + + // assign the index to the value fields and update recd_type.fieldN + recd_type->fieldN = _recd_field_list_set_index(recd_type->fieldL, 0 ); recd_type->base = base; recd_type_ref = recd_type; @@ -1451,34 +1716,6 @@ void cw::flow::recd_type_destroy( recd_type_t*& recd_type_ref ) mem::release(recd_type_ref); } -cw::rc_t cw::flow::recd_type_add_value_fields( recd_type_t* recd_type, const char* field_labels ) -{ - return _recd_type_add_value_fields( recd_type, recd_type->fieldL, field_labels ); -} - -cw::rc_t cw::flow::recd_type_add_group( recd_type_t* recd_type, const char* group_label, const char* field_labels ) -{ - rc_t rc; - - recd_field_t* f = nullptr; - - if((rc = _recd_type_add_group_field( recd_type->fieldL, group_label, f )) != kOkRC ) - { - goto errLabel; - } - - if((rc = _recd_type_add_value_fields( recd_type, f->u.group_fieldL, field_labels )) != kOkRC ) - { - goto errLabel; - } - -errLabel: - - if( rc !=kOkRC ) - rc = cwLogError(rc,"Record group add failed."); - - return rc; -} unsigned cw::flow::recd_type_max_field_count( const recd_type_t* recd_type ) { @@ -1502,31 +1739,63 @@ errLabel: return index; } +const char* cw::flow::recd_type_field_index_to_label( const recd_type_t* recd_type, unsigned field_idx ) +{ + const char* label = nullptr; + + if( field_idx >= recd_type->fieldN ) + label = recd_type_field_index_to_label(recd_type->base, field_idx - recd_type->fieldN ); + else + label = _recd_field_index_to_label(recd_type->fieldL,field_idx); + + return label; +} + + void cw::flow::recd_type_print( const recd_type_t* recd_type ) { _recd_type_print(recd_type,recd_type); } -cw::rc_t cw::flow::recd_print( const recd_type_t* rt, const recd_t* r ) -{ return _recd_print( rt, r ); } +cw::rc_t cw::flow::recd_init( const recd_type_t* recd_type, const recd_t* base, recd_t* r ) +{ + r->base = base; + return _recd_set_default_value( recd_type->fieldL, r ); + +} + +cw::rc_t cw::flow::recd_print( const recd_type_t* recd_type, const recd_t* r ) +{ return _recd_print( recd_type, r ); } -cw::rc_t cw::flow::recd_array_create( recd_array_t*& recd_array_ref, recd_type_t* recd_type, unsigned allocRecdN ) +cw::rc_t cw::flow::recd_array_create( recd_array_t*& recd_array_ref, recd_type_t* recd_type, const recd_type_t* base, unsigned allocRecdN ) { rc_t rc = kOkRC; recd_array_t* recd_array = mem::allocZ(); recd_array_ref = nullptr; - recd_array->type = recd_type; + recd_array->type = mem::allocZ(); + recd_array->type->fieldL = recd_type->fieldL; + recd_array->type->fieldN = recd_type->fieldN; + recd_array->type->base = base; + recd_array->valA = mem::allocZ(recd_array->type->fieldN * allocRecdN); recd_array->recdA = mem::allocZ(allocRecdN); recd_array->allocRecdN = allocRecdN; + + // for each record for(unsigned i=0; irecdA[i].valA = recd_array->valA + (i*recd_array->type->fieldN); + // set the value type of all records in the array + _recd_set_value_type( recd_array->type->fieldL, recd_array->recdA + i ); + } + recd_array_ref = recd_array; //if( rc != kOkRC ) @@ -1539,6 +1808,7 @@ cw::rc_t cw::flow::recd_array_destroy( recd_array_t*& recd_array_ref ) { if( recd_array_ref != nullptr ) { + mem::release(recd_array_ref->type); mem::release(recd_array_ref->valA); mem::release(recd_array_ref->recdA); mem::release(recd_array_ref); @@ -1547,100 +1817,125 @@ cw::rc_t cw::flow::recd_array_destroy( recd_array_t*& recd_array_ref ) return kOkRC; } - cw::rc_t cw::flow::value_test( const test::test_args_t& args ) { - rc_t rc = kOkRC; - recd_type_t* rt0 = nullptr; - recd_type_t* rt1 = nullptr; - recd_array_t* ra0 = nullptr; - recd_array_t* ra1 = nullptr; + rc_t rc = kOkRC; + object_t* cfg0 = nullptr; + object_t* cfg1 = nullptr; + recd_fmt_t* fmt0 = nullptr; + recd_fmt_t* fmt1 = nullptr; + recd_array_t* ra0 = nullptr; + recd_array_t* ra1 = nullptr; - if((rc = recd_type_create( rt0, nullptr, "a b c" )) != kOkRC ) - { - rc = cwLogError(rc,"rt0 create failed."); - goto errLabel; - } + const char* s0 = "{ alloc_cnt:3, fields: {" + "a: { type:bool, doc:\"A floater.\" }," + "b: { type:uint, value:1, doc:\"My uint.\" }," + "c: { type:uint, value:2, doc:\"My other uint.\" }" + "g0: { type:group, doc:\"A group.\"" + "fields:{ a:{type:int, value:0, doc:\"My int.\" }" + " b:{type:bool, value:true, doc:\"My flag.\" }" + " c:{type:double, value:1, doc:\"Another field.\" }" + "}}" + "}}"; + + const char* s1 = "{ alloc_cnt:3, fields: {" + "d: { type:double, doc:\"d doc.\" }," + "e: { type:uint, value:-1, doc:\"e doc.\" }," + "f: { type:uint, value:-1, doc:\"f doc.\" }" + "g1: { type:group, doc:\"A group.\"" + "fields:{ a:{type:int, value:0, doc:\"My int.\" }" + " b:{type:bool, value:true, doc:\"My flag.\" }" + " c:{type:uint, value:1, doc:\"Another field.\" }" + "}}" + "}}"; - if((rc = recd_type_add_group( rt0, "g0", "a b c" )) != kOkRC ) + if((rc = objectFromString(s0,cfg0)) != kOkRC ) { - rc = cwLogError(rc,"rt.g0 group create failed."); - goto errLabel; - } - - if((rc = recd_type_create( rt1, rt0, "d e f" )) != kOkRC ) - { - rc = cwLogError(rc,"rt0 create failed."); - goto errLabel; - } - - if((rc = recd_type_add_group( rt1, "g1", "a b c" )) != kOkRC ) - { - rc = cwLogError(rc,"rt.g0 group create failed."); - goto errLabel; - } - - recd_type_print( rt0 ); - recd_type_print( rt1 ); - - if((rc = recd_array_create(ra0,rt0,10)) != kOkRC ) - { - rc = cwLogError(rc,"ra0 alloc failed."); + rc = cwLogError(rc,"cfg0 parse failed."); goto errLabel; } - if((rc = recd_array_create(ra1,rt1,10)) != kOkRC ) + if((rc = objectFromString(s1,cfg1)) != kOkRC ) { - rc = cwLogError(rc,"ra1 alloc failed."); + rc = cwLogError(rc,"cfg1 parse failed."); goto errLabel; } + if((rc = recd_format_create( fmt0, cfg0 )) != kOkRC ) + { + rc = cwLogError(rc,"fmt0 create failed."); + goto errLabel; + } + + if((rc = recd_format_create( fmt1, cfg1 )) != kOkRC ) + { + rc = cwLogError(rc,"fmt1 create failed."); + goto errLabel; + } + + if((rc = recd_array_create( ra0, fmt0->recd_type, nullptr, fmt0->alloc_cnt )) != kOkRC ) + { + rc = cwLogError(rc,"recd array 0 create failed."); + goto errLabel; + } + + if((rc = recd_array_create( ra1, fmt1->recd_type, fmt0->recd_type, fmt1->alloc_cnt )) != kOkRC ) + { + rc = cwLogError(rc,"recd array 0 create failed."); + goto errLabel; + } + + for(unsigned i=0; iallocRecdN; ++i) { recd_t* r = ra0->recdA + i; - rc_t rc0 = recd_set( ra0->type, nullptr, r, recd_type_field_index(ra0->type,"a"), 0*i); - rc_t rc1 = recd_set( ra0->type, nullptr, r, recd_type_field_index(ra0->type,"b"), 1*i); - rc_t rc2 = recd_set( ra0->type, nullptr, r, recd_type_field_index(ra0->type,"c"), 2*i); - rc_t rc3 = recd_set( ra0->type, nullptr, r, recd_type_field_index(ra0->type,"g0.a"), 4.0*i); - rc_t rc4 = recd_set( ra0->type, nullptr, r, recd_type_field_index(ra0->type,"g0.b"), 5.0*i); - rc_t rc5 = recd_set( ra0->type, nullptr, r, recd_type_field_index(ra0->type,"g0.c"), 6.0*i); - if((rc = rcSelect(rc0,rc1,rc2,rc3,rc4,rc5)) != kOkRC ) + if((rc = recd_set( ra0->type, nullptr, r, + recd_type_field_index(ra0->type,"a"), 0.0f*i, + recd_type_field_index(ra0->type,"g0.a"), 4.0*i, + recd_type_field_index(ra0->type,"g0.b"), 5*i, + recd_type_field_index(ra0->type,"g0.c"), 6*i)) != kOkRC ) { - rc = cwLogError(rc,"recd_set() failed on ra0."); + cwLogError(rc,"recd_set() failed on ra0."); goto errLabel; - } + } } for(unsigned i=0; iallocRecdN; ++i) recd_print(ra0->type,ra0->recdA+i); + for(unsigned i=0; iallocRecdN; ++i) { recd_t* r = ra1->recdA + i; recd_t* r_base = ra0->recdA + i; - rc_t rc0 = recd_set( ra1->type, r_base, r, recd_type_field_index(ra1->type,"d"), 0*i*2); - rc_t rc1 = recd_set( ra1->type, r_base, r, recd_type_field_index(ra1->type,"e"), 1*i*2); - rc_t rc2 = recd_set( ra1->type, r_base, r, recd_type_field_index(ra1->type,"f"), 2*i*2); - rc_t rc3 = recd_set( ra1->type, r_base, r, recd_type_field_index(ra1->type,"g1.a"), 4.0*i*2); - rc_t rc4 = recd_set( ra1->type, r_base, r, recd_type_field_index(ra1->type,"g1.b"), 5.0*i*2); - rc_t rc5 = recd_set( ra1->type, r_base, r, recd_type_field_index(ra1->type,"g1.c"), 6.0*i*2); - if((rc = rcSelect(rc0,rc1,rc2,rc3,rc4,rc5)) != kOkRC ) + if((rc = recd_set( ra1->type, r_base, r, + recd_type_field_index(ra1->type,"d"), 0.0f*i, + recd_type_field_index(ra1->type,"g1.a"), 4.0*i*2, + recd_type_field_index(ra1->type,"g1.b"), 5*i*2, + recd_type_field_index(ra1->type,"g1.c"), 6*i*2)) != kOkRC ) { - rc = cwLogError(rc,"recd_set() failed on ra1."); + cwLogError(rc,"recd_set() failed on ra1."); goto errLabel; - } + } } for(unsigned i=0; iallocRecdN; ++i) recd_print(ra1->type,ra1->recdA+i); - recd_array_destroy(ra0); - recd_array_destroy(ra1); - recd_type_destroy(rt0); - recd_type_destroy(rt1); + + recd_array_destroy( ra0 ); + recd_array_destroy( ra1 ); + + recd_format_destroy( fmt0 ); + recd_format_destroy( fmt1 ); + + cfg0->free(); + cfg1->free(); + errLabel: return rc; } + diff --git a/cwFlowValue.h b/cwFlowValue.h index 0203dca..5e36a8e 100644 --- a/cwFlowValue.h +++ b/cwFlowValue.h @@ -83,7 +83,7 @@ namespace cw kTypeMask = 0x0003ffff, - kRuntimeTFl = 0x80000000, + kRuntimeTFl = 0x80000000, // The type of the value associated with this variable will be set by the proc instances during instantiation kNumericTFl = kBoolTFl | kUIntTFl | kIntTFl | kFloatTFl | kDoubleTFl, kMtxTFl = kBoolMtxTFl | kUIntMtxTFl | kIntMtxTFl | kFloatMtxTFl | kDoubleMtxTFl, @@ -100,38 +100,13 @@ namespace cw } u; } mtx_t; - typedef struct recd_field_str - { - bool group_fl; // set if this field record is a group - char* label; // field or group label - union - { - unsigned index; // index into recd_t.valA of the value associated with this field - struct recd_field_str* group_fieldL; - } u; - - struct recd_field_str* link; - } recd_field_t; - - typedef struct recd_type_str - { - recd_field_t* fieldL; // linked list of field spec's - unsigned fieldN; // length of fieldL list (fieldN + base->fieldN) is total field count - const struct recd_type_str* base; - } recd_type_t; - - struct value_str; - typedef struct recd_str - { - struct value_str* valA; // varA[ fieldN ] array of field values - const struct recd_str* base; // base record fields - } recd_t; - + struct recd_type_str; + struct recd_str; typedef struct rbuf_str { - const recd_type_t* type; // all msgs are formed from this type - const recd_t* recdA; // recdA[ recdN ] - unsigned recdN; // + const struct recd_type_str* type; // all msgs are formed from this type + const struct recd_str* recdA; // recdA[ recdN ] + unsigned recdN; // } rbuf_t; typedef struct value_str @@ -200,10 +175,10 @@ namespace cw void mbuf_destroy( mbuf_t*& buf ); mbuf_t* mbuf_duplicate( const mbuf_t* src ); - rbuf_t* rbuf_create( const recd_type_t* type=nullptr, const recd_t* recdA=nullptr, unsigned recdN=0 ); + rbuf_t* rbuf_create( const struct recd_type_str* type=nullptr, const struct recd_str* recdA=nullptr, unsigned recdN=0 ); void rbuf_destroy( rbuf_t*& buf ); rbuf_t* rbuf_duplicate( const rbuf_t* src ); - void rbuf_setup( rbuf_t* rbuf, recd_type_t* type, recd_t* recdA, unsigned recdN ); + void rbuf_setup( rbuf_t* rbuf, struct recd_type_str* type, struct recd_str* recdA, unsigned recdN ); inline bool value_is_abuf( const value_t* v ) { return v->tflag & kABufTFl; } @@ -215,6 +190,14 @@ namespace cw void value_release( value_t* v ); void value_duplicate( value_t& dst, const value_t& src ); + // For all numeric types this function set's the type of 'value_ref' to the type of cfg. + // For all other types sets the type of 'value_ref' to kCfgTFl and stores 'cfg' to value_ref.u.cfg; + rc_t value_from_cfg( const object_t* cfg, value_t& value_ref ); + + // Assigns src to dst. If dst has a value type then src is converted to this type. + // If the conversion is not possible then the function fail.s + rc_t value_from_value( const value_t& src, value_t& dst ); + void value_print( const value_t* value, bool info_fl=false); rc_t value_get( const value_t* val, bool& valRef ); @@ -255,6 +238,7 @@ namespace cw rc_t value_set( value_t* val, const object_t* v ); rc_t value_get( const value_t* val, midi::ch_msg_t*& valRef ); + rc_t value_get( const value_t* val, const midi::ch_msg_t*& valRef ); rc_t value_set( value_t* val, midi::ch_msg_t* v ); @@ -264,30 +248,76 @@ namespace cw // Record // - + typedef struct recd_field_str + { + bool group_fl; // set if this field record is a group + char* label; // field or group label + value_t value; // default value for this field + char* doc; // documentation field for this field + union + { + unsigned index; // index into recd_t.valA of the value associated with this field + struct recd_field_str* group_fieldL; + } u; + + struct recd_field_str* link; + } recd_field_t; + + typedef struct recd_type_str + { + recd_field_t* fieldL; // linked list of field spec's + unsigned fieldN; // length of fieldL list (fieldN + base->fieldN) is total field count + const struct recd_type_str* base; // base recd type that this field inherits from + } recd_type_t; + + typedef struct recd_fmt_str + { + unsigned alloc_cnt; // count of records to pre-allocate + recd_type_t* recd_type; // record type for this variable + } recd_fmt_t; + typedef struct recd_array_str { - recd_type_t* type; - value_t* valA; // valA[ allocRecdN * type->fieldN ] - recd_t* recdA; - unsigned allocRecdN; + recd_type_t* type; // recd_type_t of this record array + value_t* valA; // valA[ allocRecdN * type->fieldN ] + struct recd_str* recdA; // recdA[ allocRecdN ] + unsigned allocRecdN; // } recd_array_t; - rc_t recd_type_create( recd_type_t*& recd_type_ref, const recd_type_t* base_type, const char* fields_string=nullptr ); - void recd_type_destroy( recd_type_t*& recd_type ); + typedef struct recd_str + { + struct value_str* valA; // varA[ recd_type_t.fieldN ] array of field values + const struct recd_str* base; // Pointer to the records inherited fields. + } recd_t; - rc_t recd_type_add_value_fields( recd_type_t* recd_type, const char* field_labels ); - rc_t recd_type_add_group( recd_type_t* recd_type, const char* group_label, const char* field_labels ); + + // Create/destroy a recd_format_t object. + rc_t recd_format_create( recd_fmt_t*& recd_fmt_ref, const object_t* cfg ); + void recd_format_destroy( recd_fmt_t*& recd_fmt_ref ); + + // Create a recd_type_t instance from a cfg. description. + rc_t recd_type_create( recd_type_t*& recd_type_ref, const recd_type_t* base_type, const object_t* cfg ); + void recd_type_destroy( recd_type_t*& recd_type ); // Count of fields combined local and base record types. rc_t recd_type_max_field_count( const recd_type_t* recd_type ); - - // use '.' notation to separate groups from fields. + + // Get the field index associated with a named field. + // Use '.' notation to separate groups from fields. // Note if this is a 'local' field then the high bit in the returned index will be set. unsigned recd_type_field_index( const recd_type_t* recd_type, const char* field_label); + // Given a field index return the field label. + const char* recd_type_field_index_to_label( const recd_type_t* recd_type, unsigned field_idx ); + + // Set the record base pointer and the value of all fields with default values. + rc_t recd_init( const recd_type_t* recd_type, const recd_t* base, recd_t* r ); + + // Print the recd_type info. to the console. void recd_type_print( const recd_type_t* recd_type ); + + // Read the value from a single record field template< typename T > rc_t recd_get( const recd_type_t* type, const recd_t* recd, unsigned field_idx, T& val_ref ) { @@ -297,6 +327,27 @@ namespace cw return recd_get( type->base, recd->base, field_idx - type->fieldN, val_ref ); } + inline rc_t _recd_get(const recd_type_t* recd_type, recd_t* r ) { return kOkRC; } + + template< typename T1, typename... ARGS > + rc_t _recd_get( const recd_type_t* recd_type, const recd_t* recd, unsigned field_idx, T1& val, ARGS&&... args ) + { + rc_t rc = kOkRC; + + if((rc = recd_get(recd_type,recd,field_idx,val)) != kOkRC ) + return rc; + + return _recd_get(recd_type,recd,std::forward(args)...); + } + + // Read the value of multiple record fields. + template< typename T1, typename... ARGS > + rc_t recd_get( const recd_type_t* recd_type, const recd_t* recd, unsigned field_idx, T1& val, ARGS&&... args ) + { + return _recd_get(recd_type,recd,field_idx,val,args...); + } + + // Set the base record pointer for a record with an inherited base inline rc_t recd_set_base( const recd_type_t* type, recd_t* recd, const recd_t* base ) { // if we are setting base then the type must have a base type @@ -318,9 +369,50 @@ namespace cw return value_set( recd->valA + field_idx, val ); } + inline rc_t _recd_set( const recd_type_t* recd_type, recd_t* recd ) { return kOkRC; } + + template< typename T1, typename... ARGS > + rc_t _recd_set( const recd_type_t* recd_type, recd_t* recd, unsigned field_idx, const T1& val, ARGS&&... args ) + { + rc_t rc = kOkRC; + + if( field_idx >= recd_type->fieldN ) + return cwLogError(kInvalidArgRC,"Fields in the inherited record may not be set."); + + if((rc = value_set( recd->valA + field_idx, val)) != kOkRC ) + { + rc = cwLogError(rc,"Field set failed on '%s'.", cwStringNullGuard(recd_type_field_index_to_label( recd_type, field_idx ))); + goto errLabel; + } + + return _recd_set(recd_type,recd,std::forward(args)...); + + errLabel: + return rc; + } + + // Set multiple fields of a record. + template< typename T1, typename... ARGS > + rc_t recd_set( const recd_type_t* recd_type, const recd_t* base, recd_t* recd, unsigned field_idx, const T1& val, ARGS&&... args ) + { + rc_t rc = kOkRC; + if((rc = recd_init( recd_type, base, recd )) != kOkRC ) + goto errLabel; + + + if((rc = _recd_set(recd_type,recd,field_idx,val,args...)) != kOkRC ) + goto errLabel; + + errLabel: + return rc; + + } + + // Print a record to the console. rc_t recd_print( const recd_type_t* recd_type, const recd_t* r ); - rc_t recd_array_create( recd_array_t*& recd_array_ref, recd_type_t* recd_type, unsigned allocRecdN ); + // Create/destroy a buffer of records. + rc_t recd_array_create( recd_array_t*& recd_array_ref, recd_type_t* recd_type, const recd_type_t* base, unsigned allocRecdN ); rc_t recd_array_destroy( recd_array_t*& recd_array_ref ); rc_t value_test( const test::test_args_t& args );