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