comparison mupdf-source/thirdparty/leptonica/src/fhmtauto.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
27
28 /*!
29 * \file fhmtauto.c
30 * <pre>
31 *
32 * Main function calls:
33 * l_int32 fhmtautogen()
34 * l_int32 fhmtautogen1()
35 * l_int32 fhmtautogen2()
36 *
37 * Static helpers:
38 * static SARRAY *sarrayMakeWplsCode()
39 * static SARRAY *sarrayMakeInnerLoopDWACode()
40 * static char *makeBarrelshiftString()
41 *
42 * This automatically generates dwa code for the hit-miss transform.
43 * Here's a road map for how it all works.
44 *
45 * (1) You generate an array (a SELA) of hit-miss transform SELs.
46 * This can be done in several ways, including
47 * (a) calling the function selaAddHitMiss() for
48 * pre-compiled SELs
49 * (b) generating the SELA in code in line
50 * (c) reading in a SELA from file, using selaRead()
51 * or various other formats.
52 *
53 * (2) You call fhmtautogen1() and fhmtautogen2() on this SELA.
54 * This uses the text files hmttemplate1.txt and
55 * hmttemplate2.txt for building up the source code. See the file
56 * prog/fhmtautogen.c for an example of how this is done.
57 * The output is written to files named fhmtgen.*.c
58 * and fhmtgenlow.*.c, where "*" is an integer that you
59 * input to this function. That integer labels both
60 * the output files, as well as all the functions that
61 * are generated. That way, using different integers,
62 * you can invoke fhmtautogen() any number of times
63 * to get functions that all have different names so that
64 * they can be linked into one program.
65 *
66 * (3) You copy the generated source code back to your src
67 * directory for compilation. Put their names in the
68 * Makefile, regnerate the prototypes, and recompile
69 * the libraries. Look at the Makefile to see how I've
70 * included fhmtgen.1.c and fhmtgenlow.1.c. These files
71 * provide the single high-level interface for the hmt, and
72 * the lower-level functions to do the actual work.
73 *
74 * (4) In an application, you now use this interface. Again
75 * for the example files generated, using integer "1":
76 *
77 * PIX *pixHMTDwa_1(PIX *pixd, PIX *pixs, const char *selname);
78 *
79 * where the selname is one of the set that were defined
80 * as the name field of sels. This set is listed at the
81 * beginning of the file fhmtgen.1.c.
82 *
83 * N.B. Although pixFHMTGen_1() is global, you must NOT
84 * use it, because it assumes that 32 or 64 border pixels
85 * have been added to each side, and it will crash without those
86 * added pixels.
87 *
88 * As an example, see the file prog/fhmtauto_reg.c, which
89 * verifies the correctness of the implementation by
90 * comparing the dwa result with that of full-image
91 * rasterops.
92 * </pre>
93 */
94
95 #ifdef HAVE_CONFIG_H
96 #include <config_auto.h>
97 #endif /* HAVE_CONFIG_H */
98
99 #include <string.h>
100 #include "allheaders.h"
101
102 #define OUTROOT "fhmtgen"
103 #define TEMPLATE1 "hmttemplate1.txt"
104 #define TEMPLATE2 "hmttemplate2.txt"
105
106 #define PROTOARGS "(l_uint32 *, l_int32, l_int32, l_int32, l_uint32 *, l_int32);"
107
108 #define L_BUF_SIZE 512
109
110 static char * makeBarrelshiftString(l_int32 delx, l_int32 dely, l_int32 type);
111 static SARRAY * sarrayMakeInnerLoopDWACode(SEL *sel, l_int32 nhits, l_int32 nmisses);
112 static SARRAY * sarrayMakeWplsCode(SEL *sel);
113
114 static char wpldecls[][60] = {
115 "l_int32 wpls2;",
116 "l_int32 wpls2, wpls3;",
117 "l_int32 wpls2, wpls3, wpls4;",
118 "l_int32 wpls5;",
119 "l_int32 wpls5, wpls6;",
120 "l_int32 wpls5, wpls6, wpls7;",
121 "l_int32 wpls5, wpls6, wpls7, wpls8;",
122 "l_int32 wpls9;",
123 "l_int32 wpls9, wpls10;",
124 "l_int32 wpls9, wpls10, wpls11;",
125 "l_int32 wpls9, wpls10, wpls11, wpls12;",
126 "l_int32 wpls13;",
127 "l_int32 wpls13, wpls14;",
128 "l_int32 wpls13, wpls14, wpls15;",
129 "l_int32 wpls13, wpls14, wpls15, wpls16;",
130 "l_int32 wpls17;",
131 "l_int32 wpls17, wpls18;",
132 "l_int32 wpls17, wpls18, wpls19;",
133 "l_int32 wpls17, wpls18, wpls19, wpls20;",
134 "l_int32 wpls21;",
135 "l_int32 wpls21, wpls22;",
136 "l_int32 wpls21, wpls22, wpls23;",
137 "l_int32 wpls21, wpls22, wpls23, wpls24;",
138 "l_int32 wpls25;",
139 "l_int32 wpls25, wpls26;",
140 "l_int32 wpls25, wpls26, wpls27;",
141 "l_int32 wpls25, wpls26, wpls27, wpls28;",
142 "l_int32 wpls29;",
143 "l_int32 wpls29, wpls30;",
144 "l_int32 wpls29, wpls30, wpls31;"};
145
146 static char wpldefs[][24] = {
147 " wpls2 = 2 * wpls;",
148 " wpls3 = 3 * wpls;",
149 " wpls4 = 4 * wpls;",
150 " wpls5 = 5 * wpls;",
151 " wpls6 = 6 * wpls;",
152 " wpls7 = 7 * wpls;",
153 " wpls8 = 8 * wpls;",
154 " wpls9 = 9 * wpls;",
155 " wpls10 = 10 * wpls;",
156 " wpls11 = 11 * wpls;",
157 " wpls12 = 12 * wpls;",
158 " wpls13 = 13 * wpls;",
159 " wpls14 = 14 * wpls;",
160 " wpls15 = 15 * wpls;",
161 " wpls16 = 16 * wpls;",
162 " wpls17 = 17 * wpls;",
163 " wpls18 = 18 * wpls;",
164 " wpls19 = 19 * wpls;",
165 " wpls20 = 20 * wpls;",
166 " wpls21 = 21 * wpls;",
167 " wpls22 = 22 * wpls;",
168 " wpls23 = 23 * wpls;",
169 " wpls24 = 24 * wpls;",
170 " wpls25 = 25 * wpls;",
171 " wpls26 = 26 * wpls;",
172 " wpls27 = 27 * wpls;",
173 " wpls28 = 28 * wpls;",
174 " wpls29 = 29 * wpls;",
175 " wpls30 = 30 * wpls;",
176 " wpls31 = 31 * wpls;"};
177
178 static char wplstrp[][10] = {"+ wpls", "+ wpls2", "+ wpls3", "+ wpls4",
179 "+ wpls5", "+ wpls6", "+ wpls7", "+ wpls8",
180 "+ wpls9", "+ wpls10", "+ wpls11", "+ wpls12",
181 "+ wpls13", "+ wpls14", "+ wpls15", "+ wpls16",
182 "+ wpls17", "+ wpls18", "+ wpls19", "+ wpls20",
183 "+ wpls21", "+ wpls22", "+ wpls23", "+ wpls24",
184 "+ wpls25", "+ wpls26", "+ wpls27", "+ wpls28",
185 "+ wpls29", "+ wpls30", "+ wpls31"};
186
187 static char wplstrm[][10] = {"- wpls", "- wpls2", "- wpls3", "- wpls4",
188 "- wpls5", "- wpls6", "- wpls7", "- wpls8",
189 "- wpls9", "- wpls10", "- wpls11", "- wpls12",
190 "- wpls13", "- wpls14", "- wpls15", "- wpls16",
191 "- wpls17", "- wpls18", "- wpls19", "- wpls20",
192 "- wpls21", "- wpls22", "- wpls23", "- wpls24",
193 "- wpls25", "- wpls26", "- wpls27", "- wpls28",
194 "- wpls29", "- wpls30", "- wpls31"};
195
196
197 /*!
198 * \brief fhmtautogen()
199 *
200 * \param[in] sela
201 * \param[in] fileindex
202 * \param[in] filename [optional]; can be null
203 * \return 0 if OK; 1 on error
204 *
205 * <pre>
206 * Notes:
207 * (1) This function generates all the code for implementing
208 * dwa morphological operations using all the sels in the sela.
209 * (2) See fhmtautogen1() and fhmtautogen2() for details.
210 * </pre>
211 */
212 l_ok
213 fhmtautogen(SELA *sela,
214 l_int32 fileindex,
215 const char *filename)
216 {
217 l_int32 ret1, ret2;
218
219 if (!sela)
220 return ERROR_INT("sela not defined", __func__, 1);
221 ret1 = fhmtautogen1(sela, fileindex, filename);
222 ret2 = fhmtautogen2(sela, fileindex, filename);
223 if (ret1 || ret2)
224 return ERROR_INT("code generation problem", __func__, 1);
225 return 0;
226 }
227
228
229 /*!
230 * \brief fhmtautogen1()
231 *
232 * \param[in] sela array
233 * \param[in] fileindex
234 * \param[in] filename [optional]; can be null
235 * \return 0 if OK; 1 on error
236 *
237 * <pre>
238 * Notes:
239 * (1) This function uses hmttemplate1.txt to create a
240 * top-level file that contains two functions that carry
241 * out the hit-miss transform for any of the sels in
242 * the input sela.
243 * (2) The fileindex parameter is inserted into the output
244 * filename, as described below.
245 * (3) If filename == NULL, the output file is fhmtgen.[n].c,
246 * where [n] is equal to the 'fileindex' parameter.
247 * (4) If filename != NULL, the output file is [filename].[n].c.
248 * (5) Each sel must have at least one hit. A sel with only misses
249 * generates code that will abort the operation if it is called.
250 * </pre>
251 */
252 l_ok
253 fhmtautogen1(SELA *sela,
254 l_int32 fileindex,
255 const char *filename)
256 {
257 char *filestr;
258 char *str_proto1, *str_proto2, *str_proto3;
259 char *str_doc1, *str_doc2, *str_doc3, *str_doc4;
260 char *str_def1, *str_def2, *str_proc1, *str_proc2;
261 char *str_dwa1, *str_low_dt, *str_low_ds;
262 char bigbuf[L_BUF_SIZE];
263 l_int32 i, nsels, nbytes, actstart, end, newstart;
264 size_t size;
265 SARRAY *sa1, *sa2, *sa3;
266
267 if (!sela)
268 return ERROR_INT("sela not defined", __func__, 1);
269 if (fileindex < 0)
270 fileindex = 0;
271 if ((nsels = selaGetCount(sela)) == 0)
272 return ERROR_INT("no sels in sela", __func__, 1);
273
274 /* Make array of textlines from from hmttemplate1.txt */
275 if ((filestr = (char *)l_binaryRead(TEMPLATE1, &size)) == NULL)
276 return ERROR_INT("filestr not made", __func__, 1);
277 sa2 = sarrayCreateLinesFromString(filestr, 1);
278 LEPT_FREE(filestr);
279 if (!sa2)
280 return ERROR_INT("sa2 not made", __func__, 1);
281
282 /* Make array of sel names */
283 sa1 = selaGetSelnames(sela);
284
285 /* Make strings containing function call names */
286 sprintf(bigbuf, "PIX *pixHMTDwa_%d(PIX *pixd, PIX *pixs, "
287 "const char *selname);", fileindex);
288 str_proto1 = stringNew(bigbuf);
289 sprintf(bigbuf, "PIX *pixFHMTGen_%d(PIX *pixd, PIX *pixs, "
290 "const char *selname);", fileindex);
291 str_proto2 = stringNew(bigbuf);
292 sprintf(bigbuf, "l_int32 fhmtgen_low_%d(l_uint32 *datad, l_int32 w,\n"
293 " l_int32 h, l_int32 wpld,\n"
294 " l_uint32 *datas, l_int32 wpls,\n"
295 " l_int32 index);", fileindex);
296 str_proto3 = stringNew(bigbuf);
297 sprintf(bigbuf, " * PIX *pixHMTDwa_%d()", fileindex);
298 str_doc1 = stringNew(bigbuf);
299 sprintf(bigbuf, " * PIX *pixFHMTGen_%d()", fileindex);
300 str_doc2 = stringNew(bigbuf);
301 sprintf(bigbuf, " * \\brief pixHMTDwa_%d()", fileindex);
302 str_doc3 = stringNew(bigbuf);
303 sprintf(bigbuf, " * \\brief pixFHMTGen_%d()", fileindex);
304 str_doc4 = stringNew(bigbuf);
305 sprintf(bigbuf, "pixHMTDwa_%d(PIX *pixd,", fileindex);
306 str_def1 = stringNew(bigbuf);
307 sprintf(bigbuf, "pixFHMTGen_%d(PIX *pixd,", fileindex);
308 str_def2 = stringNew(bigbuf);
309 sprintf(bigbuf, " PROCNAME(\"pixHMTDwa_%d\");", fileindex);
310 str_proc1 = stringNew(bigbuf);
311 sprintf(bigbuf, " PROCNAME(\"pixFHMTGen_%d\");", fileindex);
312 str_proc2 = stringNew(bigbuf);
313 sprintf(bigbuf, " pixt2 = pixFHMTGen_%d(NULL, pixt1, selname);",
314 fileindex);
315 str_dwa1 = stringNew(bigbuf);
316 sprintf(bigbuf,
317 " fhmtgen_low_%d(datad, w, h, wpld, datat, wpls, index);",
318 fileindex);
319 str_low_dt = stringNew(bigbuf);
320 sprintf(bigbuf,
321 " fhmtgen_low_%d(datad, w, h, wpld, datas, wpls, index);",
322 fileindex);
323 str_low_ds = stringNew(bigbuf);
324
325 /* Make the output sa */
326 sa3 = sarrayCreate(0);
327
328 /* Copyright notice and info header */
329 sarrayParseRange(sa2, 0, &actstart, &end, &newstart, "--", 0);
330 sarrayAppendRange(sa3, sa2, actstart, end);
331
332 /* Insert function names as documentation */
333 sarrayAddString(sa3, str_doc1, L_INSERT);
334 sarrayAddString(sa3, str_doc2, L_INSERT);
335
336 /* Add '#include's */
337 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
338 sarrayAppendRange(sa3, sa2, actstart, end);
339
340 /* Insert function prototypes */
341 sarrayAddString(sa3, str_proto1, L_INSERT);
342 sarrayAddString(sa3, str_proto2, L_INSERT);
343 sarrayAddString(sa3, str_proto3, L_INSERT);
344
345 /* Add static globals */
346 sprintf(bigbuf, "\nstatic l_int32 NUM_SELS_GENERATED = %d;", nsels);
347 sarrayAddString(sa3, bigbuf, L_COPY);
348 sprintf(bigbuf, "static char SEL_NAMES[][80] = {");
349 sarrayAddString(sa3, bigbuf, L_COPY);
350 for (i = 0; i < nsels - 1; i++) {
351 sprintf(bigbuf, " \"%s\",",
352 sarrayGetString(sa1, i, L_NOCOPY));
353 sarrayAddString(sa3, bigbuf, L_COPY);
354 }
355 sprintf(bigbuf, " \"%s\"};",
356 sarrayGetString(sa1, i, L_NOCOPY));
357 sarrayAddString(sa3, bigbuf, L_COPY);
358
359 /* Start pixHMTDwa_*() function description */
360 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
361 sarrayAppendRange(sa3, sa2, actstart, end);
362 sarrayAddString(sa3, str_doc3, L_INSERT);
363 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
364 sarrayAppendRange(sa3, sa2, actstart, end);
365
366 /* Finish pixHMTDwa_*() function definition */
367 sarrayAddString(sa3, str_def1, L_INSERT);
368 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
369 sarrayAppendRange(sa3, sa2, actstart, end);
370 sarrayAddString(sa3, str_proc1, L_INSERT);
371 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
372 sarrayAppendRange(sa3, sa2, actstart, end);
373 sarrayAddString(sa3, str_dwa1, L_INSERT);
374 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
375 sarrayAppendRange(sa3, sa2, actstart, end);
376
377 /* Start pixFHMTGen_*() function description */
378 sarrayAddString(sa3, str_doc4, L_INSERT);
379 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
380 sarrayAppendRange(sa3, sa2, actstart, end);
381
382 /* Finish pixFHMTGen_*() function description */
383 sarrayAddString(sa3, str_def2, L_INSERT);
384 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
385 sarrayAppendRange(sa3, sa2, actstart, end);
386 sarrayAddString(sa3, str_proc2, L_INSERT);
387 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
388 sarrayAppendRange(sa3, sa2, actstart, end);
389 sarrayAddString(sa3, str_low_dt, L_INSERT);
390 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
391 sarrayAppendRange(sa3, sa2, actstart, end);
392 sarrayAddString(sa3, str_low_ds, L_INSERT);
393 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
394 sarrayAppendRange(sa3, sa2, actstart, end);
395
396 filestr = sarrayToString(sa3, 1);
397 nbytes = strlen(filestr);
398 if (filename)
399 snprintf(bigbuf, L_BUF_SIZE, "%s.%d.c", filename, fileindex);
400 else
401 sprintf(bigbuf, "%s.%d.c", OUTROOT, fileindex);
402 l_binaryWrite(bigbuf, "w", filestr, nbytes);
403 sarrayDestroy(&sa1);
404 sarrayDestroy(&sa2);
405 sarrayDestroy(&sa3);
406 LEPT_FREE(filestr);
407 return 0;
408 }
409
410
411 /*!
412 * \brief fhmtautogen2()
413 *
414 * \param[in] sela array
415 * \param[in] fileindex
416 * \param[in] filename [optional]; can be null
417 * \return 0 if OK; 1 on error
418 *
419 * <pre>
420 * Notes:
421 * (1) This function uses hmttemplate2.txt to create a
422 * low-level file that contains the low-level functions for
423 * implementing the hit-miss transform for every sel
424 * in the input sela.
425 * (2) The fileindex parameter is inserted into the output
426 * filename, as described below.
427 * (3) If filename == NULL, the output file is fhmtgenlow.[n].c,
428 * where [n] is equal to the %fileindex parameter.
429 * (4) If filename != NULL, the output file is [filename]low.[n].c.
430 * </pre>
431 */
432 l_ok
433 fhmtautogen2(SELA *sela,
434 l_int32 fileindex,
435 const char *filename)
436 {
437 char *filestr, *fname, *linestr;
438 char *str_doc1, *str_doc2, *str_doc3, *str_def1;
439 char bigbuf[L_BUF_SIZE];
440 char breakstring[] = " break;";
441 char staticstring[] = "static void";
442 l_int32 i, k, l, nsels, nbytes, nhits, nmisses;
443 l_int32 actstart, end, newstart;
444 l_int32 argstart, argend, loopstart, loopend, finalstart, finalend;
445 size_t size;
446 SARRAY *sa1, *sa2, *sa3, *sa4, *sa5, *sa6;
447 SEL *sel;
448
449 if (!sela)
450 return ERROR_INT("sela not defined", __func__, 1);
451 if (fileindex < 0)
452 fileindex = 0;
453 if ((nsels = selaGetCount(sela)) == 0)
454 return ERROR_INT("no sels in sela", __func__, 1);
455
456 /* Make the array of textlines from hmttemplate2.txt */
457 if ((filestr = (char *)l_binaryRead(TEMPLATE2, &size)) == NULL)
458 return ERROR_INT("filestr not made", __func__, 1);
459 sa1 = sarrayCreateLinesFromString(filestr, 1);
460 LEPT_FREE(filestr);
461 if (!sa1)
462 return ERROR_INT("sa1 not made", __func__, 1);
463
464 /* Make the array of static function names */
465 if ((sa2 = sarrayCreate(nsels)) == NULL) {
466 sarrayDestroy(&sa1);
467 return ERROR_INT("sa2 not made", __func__, 1);
468 }
469 for (i = 0; i < nsels; i++) {
470 sprintf(bigbuf, "fhmt_%d_%d", fileindex, i);
471 sarrayAddString(sa2, bigbuf, L_COPY);
472 }
473
474 /* Make the static prototype strings */
475 sa3 = sarrayCreate(2 * nsels); /* should be ok */
476 for (i = 0; i < nsels; i++) {
477 fname = sarrayGetString(sa2, i, L_NOCOPY);
478 sprintf(bigbuf, "static void %s%s", fname, PROTOARGS);
479 sarrayAddString(sa3, bigbuf, L_COPY);
480 }
481
482 /* Make strings containing function names */
483 sprintf(bigbuf, " * l_int32 fhmtgen_low_%d()",
484 fileindex);
485 str_doc1 = stringNew(bigbuf);
486 sprintf(bigbuf, " * void fhmt_%d_*()", fileindex);
487 str_doc2 = stringNew(bigbuf);
488
489 /* Output to this sa */
490 sa4 = sarrayCreate(0);
491
492 /* Copyright notice and info header */
493 sarrayParseRange(sa1, 0, &actstart, &end, &newstart, "--", 0);
494 sarrayAppendRange(sa4, sa1, actstart, end);
495
496 /* Insert function names as documentation */
497 sarrayAddString(sa4, str_doc1, L_INSERT);
498 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
499 sarrayAppendRange(sa4, sa1, actstart, end);
500 sarrayAddString(sa4, str_doc2, L_INSERT);
501 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
502 sarrayAppendRange(sa4, sa1, actstart, end);
503
504 /* Insert static protos */
505 for (i = 0; i < nsels; i++) {
506 if ((linestr = sarrayGetString(sa3, i, L_COPY)) == NULL) {
507 sarrayDestroy(&sa1);
508 sarrayDestroy(&sa2);
509 sarrayDestroy(&sa3);
510 sarrayDestroy(&sa4);
511 return ERROR_INT("linestr not retrieved", __func__, 1);
512 }
513 sarrayAddString(sa4, linestr, L_INSERT);
514 }
515
516 /* Make more strings containing function names */
517 sprintf(bigbuf, " * fhmtgen_low_%d()", fileindex);
518 str_doc3 = stringNew(bigbuf);
519 sprintf(bigbuf, "fhmtgen_low_%d(l_uint32 *datad,", fileindex);
520 str_def1 = stringNew(bigbuf);
521
522 /* Insert function header */
523 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
524 sarrayAppendRange(sa4, sa1, actstart, end);
525 sarrayAddString(sa4, str_doc3, L_INSERT);
526 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
527 sarrayAppendRange(sa4, sa1, actstart, end);
528 sarrayAddString(sa4, str_def1, L_INSERT);
529 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
530 sarrayAppendRange(sa4, sa1, actstart, end);
531
532 /* Generate and insert the dispatcher code */
533 for (i = 0; i < nsels; i++) {
534 sprintf(bigbuf, " case %d:", i);
535 sarrayAddString(sa4, bigbuf, L_COPY);
536 sprintf(bigbuf, " %s(datad, w, h, wpld, datas, wpls);",
537 sarrayGetString(sa2, i, L_NOCOPY));
538 sarrayAddString(sa4, bigbuf, L_COPY);
539 sarrayAddString(sa4, breakstring, L_COPY);
540 }
541
542 /* Finish the dispatcher and introduce the low-level code */
543 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
544 sarrayAppendRange(sa4, sa1, actstart, end);
545
546 /* Get the range for the args common to all functions */
547 sarrayParseRange(sa1, newstart, &argstart, &argend, &newstart, "--", 0);
548
549 /* Get the range for the loop code common to all functions */
550 sarrayParseRange(sa1, newstart, &loopstart, &loopend, &newstart, "--", 0);
551
552 /* Get the range for the ending code common to all functions */
553 sarrayParseRange(sa1, newstart, &finalstart, &finalend, &newstart, "--", 0);
554
555 /* Do all the static functions */
556 for (i = 0; i < nsels; i++) {
557 /* Generate the function header and add the common args */
558 sarrayAddString(sa4, staticstring, L_COPY);
559 fname = sarrayGetString(sa2, i, L_NOCOPY);
560 sprintf(bigbuf, "%s(l_uint32 *datad,", fname);
561 sarrayAddString(sa4, bigbuf, L_COPY);
562 sarrayAppendRange(sa4, sa1, argstart, argend);
563
564 /* Declare and define wplsN args, as necessary */
565 if ((sel = selaGetSel(sela, i)) == NULL) {
566 sarrayDestroy(&sa1);
567 sarrayDestroy(&sa2);
568 sarrayDestroy(&sa3);
569 sarrayDestroy(&sa4);
570 return ERROR_INT("sel not returned", __func__, 1);
571 }
572 sa5 = sarrayMakeWplsCode(sel);
573 sarrayJoin(sa4, sa5);
574 sarrayDestroy(&sa5);
575
576 /* Make sure sel has at least one hit */
577 nhits = 0;
578 nmisses = 0;
579 for (k = 0; k < sel->sy; k++) {
580 for (l = 0; l < sel->sx; l++) {
581 if (sel->data[k][l] == 1)
582 nhits++;
583 else if (sel->data[k][l] == 2)
584 nmisses++;
585 }
586 }
587 if (nhits == 0) {
588 linestr = stringNew(" "
589 "lept_stderr(\"Error in HMT: no hits in sel!\\n\");\n}\n\n");
590 sarrayAddString(sa4, linestr, L_INSERT);
591 continue;
592 }
593
594 /* Add the function loop code */
595 sarrayAppendRange(sa4, sa1, loopstart, loopend);
596
597 /* Insert barrel-op code for *dptr */
598 if ((sa6 = sarrayMakeInnerLoopDWACode(sel, nhits, nmisses)) == NULL) {
599 sarrayDestroy(&sa1);
600 sarrayDestroy(&sa2);
601 sarrayDestroy(&sa3);
602 sarrayDestroy(&sa4);
603 return ERROR_INT("sa6 not made", __func__, 1);
604 }
605 sarrayJoin(sa4, sa6);
606 sarrayDestroy(&sa6);
607
608 /* Finish the function code */
609 sarrayAppendRange(sa4, sa1, finalstart, finalend);
610 }
611
612 /* Output to file */
613 filestr = sarrayToString(sa4, 1);
614 nbytes = strlen(filestr);
615 if (filename)
616 snprintf(bigbuf, L_BUF_SIZE, "%slow.%d.c", filename, fileindex);
617 else
618 sprintf(bigbuf, "%slow.%d.c", OUTROOT, fileindex);
619 l_binaryWrite(bigbuf, "w", filestr, nbytes);
620 sarrayDestroy(&sa1);
621 sarrayDestroy(&sa2);
622 sarrayDestroy(&sa3);
623 sarrayDestroy(&sa4);
624 LEPT_FREE(filestr);
625 return 0;
626 }
627
628
629
630 /*--------------------------------------------------------------------------*
631 * Helper code for sel *
632 *--------------------------------------------------------------------------*/
633 /*!
634 * \brief sarrayMakeWplsCode()
635 */
636 static SARRAY *
637 sarrayMakeWplsCode(SEL *sel)
638 {
639 char emptystring[] = "";
640 l_int32 i, j, ymax, dely;
641 SARRAY *sa;
642
643 if (!sel)
644 return (SARRAY *)ERROR_PTR("sel not defined", __func__, NULL);
645
646 ymax = 0;
647 for (i = 0; i < sel->sy; i++) {
648 for (j = 0; j < sel->sx; j++) {
649 if (sel->data[i][j] == 1 || sel->data[i][j] == 2) {
650 dely = L_ABS(i - sel->cy);
651 ymax = L_MAX(ymax, dely);
652 }
653 }
654 }
655 if (ymax > 31) {
656 L_WARNING("ymax > 31; truncating to 31\n", __func__);
657 ymax = 31;
658 }
659
660 sa = sarrayCreate(0);
661
662 /* Declarations */
663 if (ymax > 4)
664 sarrayAddString(sa, wpldecls[2], L_COPY);
665 if (ymax > 8)
666 sarrayAddString(sa, wpldecls[6], L_COPY);
667 if (ymax > 12)
668 sarrayAddString(sa, wpldecls[10], L_COPY);
669 if (ymax > 16)
670 sarrayAddString(sa, wpldecls[14], L_COPY);
671 if (ymax > 20)
672 sarrayAddString(sa, wpldecls[18], L_COPY);
673 if (ymax > 24)
674 sarrayAddString(sa, wpldecls[22], L_COPY);
675 if (ymax > 28)
676 sarrayAddString(sa, wpldecls[26], L_COPY);
677 if (ymax > 1)
678 sarrayAddString(sa, wpldecls[ymax - 2], L_COPY);
679
680 sarrayAddString(sa, emptystring, L_COPY);
681
682 /* Definitions */
683 for (i = 2; i <= ymax; i++)
684 sarrayAddString(sa, wpldefs[i - 2], L_COPY);
685
686 return sa;
687 }
688
689
690 /*!
691 * \brief sarrayMakeInnerLoopDWACode()
692 */
693 static SARRAY *
694 sarrayMakeInnerLoopDWACode(SEL *sel,
695 l_int32 nhits,
696 l_int32 nmisses)
697 {
698 char *string;
699 char land[] = "&";
700 char bigbuf[L_BUF_SIZE];
701 l_int32 i, j, ntot, nfound, type, delx, dely;
702 SARRAY *sa;
703
704 if (!sel)
705 return (SARRAY *)ERROR_PTR("sel not defined", __func__, NULL);
706
707 sa = sarrayCreate(0);
708 ntot = nhits + nmisses;
709 nfound = 0;
710 for (i = 0; i < sel->sy; i++) {
711 for (j = 0; j < sel->sx; j++) {
712 type = sel->data[i][j];
713 if (type == SEL_HIT || type == SEL_MISS) {
714 nfound++;
715 dely = i - sel->cy;
716 delx = j - sel->cx;
717 if ((string = makeBarrelshiftString(delx, dely, type))
718 == NULL) {
719 L_WARNING("barrel shift string not made\n", __func__);
720 continue;
721 }
722 if (ntot == 1) /* just one item */
723 sprintf(bigbuf, " *dptr = %s;", string);
724 else if (nfound == 1)
725 sprintf(bigbuf, " *dptr = %s %s", string, land);
726 else if (nfound < ntot)
727 sprintf(bigbuf, " %s %s", string, land);
728 else /* nfound == ntot */
729 sprintf(bigbuf, " %s;", string);
730 sarrayAddString(sa, bigbuf, L_COPY);
731 LEPT_FREE(string);
732 }
733 }
734 }
735
736 return sa;
737 }
738
739
740 /*!
741 * \brief makeBarrelshiftString()
742 */
743 static char *
744 makeBarrelshiftString(l_int32 delx, /* j - cx */
745 l_int32 dely, /* i - cy */
746 l_int32 type) /* SEL_HIT or SEL_MISS */
747 {
748 l_int32 absx, absy;
749 char bigbuf[L_BUF_SIZE];
750
751 if (delx < -31 || delx > 31)
752 return (char *)ERROR_PTR("delx out of bounds", __func__, NULL);
753 if (dely < -31 || dely > 31)
754 return (char *)ERROR_PTR("dely out of bounds", __func__, NULL);
755 absx = L_ABS(delx);
756 absy = L_ABS(dely);
757
758 if (type == SEL_HIT) {
759 if ((delx == 0) && (dely == 0))
760 sprintf(bigbuf, "(*sptr)");
761 else if ((delx == 0) && (dely < 0))
762 sprintf(bigbuf, "(*(sptr %s))", wplstrm[absy - 1]);
763 else if ((delx == 0) && (dely > 0))
764 sprintf(bigbuf, "(*(sptr %s))", wplstrp[absy - 1]);
765 else if ((delx < 0) && (dely == 0))
766 sprintf(bigbuf, "((*(sptr) >> %d) | (*(sptr - 1) << %d))",
767 absx, 32 - absx);
768 else if ((delx > 0) && (dely == 0))
769 sprintf(bigbuf, "((*(sptr) << %d) | (*(sptr + 1) >> %d))",
770 absx, 32 - absx);
771 else if ((delx < 0) && (dely < 0))
772 sprintf(bigbuf, "((*(sptr %s) >> %d) | (*(sptr %s - 1) << %d))",
773 wplstrm[absy - 1], absx, wplstrm[absy - 1], 32 - absx);
774 else if ((delx > 0) && (dely < 0))
775 sprintf(bigbuf, "((*(sptr %s) << %d) | (*(sptr %s + 1) >> %d))",
776 wplstrm[absy - 1], absx, wplstrm[absy - 1], 32 - absx);
777 else if ((delx < 0) && (dely > 0))
778 sprintf(bigbuf, "((*(sptr %s) >> %d) | (*(sptr %s - 1) << %d))",
779 wplstrp[absy - 1], absx, wplstrp[absy - 1], 32 - absx);
780 else /* ((delx > 0) && (dely > 0)) */
781 sprintf(bigbuf, "((*(sptr %s) << %d) | (*(sptr %s + 1) >> %d))",
782 wplstrp[absy - 1], absx, wplstrp[absy - 1], 32 - absx);
783 } else { /* type == SEL_MISS */
784 if ((delx == 0) && (dely == 0))
785 sprintf(bigbuf, "(~*sptr)");
786 else if ((delx == 0) && (dely < 0))
787 sprintf(bigbuf, "(~*(sptr %s))", wplstrm[absy - 1]);
788 else if ((delx == 0) && (dely > 0))
789 sprintf(bigbuf, "(~*(sptr %s))", wplstrp[absy - 1]);
790 else if ((delx < 0) && (dely == 0))
791 sprintf(bigbuf, "((~*(sptr) >> %d) | (~*(sptr - 1) << %d))",
792 absx, 32 - absx);
793 else if ((delx > 0) && (dely == 0))
794 sprintf(bigbuf, "((~*(sptr) << %d) | (~*(sptr + 1) >> %d))",
795 absx, 32 - absx);
796 else if ((delx < 0) && (dely < 0))
797 sprintf(bigbuf, "((~*(sptr %s) >> %d) | (~*(sptr %s - 1) << %d))",
798 wplstrm[absy - 1], absx, wplstrm[absy - 1], 32 - absx);
799 else if ((delx > 0) && (dely < 0))
800 sprintf(bigbuf, "((~*(sptr %s) << %d) | (~*(sptr %s + 1) >> %d))",
801 wplstrm[absy - 1], absx, wplstrm[absy - 1], 32 - absx);
802 else if ((delx < 0) && (dely > 0))
803 sprintf(bigbuf, "((~*(sptr %s) >> %d) | (~*(sptr %s - 1) << %d))",
804 wplstrp[absy - 1], absx, wplstrp[absy - 1], 32 - absx);
805 else /* ((delx > 0) && (dely > 0)) */
806 sprintf(bigbuf, "((~*(sptr %s) << %d) | (~*(sptr %s + 1) >> %d))",
807 wplstrp[absy - 1], absx, wplstrp[absy - 1], 32 - absx);
808 }
809
810 return stringNew(bigbuf);
811 }