omdl  v0.9.5
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/pgid_path_pstem_pg.amu)
34 *******************************************************************************/
35 
36 //----------------------------------------------------------------------------//
37 // validation.
38 //----------------------------------------------------------------------------//
39 
40 /***************************************************************************//**
41  \amu_include (include/amu/validate_log_th.amu)
42  \amu_include (include/amu/validate_log_td.amu)
43  \amu_include (include/amu/validate_results.amu)
44 *******************************************************************************/
45 
46 //----------------------------------------------------------------------------//
47 // group.
48 //----------------------------------------------------------------------------//
49 
50 /***************************************************************************//**
51  \amu_include (include/amu/group_in_parent_start.amu)
52  \amu_include (include/amu/includes_required.amu)
53 
54  \details
55 
56  \amu_include (include/amu/validate_summary.amu)
57 *******************************************************************************/
58 
59 //----------------------------------------------------------------------------//
60 
61 //! Test if a value has multiple parts and is iterable.
62 /***************************************************************************//**
63  \param v <value> A value.
64 
65  \returns <boolean> \b true when the value is an iterable multi-part value
66  and \b false otherwise.
67 
68  \details
69 
70  input value | function return
71  :-----------:|:-----------------:
72  \em number | \b false
73  \em boolean | \b false
74  \em string | \b true
75  \em list | \b true
76  \em range | \b false
77  \b undef | \b false
78  \b inf | \b false
79  \b nan | \b false
80 
81  \note The empty list and empty string return \b true.
82 *******************************************************************************/
83 function is_iterable
84 (
85  v
86 ) = is_string(v) || is_list(v);
87 
88 //! Test if an iterable value is empty.
89 /***************************************************************************//**
90  \param v <iterable> An iterable data type value.
91 
92  \returns <boolean> \b true when the iterable value has zero elements
93  and \b false otherwise. Returns \b true when \p v is not
94  an iterable value.
95 *******************************************************************************/
96 function is_empty
97 (
98  v
99 ) = !is_iterable(v) ? true
100  : (len(v) == 0);
101 
102 //! Test if all elements of an iterable value equal a comparison value.
103 /***************************************************************************//**
104  \param v <iterable> An iterable data type value.
105  \param cv <value> A comparison value.
106 
107  \returns <boolean> \b true when all elements of \p v equal the value
108  \p cv and \b false otherwise. Returns \b true when \p v is
109  empty.
110 *******************************************************************************/
111 function all_equal
112 (
113  v,
114  cv
115 ) = !is_iterable(v) ? (v == cv)
116  : is_empty(v) ? true
117  : (first(v) != cv) ? false
118  : all_equal(tailn(v), cv);
119 
120 //! Test if any element of an iterable value equal a comparison value.
121 /***************************************************************************//**
122  \param v <iterable> An iterable data type value.
123  \param cv <value> A comparison value.
124 
125  \returns <boolean> \b true when any element of \p v equals the value
126  \p cv and \b false otherwise. Returns \b false when \p v is
127  empty.
128 *******************************************************************************/
129 function any_equal
130 (
131  v,
132  cv
133 ) = !is_iterable(v) ? (v == cv)
134  : is_empty(v) ? false
135  : (first(v) == cv) ? true
136  : any_equal(tailn(v), cv);
137 
138 //! Test if all elements of an iterable value equal one of the comparison values.
139 /***************************************************************************//**
140  \param v <iterable> An iterable data type value.
141  \param cv <value> An iterable of one more more comparison values.
142 
143  \returns <boolean> \b true when all elements of \p v equal one of
144  the values in \p cv and \b false otherwise.
145  Returns \b true when \p v is empty.
146 
147  \details
148 
149  When \p v is a string, \p cv must also be a string.
150 *******************************************************************************/
151 function all_oneof
152 (
153  v,
154  cv
155 ) = let
156  (
157  v_i = is_iterable(v),
158  cv_i = is_iterable(cv)
159  )
160  (!v_i && !cv_i) ? (v == cv)
161  : ( v_i && !cv_i) ? all_equal(v, cv)
162  : (!v_i && cv_i) ? any_equal(cv, v)
163  // v_i && cv_i: case 'v' is a string and 'cv' is not a string
164  : (is_string(v) && !is_string(cv)) ? false
165  // v_i && cv_i: remaining three cases
166  : !any_equal(search(v, cv, 0, 0), empty_lst);
167 
168 //! Test if no element of an iterable value has an undefined value.
169 /***************************************************************************//**
170  \param v <iterable> An iterable data type value.
171 
172  \returns <boolean> \b true when no element of \p v has its value
173  equal to \b undef and \b false otherwise. Returns \b true
174  when the iterable \p v is empty.
175 *******************************************************************************/
176 function all_defined(v) = !any_equal(v, undef);
177 
178 //! Test if at least one element of an iterable value has a defined value.
179 /***************************************************************************//**
180  \param v <iterable> An iterable data type value.
181 
182  \returns <boolean> \b true when any element of \p v has a defined
183  value and \b false otherwise. Returns \b false when \p v is
184  empty.
185 *******************************************************************************/
186 function any_defined(v) = !all_equal(v, undef);
187 
188 //! Test if at least one element of an iterable value has an undefined value.
189 /***************************************************************************//**
190  \param v <iterable> An iterable data type value.
191 
192  \returns <boolean> \b true when any element of \p v has an undefined
193  value and \b false otherwise. Returns \b false when \p v is
194  empty.
195 *******************************************************************************/
196 function any_undefined(v) = any_equal(v, undef);
197 
198 //! Test if all elements of an iterable value are scalar values.
199 /***************************************************************************//**
200  \param v <iterable> An iterable data type value.
201 
202  \returns <boolean> \b true when all elements of \p v are scalar
203  values and \b false otherwise. Returns \b true when \p v is
204  a single scalar value and \b true when the \p v is an empty,
205  or undefined.
206 *******************************************************************************/
207 function all_scalars
208 (
209  v
210 ) = !is_iterable(v) ? true
211  : is_empty(v) ? true
212  : !is_scalar(first(v)) ? false
213  : all_scalars(tailn(v));
214 
215 //! Test if all elements of an iterable value are iterable.
216 /***************************************************************************//**
217  \param v <iterable> An iterable data type value.
218 
219  \returns <boolean> \b true when all elements of \p v are iterable
220  and \b false otherwise. Returns \b true when \p v is a
221  single iterable value and returns \b true when \p v is a
222  empty. Returns \b false when \p v is undefined.
223 *******************************************************************************/
224 function all_iterables
225 (
226  v
227 ) = !is_iterable(v) ? false
228  : is_empty(v) ? true
229  : !is_iterable(first(v)) ? false
230  : all_iterables(tailn(v));
231 
232 //! Test if all elements of an iterable value are lists.
233 /***************************************************************************//**
234  \param v <iterable> An iterable data type value.
235  \param c <integer> (\em internal) Count of passing comparisons.
236 
237  \returns <boolean> \b true when all elements of \p v are lists
238  and \b false otherwise. Returns \b true when \p v is a
239  single iterable list.
240 
241  \details
242 
243  \note The parameter \p c is an internal variable used to count
244  the number of successful comparisons performed while
245  traversing \p v. This parameter should not be initialized
246  under normal circumstances.
247 *******************************************************************************/
248 function all_lists
249 (
250  v,
251  c = 0
252 ) = !is_iterable(v) ? false
253  : is_empty(v) ? ((c>0) || is_list(v))
254  : !is_list(first(v)) ? false
255  : all_lists(tailn(v), c+1);
256 
257 //! Test if all elements of an iterable value are strings.
258 /***************************************************************************//**
259  \param v <iterable> An iterable data type value.
260  \param c <integer> (\em internal) Count of passing comparisons.
261 
262  \returns <boolean> \b true when all elements of \p v are strings
263  and \b false otherwise. Returns \b true when \p v is a
264  single string.
265 
266  \details
267 
268  \note The parameter \p c is an internal variable used to count
269  the number of successful comparisons performed while
270  traversing \p v. This parameter should not be initialized
271  under normal circumstances.
272 *******************************************************************************/
273 function all_strings
274 (
275  v,
276  c = 0
277 ) = !is_iterable(v) ? false
278  : is_empty(v) ? ((c>0) || is_string(v))
279  : !is_string(first(v)) ? false
280  : all_strings(tailn(v), c+1);
281 
282 //! Test if all elements of an iterable value are numbers.
283 /***************************************************************************//**
284  \param v <iterable> An iterable data type value.
285  \param c <integer> (\em internal) Count of passing comparisons.
286 
287  \returns <boolean> \b true when all elements of \p v are numerical
288  values and \b false otherwise. Returns \b true when \p v is
289  a single numerical value.
290 
291  \details
292 
293  \note The parameter \p c is an internal variable used to count
294  the number of successful comparisons performed while
295  traversing \p v. This parameter should not be initialized
296  under normal circumstances.
297 *******************************************************************************/
298 function all_numbers
299 (
300  v,
301  c = 0
302 ) = !is_iterable(v) ? is_number(v)
303  : is_empty(v) ? (c>0)
304  : !is_number(first(v)) ? false
305  : all_numbers(tailn(v), c+1);
306 
307 //! Test if all elements of an iterable value are iterable with a fixed length.
308 /***************************************************************************//**
309  \param v <iterable> An iterable data type value.
310  \param l <integer> The required length of each value.
311 
312  \returns <boolean> \b true when all elements of \p v are iterable
313  values with lengths equal to \p l and \b false otherwise.
314 *******************************************************************************/
315 function all_len
316 (
317  v,
318  l,
319  c = 0
320 ) = !is_iterable(v) ? false
321  : is_empty(v) ? (c>0)
322  : !is_iterable(first(v)) ? false
323  : (len(first(v)) != l) ? false
324  : all_len(tailn(v),l, c+1);
325 
326 //! @}
327 //! @}
328 
329 //----------------------------------------------------------------------------//
330 // openscad-amu auxiliary scripts
331 //----------------------------------------------------------------------------//
332 
333 /*
334 BEGIN_SCOPE validate;
335  BEGIN_OPENSCAD;
336  include <omdl-base.scad>;
337  include <common/validation.scad>;
338 
339  function fmt( id, td, v1, v2, v3 ) = table_validate_fmt(id, td, v1, v2, v3);
340  function v1(db, id) = table_validate_get_v1(db, id);
341  t = true; f = false; u = undef; s = validation_skip;
342 
343  tbl_test_values =
344  [
345  fmt("t01", "The undefined value", undef),
346  fmt("t02", "An odd integer", 1),
347  fmt("t03", "The boolean true", true),
348  fmt("t04", "The boolean false", false),
349  fmt("t05", "A character string", "a"),
350  fmt("t06", "A string", "This is a longer string"),
351  fmt("t07", "The empty string", empty_str),
352  fmt("t08", "The empty list", empty_lst),
353  fmt("t09", "A shorthand range", [0:9]),
354  fmt("t10", "A range", [0:0.5:9]),
355  fmt("t11", "Single item list: 1 undef", [undef]),
356  fmt("t12", "Single item list: 1 number", [1]),
357  fmt("t13", "List of 3 numbers", [1, 2, 3]),
358  fmt("t14", "List of single num lists", [[1], [2], [3], [4], [5]]),
359  fmt("t15", "List of number pairs", [[1,2], [2,3]]),
360  fmt("t16", "List of num pairs and str", [[1,2], [2,3], [4,5], "ab"]),
361  fmt("t17", "List of mixed tuples", [[1,2,3], [4,5,6], [7,8,9], ["a", "b", "c"]]),
362  fmt("t18", "List of number with undef", [1, 2, 3, undef]),
363  fmt("t19", "List of items, all = undef", [undef, undef, undef, undef]),
364  fmt("t20", "List of lists, all = undef", [[undef], [undef], [undef]]),
365  fmt("t21", "List of mixed booleans mt", [true, true, true, true, false]),
366  fmt("t22", "List of mixed booleans mf", [true, false, false, false, false]),
367  fmt("t23", "List of booleans = true", [true, true, true, true])
368  ];
369 
370  tbl_test_answers =
371  [ // function 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
372  ["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],
373  ["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],
374  ["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],
375  ["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],
376  ["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],
377  ["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],
378  ["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],
379  ["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],
380  ["all_oneof_S1", t, t, t, t, f, f, f, t, f, f, t, t, t, f, f, f, f, t, t, f, t, t, t],
381  ["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],
382  ["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],
383  ["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],
384  ["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],
385  ["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],
386  ["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],
387  ["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],
388  ["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],
389  ["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],
390  ["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],
391  ["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]
392  ];
393 
394  db = table_validate_init( tbl_test_values, tbl_test_answers );
395 
396  table_validate_start( db );
397  test_ids = table_validate_get_ids( db );
398 
399  for (id=test_ids) table_validate( db, id, "is_iterable", 1, is_iterable( v1(db,id) ) );
400  for (id=test_ids) table_validate( db, id, "is_empty", 1, is_empty( v1(db,id) ) );
401  for (id=test_ids) table_validate( db, id, "all_equal_T", 1, all_equal( v1(db,id), t ) );
402  for (id=test_ids) table_validate( db, id, "all_equal_F", 1, all_equal( v1(db,id), f ) );
403  for (id=test_ids) table_validate( db, id, "all_equal_U", 1, all_equal( v1(db,id), u ) );
404  for (id=test_ids) table_validate( db, id, "any_equal_T", 1, any_equal( v1(db,id), t ) );
405  for (id=test_ids) table_validate( db, id, "any_equal_F", 1, any_equal( v1(db,id), f ) );
406  for (id=test_ids) table_validate( db, id, "any_equal_U", 1, any_equal( v1(db,id), u ) );
407  for (id=test_ids) table_validate( db, id, "all_oneof_S1", 1, all_oneof( v1(db,id), [undef, 1, 2, 3, true, false] ) );
408  for (id=test_ids) table_validate( db, id, "all_defined", 1, all_defined( v1(db,id) ) );
409  for (id=test_ids) table_validate( db, id, "any_defined", 1, any_defined( v1(db,id) ) );
410  for (id=test_ids) table_validate( db, id, "any_undefined", 1, any_undefined( v1(db,id) ) );
411  for (id=test_ids) table_validate( db, id, "all_scalars", 1, all_scalars( v1(db,id) ) );
412  for (id=test_ids) table_validate( db, id, "all_iterables", 1, all_iterables( v1(db,id) ) );
413  for (id=test_ids) table_validate( db, id, "all_lists", 1, all_lists( v1(db,id) ) );
414  for (id=test_ids) table_validate( db, id, "all_strings", 1, all_strings( v1(db,id) ) );
415  for (id=test_ids) table_validate( db, id, "all_numbers", 1, all_numbers( v1(db,id) ) );
416 
417  for (id=test_ids) table_validate( db, id, "all_len_1", 1, all_len( v1(db,id), 1 ) );
418  for (id=test_ids) table_validate( db, id, "all_len_2", 1, all_len( v1(db,id), 2 ) );
419  for (id=test_ids) table_validate( db, id, "all_len_3", 1, all_len( v1(db,id), 3 ) );
420 
421  // end_include
422  END_OPENSCAD;
423 
424  BEGIN_MFSCRIPT;
425  include --path "${INCLUDE_PATH}" {var_init,var_gen_term}.mfs;
426  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
427  END_MFSCRIPT;
428 END_SCOPE;
429 */
430 
431 //----------------------------------------------------------------------------//
432 // end of file
433 //----------------------------------------------------------------------------//
empty_lst
<list> A list with no values (the empty list).
Definition: constants.scad:304
function first(v)
Return the first element of an iterable value.
function tailn(v, n=1)
Return a list containing all but the first n elements of an iterable value.
function all_len(v, l, c=0)
Test if all elements of an iterable value are iterable with a fixed length.
function all_numbers(v, c=0)
Test if all elements of an iterable value are numbers.
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 all_lists(v, c=0)
Test if all elements of an iterable value are lists.
function is_iterable(v)
Test if a value has multiple parts and is iterable.
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_oneof(v, cv)
Test if all elements of an iterable value equal one of the comparison values.
function all_strings(v, c=0)
Test if all elements of an iterable value are strings.
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.