mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-28 15:59:45 +00:00
fix structs to work as documented (support arbitrary type keys)
and check usage texts
This commit is contained in:
parent
65615dc07d
commit
49ce521c7c
3 changed files with 76 additions and 57 deletions
|
@ -120,7 +120,7 @@ _hose_waist = [1.7698, 1.8251, 3.95998];
|
|||
|
||||
// Module: modular_hose()
|
||||
// Usage:
|
||||
// modular_hose(size, type, [clearance], [waist_len], [anchor], [spin], [orient]) [attachments]
|
||||
// modular_hose(size, type, [clearance], [waist_len], [anchor], [spin], [orient]) [ATTACHMENTS];
|
||||
// Description:
|
||||
// Construct moduler hose segments or modular hose ends for connection to standard
|
||||
// modular hose systems. The 1/4", 1/2" and 3/4" sizes are supported and you can
|
||||
|
|
107
structs.scad
107
structs.scad
|
@ -1,6 +1,8 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// LibFile: structs.scad
|
||||
// Struct/Dictionary manipulation functions.
|
||||
// This file provides manipulation of "structs". A "struct" is a data structure that
|
||||
// associates keywords with values and allows you to get and set values
|
||||
// by keyword.
|
||||
// Includes:
|
||||
// include <BOSL2/std.scad>
|
||||
// include <BOSL2/structs.scad>
|
||||
|
@ -11,69 +13,74 @@
|
|||
|
||||
// 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.
|
||||
// A struct is a data structure that associates arbitrary keys (of any type) with values (of any type).
|
||||
// Structures are implemented as lists of [key, 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])
|
||||
// struct_set(struct, key, value, [grow=])
|
||||
// struct_set(struct, [key1, value1, key2, 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.
|
||||
// Sets the key(s) in the structure to the specified value(s), returning a new updated structure. If a key
|
||||
// exists its value is changed, otherwise the key is added to the structure. If grow is set to false then
|
||||
// it is an error to set a key not already defined in the structure. If you specify the same key twice
|
||||
// that is also an error. Note that key order will change when you change a key's value.
|
||||
// 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) =
|
||||
!is_list(keyword)? (
|
||||
let( ind=search([keyword],struct,1,0)[0] )
|
||||
ind==[]? (
|
||||
assert(grow,str("Unknown keyword \"",keyword))
|
||||
concat(struct, [[keyword,value]])
|
||||
) : list_set(struct, [ind], [[keyword,value]])
|
||||
) : _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 :
|
||||
_parse_pairs(spec,input,grow,index+2,struct_set(result, input[index], input[index+1],grow));
|
||||
// struct = input structure.
|
||||
// key = key to set or list of key,value pairs to set
|
||||
// value = value to set the key to (when giving a single key and value)
|
||||
// ---
|
||||
// grow = Set to true to allow structure to grow, or false for new keys to generate an error. Default: true
|
||||
function struct_set(struct, key, value, grow=true) =
|
||||
is_def(value) ? struct_set(struct,[key,value],grow=grow)
|
||||
:
|
||||
assert(is_list(key) && len(key)%2==0, "[key,value] pair list is not a list or has an odd length")
|
||||
let(
|
||||
new_entries = [for(i=[0:1:len(key)/2-1]) [key[2*i], key[2*i+1]]],
|
||||
newkeys = column(new_entries,0),
|
||||
indlist = search(newkeys, struct,0,0),
|
||||
badkeys = grow ? (search([undef],new_entries,1,0)[0] != [] ? [undef] : [])
|
||||
: [for(i=idx(indlist)) if (is_undef(newkeys[i]) || len(indlist[i])==0) newkeys[i]],
|
||||
ind = flatten(indlist),
|
||||
dupfind = search(newkeys, new_entries,0,0),
|
||||
dupkeys = [for(i=idx(dupfind)) if (len(dupfind[i])>1) newkeys[i]]
|
||||
)
|
||||
assert(badkeys==[], str("Unknown or bad key ",_format_key(badkeys[0])," in struct_set"))
|
||||
assert(dupkeys==[], str("Duplicate key ",_format_key(dupkeys[0])," for struct"))
|
||||
concat(list_remove(struct,ind), new_entries);
|
||||
|
||||
function _format_key(key) = is_string(key) ? str("\"",key,"\""): key;
|
||||
|
||||
// Function: struct_remove()
|
||||
// Usage:
|
||||
// struct_remove(struct, keyword)
|
||||
// struct_remove(struct, key)
|
||||
// Description:
|
||||
// Remove keyword or keyword list from a structure
|
||||
// Remove key or list of keys from a structure. If you want to remove a single key which is a list
|
||||
// you must pass it as a singleton list, or struct_remove will attempt to remove the listed items as keys.
|
||||
// If you list the same item multiple times for removal it will be removed without error.
|
||||
// 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))
|
||||
// key = a single key or list of keys to remove.
|
||||
function struct_remove(struct, key) =
|
||||
!is_list(key) ? struct_remove(struct, [key]) :
|
||||
let(ind = search(key, struct))
|
||||
list_remove(struct, ind);
|
||||
|
||||
|
||||
// Function: struct_val()
|
||||
// Usage:
|
||||
// struct_val(struct, keyword, default)
|
||||
// struct_val(struct, key, default)
|
||||
// Description:
|
||||
// Returns the value for the specified keyword in the structure, or default value if the keyword is not present
|
||||
// Returns the value for the specified key in the structure, or default value if the key is not present
|
||||
// Arguments:
|
||||
// struct = input structure
|
||||
// keyword = keyword whose value to return
|
||||
// default = default value to return if keyword is not present, defaults to undef
|
||||
function struct_val(struct, keyword, default=undef) =
|
||||
assert(is_def(keyword),"keyword is missing")
|
||||
let(ind = search([keyword],struct)[0])
|
||||
// key = key whose value to return
|
||||
// default = default value to return if key is not present. Default: undef
|
||||
function struct_val(struct, key, default=undef) =
|
||||
assert(is_def(key),"key is missing")
|
||||
let(ind = search([key],struct)[0])
|
||||
ind == [] ? default : struct[ind][1];
|
||||
|
||||
|
||||
|
@ -84,15 +91,14 @@ function struct_val(struct, keyword, default=undef) =
|
|||
// Returns a list of the keys in a structure
|
||||
// Arguments:
|
||||
// struct = input structure
|
||||
function struct_keys(struct) =
|
||||
[for(entry=struct) entry[0]];
|
||||
function struct_keys(struct) = column(struct,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.
|
||||
// Displays a list of structure keys 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: ""
|
||||
|
@ -111,16 +117,9 @@ module struct_echo(struct,name="") {
|
|||
// Usage:
|
||||
// is_struct(struct)
|
||||
// Description:
|
||||
// Returns true if the input has the form of a structure, false otherwise.
|
||||
// Returns true if the input is a list of pairs, false otherwise.
|
||||
function is_struct(x) =
|
||||
is_list(x) && [
|
||||
for (xx=x) if(
|
||||
!is_list(xx) ||
|
||||
len(xx) != 2 ||
|
||||
!is_string(xx[0])
|
||||
) 1
|
||||
] == [];
|
||||
|
||||
is_list(x) && [for (xx=x) if(!(is_list(xx) && len(xx)==2)) 1] == [];
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
|
|
|
@ -8,7 +8,17 @@ module test_struct_set() {
|
|||
st2 = struct_set(st, "Bar", 28);
|
||||
assert(st2 == [["Foo",42],["Bar",28]]);
|
||||
st3 = struct_set(st2, "Foo", 91);
|
||||
assert(st3 == [["Foo",91],["Bar",28]]);
|
||||
assert(st3 == [["Bar",28],["Foo",91]]);
|
||||
st4 = struct_set(st3, [3,4,5,6]);
|
||||
assert(st4 == [["Bar", 28],["Foo",91],[3,4],[5,6]]);
|
||||
st5 = struct_set(st3, [[3,4],[5,6]]);
|
||||
assert(st5 == [["Bar", 28],["Foo",91],[[3,4],[5,6]]]);
|
||||
st6 = struct_set(st3, [3,4],true);
|
||||
assert(st6 == [["Bar", 28],["Foo",91],[[3,4],true]]);
|
||||
st7 = struct_set(st3, [3,4,[5,7],99]);
|
||||
assert(st7 == [["Bar", 28],["Foo",91],[3,4],[[5,7],99]]);
|
||||
st8 = struct_set(st3,[]);
|
||||
assert(st8==st3);
|
||||
}
|
||||
test_struct_set();
|
||||
|
||||
|
@ -18,18 +28,26 @@ module test_struct_remove() {
|
|||
assert(struct_remove(st, "Foo") == [["Bar",28],["Baz",9]]);
|
||||
assert(struct_remove(st, "Bar") == [["Foo",91],["Baz",9]]);
|
||||
assert(struct_remove(st, "Baz") == [["Foo",91],["Bar",28]]);
|
||||
assert(struct_remove(st, ["Baz","Baz"]) == [["Foo",91],["Bar",28]]);
|
||||
assert(struct_remove(st, ["Baz","Foo"]) == [["Bar",28]]);
|
||||
assert(struct_remove(st, []) == st);
|
||||
assert(struct_remove(st, struct_keys(st)) == []);
|
||||
}
|
||||
test_struct_remove();
|
||||
|
||||
|
||||
module test_struct_val() {
|
||||
st = [["Foo",91],["Bar",28],["Baz",9]];
|
||||
st = [["Foo",91],["Bar",28],[true,99],["Baz",9],[[5,4],3], [7,92]];
|
||||
assert(struct_val(st,"Foo") == 91);
|
||||
assert(struct_val(st,"Bar") == 28);
|
||||
assert(struct_val(st,"Baz") == 9);
|
||||
assert(struct_val(st,"Baz",5) == 9);
|
||||
assert(struct_val(st,"Qux") == undef);
|
||||
assert(struct_val(st,"Qux",5) == 5);
|
||||
assert(struct_val(st,[5,4])==3);
|
||||
assert(struct_val(st,true)==99);
|
||||
assert(struct_val(st,5) == undef);
|
||||
assert(struct_val(st,7) == 92);
|
||||
}
|
||||
test_struct_val();
|
||||
|
||||
|
@ -37,6 +55,7 @@ test_struct_val();
|
|||
module test_struct_keys() {
|
||||
assert(struct_keys([["Foo",3],["Bar",2],["Baz",1]]) == ["Foo","Bar","Baz"]);
|
||||
assert(struct_keys([["Zee",1],["Why",2],["Exx",3]]) == ["Zee","Why","Exx"]);
|
||||
assert(struct_keys([["Zee",1],[[3,4],2],["Why",2],[9,1],["Exx",3]]) == ["Zee",[3,4],"Why",9,"Exx"]);
|
||||
}
|
||||
test_struct_keys();
|
||||
|
||||
|
@ -55,6 +74,7 @@ module test_is_struct() {
|
|||
assert(!is_struct(3));
|
||||
assert(!is_struct(true));
|
||||
assert(!is_struct("foo"));
|
||||
assert(is_struct([]));
|
||||
}
|
||||
test_is_struct();
|
||||
|
||||
|
|
Loading…
Reference in a new issue