1//////////////////////////////////////////////////////////////////////
2// LibFile: structs.scad
3// This file provides manipulation of "structs". A "struct" is a data structure that
4// associates arbitrary keys with values and allows you to get and set values
5// by key.
6// Includes:
7// include <BOSL2/std.scad>
8// include <BOSL2/structs.scad>
9// FileGroup: Data Management
10// FileSummary: Structure/Dictionary Manipulation
11//////////////////////////////////////////////////////////////////////
12
13
14// Section: struct operations
15//
16// A struct is a data structure that associates arbitrary keys (of any type) with values (of any type).
17// Structures are implemented as lists of [key, value] pairs.
18//
19// An empty list `[]` is an empty structure and can be used wherever a structure input is required.
20
21// Function: struct_set()
22// Usage:
23// struct_set(struct, key, value, [grow=])
24// struct_set(struct, [key1, value1, key2, value2, ...], [grow=])
25// Description:
26// Sets the key(s) in the structure to the specified value(s), returning a new updated structure. If a key
27// exists its value is changed, otherwise the key is added to the structure. If grow is set to false then
28// it is an error to set a key not already defined in the structure. If you specify the same key twice
29// that is also an error. Note that key order will change when you change a key's value.
30// Arguments:
31// struct = input structure.
32// key = key to set or list of key,value pairs to set
33// value = value to set the key to (when giving a single key and value)
34// ---
35// grow = Set to true to allow structure to grow, or false for new keys to generate an error. Default: true
36function struct_set(struct, key, value, grow=true) =
37 is_def(value) ? struct_set(struct,[key,value],grow=grow)
38 :
39 assert(is_list(key) && len(key)%2==0, "[key,value] pair list is not a list or has an odd length")
40 let(
41 new_entries = [for(i=[0:1:len(key)/2-1]) [key[2*i], key[2*i+1]]],
42 newkeys = column(new_entries,0),
43 indlist = search(newkeys, struct,0,0),
44 badkeys = grow ? (search([undef],new_entries,1,0)[0] != [] ? [undef] : [])
45 : [for(i=idx(indlist)) if (is_undef(newkeys[i]) || len(indlist[i])==0) newkeys[i]],
46 ind = flatten(indlist),
47 dupfind = search(newkeys, new_entries,0,0),
48 dupkeys = [for(i=idx(dupfind)) if (len(dupfind[i])>1) newkeys[i]]
49 )
50 assert(badkeys==[], str("Unknown or bad key ",_format_key(badkeys[0])," in struct_set"))
51 assert(dupkeys==[], str("Duplicate key ",_format_key(dupkeys[0])," for struct"))
52 concat(list_remove(struct,ind), new_entries);
53
54function _format_key(key) = is_string(key) ? str("\"",key,"\""): key;
55
56// Function: struct_remove()
57// Usage:
58// struct_remove(struct, key)
59// Description:
60// Remove key or list of keys from a structure. If you want to remove a single key which is a list
61// you must pass it as a singleton list, or struct_remove will attempt to remove the listed items as keys.
62// If you list the same item multiple times for removal it will be removed without error.
63// Arguments:
64// struct = input structure
65// key = a single key or list of keys to remove.
66function struct_remove(struct, key) =
67 !is_list(key) ? struct_remove(struct, [key]) :
68 let(ind = search(key, struct))
69 list_remove(struct, ind);
70
71
72// Function: struct_val()
73// Usage:
74// struct_val(struct, key, default)
75// Description:
76// Returns the value for the specified key in the structure, or default value if the key is not present
77// Arguments:
78// struct = input structure
79// key = key whose value to return
80// default = default value to return if key is not present. Default: undef
81function struct_val(struct, key, default=undef) =
82 assert(is_def(key),"key is missing")
83 let(ind = search([key],struct)[0])
84 ind == [] ? default : struct[ind][1];
85
86
87// Function: struct_keys()
88// Usage:
89// keys = struct_keys(struct)
90// Description:
91// Returns a list of the keys in a structure
92// Arguments:
93// struct = input structure
94function struct_keys(struct) = column(struct,0);
95
96
97// Function&Module: echo_struct()
98// Usage:
99// echo_struct(struct, [name])
100// Description:
101// Displays a list of structure keys and values, one pair per line, for easier reading.
102// Arguments:
103// struct = input structure
104// name = optional structure name to list at the top of the output. Default: ""
105function echo_struct(struct,name="") =
106 let( keylist = [for(entry=struct) str(" ",entry[0],": ",entry[1],"\n")])
107 echo(str("\nStructure ",name,"\n",str_join(keylist)))
108 undef;
109
110module echo_struct(struct,name="") {
111 no_children($children);
112 dummy = echo_struct(struct,name);
113}
114
115
116// Function: is_struct()
117// Usage:
118// is_struct(struct)
119// Description:
120// Returns true if the input is a list of pairs, false otherwise.
121function is_struct(x) =
122 is_list(x) && [for (xx=x) if(!(is_list(xx) && len(xx)==2)) 1] == [];
123
124
125// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap