cwFlowValue.h/cpp,cwFlowTypes.h : Initial flow::list_t implementation

This commit is contained in:
kevin 2025-04-06 13:44:36 -04:00
parent f1a85bae5d
commit af103abe97
3 changed files with 286 additions and 1 deletions

View File

@ -106,6 +106,8 @@ namespace cw
struct variable_str* src_var; // pointer to this input variables source link (or null if it uses the local_value) struct variable_str* src_var; // pointer to this input variables source link (or null if it uses the local_value)
value_t* value; // pointer to the value associated with this variable value_t* value; // pointer to the value associated with this variable
const list_t* value_list; // list of valid values for this variable or nullptr if not applicable
struct variable_str* var_link; // instance.varL list link struct variable_str* var_link; // instance.varL list link
struct variable_str* ch_link; // list of channels that share this variable (rooted on 'any' channel - in order by channel number) struct variable_str* ch_link; // list of channels that share this variable (rooted on 'any' channel - in order by channel number)
@ -546,7 +548,6 @@ namespace cw
// Disconnect an in_var from it's source // Disconnect an in_var from it's source
void var_disconnect( variable_t* in_var ); void var_disconnect( variable_t* in_var );
// Get the count of 'mult' vars associated with this var label. // Get the count of 'mult' vars associated with this var label.
unsigned var_mult_count( proc_t* proc, const char* var_label ); unsigned var_mult_count( proc_t* proc, const char* var_label );

View File

@ -1814,6 +1814,215 @@ cw::rc_t cw::flow::recd_array_destroy( recd_array_t*& recd_array_ref )
return kOkRC; return kOkRC;
} }
//------------------------------------------------------------------------------------------------------------------------
//
// List
//
namespace cw {
namespace flow {
rc_t _list_destroy( list_t*& list_ref )
{
if( list_ref != nullptr )
{
for(unsigned i=0; i<list_ref->eleN; ++i)
{
mem::release(list_ref->eleA[i].label);
value_release(&list_ref->eleA[i].value );
}
mem::release(list_ref);
}
return kOkRC;
}
}
}
cw::rc_t cw::flow::list_create( list_t*& list_ref, const object_t* cfg )
{
rc_t rc = kOkRC;
bool labelOnlyListFl = false;
if( !cfg->is_list() && !cfg->is_dict() )
{
rc = cwLogError(kInvalidDataTypeRC,"The cfg. given to a flow list is not a JSON list or dictionary.");
goto errLabel;
}
if( cfg->child_count() == 0 )
cwLogWarning("The cfg. list used to form a flow list is empty.");
if((rc = list_create(list_ref, cfg->child_count())) != kOkRC )
goto errLabel;
if( list_ref->eleAllocN == 0 )
goto errLabel;
if( cfg->is_list() )
labelOnlyListFl = true;
for(unsigned i=0; i<list_ref->eleAllocN; ++i)
{
const object_t* ele = cfg->child_ele(i);
const char* label = nullptr;
value_t value;
// if this is a label-only list ...
if( labelOnlyListFl )
{
// this is a label-only list and so all elements must be strings
if( ele->is_string()==false )
{
rc = cwLogError(kSyntaxErrorRC,"The list element at index '%i' is not a string.",i);
goto errLabel;
}
// get the element label
if( ele->value(label) != kOkRC )
{
rc = cwLogError(kSyntaxErrorRC,"Could not parse the list element at index '%i'.",i);
goto errLabel;
}
// ... then the value is the list element index
value_set(&value,i);
}
else // ... otherwise this is (label,value) dictioanry
{
// verify that the list element is a (label,element) pair.
if( !ele->is_pair() )
{
rc = cwLogError(kSyntaxErrorRC,"The list dictionary element at index '%i' is not a (label,value) pair.",i);
goto errLabel;
}
// validate the dictionary label
if( ele->pair_label() == nullptr )
{
rc = cwLogError(kSyntaxErrorRC,"The list dictionary element is missing it's label at index '%i'.",i);
goto errLabel;
}
// convert the dict value to a flow value
if((rc = value_from_cfg(ele->pair_value(),value)) != kOkRC )
{
rc = cwLogError(rc,"Unable to parse the dict. element value field for '%s' at index '%i'.",ele->pair_label(),i);
goto errLabel;
}
// if the conversion did not result in a numeric or string data type
if( cwIsFlag(value.tflag,kCfgTFl) )
{
rc = cwLogError(rc,"List element value field at index '%i' is not a numeric or string type.",i);
goto errLabel;
}
label = ele->pair_label();
}
// add the element to the list
if((rc = list_append( list_ref, label, value )) != kOkRC )
{
rc = cwLogError(rc,"List append failed at index '%i'.",i);
goto errLabel;
}
}
errLabel:
if( rc != kOkRC )
_list_destroy(list_ref);
return rc;
}
cw::rc_t cw::flow::list_create( list_t*& list_ref, unsigned count )
{
rc_t rc = kOkRC;
if((rc = list_destroy(list_ref)) != kOkRC )
return rc;
list_ref = mem::allocZ< list_t >();
list_ref->eleA = mem::allocZ< list_ele_t >( count );
list_ref->eleAllocN = count;
list_ref->eleN = 0;
return rc;
}
cw::rc_t cw::flow::list_destroy( list_t*& list_ref )
{
return _list_destroy(list_ref);
}
cw::rc_t cw::flow::list_append( list_t* list, const char* label, const value_t& value )
{
rc_t rc = kOkRC;
if( textLength(label) == 0 )
{
rc = cwLogError(kInvalidArgRC,"List elements must have a valid label.");
goto errLabel;
}
if( list->eleN >= list->eleAllocN )
{
rc = cwLogError(kBufTooSmallRC,"Cannot append '%s' to a full list.",label);
goto errLabel;
}
if( list->eleN == 0 )
list->eleA[0].value.tflag = value.tflag;
else
list->eleA[list->eleN].value.tflag = list->eleA[0].value.tflag;
if((rc = value_from_value( value, list->eleA[list->eleN].value )) != kOkRC )
{
rc = cwLogError(rc,"Value conversion failed. All value types must be convertiable to type of the first list value.");
goto errLabel;
}
list->eleA[list->eleN].label = mem::duplStr(label);
list->eleN += 1;
errLabel:
if( rc != kOkRC )
rc = cwLogError(rc,"List append failed.");
return rc;
}
const char* cw::flow::list_ele_label( const list_t* list, unsigned index )
{
assert( list != nullptr );
if( index >= list->eleN )
{
cwLogError(kInvalidArgRC,"The list index '%i' is invalid for a list of length '%i'.",index,list->eleN);
return nullptr;
}
return list->eleA[ index ].label;
}
unsigned cw::flow::list_ele_index( const list_t* list, const char* label )
{
assert( list != nullptr );
for(unsigned i=0; i<list->eleN; ++i)
if( textIsEqual(list->eleA[i].label,label) )
return i;
return kInvalidIdx;
}
//------------------------------------------------------------------------------------------------------------------------
cw::rc_t cw::flow::value_test( const test::test_args_t& args ) cw::rc_t cw::flow::value_test( const test::test_args_t& args )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;

View File

@ -424,6 +424,81 @@ namespace cw
// function does very little to verify that the actually are. // function does very little to verify that the actually are.
rc_t recd_copy( const recd_type_t* src_recd_type, const recd_t* src_recdA, unsigned src_recdN, recd_array_t* dest_recd_array ); rc_t recd_copy( const recd_type_t* src_recd_type, const recd_t* src_recdA, unsigned src_recdN, recd_array_t* dest_recd_array );
//------------------------------------------------------------------------------------------------------------------------
//
// List
//
typedef struct list_ele_str
{
char* label;
value_t value;
} list_ele_t;
typedef struct list_str
{
unsigned tflag; // all elements of the list share the same value type.
list_ele_t* eleA;
unsigned eleAllocN;
unsigned eleN;
} list_t;
// Cfg: [ <label0>, <label1> ... <labelN> ] (value is the same as the element index)
// or
// [ (<label0>,<value0> ... (<labelN>,<valueN>) ]
rc_t list_create( list_t*& list_ref, const object_t* cfg );
rc_t list_create( list_t*& list_ref, unsigned count );
rc_t list_destroy( list_t*& list_ref );
rc_t list_append( list_t* list, const char* label, const value_t& value );
template< typename T >
rc_t list_append( list_t* list, const char* label, const T& v )
{
rc_t rc;
value_t value;
value.tflag = kInvalidTFl;
if((rc = value_set(&value,v)) != kOkRC )
goto errLabel;
if((rc = list_append(list,label,value)) != kOkRC )
goto errLabel;
errLabel:
return rc;
}
const char* list_ele_label( const list_t* list, unsigned index );
unsigned list_ele_index( const list_t* list, const char* label );
template< typename T >
rc_t list_ele_value( const list_t* list, unsigned index, T& v )
{
rc_t rc = kOkRC;
if( index >= list->eleN )
{
rc = cwLogError(rc,"The list element index '%i' is invalid on a list of length '%i'.",index,list->eleN);
goto errLabel;
}
if((rc = value_get(&list->eleA[index].value,v)) != kOkRC )
{
rc = cwLogError(rc,"Read of list element value at index '%i' failed.",index,list->eleN);
goto errLabel;
}
errLabel:
return rc;
}
//------------------------------------------------------------------------------------------------------------------------
rc_t value_test( const test::test_args_t& args ); rc_t value_test( const test::test_args_t& args );