omdl  v1.0
OpenSCAD Mechanical Design Library
iterable_test.scad
Go to the documentation of this file.
1 //! Iterable data type tests.
2 /***************************************************************************//**
3  \file
4  \author Roy Allen Sutton
5  \date 2015-2023
6 
7  \copyright
8 
9  This file is part of [omdl] (https://github.com/royasutton/omdl),
10  an OpenSCAD mechanical design library.
11 
12  The \em omdl is free software; you can redistribute it and/or modify
13  it under the terms of the [GNU Lesser General Public License]
14  (http://www.gnu.org/licenses/lgpl.html) as published by the Free
15  Software Foundation; either version 2.1 of the License, or (at
16  your option) any later version.
17 
18  The \em omdl is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  Lesser General Public License for more details.
22 
23  You should have received a copy of the GNU Lesser General Public
24  License along with the \em omdl; if not, write to the Free Software
25  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26  02110-1301, USA; or see <http://www.gnu.org/licenses/>.
27 
28  \details
29 
30  \amu_define group_name (Iterable Tests)
31  \amu_define group_brief (Tests to differentiate iterable data types.)
32 
33  \amu_include (include/amu/doxyg_init_pd_gds_ipg.amu)
34 *******************************************************************************/
35 
36 // auto-tests (add to test results page)
37 /***************************************************************************//**
38  \amu_include (include/amu/validate_log.amu)
39  \amu_include (include/amu/validate_results.amu)
40 *******************************************************************************/
41 
42 // group(s) begin (test summary and includes-required)
43 /***************************************************************************//**
44  \amu_include (include/amu/doxyg_define_in_parent_open.amu)
45  \amu_include (include/amu/validate_summary.amu)
46  \amu_include (include/amu/includes_required.amu)
47 *******************************************************************************/
48 
49 // member-wide reference definitions
50 /***************************************************************************//**
51  \amu_define group_references
52  (
53  )
54 *******************************************************************************/
55 
56 // member-wide documentation and conventions
57 /***************************************************************************//**
58  \addtogroup \amu_eval(${group})
59  \details
60  \anchor \amu_eval(${group})_conventions
61  \par Conventions
62 
63  - The primary parameter is always \p v (the iterable value under test).
64  - The comparison value is always \p cv.
65  - All \c all_* functions return \b true vacuously for an empty \p v,
66  except all_lists(), all_strings(), all_numbers(), and all_len(),
67  which require at least one matching element (c > 0) and return \b false
68  for an empty iterable.
69  - The parameter \p c in all_lists(), all_strings(), all_numbers(),
70  and all_len() is an \em internal recursion counter. It must not be
71  initialised by callers; doing so produces incorrect results.
72  - When \p v is a non-iterable scalar, functions return the result of
73  applying the predicate directly to \p v rather than returning \b undef.
74 *******************************************************************************/
75 
76 //----------------------------------------------------------------------------//
77 // members
78 //----------------------------------------------------------------------------//
79 
80 //! Test if a value has multiple parts and is iterable.
81 /***************************************************************************//**
82  \param v <value> A value.
83 
84  \returns <boolean> \b true when the value is an iterable multi-part value
85  and \b false otherwise.
86 
87  \details
88 
89  input value | function return
90  :-----------:|:-----------------:
91  number | false
92  boolean | false
93  string | true
94  list | true
95  range | false
96  undef | false
97  inf | false
98  nan | false
99 
100  \note The empty list and empty string return \b true.
101 *******************************************************************************/
102 function is_iterable
103 (
104  v
105 ) = is_string(v) || is_list(v);
106 
107 //! Test if an iterable value is empty.
108 /***************************************************************************//**
109  \param v <iterable> An iterable data type value.
110 
111  \returns <boolean> \b true when the iterable value has zero elements
112  and \b false otherwise. Returns \b true when \p v is not
113  an iterable value.
114 *******************************************************************************/
115 function is_empty
116 (
117  v
118 ) = !is_iterable(v) ? true
119  : (len(v) == 0);
120 
121 //! Test if all elements of an iterable value equal a comparison value.
122 /***************************************************************************//**
123  \param v <iterable> An iterable data type value.
124  \param cv <value> A comparison value.
125 
126  \returns <boolean> \b true when all elements of \p v equal the value
127  \p cv and \b false otherwise. Returns \b true when \p v is
128  empty.
129 *******************************************************************************/
130 function all_equal
131 (
132  v,
133  cv
134 ) = !is_iterable(v) ? (v == cv)
135  : (len([for (e = v) if (e != cv) true]) == 0);
136 
137 //! Test if any element of an iterable value equal a comparison value.
138 /***************************************************************************//**
139  \param v <iterable> An iterable data type value.
140  \param cv <value> A comparison value.
141 
142  \returns <boolean> \b true when any element of \p v equals the value
143  \p cv and \b false otherwise. Returns \b false when \p v is
144  empty.
145 *******************************************************************************/
146 function any_equal
147 (
148  v,
149  cv
150 ) = !is_iterable(v) ? (v == cv)
151  : (len([for (e = v) if (e == cv) true]) > 0);
152 
153 //! Test if a value equals one of the comparison values.
154 /***************************************************************************//**
155  \param v <value> A value.
156  \param cv <iterable> An iterable of one or more comparison values.
157 
158  \returns <boolean> \b true when \p v equals any one of the values in
159  \p cv and \b false otherwise.
160 *******************************************************************************/
161 function is_oneof
162 (
163  v,
164  cv
165 ) = any_equal(cv, v);
166 
167 //! Test if all elements of an iterable value equal one of the comparison values.
168 /***************************************************************************//**
169  \param v <iterable> An iterable data type value.
170  \param cv <value> An iterable of one more more comparison values.
171 
172  \returns <boolean> \b true when all elements of \p v equal one of
173  the values in \p cv and \b false otherwise.
174  Returns \b true when \p v is empty.
175 
176  \details
177 
178  When \p v is a string, \p cv must also be a string.
179 *******************************************************************************/
180 function all_oneof
181 (
182  v,
183  cv
184 ) = let
185  (
186  v_i = is_iterable(v),
187  cv_i = is_iterable(cv)
188  )
189  (!v_i && !cv_i) ? (v == cv)
190  : ( v_i && !cv_i) ? all_equal(v, cv)
191  : (!v_i && cv_i) ? any_equal(cv, v)
192  // v_i && cv_i: case 'v' is a string and 'cv' is not a string
193  : (is_string(v) && !is_string(cv)) ? is_empty(v)
194  // v_i && cv_i: remaining three cases
195  // search returns [] for any unmatched element; true only if none are unmatched
196  : !any_equal(search(v, cv, 0, 0), empty_lst);
197 
198 //! Test if no element of an iterable value has an undefined value.
199 /***************************************************************************//**
200  \param v <iterable> An iterable data type value.
201 
202  \returns <boolean> \b true when no element of \p v has its value
203  equal to \b undef and \b false otherwise. Returns \b true
204  when the iterable \p v is empty.
205 *******************************************************************************/
206 function all_defined(v) = !any_equal(v, undef);
207 
208 //! Test if at least one element of an iterable value has a defined value.
209 /***************************************************************************//**
210  \param v <iterable> An iterable data type value.
211 
212  \returns <boolean> \b true when any element of \p v has a defined
213  value and \b false otherwise. Returns \b false when \p v is
214  empty.
215 *******************************************************************************/
216 function any_defined(v) = !all_equal(v, undef);
217 
218 //! Test if at least one element of an iterable value has an undefined value.
219 /***************************************************************************//**
220  \param v <iterable> An iterable data type value.
221 
222  \returns <boolean> \b true when any element of \p v has an undefined
223  value and \b false otherwise. Returns \b false when \p v is
224  empty.
225 *******************************************************************************/
226 function any_undefined(v) = any_equal(v, undef);
227 
228 //! Test if all elements of an iterable value are scalar values.
229 /***************************************************************************//**
230  \param v <iterable> An iterable data type value.
231 
232  \returns <boolean> \b true when all elements of \p v are scalar
233  values and \b false otherwise. Returns \b true when \p v is
234  a single scalar value and \b true when the \p v is an empty,
235  or undefined.
236 *******************************************************************************/
237 function all_scalars
238 (
239  v
240 ) = !is_iterable(v) ? true
241  : (len([for (e = v) if (!is_scalar(e)) true]) == 0);
242 
243 //! Test if all elements of an iterable value are iterable.
244 /***************************************************************************//**
245  \param v <iterable> An iterable data type value.
246 
247  \returns <boolean> \b true when all elements of \p v are iterable
248  and \b false otherwise. Returns \b true when \p v is a
249  single iterable value and returns \b true when \p v is a
250  empty. Returns \b false when \p v is undefined.
251 *******************************************************************************/
252 function all_iterables
253 (
254  v
255 ) = !is_iterable(v) ? false
256  : (len([for (e = v) if (!is_iterable(e)) true]) == 0);
257 
258 //! Test if all elements of an iterable value are lists.
259 /***************************************************************************//**
260  \param v <iterable> An iterable data type value.
261 
262  \returns <boolean> \b true when all elements of \p v are lists
263  and \b false otherwise. Returns \b true when \p v is a
264  single iterable list.
265 *******************************************************************************/
266 function all_lists
267 (
268  v
269 ) = !is_iterable(v) ? false
270  : is_empty(v) ? is_list(v)
271  : (len([for (e = v) if (!is_list(e)) true]) == 0);
272 
273 //! Test if all elements of an iterable value are strings.
274 /***************************************************************************//**
275  \param v <iterable> An iterable data type value.
276 
277  \returns <boolean> \b true when all elements of \p v are strings
278  and \b false otherwise. Returns \b true when \p v is a
279  single string.
280 *******************************************************************************/
281 function all_strings
282 (
283  v
284 ) = !is_iterable(v) ? false
285  : is_empty(v) ? is_string(v)
286  : (len([for (e = v) if (!is_string(e)) true]) == 0);
287 
288 //! Test if all elements of an iterable value are numbers.
289 /***************************************************************************//**
290  \param v <iterable> An iterable data type value.
291 
292  \returns <boolean> \b true when all elements of \p v are numerical
293  values and \b false otherwise. Returns \b true when \p v is
294  a single numerical value.
295 *******************************************************************************/
296 function all_numbers
297 (
298  v
299 ) = !is_iterable(v) ? is_number(v)
300  : is_empty(v) ? false
301  : (len([for (e = v) if (!is_number(e)) true]) == 0);
302 
303 //! Test if all elements of an iterable value are iterable with a fixed length.
304 /***************************************************************************//**
305  \param v <iterable> An iterable data type value.
306  \param l <integer> The required length of each value.
307 
308  \returns <boolean> \b true when all elements of \p v are iterable
309  values with lengths equal to \p l and \b false otherwise.
310 *******************************************************************************/
311 function all_len
312 (
313  v,
314  l
315 ) = !is_iterable(v) ? false
316  : is_empty(v) ? false
317  : (len([for (e = v) if (!is_iterable(e) || (len(e) != l)) true]) == 0);
318 
319 //! @}
320 //! @}
321 
322 //----------------------------------------------------------------------------//
323 // openscad-amu auxiliary scripts
324 //----------------------------------------------------------------------------//
325 
326 /*
327 BEGIN_SCOPE validate;
328  BEGIN_OPENSCAD;
329  include <omdl-base.scad>;
330  include <common/validation.scad>;
331 
332  function fmt( id, td, v1, v2, v3 ) = table_validate_fmt(id, td, v1, v2, v3);
333  function v1(db, id) = table_validate_get_v1(db, id);
334  t = true; f = false; u = undef; s = validation_skip;
335 
336  tbl_test_values =
337  [
338  fmt("t01", "The undefined value", undef),
339  fmt("t02", "An odd integer", 1),
340  fmt("t03", "The boolean true", true),
341  fmt("t04", "The boolean false", false),
342  fmt("t05", "A character string", "a"),
343  fmt("t06", "A string", "This is a longer string"),
344  fmt("t07", "The empty string", empty_str),
345  fmt("t08", "The empty list", empty_lst),
346  fmt("t09", "A shorthand range", [0:9]),
347  fmt("t10", "A range", [0:0.5:9]),
348  fmt("t11", "Single item list: 1 undef", [undef]),
349  fmt("t12", "Single item list: 1 number", [1]),
350  fmt("t13", "List of 3 numbers", [1, 2, 3]),
351  fmt("t14", "List of single num lists", [[1], [2], [3], [4], [5]]),
352  fmt("t15", "List of number pairs", [[1,2], [2,3]]),
353  fmt("t16", "List of num pairs and str", [[1,2], [2,3], [4,5], "ab"]),
354  fmt("t17", "List of mixed tuples", [[1,2,3], [4,5,6], [7,8,9], ["a", "b", "c"]]),
355  fmt("t18", "List of number with undef", [1, 2, 3, undef]),
356  fmt("t19", "List of items, all = undef", [undef, undef, undef, undef]),
357  fmt("t20", "List of lists, all = undef", [[undef], [undef], [undef]]),
358  fmt("t21", "List of mixed booleans mt", [true, true, true, true, false]),
359  fmt("t22", "List of mixed booleans mf", [true, false, false, false, false]),
360  fmt("t23", "List of booleans = true", [true, true, true, true])
361  ];
362 
363  tbl_test_answers =
364  [ // function 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
365  ["is_iterable", f, f, f, f, t, t, t, t, f, f, t, t, t, t, t, t, t, t, t, t, t, t, t],
366  ["is_empty", t, t, t, t, f, f, t, t, t, t, f, f, f, f, f, f, f, f, f, f, f, f, f],
367  ["all_equal_T", f, f, t, f, f, f, t, t, f, f, f, f, f, f, f, f, f, f, f, f, f, f, t],
368  ["all_equal_F", f, f, f, t, f, f, t, t, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f],
369  ["all_equal_U", t, f, f, f, f, f, t, t, f, f, t, f, f, f, f, f, f, f, t, f, f, f, f],
370  ["any_equal_T", f, f, t, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, t, t, t],
371  ["any_equal_F", f, f, f, t, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, t, t, f],
372  ["any_equal_U", t, f, f, f, f, f, f, f, f, f, t, f, f, f, f, f, f, t, t, f, f, f, f],
373  ["all_oneof_S1", t, t, t, t, f, f, t, t, f, f, t, t, t, f, f, f, f, t, t, f, t, t, t],
374  ["all_defined", f, t, t, t, t, t, t, t, t, t, f, t, t, t, t, t, t, f, f, t, t, t, t],
375  ["any_defined", f, t, t, t, t, t, f, f, t, t, f, t, t, t, t, t, t, t, f, t, t, t, t],
376  ["any_undefined", t, f, f, f, f, f, f, f, f, f, t, f, f, f, f, f, f, t, t, f, f, f, f],
377  ["all_scalars", t, t, t, t, f, f, t, t, t, t, t, t, t, f, f, f, f, t, t, f, t, t, t],
378  ["all_iterables", f, f, f, f, t, t, t, t, f, f, f, f, f, t, t, t, t, f, f, t, f, f, f],
379  ["all_lists", f, f, f, f, f, f, f, t, f, f, f, f, f, t, t, f, t, f, f, t, f, f, f],
380  ["all_strings", f, f, f, f, t, t, t, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f],
381  ["all_numbers", f, t, f, f, f, f, f, f, f, f, f, t, t, f, f, f, f, f, f, f, f, f, f],
382  ["all_len_1", f, f, f, f, t, t, f, f, f, f, f, f, f, t, f, f, f, f, f, t, f, f, f],
383  ["all_len_2", f, f, f, f, f, f, f, f, f, f, f, f, f, f, t, t, f, f, f, f, f, f, f],
384  ["all_len_3", f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, t, f, f, f, f, f, f]
385  ];
386 
387  db = table_validate_init( tbl_test_values, tbl_test_answers );
388 
389  table_validate_start( db );
390  test_ids = table_validate_get_ids( db );
391 
392  for (id=test_ids) table_validate( db, id, "is_iterable", 1, is_iterable( v1(db,id) ) );
393  for (id=test_ids) table_validate( db, id, "is_empty", 1, is_empty( v1(db,id) ) );
394  for (id=test_ids) table_validate( db, id, "all_equal_T", 1, all_equal( v1(db,id), t ) );
395  for (id=test_ids) table_validate( db, id, "all_equal_F", 1, all_equal( v1(db,id), f ) );
396  for (id=test_ids) table_validate( db, id, "all_equal_U", 1, all_equal( v1(db,id), u ) );
397  for (id=test_ids) table_validate( db, id, "any_equal_T", 1, any_equal( v1(db,id), t ) );
398  for (id=test_ids) table_validate( db, id, "any_equal_F", 1, any_equal( v1(db,id), f ) );
399  for (id=test_ids) table_validate( db, id, "any_equal_U", 1, any_equal( v1(db,id), u ) );
400  // is_oneof()
401  for (id=test_ids) table_validate( db, id, "all_oneof_S1", 1, all_oneof( v1(db,id), [undef, 1, 2, 3, true, false] ) );
402  for (id=test_ids) table_validate( db, id, "all_defined", 1, all_defined( v1(db,id) ) );
403  for (id=test_ids) table_validate( db, id, "any_defined", 1, any_defined( v1(db,id) ) );
404  for (id=test_ids) table_validate( db, id, "any_undefined", 1, any_undefined( v1(db,id) ) );
405  for (id=test_ids) table_validate( db, id, "all_scalars", 1, all_scalars( v1(db,id) ) );
406  for (id=test_ids) table_validate( db, id, "all_iterables", 1, all_iterables( v1(db,id) ) );
407  for (id=test_ids) table_validate( db, id, "all_lists", 1, all_lists( v1(db,id) ) );
408  for (id=test_ids) table_validate( db, id, "all_strings", 1, all_strings( v1(db,id) ) );
409  for (id=test_ids) table_validate( db, id, "all_numbers", 1, all_numbers( v1(db,id) ) );
410 
411  for (id=test_ids) table_validate( db, id, "all_len_1", 1, all_len( v1(db,id), 1 ) );
412  for (id=test_ids) table_validate( db, id, "all_len_2", 1, all_len( v1(db,id), 2 ) );
413  for (id=test_ids) table_validate( db, id, "all_len_3", 1, all_len( v1(db,id), 3 ) );
414 
415  // end_include
416  END_OPENSCAD;
417 
418  BEGIN_MFSCRIPT;
419  include --path "${INCLUDE_PATH}" {var_init,var_gen_term}.mfs;
420  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
421  END_MFSCRIPT;
422 END_SCOPE;
423 */
424 
425 //----------------------------------------------------------------------------//
426 // end of file
427 //----------------------------------------------------------------------------//
empty_lst
<list> A list with no values (the empty list).
Definition: constants.scad:304
function all_len(v, l)
Test if all elements of an iterable value are iterable with a fixed length.
function all_lists(v)
Test if all elements of an iterable value are lists.
function any_defined(v)
Test if at least one element of an iterable value has a defined value.
function all_defined(v)
Test if no element of an iterable value has an undefined value.
function all_equal(v, cv)
Test if all elements of an iterable value equal a comparison value.
function all_scalars(v)
Test if all elements of an iterable value are scalar values.
function any_undefined(v)
Test if at least one element of an iterable value has an undefined value.
function is_iterable(v)
Test if a value has multiple parts and is iterable.
function is_oneof(v, cv)
Test if a value equals one of the comparison values.
function all_iterables(v)
Test if all elements of an iterable value are iterable.
function is_empty(v)
Test if an iterable value is empty.
function any_equal(v, cv)
Test if any element of an iterable value equal a comparison value.
function all_strings(v)
Test if all elements of an iterable value are strings.
function all_oneof(v, cv)
Test if all elements of an iterable value equal one of the comparison values.
function all_numbers(v)
Test if all elements of an iterable value are numbers.
function is_scalar(v)
Test if a value is a single non-iterable value.
function is_number(v)
Test if a value is a number.