diff --git a/structs.scad b/structs.scad new file mode 100644 index 0000000..e82997d --- /dev/null +++ b/structs.scad @@ -0,0 +1,97 @@ +// Section: struct operations +// +// A struct is a data structure that associates arbitrary keywords (of any type) with values (of any type). +// Structures are implemented as lists of [keyword, value] pairs. +// +// An empty list `[]` is an empty structure and can be used wherever a structure input is required. + +// Function: struct_set() +// Usage: +// struct_set(struct, keyword, value, [grow]) +// struct_set(struct, [keyword1, value1, keyword2, value2, ...], [grow]) +// Description: +// Sets the keyword(s) in the structure to the specified value(s), returning a new updated structure. If a keyword +// exists its value is changed, otherwise the keyword is added to the structure. If grow is set to false then +// it is an error to set a keyword not already defined in the structure. If you specify the same keyword twice +// that is also an error. If speed matters, use the first form with scalars rather than the list form: this is +// about thirty times faster. +// Arguments: +// struct = input structure +// keyword = keyword to set +// value = value to set the keyword to +// grow = Set to true to allow structure to grow, or false for new keywords to generate an error. Default: true +function struct_set(struct, keyword, value=undef, grow=true) = + let(aa=echo(struct=struct, keyword=keyword, value=value, grow=grow)) + !is_list(keyword) ? + let(ind=search([keyword],struct,1,0)[0]) + (ind==[] ? assert(grow,str("Unknown keyword \"",keyword)) + concat(struct, [[keyword,value]]) : + list_set([ind], [[keyword,value]],struct)) : + _parse_pairs(struct,keyword,grow); + +function _parse_pairs(spec, input, grow=true, index=0, result=undef) = + assert(len(input)%2==0,"Odd number of entries in [keyword,value] pair list") + let( result = result==undef ? spec : result) + index == len(input) ? result : let(dd=echo(dd=spec, input, grow,index, result)) + _parse_pairs(spec,input,grow,index+2,struct_set(result, input[index], input[index+1],grow)); + +// Function: struct_remove() +// Usage: +// struct_remove(struct, keyword) +// Description: +// Remove keyword or keyword list from a structure +// Arguments: +// struct = input structure +// keyword = a single string (keyword) or list of strings (keywords) to remove +function struct_remove(struct, keyword) = + is_string(keyword)? struct_remove(struct, [keyword]) : + let(ind = search(keyword, struct)) + list_remove(struct, ind); + +// Function: struct_val() +// Usage: +// struct_val(struct,keyword) +// Description: +// Returns the value for the specified keyword in the structure, or undef if the keyword is not present +// Arguments: +// struct = input structure +// keyword = keyword whose value to return +function struct_val(struct,keyword) = + let(ind = search([keyword],struct)[0]) + ind == [] ? undef : struct[ind][1]; + +// Function: struct_keys() +// Usage: +// struct_keys(struct) +// Description: +// Returns a list of the keys in a structure +// Arguments: +// struct = input structure +function struct_keys(struct) = + [for(entry=struct) entry[0]]; + +// Function&Module struct_echo() +// Usage: +// struct_echo(struct, [name]) +// Description: +// Displays a list of structure keywords and values, one pair per line, for easier reading. +// Arguments: +// struct = input structure +// name = optional structure name to list at the top of the output. Default: "" +function struct_echo(struct,name="") = + let( keylist = [for(entry=struct) str("  ",entry[0],": ",entry[1],"\n")]) + echo(str("\nStructure ",name,"\n",str_join(keylist))) + undef; + +module struct_echo(struct,name="") { + dummy = struct_echo(struct,name); +} + +// Function is_struct() +// Usage: +// is_struct(struct) +// Description: Returns true if the input has the form of a structure, false otherwise. +function is_struct(struct, ind=0) = + struct == [] || + let(dim = array_dim(struct)) + len(dim)==2 && dim[1]==2;