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
This commit is contained in:
kevin 2024-11-25 09:55:05 -05:00
parent c450378d78
commit e3423e775e
2 changed files with 621 additions and 234 deletions

View File

@ -70,6 +70,7 @@ 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);
@ -77,113 +78,175 @@ namespace cw
}
}
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;
}
new_field_ref = nullptr;
if( textLength(field_label) == 0 )
{
rc = cwLogError(kInvalidArgRC,"A blank msg field was encountered.");
goto errLabel;
}
const char* _recd_field_index_to_label(const recd_field_t* fld, unsigned field_idx)
{
const char* label = nullptr;
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;
return label;
}
rc_t _recd_field_list_from_cfg( recd_field_t*& field_list_ref, const object_t* field_dict_cfg )
{
rc_t rc = kOkRC;
if( !field_dict_cfg->is_dict() )
{
rc = cwLogError(kSyntaxErrorRC,"The field cfg. is not a dictionary.");
goto errLabel;
}
new_field = mem::allocZ<recd_field_t>();
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;
}
unsigned row_cnt = field_dict_cfg->child_count();
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;
}
rc_t _recd_type_add_value_fields( recd_type_t* recd_type, recd_field_t*& fieldL_ref, const char* field_labels )
{
rc_t rc = kOkRC;
const char* s0 = field_labels;
while(s0 != nullptr)
{
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 )
for(unsigned i=0; i<row_cnt; ++i)
{
goto errLabel;
const object_t* pair = field_dict_cfg->child_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<recd_field_t>();
// 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;
}
}
}
}
recd_type->fieldN += 1;
}
errLabel:
return rc;
}
s0 = s1;
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;
}
@ -780,6 +843,136 @@ 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,18 +1625,75 @@ 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 )
//------------------------------------------------------------------------------------------------------------------------
//
// 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<recd_fmt_t>();
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_t>();
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_t>();
recd_array_ref = nullptr;
recd_array->type = recd_type;
recd_array->type = mem::allocZ<recd_type_t>();
recd_array->type->fieldL = recd_type->fieldL;
recd_array->type->fieldN = recd_type->fieldN;
recd_array->type->base = base;
recd_array->valA = mem::allocZ<value_t>(recd_array->type->fieldN * allocRecdN);
recd_array->recdA = mem::allocZ<recd_t>(allocRecdN);
recd_array->allocRecdN = allocRecdN;
// for each record
for(unsigned i=0; i<allocRecdN; ++i)
{
// set the value array for this record
recd_array->recdA[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,67 +1817,86 @@ 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 )
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 = objectFromString(s0,cfg0)) != kOkRC )
{
rc = cwLogError(rc,"rt0 create failed.");
rc = cwLogError(rc,"cfg0 parse failed.");
goto errLabel;
}
if((rc = recd_type_add_group( rt0, "g0", "a b c" )) != kOkRC )
if((rc = objectFromString(s1,cfg1)) != kOkRC )
{
rc = cwLogError(rc,"rt.g0 group create failed.");
rc = cwLogError(rc,"cfg1 parse failed.");
goto errLabel;
}
if((rc = recd_type_create( rt1, rt0, "d e f" )) != kOkRC )
if((rc = recd_format_create( fmt0, cfg0 )) != kOkRC )
{
rc = cwLogError(rc,"rt0 create failed.");
rc = cwLogError(rc,"fmt0 create failed.");
goto errLabel;
}
if((rc = recd_type_add_group( rt1, "g1", "a b c" )) != kOkRC )
if((rc = recd_format_create( fmt1, cfg1 )) != kOkRC )
{
rc = cwLogError(rc,"rt.g0 group create failed.");
rc = cwLogError(rc,"fmt1 create failed.");
goto errLabel;
}
recd_type_print( rt0 );
recd_type_print( rt1 );
if((rc = recd_array_create(ra0,rt0,10)) != kOkRC )
if((rc = recd_array_create( ra0, fmt0->recd_type, nullptr, fmt0->alloc_cnt )) != kOkRC )
{
rc = cwLogError(rc,"ra0 alloc failed.");
rc = cwLogError(rc,"recd array 0 create failed.");
goto errLabel;
}
if((rc = recd_array_create(ra1,rt1,10)) != kOkRC )
if((rc = recd_array_create( ra1, fmt1->recd_type, fmt0->recd_type, fmt1->alloc_cnt )) != kOkRC )
{
rc = cwLogError(rc,"ra1 alloc failed.");
rc = cwLogError(rc,"recd array 0 create failed.");
goto errLabel;
}
for(unsigned i=0; i<ra0->allocRecdN; ++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;
}
}
@ -1615,20 +1904,19 @@ cw::rc_t cw::flow::value_test( const test::test_args_t& args )
for(unsigned i=0; i<ra0->allocRecdN; ++i)
recd_print(ra0->type,ra0->recdA+i);
for(unsigned i=0; i<ra1->allocRecdN; ++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;
}
}
@ -1636,11 +1924,18 @@ cw::rc_t cw::flow::value_test( const test::test_args_t& args )
for(unsigned i=0; i<ra1->allocRecdN; ++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;
}

View File

@ -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>(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>(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 );