omdl  v0.6.1
OpenSCAD Mechanical Design Library
datatypes_map.scad
Go to the documentation of this file.
1 //! Map data type operations.
2 /***************************************************************************//**
3  \file datatypes_map.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  \details
29 
30  \ingroup datatypes datatypes_map
31 *******************************************************************************/
32 
33 include <../console.scad>;
34 include <datatypes-base.scad>;
35 
36 //----------------------------------------------------------------------------//
37 /***************************************************************************//**
38  \addtogroup datatypes
39  @{
40 
41  \defgroup datatypes_map Maps
42  \brief Map data type operations.
43 
44  \details
45 
46  \b Example
47 
48  \dontinclude datatypes_map_example.scad
49  \skip use
50  \until map_dump(map);
51 
52  \b Result \include datatypes_map_example.log
53 
54  @{
55 *******************************************************************************/
56 //----------------------------------------------------------------------------//
57 
58 //! Return the index of a map key.
59 /***************************************************************************//**
60  \param m <matrix-2xN> A list of N key-value map pairs.
61  \param k <string> A map key.
62 
63  \returns <integer> The index of the map entry if it exists.
64  Returns \b undef if \p key is not a string or does not exists.
65 *******************************************************************************/
66 function get_map_i
67 (
68  m,
69  k
70 ) = !is_string(k) ? undef
71  : let(i = first(search([k], m, 1, 0 )))
72  (i == empty_lst) ? undef
73  : i;
74 
75 //! Test if a key exists.
76 /***************************************************************************//**
77  \param m <matrix-2xN> A list of N key-value map pairs.
78  \param k <string> A map key.
79 
80  \returns <boolean> \b true when the key exists and \b false otherwise.
81 *******************************************************************************/
82 function map_exists
83 (
84  m,
85  k
86 ) = is_defined(get_map_i(m, k));
87 
88 //! Get the map value associated with a key.
89 /***************************************************************************//**
90  \param m <matrix-2xN> A list of N key-value map pairs.
91  \param k <string> A map key.
92 
93  \returns <value> The value associated with \p key.
94  Returns \b undef if \p key does not exists.
95 *******************************************************************************/
96 function get_map_v
97 (
98  m,
99  k
100 ) = second(m[get_map_i(m, k)]);
101 
102 //! Get a list of all map keys.
103 /***************************************************************************//**
104  \param m <matrix-2xN> A list of N key-value map pairs.
105 
106  \returns <string-list-N> A list of key strings for all N map entries.
107 *******************************************************************************/
108 function get_map_kl
109 (
110  m
111 ) = eselect(m, f=true);
112 
113 //! Get a list of all map values.
114 /***************************************************************************//**
115  \param m <matrix-2xN> A list of N key-value map pairs.
116 
117  \returns <list-N> A list of values for all N map entries.
118 *******************************************************************************/
119 function get_map_vl
120 (
121  m
122 ) = eselect(m, l=true);
123 
124 //! Get the number of map entries.
125 /***************************************************************************//**
126  \param m <matrix-2xN> A list of N key-value map pairs.
127 
128  \returns <integer> The number of map entries.
129 *******************************************************************************/
130 function get_map_size
131 (
132  m
133 ) = len(m);
134 
135 //! Perform some basic validation/checks on a map.
136 /***************************************************************************//**
137  \param m <matrix-2xN> A list of N key-value map pairs.
138 
139  \param verbose <boolean> Be verbose during check.
140 
141  \details
142 
143  Check that: (1) each entry has key-value 2-tuple, (2) each key is a
144  string, and (3) key identifiers are unique.
145 *******************************************************************************/
146 module map_check
147 (
148  m,
149  verbose = false
150 )
151 {
152  if (verbose) log_info("begin map check");
153 
154  if (verbose) log_info ("checking map format and keys.");
155 
156  if ( get_map_size(m) > 0 )
157  for ( i = [0:get_map_size(m)-1] )
158  {
159  entry = m[i];
160  key = first(entry);
161 
162  // each entry has key-value 2-tuple.
163  if ( 2 != len(entry) )
164  {
165  log_error
166  (
167  str (
168  "map index ", i,
169  ", entry=", entry,
170  ", has incorrect count=[", len(entry),"]"
171  )
172  );
173  }
174 
175  // each key must be a string.
176  if ( is_string(key) == false )
177  {
178  log_error
179  (
180  str (
181  "map index ", i,
182  ", entry=", entry,
183  ", key=[", key,"] is not a string."
184  )
185  );
186  }
187 
188  // no repeat key identifiers
189  if ( len(first(search([key], m, 0, 0))) > 1 )
190  log_warn
191  (
192  str(
193  "map index ", i,
194  ", key=[", key,"] not unique."
195  )
196  );
197  }
198 
199  if (verbose)
200  {
201  log_info
202  (
203  str (
204  "map size: ",
205  get_map_size(m), " entries."
206  )
207  );
208 
209  log_info("end map check");
210  }
211 }
212 
213 //! Dump each map entry to the console.
214 /***************************************************************************//**
215  \param m <matrix-2xN> A list of N key-value map pairs.
216  \param sort <boolean> Sort the output by key.
217  \param number <boolean> Output index number.
218  \param p <integer> Number of places for zero-padded numbering.
219 *******************************************************************************/
220 module map_dump
221 (
222  m,
223  sort = true,
224  number = true,
225  p = 3
226 )
227 {
228  if ( get_map_size(m) > 0 )
229  {
230  keys = get_map_kl(m);
231  maxl = max( [for (i = keys) len(i)] ) + 1;
232 
233  for (key = sort ? qsort(keys) : keys)
234  {
235  idx = get_map_i(m, key);
236 
237  log_echo
238  (
239  str (
240  number ? chr(consts(p-len(str(idx)), 48)) : empty_str,
241  number ? str(idx, ": ") : empty_str,
242  chr(consts(maxl-len(key), 32)), "'", key, "' = ",
243  "'", get_map_v(m, key), "'"
244  )
245  );
246  }
247  }
248 
249  if ( number )
250  log_echo(str("map size: ", get_map_size(m), " entries."));
251 }
252 
253 //! @}
254 //! @}
255 
256 //----------------------------------------------------------------------------//
257 // openscad-amu auxiliary scripts
258 //----------------------------------------------------------------------------//
259 
260 /*
261 BEGIN_SCOPE example;
262  BEGIN_OPENSCAD;
263  include <datatypes/datatypes_map.scad>;
264 
265  map =
266  [
267  ["part1", ["screw10", [10, 11, 13]]],
268  ["part2", ["screw12", [20, 21, 30]]],
269  ["part3", ["screw10", [10, 10, -12]]],
270  ["config", ["top", "front", "rear"]],
271  ["version", [21, 5, 0]],
272  ["runid", 10]
273  ];
274 
275  map_check(map, true);
276 
277  echo( str("is part0 = ", map_exists(map, "part0")) );
278  echo( str("is part1 = ", map_exists(map, "part1")) );
279 
280  p1 = get_map_v(map, "part1");
281  echo( c=second(p1) );
282 
283  keys = get_map_kl(map);
284  parts = delete(keys, mv=["config", "version", "runid"]);
285 
286  for ( p = parts )
287  echo
288  (
289  n=p,
290  p=first(get_map_v(map, p)),
291  l=second(get_map_v(map, p))
292  );
293 
294  map_dump(map);
295  END_OPENSCAD;
296 
297  BEGIN_MFSCRIPT;
298  include --path "${INCLUDE_PATH}" {config_base,config_csg}.mfs;
299  include --path "${INCLUDE_PATH}" script_std.mfs;
300  END_MFSCRIPT;
301 END_SCOPE;
302 */
303 
304 //----------------------------------------------------------------------------//
305 // end of file
306 //----------------------------------------------------------------------------//
function get_map_vl(m)
Get a list of all map values.
module log_echo(m)
Output message to console.
Definition: console.scad:90
function map_exists(m, k)
Test if a key exists.
function second(v)
Return the second element of an iterable value.
function get_map_v(m, k)
Get the map value associated with a key.
module log_warn(m)
Output warning message to console.
Definition: console.scad:137
function qsort(v, i, r=false)
Sort the numeric or string elements of a list using quick sort.
module log_info(m)
Output information message to console.
Definition: console.scad:122
empty_lst
A list with no values (the empty list).
Definition: constants.scad:80
module log_error(m)
Output error message to console.
Definition: console.scad:166
function is_defined(v)
Test if a value is defined.
empty_str
A string with no characters (the empty string).
Definition: constants.scad:77
function get_map_i(m, k)
Return the index of a map key.
function get_map_kl(m)
Get a list of all map keys.
function first(v)
Return the first element of an iterable value.
function get_map_size(m)
Get the number of map entries.
module map_dump(m, sort=true, number=true, p=3)
Dump each map entry to the console.
function consts(l, v, u=false)
Create a sequence of constant or incrementing elements.
function is_string(v)
Test if a value is a string.
function eselect(v, f=true, l=false, i)
Select a specified element from each iterable value of a list.
module map_check(m, verbose=false)
Perform some basic validation/checks on a map.