omdl  v0.6.1
OpenSCAD Mechanical Design Library
datatypes_identify_iterable.scad
Go to the documentation of this file.
1 //! Iterable data type identification.
2 /***************************************************************************//**
3  \file datatypes_identify_iterable.scad
4  \author Roy Allen Sutton
5  \date 2015-2017
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 *******************************************************************************/
29 
30 //----------------------------------------------------------------------------//
31 /***************************************************************************//**
32  \page tv_datatypes_identify_iterable Iterables
33  \li \subpage tv_datatypes_identify_iterable_s
34  \li \subpage tv_datatypes_identify_iterable_r
35 
36  \page tv_datatypes_identify_iterable_s Script
37  \dontinclude datatypes_identify_iterable_validate.scad
38  \skip include
39  \until end-of-tests
40  \page tv_datatypes_identify_iterable_r Results
41  \include datatypes_identify_iterable_validate.log
42 *******************************************************************************/
43 //----------------------------------------------------------------------------//
44 
45 //----------------------------------------------------------------------------//
46 /***************************************************************************//**
47  \addtogroup datatypes_identify
48  @{
49 
50  \defgroup datatypes_identify_iterable Iterables
51  \brief Iterable data type identification.
52 
53  \details
54 
55  See validation \ref tv_datatypes_identify_iterable_r "results".
56  @{
57 *******************************************************************************/
58 //----------------------------------------------------------------------------//
59 
60 //! Test if a list of values equal a comparison value.
61 /***************************************************************************//**
62  \param v <list> A list of values.
63  \param cv <value> A comparison value.
64 
65  \returns <boolean> \b true when all elements equal the value \p cv
66  and \b false otherwise.
67 
68  \details
69 
70  \warning Always returns \b true when the list is empty.
71 *******************************************************************************/
72 function all_equal
73 (
74  v,
75  cv
76 ) = !is_iterable(v) ? (v == cv)
77  : is_empty(v) ? true
78  : (first(v) != cv) ? false
79  : all_equal(ntail(v), cv);
80 
81 //! Test if any element of a list of values equal a comparison value.
82 /***************************************************************************//**
83  \param v <list> A list of values.
84  \param cv <value> A comparison value.
85 
86  \returns <boolean> \b true when any element equals the value \p cv
87  and \b false otherwise.
88 
89  \details
90 
91  \warning Always returns \b false when the list is empty.
92 *******************************************************************************/
93 function any_equal
94 (
95  v,
96  cv
97 ) = !is_iterable(v) ? (v == cv)
98  : is_empty(v) ? false
99  : (first(v) == cv) ? true
100  : any_equal(ntail(v), cv);
101 
102 //! Test if no element of a list of values is undefined.
103 /***************************************************************************//**
104  \param v <list> A list of values.
105 
106  \returns <boolean> \b true when no element is undefined
107  and \b false otherwise.
108 
109  \details
110 
111  \warning Always returns \b true when the list is empty.
112 *******************************************************************************/
113 function all_defined(v) = !any_equal(v, undef);
114 
115 //! Test if any element of a list of values is undefined.
116 /***************************************************************************//**
117  \param v <list> A list of values.
118 
119  \returns <boolean> \b true when any element is undefined
120  and \b false otherwise.
121 
122  \details
123 
124  \warning Always returns \b false when the list is empty.
125 *******************************************************************************/
126 function any_undefined(v) = any_equal(v, undef);
127 
128 //! Test if all elements of a list of values are scalars.
129 /***************************************************************************//**
130  \param v <list> A list of values.
131 
132  \returns <boolean> \b true when all elements are scalar values
133  and \b false otherwise.
134  Returns \b true when the list is a single scalar value.
135 
136  \details
137 
138  \warning Always returns \b true when the list is empty.
139 *******************************************************************************/
140 function all_scalars
141 (
142  v
143 ) = not_defined(v) ? undef
144  : is_scalar(v) ? true
145  : is_empty(v) ? true
146  : !is_scalar(first(v)) ? false
147  : all_scalars(ntail(v));
148 
149 //! Test if all elements of a list of values are lists.
150 /***************************************************************************//**
151  \param v <list> A list of values.
152 
153  \returns <boolean> \b true when all elements are lists
154  and \b false otherwise.
155  Returns \b true when the list is a single list value.
156 
157  \details
158 
159  \warning Always returns \b true when the list is empty.
160 *******************************************************************************/
161 function all_lists
162 (
163  v
164 ) = not_defined(v) ? undef
165  : is_scalar(v) ? false
166  : is_empty(v) ? true
167  : !is_list(first(v)) ? false
168  : all_lists(ntail(v));
169 
170 //! Test if all elements of a list of values are strings.
171 /***************************************************************************//**
172  \param v <list> A list of values.
173 
174  \returns <boolean> \b true when all elements are string values
175  and \b false otherwise.
176  Returns \b true when the list is a single string value.
177 
178  \details
179 
180  \warning Always returns \b true when the list is empty.
181 *******************************************************************************/
182 function all_strings
183 (
184  v
185 ) = not_defined(v) ? undef
186  : is_scalar(v) ? false
187  : is_empty(v) ? true
188  : !is_string(first(v)) ? false
189  : all_strings(ntail(v));
190 
191 //! Test if all elements of a list of values are numbers.
192 /***************************************************************************//**
193  \param v <list> A list of values.
194 
195  \returns <boolean> \b true when all elements are numerical values
196  and \b false otherwise.
197  Returns \b true when the list is a single numerical value.
198 
199  \details
200 
201  \warning Always returns \b true when the list is empty.
202 *******************************************************************************/
203 function all_numbers
204 (
205  v
206 ) = not_defined(v) ? undef
207  : is_scalar(v) ? is_number(v)
208  : is_empty(v) ? true
209  : !is_number(first(v)) ? false
210  : all_numbers(ntail(v));
211 
212 //! Test if all elements of a list of values are lists of a specified length.
213 /***************************************************************************//**
214  \param v <list> A list of values.
215  \param l <integer> The test length.
216 
217  \returns <boolean> \b true when all elements are lists of the specified
218  length and \b false otherwise.
219  Returns \b true when the list is a single list of length \p l.
220 
221  \details
222 
223  \warning Always returns \b true when \p v is empty.
224 *******************************************************************************/
225 function all_len
226 (
227  v,
228  l
229 ) = not_defined(v) ? undef
230  : is_scalar(v) ? false
231  : is_empty(v) ? true
232  : (len(first(v)) != l) ? false
233  : all_len(ntail(v),l);
234 
235 //! @}
236 //! @}
237 
238 //----------------------------------------------------------------------------//
239 // openscad-amu auxiliary scripts
240 //----------------------------------------------------------------------------//
241 
242 /*
243 BEGIN_SCOPE validate;
244  BEGIN_OPENSCAD;
245  include <console.scad>;
246  include <datatypes/datatypes-base.scad>;
247  include <datatypes/datatypes_table.scad>;
248  include <validation.scad>;
249 
250  show_passing = true; // show passing tests
251  show_skipped = true; // show skipped tests
252 
253  echo( str("OpenSCAD Version ", version()) );
254 
255  // test-values columns
256  test_c =
257  [
258  ["id", "identifier"],
259  ["td", "description"],
260  ["tv", "test value"]
261  ];
262 
263  // test-values rows
264  test_r =
265  [
266  ["t01", "The undefined value", undef],
267  ["t02", "An odd integer", 1],
268  ["t03", "The boolean true", true],
269  ["t04", "The boolean false", false],
270  ["t05", "A character string", "a"],
271  ["t06", "A string", "This is a longer string"],
272  ["t07", "The empty string", empty_str],
273  ["t08", "The empty list", empty_lst],
274  ["t09", "A shorthand range", [0:9]],
275  ["t10", "A range", [0:0.5:9]],
276  ["t11", "Test list 01", [undef]],
277  ["t12", "Test list 02", [1]],
278  ["t13", "Test list 03", [1, 2, 3]],
279  ["t14", "Test list 04", [[1], [2], [3], [4], [5]]],
280  ["t15", "Test list 05", [[1,2], [2,3]]],
281  ["t16", "Test list 06", [[1,2], [2,3], [4,5], "ab"]],
282  ["t17", "Test list 07", [[1,2,3], [4,5,6], [7,8,9], ["a", "b", "c"]]],
283  ["t18", "Test list 08", [1, 2, 3, undef]],
284  ["t19", "Test list 09", [undef, undef, undef, undef]],
285  ["t20", "Test list 10", [[undef], [undef], [undef]]],
286  ["t21", "Test list 11", [true, true, true, true, false]],
287  ["t22", "Test list 12", [true, false, false, false, false]],
288  ["t23", "Test list 13", [true, true, true, true]]
289  ];
290 
291  test_ids = get_table_ridl( test_r );
292 
293  // expected columns: ("id" + one column for each test)
294  good_c = pmerge([concat("id", test_ids), concat("identifier", test_ids)]);
295 
296  // expected rows: ("golden" test results), use 's' to skip test
297  t = true; // shortcuts
298  f = false;
299  u = undef;
300  s = -1; // skip test
301 
302  good_r =
303  [ // function 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
304  ["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],
305  ["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],
306  ["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],
307  ["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],
308  ["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],
309  ["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],
310  ["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],
311  ["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],
312  ["all_scalars", u, t, t, t, f, f, s, s, s, s, t, t, t, f, f, f, f, t, t, f, t, t, t],
313  ["all_lists", u, f, f, f, f, f, t, t, f, f, f, f, f, t, t, f, t, f, f, t, f, f, f],
314  ["all_strings", u, f, f, f, t, t, t, s, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f],
315  ["all_numbers", u, t, f, f, f, f, s, s, f, f, f, t, t, f, f, f, f, f, f, f, f, f, f],
316  ["all_len_1", u, f, f, f, t, t, s, s, f, f, f, f, f, t, f, f, f, f, f, t, f, f, f],
317  ["all_len_2", u, f, f, f, f, f, s, s, f, f, f, f, f, f, t, t, f, f, f, f, f, f, f],
318  ["all_len_3", u, f, f, f, f, f, s, s, f, f, f, f, f, f, f, f, t, f, f, f, f, f, f]
319  ];
320 
321  // sanity-test tables
322  table_check( test_r, test_c, false );
323  table_check( good_r, good_c, false );
324 
325  // validate helper function and module
326  function get_value( vid ) = get_table_v(test_r, test_c, vid, "tv");
327  module run_test( fname, fresult, vid )
328  {
329  value_text = get_table_v(test_r, test_c, vid, "td");
330  pass_value = get_table_v(good_r, good_c, fname, vid);
331 
332  test_pass = validate( cv=fresult, t="equals", ev=pass_value, pf=true );
333  test_text = validate( str(fname, "(", get_value(vid), ")=", pass_value), fresult, "equals", pass_value );
334 
335  if ( pass_value != s )
336  {
337  if ( !test_pass )
338  log_warn( str(vid, "(", value_text, ") ", test_text) );
339  else if ( show_passing )
340  log_info( str(vid, " ", test_text) );
341  }
342  else if ( show_skipped )
343  log_info( str(vid, " *skip*: '", fname, "(", value_text, ")'") );
344  }
345 
346  // Indirect function calls would be very useful here!!!
347  for (vid=test_ids) run_test( "all_equal_T", all_equal(get_value(vid),t), vid );
348  for (vid=test_ids) run_test( "all_equal_F", all_equal(get_value(vid),f), vid );
349  for (vid=test_ids) run_test( "all_equal_U", all_equal(get_value(vid),u), vid );
350  for (vid=test_ids) run_test( "any_equal_T", any_equal(get_value(vid),t), vid );
351  for (vid=test_ids) run_test( "any_equal_F", any_equal(get_value(vid),f), vid );
352  for (vid=test_ids) run_test( "any_equal_U", any_equal(get_value(vid),u), vid );
353  for (vid=test_ids) run_test( "all_defined", all_defined(get_value(vid)), vid );
354  for (vid=test_ids) run_test( "any_undefined", any_undefined(get_value(vid)), vid );
355  for (vid=test_ids) run_test( "all_scalars", all_scalars(get_value(vid)), vid );
356  for (vid=test_ids) run_test( "all_lists", all_lists(get_value(vid)), vid );
357  for (vid=test_ids) run_test( "all_strings", all_strings(get_value(vid)), vid );
358  for (vid=test_ids) run_test( "all_numbers", all_numbers(get_value(vid)), vid );
359  for (vid=test_ids) run_test( "all_len_1", all_len(get_value(vid),1), vid );
360  for (vid=test_ids) run_test( "all_len_2", all_len(get_value(vid),2), vid );
361  for (vid=test_ids) run_test( "all_len_3", all_len(get_value(vid),3), vid );
362 
363  // end-of-tests
364  END_OPENSCAD;
365 
366  BEGIN_MFSCRIPT;
367  include --path "${INCLUDE_PATH}" {config_base,config_csg}.mfs;
368  include --path "${INCLUDE_PATH}" script_std.mfs;
369  END_MFSCRIPT;
370 END_SCOPE;
371 */
372 
373 //----------------------------------------------------------------------------//
374 // end of file
375 //----------------------------------------------------------------------------//
function all_numbers(v)
Test if all elements of a list of values are numbers.
function is_empty(v)
Test if an iterable value is empty.
function all_defined(v)
Test if no element of a list of values is undefined.
function all_len(v, l)
Test if all elements of a list of values are lists of a specified length.
function is_scalar(v)
Test if a value is a single non-iterable value.
function all_equal(v, cv)
Test if a list of values equal a comparison value.
function any_undefined(v)
Test if any element of a list of values is undefined.
function is_number(v)
Test if a value is a number.
function all_strings(v)
Test if all elements of a list of values are strings.
function not_defined(v)
Test if a value is not defined.
function is_list(v)
Test if a value is an iterable list of values.
function first(v)
Return the first element of an iterable value.
function all_lists(v)
Test if all elements of a list of values are lists.
function all_scalars(v)
Test if all elements of a list of values are scalars.
function is_string(v)
Test if a value is a string.
function any_equal(v, cv)
Test if any element of a list of values equal a comparison value.
function is_iterable(v)
Test if a value has multiple parts and is iterable.
function ntail(v, n=1)
Return a list containing all but the first n elements of an iterable value.