1 
2 /***********************************************************************/
3 /* Open Visualization Data Explorer                                    */
4 /* (C) Copyright IBM Corp. 1989,1999                                   */
5 /* ALL RIGHTS RESERVED                                                 */
6 /* This code licensed under the                                        */
7 /*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
8 /***********************************************************************/
9 
10 #include <dxconfig.h>
11 
12 
13 /*
14  * Header: /usr/people/gresh/code/svs/src/libdx/RCS/invalid.c,v 5.1 93/01/20 14:26:14 gda Exp Locker: gresh
15  *
16  */
17 
18 #include <stdio.h>
19 #include <string.h>
20 #include <dx/dx.h>
21 
22 static Array   CullArray(Array, int, int, InvalidComponentHandle);
23 
24 static Array   _dxfReRef(Array, int *);
25 static int    *MakeMap(InvalidComponentHandle, int, int *);
26 
27 static Object  C_Field(Field);
28 static Object  C_Field_Standard(Field);
29 static Object  C_Field_PE(Field);
30 static Object  C_Field_FLE(Field);
31 
32 static Object  IC_Field(Field);
33 static Object  IC_Field_Standard(Field);
34 static Object  IC_Field_PE(Field);
35 static Object  IC_Field_FLE(Field);
36 
37 static Object  IUP_Field(Field);
38 static Object  IUP_Field_Standard(Field);
39 static Object  IUP_Field_PE(Field);
40 static Object  IUP_Field_FLE(Field);
41 
42 /* --FIXME
43  * Never defined --remove after determining not used
44  *
45 
46 static Object  C_Object(Object);
47 static Object  IC_Object(Object);
48 static Object  IUP_Object(Object);
49 
50  */
51 
52 static Field DeleteFieldContents(Field);
53 
54 /*
55  * The following checks to find the maximum point reference in the
56  * connections array and whether the references skip any in the
57  * range.  This is a fast out for InvalidateUnreferencedPositions...
58  * if the max. reference matches the  length of the positions array
59  * and no holes were found, then no points are unreferenced.
60  */
61 #define ERROR_OCCURRED	-1
62 #define HOLES_FOUND	-2
63 static int GridSize(Array);
64 
65 #ifndef TRUE
66 #define TRUE 1
67 #endif
68 
69 #ifndef FALSE
70 #define FALSE 0
71 #endif
72 
73 /*
74  * DEP ARRAY lower-bound thresholds
75  *   DEP_STORAGE_THRESHOLD - When to switch to a DEP ARRAY when writing a field
76  *                           component (< -- SORTED_LIST; >= -- DEP_ARRAY)
77  *   DEP_MEM_THRESHOLD     - When to use a DEP for in-memory
78  *                           (i.e. InvalidComponentHandle) operations
79  *
80  *   These are different because one should favor storage size, while the
81  *   other should favors fast processing.
82  */
83 #define DEP_STORAGE_THRESHOLD(nItems) ( 0.20*(nItems) )
84 #define DEP_MEM_THRESHOLD(nItems)     ( 1024 )
85 
86 
87 #define TRAVERSE(objectMethod, fieldMethod)				\
88 {									\
89     switch(DXGetObjectClass(object))					\
90     {									\
91 	case CLASS_FIELD:						\
92 	    return (fieldMethod)((Field)object);			\
93 									\
94 	case CLASS_GROUP:						\
95 	{								\
96 	    int i = 0;							\
97 	    Group g = (Group)object;					\
98 	    Object c;							\
99 	    while(NULL != (c = DXGetEnumeratedMember(g, i++, NULL)))	\
100 	    {								\
101 		if (NULL == (objectMethod)(c))				\
102 		    return NULL;					\
103 	    }								\
104 	    return object;						\
105 	}								\
106 									\
107 	case CLASS_XFORM:						\
108 	{								\
109 	    Object c;							\
110 	    if (! DXGetXformInfo((Xform)object, &c, NULL))		\
111 		return NULL;						\
112 	    c = (objectMethod)(c);					\
113 	    if (! c)							\
114 		return NULL;						\
115 	    return object;						\
116 	}								\
117 									\
118 	case CLASS_CLIPPED:						\
119 	{								\
120 	    Object c;							\
121 	    if (! DXGetClippedInfo((Clipped)object, &c, NULL))		\
122 		return NULL;						\
123 	    c = (objectMethod)(c);					\
124 	    if (! c)							\
125 		return NULL;						\
126 	    return object;						\
127 	}								\
128 									\
129 	default:							\
130 	    return object;						\
131     }									\
132 }
133 
134 
135 Object
DXCull(Object object)136 DXCull(Object object)
137 {
138     TRAVERSE(DXCull, C_Field);
139 }
140 
141 Object
DXInvalidateConnections(Object object)142 DXInvalidateConnections(Object object)
143 {
144     TRAVERSE(DXInvalidateConnections, IC_Field);
145 }
146 
147 
148 Object
DXInvalidateUnreferencedPositions(Object object)149 DXInvalidateUnreferencedPositions(Object object)
150 {
151     TRAVERSE(DXInvalidateUnreferencedPositions, IUP_Field);
152 }
153 
154 Object
DXCullConditional(Object object)155 DXCullConditional(Object object)
156 {
157     return DXCull(object);
158 }
159 
160 static Object
C_Field(Field field)161 C_Field(Field field)
162 {
163     if (DXGetComponentValue(field, "polylines"))
164     {
165 	return C_Field_PE(field);
166     }
167     else if (DXGetComponentValue(field, "faces"))
168     {
169 	return C_Field_FLE(field);
170     }
171     else
172     {
173 	return C_Field_Standard(field);
174     }
175 }
176 
177 static Object
C_Field_PE(Field field)178 C_Field_PE(Field field)
179 {
180     Array			pArray,   plArray, eArray;
181     Array			child, 	  newChild;
182     int				nPositions, nPolylines, nEdges, nInvP, nInvPl;
183     int				nNewPositions, nNewPolylines;
184     int				i, j, k, knt;
185     int				*validPositionsMap, *validPolylinesMap;
186     Object			attr;
187     char			*reference, *dependence;
188     char			*name;
189     char			*toDelete[32];
190     int				nDelete = 0;
191     InvalidComponentHandle 	vpHandle = NULL;
192     InvalidComponentHandle	vplHandle = NULL;
193     Array			nPlArray = NULL, nEArray = NULL;
194     int				*polylines, *npolylines;
195     int				*edges, *nedges;
196 
197     if (DXEmptyField(field))
198 	return (Object)field;
199 
200     vplHandle 	        = NULL;
201     vpHandle 	        = NULL;
202     validPolylinesMap = NULL;
203     validPositionsMap   = NULL;
204     child 	        = NULL;
205 
206     pArray = (Array)DXGetComponentValue(field, "positions");
207     if (! pArray)
208     {
209 	DXSetError(ERROR_MISSING_DATA, "positions component");
210 	goto error;
211     }
212 
213     if (! DXGetArrayInfo(pArray, &nPositions, NULL, NULL, NULL, NULL))
214 	goto error;
215 
216     plArray = (Array)DXGetComponentValue(field, "polylines");
217     if (plArray)
218     {
219 	if (! DXGetArrayInfo(plArray, &nPolylines, NULL, NULL, NULL, NULL))
220 	    goto error;
221     }
222     else
223 	nPolylines = 0;
224 
225     eArray = (Array)DXGetComponentValue(field, "edges");
226     if (eArray)
227     {
228 	if (! DXGetArrayInfo(eArray, &nEdges, NULL, NULL, NULL, NULL))
229 	    goto error;
230     }
231     else
232 	nEdges = 0;
233 
234     vpHandle = DXCreateInvalidComponentHandle((Object)field, NULL, "positions");
235     if (! vpHandle)
236 	goto error;
237 
238     nInvP = DXGetInvalidCount(vpHandle);
239     if (nInvP)
240     {
241 	if (NULL == (validPositionsMap =
242 		    MakeMap(vpHandle, nPositions, &nNewPositions)))
243 	    goto error;
244 
245 	if (nNewPositions == 0)
246 	{
247 	    if (! (Object)DeleteFieldContents(field))
248 		goto error;
249 
250 	    goto done;
251 	}
252     }
253     else
254     {
255 	DXFreeInvalidComponentHandle(vpHandle);
256 	vpHandle = NULL;
257     }
258 
259     if (plArray)
260     {
261 	vplHandle = DXCreateInvalidComponentHandle((Object)field, NULL,
262 						"polylines");
263 	if (! vplHandle)
264 	    goto error;
265 
266 	nInvPl = DXGetInvalidCount(vplHandle);
267     }
268     else
269 	nInvPl = 0;
270 
271     if (nInvPl)
272     {
273 	if (NULL == (validPolylinesMap =
274 		    MakeMap(vplHandle, nPolylines, &nNewPolylines)))
275 	    goto error;
276     }
277     else
278     {
279 	DXFreeInvalidComponentHandle(vplHandle);
280 	vplHandle = NULL;
281     }
282 
283     if (nInvP == 0 && nInvPl == 0)
284     {
285 	DXDeleteComponent(field, "invalid polylines");
286 	DXDeleteComponent(field, "invalid positions");
287 	return (Object)field;
288     }
289 
290     /*
291      * Handle polylines and edges components
292      */
293     polylines = (int *)DXGetArrayData(plArray);
294     edges = (int *)DXGetArrayData(eArray);
295 
296     /*
297      * count the resulting edges
298      */
299     for (i = 0, knt = 0; i < nPolylines; i++)
300     {
301 	if (DXIsElementValid(vplHandle, i))
302 	{
303 	    int start = polylines[i];
304 	    int end   = (i == nPolylines-1) ? nEdges : polylines[i+1];
305 
306 	    knt += end - start;
307 	}
308     }
309 
310     nPlArray = DXNewArray(TYPE_INT, CATEGORY_REAL, 0);
311     nEArray  = DXNewArray(TYPE_INT, CATEGORY_REAL, 0);
312     if (! nPlArray || ! nEArray)
313 	goto error;
314 
315     if (! DXAddArrayData(nPlArray, 0, (nPolylines-nInvPl), NULL))
316 	goto error;
317 
318     if (! DXAddArrayData(nEArray, 0, knt, NULL))
319 	goto error;
320 
321     npolylines = (int *)DXGetArrayData(nPlArray);
322     nedges     = (int *)DXGetArrayData(nEArray);
323 
324     for (i = 0, j = 0, k = 0; i < nPolylines; i++)
325     {
326 	if (DXIsElementValid(vplHandle, i))
327 	{
328 	    int start = polylines[i];
329 	    int end   = (i == nPolylines-1) ? nEdges : polylines[i+1];
330 	    int n     = end - start;
331 	    int ii;
332 
333 	    npolylines[j++] = k;
334 
335 	    for (ii = 0; ii < n; ii++)
336 		nedges[k + ii] = edges[start + ii];
337 
338 	    k += n;
339 	}
340     }
341 
342     if (! DXSetAttribute((Object)nPlArray, "ref",
343 			(Object)DXNewString("edges")))
344 	goto error;
345 
346     if (! DXSetComponentValue(field, "polylines", (Object)nPlArray))
347 	goto error;
348     nPlArray = NULL;
349 
350     if (! DXSetAttribute((Object)nEArray, "ref",
351 			(Object)DXNewString("positions")))
352 	goto error;
353 
354     if (! DXSetComponentValue(field, "edges", (Object)nEArray))
355 	goto error;
356     nEArray = NULL;
357 
358     i = 0;
359     while (NULL !=
360 	(child = (Array)DXGetEnumeratedComponentValue(field, i, &name)))
361     {
362 	if (! strncmp(name, "invalid ", 8))
363 	{
364 	    toDelete[nDelete++] = name;
365 	    i++;
366 	    continue;
367 	}
368 
369 	if (! strcmp(name, "polylines"))
370 	{
371 	    i++;
372 	    continue;
373 	}
374 
375 	attr = DXGetEnumeratedComponentAttribute(field, i, NULL, "der");
376 	if (attr && strcmp(name, "neighbors"))
377 	{
378 	    toDelete[nDelete++] = name;
379 	    i++;
380 	    continue;
381 	}
382 
383 	DXReference((Object)child);
384 
385 	dependence = NULL;
386 
387 	if (! strcmp(name, "positions"))
388 	    dependence = "positions";
389 	else if (! strcmp(name, "polylines"))
390 	    dependence = "polylines";
391 	else
392 	{
393 	    attr = DXGetEnumeratedComponentAttribute(field, i, NULL, "dep");
394 	    if (attr)
395 		dependence = DXGetString((String)attr);
396 	}
397 
398 	/*
399 	 * If the component is dependent on something, then do to the
400 	 * component whatever is appropriate for the component on which
401 	 * it is dependent.
402 	 */
403 	if (dependence)
404 	{
405 	    /*
406 	     * If its dependent on positions...
407 	     */
408 	    if (! strcmp(dependence, "positions"))
409 	    {
410 		/*
411 		 *  and there are invalidated positions, cull the component
412 		 */
413 		if (vpHandle)
414 		{
415 		    if (nNewPositions == 0)
416 		    {
417 			toDelete[nDelete++] = name;
418 			DXDelete((Object)child);
419 			child = NULL;
420 			i++;
421 			continue;
422 		    }
423 		    else
424 		    {
425 			newChild = CullArray(child, nPositions,
426 						nNewPositions, vpHandle);
427 			if (! newChild)
428 			    goto error;
429 
430 			DXDelete((Object)child);
431 			child = (Array)DXReference((Object)newChild);
432 		    }
433 		}
434 	    }
435 	    /*
436 	     * Else if its dependent on polylines...
437 	     */
438 	    else if (! strcmp(dependence, "polylines"))
439 	    {
440 		if (! plArray)
441 		{
442 		    DXSetError(ERROR_DATA_INVALID,
443 			    "component dependent on nonexistent polylines");
444 		    goto error;
445 		}
446 
447 		/*
448 		 *  and there is a validPolylines array, cull the component.
449 		 */
450 		if (vplHandle)
451 		{
452 		    if (nNewPolylines == 0)
453 		    {
454 			toDelete[nDelete++] = name;
455 			DXDelete((Object)child);
456 			child = NULL;
457 			i++;
458 			continue;
459 		    }
460 		    else
461 		    {
462 			newChild = CullArray(child, nPolylines,
463 					nNewPolylines, vplHandle);
464 
465 			if (! newChild)
466 			    goto error;
467 
468 			DXDelete((Object)child);
469 			child = (Array)DXReference((Object)newChild);
470 		    }
471 		}
472 	    }
473 	}
474 
475 	/*
476 	 * Now we consider components that ref.  If the component they ref
477 	 * has been culled, we need to renumber the references to reflect
478 	 * the culled referenced array.
479 	 */
480 	attr = DXGetEnumeratedComponentAttribute(field, i, NULL, "ref");
481 	if (attr)
482 	{
483 	    reference = DXGetString((String)attr);
484 
485 	    /*
486 	     * If it references polylines...
487 	     */
488 	    if (!strcmp(reference, "polylines"))
489 	    {
490 		if (! plArray)
491 		{
492 		    DXSetError(ERROR_DATA_INVALID,
493 			    "component refers to nonexistent polylines");
494 		    goto error;
495 		}
496 
497 		/*
498 		 * And polylines have been culled, renumber the references.
499 		 */
500 		if (validPolylinesMap)
501 		{
502 		    newChild = _dxfReRef(child, validPolylinesMap);
503 		    if (! newChild)
504 			goto error;
505 
506 		    DXDelete((Object)child);
507 		    child = (Array)DXReference((Object)newChild);
508 		}
509 	    }
510 	    /*
511 	     * Else if it references positions...
512 	     */
513 	    else if (!strcmp(reference, "positions"))
514 	    {
515 		/*
516 		 * And positions have been culled, renumber the references.
517 		 */
518 		if (validPositionsMap)
519 		{
520 		    newChild = _dxfReRef(child, validPositionsMap);
521 		    if (! newChild)
522 			goto error;
523 
524 		    DXDelete((Object)child);
525 		    child = (Array)DXReference((Object)newChild);
526 		}
527 	    }
528 	}
529 
530 	if (! DXSetComponentValue(field, name, (Object)child))
531 	    goto error;
532 
533 	/*
534 	 * Remove local reference
535 	 */
536 	DXDelete((Object)child);
537 	child = NULL;
538 
539 	i++;
540     }
541 
542     for (nDelete--; nDelete >= 0; nDelete--)
543 	DXDeleteComponent(field, toDelete[nDelete]);
544 
545     field = DXEndField(field);
546 
547 done:
548     DXFree((Pointer)validPolylinesMap);
549     DXFree((Pointer)validPositionsMap);
550     DXFreeInvalidComponentHandle(vpHandle);
551     DXFreeInvalidComponentHandle(vplHandle);
552 
553     return (Object)field;
554 
555 error:
556     DXDelete((Object)nPlArray);
557     DXDelete((Object)nEArray);
558     DXDelete((Object)child);
559     DXFreeInvalidComponentHandle(vpHandle);
560     DXFreeInvalidComponentHandle(vplHandle);
561     DXFree((Pointer)validPolylinesMap);
562     DXFree((Pointer)validPositionsMap);
563 
564     return NULL;
565 }
566 
567 static Object
C_Field_FLE(Field field)568 C_Field_FLE(Field field)
569 {
570     Array			pArray, fArray, lArray, eArray;
571     Array			child, newChild;
572     int				nPositions, nFaces, nLoops;
573     int				nEdges, nInvP, nInvF;
574     int				nNewPositions, nNewFaces;
575     int				i, f, nfknt, nlknt, neknt;
576     int				*validPositionsMap, *validFacesMap;
577     Object			attr;
578     char			*reference, *dependence;
579     char			*name;
580     char			*toDelete[32];
581     int				nDelete = 0;
582     InvalidComponentHandle 	vpHandle = NULL;
583     InvalidComponentHandle	vfHandle = NULL;
584     Array			nLArray = NULL, nFArray = NULL, nEArray = NULL;
585     int				*faces, *nfaces;
586     int				*loops, *nloops;
587     int				*edges, *nedges;
588 
589     if (DXEmptyField(field))
590 	return (Object)field;
591 
592     vfHandle 	        = NULL;
593     vpHandle 	        = NULL;
594     validFacesMap       = NULL;
595     validPositionsMap   = NULL;
596     child 	        = NULL;
597 
598     pArray = (Array)DXGetComponentValue(field, "positions");
599     if (! pArray)
600     {
601 	DXSetError(ERROR_MISSING_DATA, "positions component");
602 	goto error;
603     }
604 
605     if (! DXGetArrayInfo(pArray, &nPositions, NULL, NULL, NULL, NULL))
606 	goto error;
607 
608     fArray = (Array)DXGetComponentValue(field, "faces");
609     if (fArray)
610     {
611 	if (! DXGetArrayInfo(fArray, &nFaces, NULL, NULL, NULL, NULL))
612 	    goto error;
613     }
614     else
615 	nFaces = 0;
616 
617     lArray = (Array)DXGetComponentValue(field, "loops");
618     if (lArray)
619     {
620 	if (! DXGetArrayInfo(lArray, &nLoops, NULL, NULL, NULL, NULL))
621 	    goto error;
622     }
623     else
624 	nLoops = 0;
625 
626     eArray = (Array)DXGetComponentValue(field, "edges");
627     if (eArray)
628     {
629 	if (! DXGetArrayInfo(eArray, &nEdges, NULL, NULL, NULL, NULL))
630 	    goto error;
631     }
632     else
633 	nEdges = 0;
634 
635     vpHandle = DXCreateInvalidComponentHandle((Object)field, NULL, "positions");
636     if (! vpHandle)
637 	goto error;
638 
639     nInvP = DXGetInvalidCount(vpHandle);
640     if (nInvP)
641     {
642 	if (NULL == (validPositionsMap =
643 		    MakeMap(vpHandle, nPositions, &nNewPositions)))
644 	    goto error;
645 
646 	if (nNewPositions == 0)
647 	{
648 	    if (! (Object)DeleteFieldContents(field))
649 		goto error;
650 
651 	    goto done;
652 	}
653     }
654     else
655     {
656 	DXFreeInvalidComponentHandle(vpHandle);
657 	vpHandle = NULL;
658     }
659 
660     if (fArray)
661     {
662 	vfHandle = DXCreateInvalidComponentHandle((Object)field, NULL,
663 						"faces");
664 	if (! vfHandle)
665 	    goto error;
666 
667 	nInvF = DXGetInvalidCount(vfHandle);
668     }
669     else
670 	nInvF = 0;
671 
672     if (nInvF)
673     {
674 	if (NULL == (validFacesMap =
675 		    MakeMap(vfHandle, nFaces, &nNewFaces)))
676 	    goto error;
677     }
678     else
679     {
680 	DXFreeInvalidComponentHandle(vfHandle);
681 	vfHandle = NULL;
682     }
683 
684     if (nInvP == 0 && nInvF == 0)
685     {
686 	DXDeleteComponent(field, "invalid faces");
687 	DXDeleteComponent(field, "invalid positions");
688 	return (Object)field;
689     }
690 
691     /*
692      * Handle polylines and edges components
693      */
694     faces = (int *)DXGetArrayData(fArray);
695     loops = (int *)DXGetArrayData(lArray);
696     edges = (int *)DXGetArrayData(eArray);
697 
698     /*
699      * count the resulting loops and edges
700      */
701     for (f = 0, nfknt = nlknt = neknt = 0; f < nFaces; f++)
702     {
703 	if (!vfHandle || DXIsElementValid(vfHandle, f))
704 	{
705 	    int lstart = faces[f];
706 	    int lend   = (f == nFaces-1) ? nLoops : faces[f+1];
707 	    int l;
708 
709 	    for (l = lstart; l < lend; l++)
710 	    {
711 		int estart = loops[l];
712 		int eend   = (l == nLoops-1) ? nEdges : loops[l+1];
713 		neknt += eend - estart ;
714 	    }
715 
716 	    nlknt += lend - lstart;
717 	    nfknt ++;
718 	}
719     }
720 
721     nFArray = DXNewArray(TYPE_INT, CATEGORY_REAL, 0);
722     nLArray = DXNewArray(TYPE_INT, CATEGORY_REAL, 0);
723     nEArray = DXNewArray(TYPE_INT, CATEGORY_REAL, 0);
724     if (! nFArray || ! nEArray || ! nLArray)
725 	goto error;
726 
727     if (! DXAddArrayData(nFArray, 0, nfknt, NULL))
728 	goto error;
729 
730     if (! DXAddArrayData(nLArray, 0, nlknt, NULL))
731 	goto error;
732 
733     if (! DXAddArrayData(nEArray, 0, neknt, NULL))
734 	goto error;
735 
736     nfaces = (int *)DXGetArrayData(nFArray);
737     nloops = (int *)DXGetArrayData(nLArray);
738     nedges = (int *)DXGetArrayData(nEArray);
739 
740     for (f = 0, nfknt = neknt = nlknt = 0; f < nFaces; f++)
741     {
742 	if (!vfHandle || DXIsElementValid(vfHandle, f))
743 	{
744 	    int lstart = faces[f];
745 	    int lend   = (f == nFaces-1) ? nLoops : faces[f+1];
746 	    int l;
747 
748 	    nfaces[nfknt++] = nlknt;
749 
750 	    for (l = lstart; l < lend; l++)
751 	    {
752 		int estart = loops[l];
753 		int eend   = (l == nLoops-1) ? nEdges : loops[l+1];
754 		int e;
755 
756 		nloops[nlknt++] = neknt;
757 
758 		for (e = estart; e < eend; e++)
759 		    nedges[neknt++] = edges[e];
760 	    }
761 	}
762     }
763 
764     if (! DXSetAttribute((Object)nFArray, "ref",
765 			(Object)DXNewString("loops")))
766 	goto error;
767 
768     if (! DXSetComponentValue(field, "faces", (Object)nFArray))
769 	goto error;
770     nFArray = NULL;
771 
772     if (! DXSetAttribute((Object)nLArray, "ref",
773 			(Object)DXNewString("edges")))
774 	goto error;
775 
776     if (! DXSetComponentValue(field, "loops", (Object)nLArray))
777 	goto error;
778     nLArray = NULL;
779 
780     if (! DXSetAttribute((Object)nEArray, "ref",
781 			(Object)DXNewString("positions")))
782 	goto error;
783 
784     if (! DXSetComponentValue(field, "edges", (Object)nEArray))
785 	goto error;
786     nEArray = NULL;
787 
788     i = 0;
789     while (NULL !=
790 	(child = (Array)DXGetEnumeratedComponentValue(field, i, &name)))
791     {
792 	if (! strncmp(name, "invalid ", 8))
793 	{
794 	    toDelete[nDelete++] = name;
795 	    i++;
796 	    continue;
797 	}
798 
799 	if (! strcmp(name, "faces") ||
800 	    ! strcmp(name, "loops"))
801 	{
802 	    i++;
803 	    continue;
804 	}
805 
806 	attr = DXGetEnumeratedComponentAttribute(field, i, NULL, "der");
807 	if (attr && strcmp(name, "neighbors"))
808 	{
809 	    toDelete[nDelete++] = name;
810 	    i++;
811 	    continue;
812 	}
813 
814 	DXReference((Object)child);
815 
816 	dependence = NULL;
817 
818 	if (! strcmp(name, "positions"))
819 	    dependence = "positions";
820 	else if (! strcmp(name, "faces"))
821 	    dependence = "faces";
822 	else
823 	{
824 	    attr = DXGetEnumeratedComponentAttribute(field, i, NULL, "dep");
825 	    if (attr)
826 		dependence = DXGetString((String)attr);
827 	}
828 
829 	/*
830 	 * If the component is dependent on something, then do to the
831 	 * component whatever is appropriate for the component on which
832 	 * it is dependent.
833 	 */
834 	if (dependence)
835 	{
836 	    /*
837 	     * If its dependent on positions...
838 	     */
839 	    if (! strcmp(dependence, "positions"))
840 	    {
841 		/*
842 		 *  and there are invalidated positions, cull the component
843 		 */
844 		if (vpHandle)
845 		{
846 		    if (nNewPositions == 0)
847 		    {
848 			toDelete[nDelete++] = name;
849 			DXDelete((Object)child);
850 			child = NULL;
851 			i++;
852 			continue;
853 		    }
854 		    else
855 		    {
856 			newChild = CullArray(child, nPositions,
857 						nNewPositions, vpHandle);
858 			if (! newChild)
859 			    goto error;
860 
861 			DXDelete((Object)child);
862 			child = (Array)DXReference((Object)newChild);
863 		    }
864 		}
865 	    }
866 	    /*
867 	     * Else if its dependent on faces...
868 	     */
869 	    else if (! strcmp(dependence, "faces"))
870 	    {
871 		if (! fArray)
872 		{
873 		    DXSetError(ERROR_DATA_INVALID,
874 			    "component dependent on nonexistent faces");
875 		    goto error;
876 		}
877 
878 		/*
879 		 *  and there is a validFaces array, cull the component.
880 		 */
881 		if (vfHandle)
882 		{
883 		    if (nNewFaces == 0)
884 		    {
885 			toDelete[nDelete++] = name;
886 			DXDelete((Object)child);
887 			child = NULL;
888 			i++;
889 			continue;
890 		    }
891 		    else
892 		    {
893 			newChild = CullArray(child, nFaces,
894 					nNewFaces, vfHandle);
895 
896 			if (! newChild)
897 			    goto error;
898 
899 			DXDelete((Object)child);
900 			child = (Array)DXReference((Object)newChild);
901 		    }
902 		}
903 	    }
904 	}
905 
906 	/*
907 	 * Now we consider components that ref.  If the component they ref
908 	 * has been culled, we need to renumber the references to reflect
909 	 * the culled referenced array.
910 	 */
911 	attr = DXGetEnumeratedComponentAttribute(field, i, NULL, "ref");
912 	if (attr)
913 	{
914 	    reference = DXGetString((String)attr);
915 
916 	    /*
917 	     * If it references faces...
918 	     */
919 	    if (!strcmp(reference, "faces"))
920 	    {
921 		if (! fArray)
922 		{
923 		    DXSetError(ERROR_DATA_INVALID,
924 			    "component refers to nonexistent faces");
925 		    goto error;
926 		}
927 
928 		/*
929 		 * And faces have been culled, renumber the references.
930 		 */
931 		if (validFacesMap)
932 		{
933 		    newChild = _dxfReRef(child, validFacesMap);
934 		    if (! newChild)
935 			goto error;
936 
937 		    DXDelete((Object)child);
938 		    child = (Array)DXReference((Object)newChild);
939 		}
940 	    }
941 	    /*
942 	     * Else if it references positions...
943 	     */
944 	    else if (!strcmp(reference, "positions"))
945 	    {
946 		/*
947 		 * And positions have been culled, renumber the references.
948 		 */
949 		if (validPositionsMap)
950 		{
951 		    newChild = _dxfReRef(child, validPositionsMap);
952 		    if (! newChild)
953 			goto error;
954 
955 		    DXDelete((Object)child);
956 		    child = (Array)DXReference((Object)newChild);
957 		}
958 	    }
959 	}
960 
961 	if (! DXSetComponentValue(field, name, (Object)child))
962 	    goto error;
963 
964 	/*
965 	 * Remove local reference
966 	 */
967 	DXDelete((Object)child);
968 	child = NULL;
969 
970 	i++;
971     }
972 
973     for (nDelete--; nDelete >= 0; nDelete--)
974 	DXDeleteComponent(field, toDelete[nDelete]);
975 
976     field = DXEndField(field);
977 
978 done:
979     DXFree((Pointer)validFacesMap);
980     DXFree((Pointer)validPositionsMap);
981     DXFreeInvalidComponentHandle(vpHandle);
982     DXFreeInvalidComponentHandle(vfHandle);
983 
984     return (Object)field;
985 
986 error:
987     DXDelete((Object)nFArray);
988     DXDelete((Object)nLArray);
989     DXDelete((Object)nEArray);
990     DXDelete((Object)child);
991     DXFreeInvalidComponentHandle(vpHandle);
992     DXFreeInvalidComponentHandle(vfHandle);
993     DXFree((Pointer)validFacesMap);
994     DXFree((Pointer)validPositionsMap);
995 
996     return NULL;
997 }
998 
999 static Object
C_Field_Standard(Field field)1000 C_Field_Standard(Field field)
1001 {
1002     Array			pArray,   cArray;
1003     Array			child, 	  newChild;
1004     int				nPositions, nConnections, nInvP, nInvC;
1005     int				nNewPositions, nNewConnections;
1006     int				i;
1007     int				*validPositionsMap, *validConnectionsMap;
1008     Object			attr;
1009     char			*reference, *dependence;
1010     char			*name;
1011     char			*toDelete[32];
1012     int				nDelete = 0;
1013     InvalidComponentHandle 	vpHandle = NULL;
1014     InvalidComponentHandle	vcHandle = NULL;
1015 
1016     if (DXEmptyField(field))
1017 	return (Object)field;
1018 
1019     vcHandle 	        = NULL;
1020     vpHandle 	        = NULL;
1021     validConnectionsMap = NULL;
1022     validPositionsMap   = NULL;
1023     child 	        = NULL;
1024 
1025     pArray = (Array)DXGetComponentValue(field, "positions");
1026     if (! pArray)
1027     {
1028 	DXSetError(ERROR_MISSING_DATA, "positions component");
1029 	goto error;
1030     }
1031 
1032     if (! DXGetArrayInfo(pArray, &nPositions, NULL, NULL, NULL, NULL))
1033 	goto error;
1034 
1035     cArray = (Array)DXGetComponentValue(field, "connections");
1036     if (cArray)
1037     {
1038 	if (! DXGetArrayInfo(cArray, &nConnections, NULL, NULL, NULL, NULL))
1039 	    goto error;
1040     }
1041     else
1042 	nConnections = 0;
1043 
1044     vpHandle = DXCreateInvalidComponentHandle((Object)field, NULL, "positions");
1045     if (! vpHandle)
1046 	goto error;
1047 
1048     nInvP = DXGetInvalidCount(vpHandle);
1049     if (nInvP)
1050     {
1051 	if (NULL == (validPositionsMap =
1052 		    MakeMap(vpHandle, nPositions, &nNewPositions)))
1053 	    goto error;
1054 
1055 	if (nNewPositions == 0)
1056 	{
1057 	    if (! (Object)DeleteFieldContents(field))
1058 		goto error;
1059 
1060 	    goto done;
1061 	}
1062     }
1063     else
1064     {
1065 	DXFreeInvalidComponentHandle(vpHandle);
1066 	vpHandle = NULL;
1067     }
1068 
1069     if (cArray)
1070     {
1071 	vcHandle = DXCreateInvalidComponentHandle((Object)field, NULL,
1072 						"connections");
1073 	if (! vcHandle)
1074 	    goto error;
1075 
1076 	nInvC = DXGetInvalidCount(vcHandle);
1077     }
1078     else
1079 	nInvC = 0;
1080 
1081     if (nInvC)
1082     {
1083 	if (NULL == (validConnectionsMap =
1084 		    MakeMap(vcHandle, nConnections, &nNewConnections)))
1085 	    goto error;
1086     }
1087     else
1088     {
1089 	DXFreeInvalidComponentHandle(vcHandle);
1090 	vcHandle = NULL;
1091     }
1092 
1093     if (nInvP == 0 && nInvC == 0)
1094     {
1095 	DXDeleteComponent(field, "invalid connections");
1096 	DXDeleteComponent(field, "invalid positions");
1097 	return (Object)field;
1098     }
1099 
1100     i = 0;
1101     while (NULL !=
1102 	(child = (Array)DXGetEnumeratedComponentValue(field, i, &name)))
1103     {
1104 	if (! strncmp(name, "invalid ", 8))
1105 	{
1106 	    toDelete[nDelete++] = name;
1107 	    i++;
1108 	    continue;
1109 	}
1110 
1111 	attr = DXGetEnumeratedComponentAttribute(field, i, NULL, "der");
1112 	if (attr && strcmp(name, "neighbors"))
1113 	{
1114 	    toDelete[nDelete++] = name;
1115 	    i++;
1116 	    continue;
1117 	}
1118 
1119 	DXReference((Object)child);
1120 
1121 	dependence = NULL;
1122 
1123 	if (! strcmp(name, "positions"))
1124 	    dependence = "positions";
1125 	else if (! strcmp(name, "connections"))
1126 	    dependence = "connections";
1127 	else
1128 	{
1129 	    attr = DXGetEnumeratedComponentAttribute(field, i, NULL, "dep");
1130 	    if (attr)
1131 		dependence = DXGetString((String)attr);
1132 	}
1133 
1134 	/*
1135 	 * If the component is dependent on something, then do to the
1136 	 * component whatever is appropriate for the component on which
1137 	 * it is dependent.
1138 	 */
1139 	if (dependence)
1140 	{
1141 	    /*
1142 	     * If its dependent on positions...
1143 	     */
1144 	    if (! strcmp(dependence, "positions"))
1145 	    {
1146 		/*
1147 		 *  and there are invalidated positions, cull the component
1148 		 */
1149 		if (vpHandle)
1150 		{
1151 		    if (nNewPositions == 0)
1152 		    {
1153 			toDelete[nDelete++] = name;
1154 			DXDelete((Object)child);
1155 			child = NULL;
1156 			i++;
1157 			continue;
1158 		    }
1159 		    else
1160 		    {
1161 			newChild = CullArray(child, nPositions,
1162 						nNewPositions, vpHandle);
1163 			if (! newChild)
1164 			    goto error;
1165 
1166 			DXDelete((Object)child);
1167 			child = (Array)DXReference((Object)newChild);
1168 		    }
1169 		}
1170 	    }
1171 	    /*
1172 	     * Else if its dependent on connections...
1173 	     */
1174 	    else if (! strcmp(dependence, "connections"))
1175 	    {
1176 		if (! cArray)
1177 		{
1178 		    DXSetError(ERROR_DATA_INVALID,
1179 			    "component dependent on nonexistent connections");
1180 		    goto error;
1181 		}
1182 
1183 		/*
1184 		 *  and there is a validConnections array, cull the component.
1185 		 */
1186 		if (vcHandle)
1187 		{
1188 		    if (nNewConnections == 0)
1189 		    {
1190 			toDelete[nDelete++] = name;
1191 			DXDelete((Object)child);
1192 			child = NULL;
1193 			i++;
1194 			continue;
1195 		    }
1196 		    else
1197 		    {
1198 			newChild = CullArray(child, nConnections,
1199 					nNewConnections, vcHandle);
1200 
1201 			if (! newChild)
1202 			    goto error;
1203 
1204 			DXDelete((Object)child);
1205 			child = (Array)DXReference((Object)newChild);
1206 		    }
1207 		}
1208 	    }
1209 	}
1210 
1211 	/*
1212 	 * Now we consider components that ref.  If the component they ref
1213 	 * has been culled, we need to renumber the references to reflect
1214 	 * the culled referenced array.
1215 	 */
1216 	attr = DXGetEnumeratedComponentAttribute(field, i, NULL, "ref");
1217 	if (attr)
1218 	{
1219 	    reference = DXGetString((String)attr);
1220 
1221 	    /*
1222 	     * If it references connections...
1223 	     */
1224 	    if (!strcmp(reference, "connections"))
1225 	    {
1226 		if (! cArray)
1227 		{
1228 		    DXSetError(ERROR_DATA_INVALID,
1229 			    "component refers to nonexistent connections");
1230 		    goto error;
1231 		}
1232 
1233 		/*
1234 		 * And connections have been culled, renumber the references.
1235 		 */
1236 		if (validConnectionsMap)
1237 		{
1238 		    newChild = _dxfReRef(child, validConnectionsMap);
1239 		    if (! newChild)
1240 			goto error;
1241 
1242 		    DXDelete((Object)child);
1243 		    child = (Array)DXReference((Object)newChild);
1244 		}
1245 	    }
1246 	    /*
1247 	     * Else if it references positions...
1248 	     */
1249 	    else if (!strcmp(reference, "positions"))
1250 	    {
1251 		/*
1252 		 * And positions have been culled, renumber the references.
1253 		 */
1254 		if (validPositionsMap)
1255 		{
1256 		    newChild = _dxfReRef(child, validPositionsMap);
1257 		    if (! newChild)
1258 			goto error;
1259 
1260 		    DXDelete((Object)child);
1261 		    child = (Array)DXReference((Object)newChild);
1262 		}
1263 	    }
1264 	}
1265 
1266 	if (! DXSetComponentValue(field, name, (Object)child))
1267 	    goto error;
1268 
1269 	/*
1270 	 * Remove local reference
1271 	 */
1272 	DXDelete((Object)child);
1273 	child = NULL;
1274 
1275 	i++;
1276     }
1277 
1278     for (nDelete--; nDelete >= 0; nDelete--)
1279 	DXDeleteComponent(field, toDelete[nDelete]);
1280 
1281     field = DXEndField(field);
1282 
1283 done:
1284     DXFree((Pointer)validConnectionsMap);
1285     DXFree((Pointer)validPositionsMap);
1286     DXFreeInvalidComponentHandle(vpHandle);
1287     DXFreeInvalidComponentHandle(vcHandle);
1288 
1289     return (Object)field;
1290 
1291 error:
1292     DXDelete((Object)child);
1293     DXFreeInvalidComponentHandle(vpHandle);
1294     DXFreeInvalidComponentHandle(vcHandle);
1295     DXFree((Pointer)validConnectionsMap);
1296     DXFree((Pointer)validPositionsMap);
1297 
1298     return NULL;
1299 }
1300 
1301 static Array
CullArray(Array oldArray,int nOld,int nNew,InvalidComponentHandle handle)1302 CullArray(Array oldArray, int nOld, int nNew, InvalidComponentHandle handle)
1303 {
1304     Array       newArray;
1305     Type        type;
1306     Category    cat;
1307     int         rank;
1308     int         shape[100];
1309     Pointer     buf = NULL;
1310     ArrayHandle aHandle = NULL;
1311 
1312     DXGetArrayInfo(oldArray, NULL, &type, &cat, &rank, shape);
1313 
1314     if (DXQueryConstantArray(oldArray, NULL, NULL))
1315     {
1316 	newArray = (Array)DXNewConstantArrayV(nNew,
1317 	    DXGetConstantArrayData((Array)oldArray), type, cat, rank, shape);
1318     }
1319     else
1320     {
1321 	int   itemSize, i, nKnt;
1322 	ubyte *nPtr;
1323 
1324 	itemSize = DXGetItemSize(oldArray);
1325 	buf      = DXAllocate(itemSize);
1326 	aHandle  = DXCreateArrayHandle(oldArray);
1327 	newArray = DXNewArrayV(type, cat, rank, shape);
1328 	if (! buf || ! aHandle || ! newArray)
1329 	    goto error;
1330 
1331 	if (! DXAddArrayData(newArray, 0, nNew, NULL))
1332 	    goto error;
1333 
1334 	nPtr = (ubyte *)DXGetArrayData(newArray);
1335 
1336 	for (i = 0, nKnt = 0; i < nOld; i++)
1337 	    if (! DXIsElementInvalidSequential(handle, i))
1338 	    {
1339 		memcpy(nPtr, DXGetArrayEntry(aHandle, i, buf), itemSize);
1340 		nPtr += itemSize;
1341 		if (++nKnt > nNew)
1342 		{
1343 		    DXSetError(ERROR_INTERNAL, "invalid count mismatch");
1344 		    goto error;
1345 		}
1346 	    }
1347 
1348 	DXFree(buf); buf = NULL;
1349 	DXFreeArrayHandle(aHandle); aHandle = NULL;
1350     }
1351 
1352     return newArray;
1353 
1354 error:
1355     DXFree(buf);
1356     DXFreeArrayHandle(aHandle);
1357     DXDelete((Object)newArray);
1358     return NULL;
1359 }
1360 
1361 static Array
_dxfReRef(Array oldArray,int * map)1362 _dxfReRef(Array oldArray, int *map)
1363 {
1364     Array 	newArray;
1365     Type	type;
1366     Category	cat;
1367     int		rank, shape[32];
1368     int		*oldPtr, *newPtr;
1369     int		i, itemSize;
1370     int  	nElements;
1371 
1372     if (! DXGetArrayInfo(oldArray, &nElements, &type, &cat, &rank, shape))
1373 	return NULL;
1374 
1375     if (type != TYPE_INT || cat != CATEGORY_REAL)
1376     {
1377 	DXSetError(ERROR_DATA_INVALID, "invalid data array is not int/real");
1378 	return NULL;
1379     }
1380 
1381     itemSize = 1;
1382     for(i = 0; i < rank; i++)
1383 	itemSize *= shape[i];
1384 
1385     if (NULL == (oldPtr = (int *)DXGetArrayData(oldArray)))
1386 	return NULL;
1387 
1388     if (NULL == (newArray = DXNewArrayV(type, cat, rank, shape)))
1389 	return NULL;
1390 
1391     if (! DXAddArrayData(newArray, 0, nElements, NULL))
1392     {
1393 	DXDelete((Object)newArray);
1394 	return NULL;
1395     }
1396 
1397     if (NULL == (newPtr = (int *)DXGetArrayData(newArray)))
1398     {
1399 	DXDelete((Object)newArray);
1400 	return NULL;
1401     }
1402 
1403     if (NULL == (oldPtr = (int *)DXGetArrayData(oldArray)))
1404     {
1405 	DXDelete((Object)newArray);
1406 	return NULL;
1407     }
1408 
1409     for (i = 0; i < nElements*itemSize; i++)
1410     {
1411 	if (*oldPtr != -1)
1412 	    *newPtr = map[*oldPtr];
1413 	else
1414 	    *newPtr = -1;
1415 
1416 	oldPtr++;
1417 	newPtr++;
1418     }
1419 
1420     return newArray;
1421 }
1422 
1423 static int *
MakeMap(InvalidComponentHandle handle,int nIn,int * nNew)1424 MakeMap(InvalidComponentHandle handle, int nIn, int *nNew)
1425 {
1426     int *map;
1427     int i, j;
1428 
1429     map = (int *)DXAllocate(nIn * sizeof(int));
1430     if (! map)
1431 	return NULL;
1432 
1433     for (i = 0, j = 0; i < nIn; i++)
1434 	if (DXIsElementInvalidSequential(handle, i))
1435 	    map[i] = -1;
1436 	else
1437 	    map[i] = j++;
1438 
1439     *nNew = j;
1440 
1441     return map;
1442 }
1443 
1444 /*
1445  * Any connections referencing invalidated positions are invalidated.
1446  */
1447 static Object
IC_Field(Field field)1448 IC_Field(Field field)
1449 {
1450     if (DXGetComponentValue(field, "polylines"))
1451     {
1452 	return IC_Field_PE(field);
1453     }
1454     else if (DXGetComponentValue(field, "faces"))
1455     {
1456 	return IC_Field_FLE(field);
1457     }
1458     else
1459     {
1460 	return IC_Field_Standard(field);
1461     }
1462 }
1463 
1464 /*
1465  * Any polylines referencing invalidated positions are invalidated.
1466  */
1467 static Object
IC_Field_PE(Field field)1468 IC_Field_PE(Field field)
1469 {
1470     Array	           plArray, eArray;
1471     InvalidComponentHandle vp = NULL, vplIn = NULL, vplOut = NULL;
1472     int		           i, j;
1473     int			   nPl, nE;
1474     int			   *polylines = NULL, *edges = NULL;
1475 
1476     if (DXEmptyField(field))
1477 	return (Object)field;
1478 
1479     /*
1480      * If there are no polylines, then there are none to invalidate
1481      */
1482     if (NULL == (plArray = (Array)DXGetComponentValue(field, "polylines")))
1483 	return (Object)field;
1484 
1485     if (! DXGetArrayInfo(plArray, &nPl, NULL, NULL, NULL, NULL))
1486 	goto error;
1487 
1488 
1489     if (nPl == 0)
1490 	return (Object)field;
1491 
1492     eArray = (Array)DXGetComponentValue(field, "edges");
1493     if (! eArray)
1494     {
1495 	DXSetError(ERROR_DATA_INVALID, "polylines with no edges");
1496 	goto error;
1497     }
1498 
1499     if (! DXGetArrayInfo(eArray, &nE, NULL, NULL, NULL, NULL))
1500 	goto error;
1501 
1502     vplIn  = NULL;
1503     vplOut = NULL;
1504 
1505     /*
1506      * Get the valid positions array.  If there isn't one, then we
1507      * assume all positions are valid and there's nothing to do.
1508      */
1509     vp = DXCreateInvalidComponentHandle((Object)field, NULL,
1510 						"positions");
1511     if (! vp)
1512 	goto error;
1513 
1514     if (DXGetInvalidCount(vp) == 0)
1515     {
1516 	DXFreeInvalidComponentHandle(vp);
1517 	return (Object)field;
1518     }
1519 
1520     vplIn  = DXCreateInvalidComponentHandle((Object)field, NULL,
1521 						"polylines");
1522     if (! vplIn)
1523 	goto error;
1524 
1525     if (DXGetInvalidCount(vplIn) == 0)
1526     {
1527 	DXFreeInvalidComponentHandle(vplIn);
1528 	vplIn = NULL;
1529     }
1530 
1531     polylines = (int *)DXGetArrayData(plArray);
1532     edges = (int *)DXGetArrayData(eArray);
1533 
1534     /*
1535      * For each connections element, consider each referent.  If its
1536      * invalid, invalidate the connections element.
1537      */
1538     for (i = 0; i < nPl; i++)
1539     {
1540 	int valid = !vplIn || !DXIsElementInvalidSequential(vplIn, i);
1541 
1542 	if (valid)
1543 	{
1544 	    int start = polylines[i];
1545 	    int end   = (i == nPl-1) ? nE - 1 : polylines[i+1] - 1;
1546 
1547 	    for (j = start; j <= end  && valid; j++)
1548 		valid = ! DXIsElementInvalid(vp, edges[start+j]);
1549 	}
1550 
1551 	if (! valid)
1552 	{
1553 	    /*
1554 	     * If we haven't invalidated anything yet,
1555 	     * we need to set up the invalid connections
1556 	     * array, creating one and initializing it
1557 	     * if necessary.
1558 	     */
1559 	    if (! vplOut)
1560 	    {
1561 		vplOut = DXCreateInvalidComponentHandle((Object)field, NULL,
1562 						    "polylines");
1563 
1564 		if (! vplOut)
1565 		    goto error;
1566 	    }
1567 
1568 	    if (! DXSetElementInvalid(vplOut, i))
1569 		goto error;
1570 	}
1571     }
1572 
1573     if (vplOut)
1574     {
1575 	if (! DXSaveInvalidComponent(field, vplOut))
1576 	    goto error;
1577     }
1578 
1579     DXFreeInvalidComponentHandle(vp);
1580     DXFreeInvalidComponentHandle(vplIn);
1581     DXFreeInvalidComponentHandle(vplOut);
1582 
1583     return (Object)field;
1584 
1585 error:
1586 
1587     DXFreeInvalidComponentHandle(vp);
1588     DXFreeInvalidComponentHandle(vplIn);
1589     DXFreeInvalidComponentHandle(vplOut);
1590 
1591     return NULL;
1592 }
1593 
1594 /*
1595  * Any faces referencing invalidated positions are invalidated.
1596  */
1597 static Object
IC_Field_FLE(Field field)1598 IC_Field_FLE(Field field)
1599 {
1600     Array	           fArray, lArray, eArray;
1601     InvalidComponentHandle vp = NULL, vfIn = NULL, vfOut = NULL;
1602     int		           face;
1603     int			   nF, nL, nE;
1604     int			   *faces = NULL, *loops = NULL, *edges = NULL;
1605 
1606     if (DXEmptyField(field))
1607 	return (Object)field;
1608 
1609     /*
1610      * If there are no faces, then there are none to invalidate
1611      */
1612     if (NULL == (fArray = (Array)DXGetComponentValue(field, "faces")))
1613 	return (Object)field;
1614 
1615     if (! DXGetArrayInfo(fArray, &nF, NULL, NULL, NULL, NULL))
1616 	goto error;
1617 
1618     if (nF == 0)
1619 	return (Object)field;
1620 
1621     lArray = (Array)DXGetComponentValue(field, "loops");
1622     if (! lArray)
1623     {
1624 	DXSetError(ERROR_DATA_INVALID, "faces with no loops");
1625 	goto error;
1626     }
1627 
1628     if (! DXGetArrayInfo(lArray, &nL, NULL, NULL, NULL, NULL))
1629 	goto error;
1630 
1631     eArray = (Array)DXGetComponentValue(field, "edges");
1632     if (! eArray)
1633     {
1634 	DXSetError(ERROR_DATA_INVALID, "faces with no edges");
1635 	goto error;
1636     }
1637 
1638     if (! DXGetArrayInfo(eArray, &nE, NULL, NULL, NULL, NULL))
1639 	goto error;
1640 
1641     vfIn  = NULL;
1642     vfOut = NULL;
1643 
1644     /*
1645      * Get the valid positions array.  If there isn't one, then we
1646      * assume all positions are valid and there's nothing to do.
1647      */
1648     vp = DXCreateInvalidComponentHandle((Object)field, NULL,
1649 						"positions");
1650     if (! vp)
1651 	goto error;
1652 
1653     if (DXGetInvalidCount(vp) == 0)
1654     {
1655 	DXFreeInvalidComponentHandle(vp);
1656 	return (Object)field;
1657     }
1658 
1659     vfIn  = DXCreateInvalidComponentHandle((Object)field, NULL,
1660 						"faces");
1661     if (! vfIn)
1662 	goto error;
1663 
1664     if (DXGetInvalidCount(vfIn) == 0)
1665     {
1666 	DXFreeInvalidComponentHandle(vfIn);
1667 	vfIn = NULL;
1668     }
1669 
1670     faces = (int *)DXGetArrayData(fArray);
1671     loops = (int *)DXGetArrayData(lArray);
1672     edges = (int *)DXGetArrayData(eArray);
1673 
1674     /*
1675      * For each connections element, consider each referent.  If its
1676      * invalid, invalidate the connections element.
1677      */
1678     for (face = 0; face < nF; face++)
1679     {
1680 	int valid = !vfIn || !DXIsElementInvalidSequential(vfIn, face);
1681 
1682 	if (valid)
1683 	{
1684 	    int lstart = faces[face];
1685 	    int lend   = (face == nF-1) ? nL : faces[face+1];
1686 	    int loop;
1687 
1688 	    for (loop = lstart; loop < lend  && valid; loop++)
1689 	    {
1690 		int estart = loops[loop];
1691 		int eend   = (loop == nL-1) ? nE : loops[loop+1];
1692 		int edge;
1693 
1694 		for (edge = estart; edge < eend  && valid; edge++)
1695 		    valid = ! DXIsElementInvalid(vp, edges[edge]);
1696 	    }
1697 	}
1698 
1699 	if (! valid)
1700 	{
1701 	    /*
1702 	     * If we haven't invalidated anything yet,
1703 	     * we need to set up the invalid connections
1704 	     * array, creating one and initializing it
1705 	     * if necessary.
1706 	     */
1707 	    if (! vfOut)
1708 	    {
1709 		vfOut = DXCreateInvalidComponentHandle((Object)field, NULL,
1710 						    "faces");
1711 
1712 		if (! vfOut)
1713 		    goto error;
1714 	    }
1715 
1716 	    if (! DXSetElementInvalid(vfOut, face))
1717 		goto error;
1718 	}
1719     }
1720 
1721     if (vfOut)
1722     {
1723 	if (! DXSaveInvalidComponent(field, vfOut))
1724 	    goto error;
1725     }
1726 
1727     DXFreeInvalidComponentHandle(vp);
1728     DXFreeInvalidComponentHandle(vfIn);
1729     DXFreeInvalidComponentHandle(vfOut);
1730 
1731     return (Object)field;
1732 
1733 error:
1734 
1735     DXFreeInvalidComponentHandle(vp);
1736     DXFreeInvalidComponentHandle(vfIn);
1737     DXFreeInvalidComponentHandle(vfOut);
1738 
1739     return NULL;
1740 }
1741 
1742 /*
1743  * Any connections referencing invalidated positions are invalidated.
1744  */
1745 static Object
IC_Field_Standard(Field field)1746 IC_Field_Standard(Field field)
1747 {
1748     Array	           cArray;
1749     InvalidComponentHandle vp = NULL, vcIn = NULL, vcOut = NULL;
1750     int		           ptsPerPrim;
1751     int		           *cPtr = NULL;
1752     int		           i, j, nCons;
1753     ArrayHandle		   cHandle = NULL;
1754     Pointer		   cBuf = NULL;
1755 
1756     if (DXEmptyField(field))
1757 	return (Object)field;
1758 
1759     /*
1760      * If there are no connections, then there are none to invalidate
1761      */
1762     if (NULL == (cArray = (Array)DXGetComponentValue(field, "connections")))
1763 	return (Object)field;
1764 
1765     vcIn  = NULL;
1766     vcOut = NULL;
1767 
1768     /*
1769      * Get the valid positions array.  If there isn't one, then we
1770      * assume all positions are valid and there's nothing to do.
1771      */
1772     vp = DXCreateInvalidComponentHandle((Object)field, NULL,
1773 						"positions");
1774     if (! vp)
1775 	goto error;
1776 
1777     if (DXGetInvalidCount(vp) == 0)
1778     {
1779 	DXFreeInvalidComponentHandle(vp);
1780 	return (Object)field;
1781     }
1782 
1783     vcIn  = DXCreateInvalidComponentHandle((Object)field, NULL,
1784 						"connections");
1785     if (! vcIn)
1786 	goto error;
1787 
1788     if (DXGetInvalidCount(vcIn) == 0)
1789     {
1790 	DXFreeInvalidComponentHandle(vcIn);
1791 	vcIn = NULL;
1792     }
1793 
1794     cBuf = DXAllocate(DXGetItemSize(cArray));
1795     if (! cBuf)
1796 	goto error;
1797 
1798     cHandle = DXCreateArrayHandle(cArray);
1799     if (! cHandle)
1800 	goto error;
1801 
1802     if (! DXGetArrayInfo(cArray, &nCons, NULL, NULL, NULL, &ptsPerPrim))
1803 	goto error;
1804 
1805     /*
1806      * For each connections element, consider each referent.  If its
1807      * invalid, invalidate the connections element.
1808      */
1809     for (i = 0; i < nCons; i++)
1810     {
1811 	int valid = !vcIn || !DXIsElementInvalidSequential(vcIn, i);
1812 
1813 	if (valid)
1814 	{
1815 	    cPtr = (int *)DXGetArrayEntry(cHandle, i, (Pointer)cBuf);
1816 
1817 	    for (j = 0; j < ptsPerPrim && valid; j++)
1818 		valid = ! DXIsElementInvalid(vp, cPtr[j]);
1819 	}
1820 
1821 	if (! valid)
1822 	{
1823 	    /*
1824 	     * If we haven't invalidated anything yet,
1825 	     * we need to set up the invalid connections
1826 	     * array, creating one and initializing it
1827 	     * if necessary.
1828 	     */
1829 	    if (! vcOut)
1830 	    {
1831 		vcOut = DXCreateInvalidComponentHandle((Object)field, NULL,
1832 						    "connections");
1833 
1834 		if (! vcOut)
1835 		    goto error;
1836 	    }
1837 
1838 	    if (! DXSetElementInvalid(vcOut, i))
1839 		goto error;
1840 	}
1841     }
1842 
1843     if (vcOut)
1844     {
1845 	if (! DXSaveInvalidComponent(field, vcOut))
1846 	    goto error;
1847     }
1848 
1849     DXFree(cBuf);
1850     DXFreeArrayHandle(cHandle);
1851     DXFreeInvalidComponentHandle(vp);
1852     DXFreeInvalidComponentHandle(vcIn);
1853     DXFreeInvalidComponentHandle(vcOut);
1854 
1855     return (Object)field;
1856 
1857 error:
1858 
1859     DXFree(cBuf);
1860     DXFreeArrayHandle(cHandle);
1861     DXFreeInvalidComponentHandle(vp);
1862     DXFreeInvalidComponentHandle(vcIn);
1863     DXFreeInvalidComponentHandle(vcOut);
1864 
1865     return NULL;
1866 }
1867 
1868 /*
1869  * Any connections referencing invalidated positions are invalidated.
1870  */
1871 static Object
IUP_Field(Field field)1872 IUP_Field(Field field)
1873 {
1874     if (DXGetComponentValue(field, "polylines"))
1875     {
1876 	return IUP_Field_PE(field);
1877     }
1878     else if (DXGetComponentValue(field, "faces"))
1879     {
1880 	return IUP_Field_FLE(field);
1881     }
1882     else
1883     {
1884 	return IUP_Field_Standard(field);
1885     }
1886 }
1887 
1888 static Object
IUP_Field_Standard(Field field)1889 IUP_Field_Standard(Field field)
1890 {
1891     Array       	   pArray,  cArray;
1892     InvalidComponentHandle vpHandle = NULL, vcHandle = NULL;
1893     int         	   *refs = NULL, *cons;
1894     int	        	   i, j, ptsPerPrim, nCons, nPts;
1895     int         	   unReffedPositions;
1896     ArrayHandle 	   cHandle = NULL;
1897     Pointer     	   cBuf = NULL;
1898 
1899     if (DXEmptyField(field))
1900 	return (Object)field;
1901 
1902     if (NULL == (pArray = (Array)DXGetComponentValue(field, "positions")))
1903         return (Object)field;
1904 
1905     if (! DXGetArrayInfo(pArray, &nPts, NULL, NULL, NULL, NULL))
1906 	goto error;
1907 
1908     /*
1909      * Allow for no connections component... If none are present, all
1910      * positions are invalidated
1911      */
1912     if (NULL == (cArray = (Array)DXGetComponentValue(field, "connections")))
1913     {
1914 	Array invPos;
1915 	byte valid;
1916 
1917 	valid =  DATA_INVALID;
1918 
1919 	invPos = (Array)DXNewConstantArray(nPts, (Pointer)&valid,
1920 					    TYPE_UBYTE, CATEGORY_REAL, 0);
1921 	if (! invPos)
1922 	    goto error;
1923 
1924 	if (! DXSetComponentValue(field, "invalid positions", (Object)invPos))
1925 	    goto error;
1926 
1927 	if (! DXSetComponentAttribute(field, "invalid positions", "dep",
1928 				(Object)DXNewString("positions")))
1929 	    goto error;
1930 
1931 	goto done;
1932     }
1933 
1934     /*
1935      * Get the valid connections information
1936      */
1937     vcHandle = DXCreateInvalidComponentHandle((Object)field, NULL,
1938 						"connections");
1939     if (! vcHandle)
1940 	goto error;
1941 
1942     /*
1943      * If no connections are invalidated, we have regular positions and
1944      * connections and the counts match, all are valid - take the fast
1945      * path.
1946      */
1947     if (DXGetInvalidCount(vcHandle) == 0)
1948     {
1949 	int nRef = GridSize(cArray);
1950 	if (nRef == ERROR_OCCURRED)
1951 	    goto error;
1952 	else if (nRef != HOLES_FOUND && nRef == nPts)
1953 	    goto done;
1954     }
1955 
1956     if (! DXGetArrayInfo(cArray, &nCons, NULL, NULL, NULL, &ptsPerPrim))
1957 	return NULL;
1958 
1959     cHandle = DXCreateArrayHandle(cArray);
1960     if (! cHandle)
1961 	goto error;
1962 
1963     cBuf = DXAllocate(DXGetItemSize(cArray));
1964     if (! cBuf)
1965 	goto error;
1966 
1967     if (NULL == (refs = (int *)DXAllocateZero(nPts*sizeof(int))))
1968 	return NULL;
1969 
1970     /*
1971      * Assume that we have already invalidated the connections.
1972      * If there's no valid connections input info, assume all connection
1973      * elements are valid.  Otherwise, test on an element by element basis
1974      */
1975     for (i = 0; i < nCons; i++)
1976     {
1977 	if (! DXIsElementInvalidSequential(vcHandle, i))
1978 	{
1979 	    cons = (int *)DXGetArrayEntry(cHandle, i, cBuf);
1980 
1981 	    for (j = 0; j < ptsPerPrim; j++)
1982 		refs[*cons++]++;
1983 	}
1984     }
1985 
1986     /*
1987      * See if we have any unreffed positions
1988      */
1989     for (i = 0; i < nPts; i++)
1990 	if (! refs[i])
1991 	    break;
1992 
1993     if (i != nPts)
1994 	unReffedPositions = 1;
1995     else
1996 	unReffedPositions = 0;
1997 
1998     vpHandle = DXCreateInvalidComponentHandle((Object)field, NULL,
1999 						"positions");
2000     if (! vpHandle)
2001 	goto error;
2002 
2003     /*
2004      * Invalidate unreferenced positions
2005      */
2006     if (unReffedPositions)
2007     {
2008 	for (i = 0; i < nPts; i++)
2009 	    if (! refs[i])
2010 	        DXSetElementInvalid(vpHandle, i);
2011     }
2012 
2013     if (! DXSaveInvalidComponent(field, vpHandle))
2014 	goto error;
2015 
2016 done:
2017     DXFreeInvalidComponentHandle(vcHandle);
2018     DXFreeInvalidComponentHandle(vpHandle);
2019     DXFreeArrayHandle(cHandle);
2020     DXFree(cBuf);
2021     DXFree((Pointer)refs);
2022 
2023     return (Object)field;
2024 
2025 error:
2026     DXFreeInvalidComponentHandle(vcHandle);
2027     DXFreeInvalidComponentHandle(vpHandle);
2028     DXFreeArrayHandle(cHandle);
2029     DXFree(cBuf);
2030     DXFree((Pointer)refs);
2031     return NULL;
2032 }
2033 
2034 static Object
IUP_Field_PE(Field field)2035 IUP_Field_PE(Field field)
2036 {
2037     Array       	   pArray,  plArray, eArray;
2038     InvalidComponentHandle vpHandle = NULL, vplHandle = NULL;
2039     ubyte         	   *refs = NULL;
2040     int	        	   i, j, nPls, nEs, nPts;
2041     int         	   unReffedPositions;
2042     ArrayHandle 	   plHandle = NULL, eHandle = NULL;
2043 
2044     if (DXEmptyField(field))
2045 	return (Object)field;
2046 
2047     if (NULL == (pArray = (Array)DXGetComponentValue(field, "positions")))
2048         return (Object)field;
2049 
2050     if (! DXGetArrayInfo(pArray, &nPts, NULL, NULL, NULL, NULL))
2051 	goto error;
2052 
2053     /*
2054      * We wouldn't get here unless we found a polylines component
2055      */
2056     plArray = (Array)DXGetComponentValue(field, "polylines");
2057 
2058     eArray = (Array)DXGetComponentValue(field, "edges");
2059     if (! eArray)
2060     {
2061 	DXSetError(ERROR_DATA_INVALID, "polylines with no edges component");
2062 	goto error;
2063     }
2064 
2065     plHandle = DXCreateArrayHandle(plArray);
2066     eHandle  = DXCreateArrayHandle(eArray);
2067     if (! plHandle || ! eHandle)
2068 	goto error;
2069 
2070     DXGetArrayInfo(plArray, &nPls, NULL, NULL, NULL, NULL);
2071     DXGetArrayInfo(eArray, &nEs, NULL, NULL, NULL, NULL);
2072     DXGetArrayInfo(pArray, &nPts, NULL, NULL, NULL, NULL);
2073 
2074     refs = (ubyte *)DXAllocateZero(nPts*sizeof(ubyte));
2075     if (! refs)
2076 	goto error;
2077 
2078     /*
2079      * Get the valid connections information
2080      */
2081     vplHandle = DXCreateInvalidComponentHandle((Object)field, NULL,
2082 						"polylines");
2083     if (! vplHandle)
2084 	goto error;
2085 
2086     /*
2087      * Assume that we have already invalidated the connections.
2088      * If there's no valid connections input info, assume all connection
2089      * elements are valid.  Otherwise, test on an element by element basis
2090      */
2091     for (i = 0; i < nPls; i++)
2092     {
2093 	if (! DXIsElementInvalidSequential(vplHandle, i))
2094 	{
2095 	    int startBuf, *start;
2096 	    int endBuf, *end;
2097 
2098 	    start = (int *)DXGetArrayEntry(plHandle, i, (Pointer)&startBuf);
2099 	    if (i == (nPls-1))
2100 		end = &nEs;
2101 	    else
2102 	        end = (int *)DXGetArrayEntry(plHandle, i+1, (Pointer)&endBuf);
2103 
2104 	    for (j = *start; j < *end; j++)
2105 	    {
2106 		int ptrBuf, *ptr;
2107 
2108 		ptr = (int *)DXGetArrayEntry(eHandle, j, (Pointer)&ptrBuf);
2109 		refs[*ptr] = 1;
2110 	    }
2111 	}
2112     }
2113 
2114     /*
2115      * See if we have any unreffed positions
2116      */
2117     for (i = 0; i < nPts; i++)
2118 	if (! refs[i])
2119 	    break;
2120 
2121     if (i != nPts)
2122 	unReffedPositions = 1;
2123     else
2124 	unReffedPositions = 0;
2125 
2126     vpHandle = DXCreateInvalidComponentHandle((Object)field, NULL,
2127 						"positions");
2128     if (! vpHandle)
2129 	goto error;
2130 
2131     /*
2132      * Invalidate unreferenced positions
2133      */
2134     if (unReffedPositions)
2135     {
2136 	for (i = 0; i < nPts; i++)
2137 	    if (! refs[i])
2138 	        DXSetElementInvalid(vpHandle, i);
2139     }
2140 
2141     if (! DXSaveInvalidComponent(field, vpHandle))
2142 	goto error;
2143 
2144 /* done: */
2145     DXFreeInvalidComponentHandle(vpHandle);
2146     DXFreeInvalidComponentHandle(vplHandle);
2147     DXFreeArrayHandle(plHandle);
2148     DXFreeArrayHandle(eHandle);
2149     DXFree((Pointer)refs);
2150 
2151     return (Object)field;
2152 
2153 error:
2154     DXFreeInvalidComponentHandle(vpHandle);
2155     DXFreeInvalidComponentHandle(vplHandle);
2156     DXFreeArrayHandle(plHandle);
2157     DXFreeArrayHandle(eHandle);
2158     DXFree((Pointer)refs);
2159 
2160     return NULL;
2161 }
2162 
2163 static Object
IUP_Field_FLE(Field field)2164 IUP_Field_FLE(Field field)
2165 {
2166     Array       	   pArray,  fArray, lArray, eArray;
2167     InvalidComponentHandle vpHandle = NULL, vfHandle = NULL;
2168     ubyte         	   *refs = NULL;
2169     int	        	   f, e, i, nFs, nLs, nEs, nPts;
2170     int         	   unReffedPositions;
2171     ArrayHandle 	   fHandle = NULL, lHandle = NULL, eHandle = NULL;
2172 
2173     if (DXEmptyField(field))
2174 	return (Object)field;
2175 
2176     if (NULL == (pArray = (Array)DXGetComponentValue(field, "positions")))
2177         return (Object)field;
2178 
2179     if (! DXGetArrayInfo(pArray, &nPts, NULL, NULL, NULL, NULL))
2180 	goto error;
2181 
2182     /*
2183      * We wouldn't get here unless we found a polylines component
2184      */
2185     fArray = (Array)DXGetComponentValue(field, "faces");
2186 
2187     lArray = (Array)DXGetComponentValue(field, "loops");
2188     eArray = (Array)DXGetComponentValue(field, "edges");
2189     if (! eArray || ! lArray)
2190     {
2191 	DXSetError(ERROR_DATA_INVALID,
2192 		"faces with no edges or loops component");
2193 	goto error;
2194     }
2195 
2196     fHandle = DXCreateArrayHandle(fArray);
2197     lHandle = DXCreateArrayHandle(lArray);
2198     eHandle  = DXCreateArrayHandle(eArray);
2199     if (! fHandle || ! lHandle || ! eHandle)
2200 	goto error;
2201 
2202     DXGetArrayInfo(fArray, &nFs, NULL, NULL, NULL, NULL);
2203     DXGetArrayInfo(lArray, &nLs, NULL, NULL, NULL, NULL);
2204     DXGetArrayInfo(eArray, &nEs, NULL, NULL, NULL, NULL);
2205     DXGetArrayInfo(pArray, &nPts, NULL, NULL, NULL, NULL);
2206 
2207     refs = (ubyte *)DXAllocateZero(nPts*sizeof(ubyte));
2208     if (! refs)
2209 	goto error;
2210 
2211     /*
2212      * Get the valid connections information
2213      */
2214     vfHandle = DXCreateInvalidComponentHandle((Object)field, NULL,
2215 						"faces");
2216     if (! vfHandle)
2217 	goto error;
2218 
2219     /*
2220      * Assume that we have already invalidated the connections.
2221      * If there's no valid connections input info, assume all connection
2222      * elements are valid.  Otherwise, test on an element by element basis
2223      */
2224     for (f = 0; f < nFs; f++)
2225     {
2226 	int lStartBuf, *lStart;
2227 	int lEndBuf, *lEnd;
2228 	int l;
2229 
2230 	if (DXIsElementInvalidSequential(vfHandle, f))
2231 	    continue;
2232 
2233 	lStart = (int *)DXGetArrayEntry(fHandle, f, (Pointer)&lStartBuf);
2234 	if (f == (nFs-1))
2235 	    lEnd = &nLs;
2236 	else
2237 	    lEnd = (int *)DXGetArrayEntry(fHandle, f+1, (Pointer)&lEndBuf);
2238 
2239 	for (l = *lStart; l < *lEnd;  l++)
2240 	{
2241 	    int eStartBuf, *eStart;
2242 	    int eEndBuf, *eEnd;
2243 
2244 	    eStart = (int *)DXGetArrayEntry(lHandle, l, (Pointer)&eStartBuf);
2245 	    if (l == (nLs-1))
2246 		eEnd = &nEs;
2247 	    else
2248 		eEnd = (int *)DXGetArrayEntry(lHandle, l+1, (Pointer)&eEndBuf);
2249 
2250 	    for (e = *eStart; e < *eEnd; e++)
2251 	    {
2252 		int ptrBuf, *ptr;
2253 
2254 		ptr = (int *)DXGetArrayEntry(eHandle, e, (Pointer)&ptrBuf);
2255 		refs[*ptr] = 1;
2256 	    }
2257 	}
2258     }
2259 
2260     /*
2261      * See if we have any unreffed positions
2262      */
2263     for (i = 0; i < nPts; i++)
2264 	if (! refs[i])
2265 	    break;
2266 
2267     if (i != nPts)
2268 	unReffedPositions = 1;
2269     else
2270 	unReffedPositions = 0;
2271 
2272     vpHandle = DXCreateInvalidComponentHandle((Object)field, NULL,
2273 						"positions");
2274     if (! vpHandle)
2275 	goto error;
2276 
2277     /*
2278      * Invalidate unreferenced positions
2279      */
2280     if (unReffedPositions)
2281     {
2282 	for (i = 0; i < nPts; i++)
2283 	    if (! refs[i])
2284 	        DXSetElementInvalid(vpHandle, i);
2285     }
2286 
2287     if (! DXSaveInvalidComponent(field, vpHandle))
2288 	goto error;
2289 
2290 /* done: */
2291     DXFreeInvalidComponentHandle(vpHandle);
2292     DXFreeInvalidComponentHandle(vfHandle);
2293     DXFreeArrayHandle(fHandle);
2294     DXFreeArrayHandle(lHandle);
2295     DXFreeArrayHandle(eHandle);
2296     DXFree((Pointer)refs);
2297 
2298     return (Object)field;
2299 
2300 error:
2301     DXFreeInvalidComponentHandle(vpHandle);
2302     DXFreeInvalidComponentHandle(vfHandle);
2303     DXFreeArrayHandle(fHandle);
2304     DXFreeArrayHandle(lHandle);
2305     DXFreeArrayHandle(eHandle);
2306     DXFree((Pointer)refs);
2307 
2308     return NULL;
2309 }
2310 
2311 #define TYPE      int
2312 #define LT(a,b)   ((*(a))<(*(b)))
2313 #define GT(a,b)   ((*(a))>(*(b)))
2314 #define QUICKSORT refsort
2315 
2316 #include "qsort.c"
2317 
2318 static Error SetMark(InvalidComponentHandle, int);
2319 static Error RemoveMark(InvalidComponentHandle, int);
2320 static int   RemoveContents(InvalidComponentHandle);
2321 static Error IsElementMarked(InvalidComponentHandle, int);
2322 static Error MakeSortList(InvalidComponentHandle);
2323 static int   GetNextMarked(InvalidComponentHandle);
2324 
2325 InvalidComponentHandle
DXCreateInvalidComponentHandle(Object o,Array iarray,char * name)2326 DXCreateInvalidComponentHandle(Object o, Array iarray, char *name)
2327 {
2328     Field field = NULL;
2329     Array array;
2330     int   nItems, nInv;
2331     InvalidComponentHandle handle = NULL;
2332 
2333     if (o)
2334     {
2335 	if (DXGetObjectClass(o) == CLASS_FIELD)
2336 	{
2337 	    char sbuf[128];
2338 
2339 	    field = (Field)o;
2340 
2341 	    if (! name)
2342 	    {
2343 		DXSetError(ERROR_BAD_PARAMETER, "null invalid component name");
2344 		goto error;
2345 	    }
2346 
2347 	    if (name == NULL)
2348 	    {
2349 		DXSetError(ERROR_BAD_PARAMETER, "component name required");
2350 		goto error;
2351 	    }
2352 
2353 	    array = (Array)DXGetComponentValue(field, name);
2354 	    if (! array)
2355 	    {
2356 		DXSetError(ERROR_BAD_PARAMETER,
2357 		    "cannot create invalid component handle for component %s",
2358 		    name);
2359 		goto error;
2360 	    }
2361 
2362 	    sprintf(sbuf, "invalid %s", name);
2363 
2364 	    if (! iarray)
2365 		iarray = (Array)DXGetComponentValue(field, sbuf);
2366 
2367 	}
2368 	else if (DXGetObjectClass(o) == CLASS_ARRAY)
2369 	{
2370 	    array = (Array)o;
2371 	}
2372 	else
2373 	{
2374 	    DXSetError(ERROR_BAD_CLASS, "unknown object class");
2375 	    goto error;
2376 	}
2377 
2378 	DXGetArrayInfo(array, &nItems, NULL, NULL, NULL, NULL);
2379     }
2380     else
2381     {
2382 	nItems = -1;
2383     }
2384 
2385 
2386     handle = (InvalidComponentHandle)
2387 			DXAllocateZero(sizeof(struct invalidComponentHandle));
2388     if (! handle)
2389 	goto error;
2390 
2391     handle->nItems = nItems;
2392     handle->sense  = IC_MARKS_INDICATE_INVALID;
2393 
2394     if (name)
2395     {
2396 	handle->iName = (char *)DXAllocate(strlen(name) + 1);
2397 	if (! handle->iName)
2398 	    goto error;
2399 
2400 	sprintf(handle->iName, "%s", name);
2401     }
2402     else
2403 	handle->iName = NULL;
2404 
2405     /*
2406      * If there's any pre-existing invalid data, initialize with it.
2407      */
2408     if (iarray)
2409     {
2410 	Type type;
2411 	Category cat;
2412 	int rank, shape[100];
2413 	int i;
2414 	ubyte *dPtr;
2415 
2416 	DXGetArrayInfo(iarray, &nInv, &type, &cat, &rank, shape);
2417 
2418 	/*
2419 	 * If there was no original array, then we can get a
2420 	 * dependency size here.
2421 	 */
2422 	nItems = nInv;
2423 
2424 	/*
2425 	 * If so, is is dependent or referential?
2426 	 */
2427 	if (DXGetAttribute((Object)iarray, "dep"))
2428 	{
2429 	    if ( nInv != nItems      			  ||
2430 		(type != TYPE_UBYTE && type != TYPE_BYTE) ||
2431 		 cat  != CATEGORY_REAL 			  ||
2432 		 rank != 0)
2433 	    {
2434 		DXSetError(ERROR_DATA_INVALID,
2435 		    "dependent invalid data component must be scalar bytes");
2436 		goto error;
2437 	    }
2438 
2439 	    /*
2440 	     * If its a constant array, then its either all valid or all
2441 	     * invalid.
2442 	     */
2443 	    if (DXGetArrayClass(iarray) == CLASS_CONSTANTARRAY)
2444 	    {
2445 		ubyte v = *(ubyte *)DXGetConstantArrayData(iarray);
2446 
2447 		handle->array = NULL;
2448 
2449 		if (v == DATA_INVALID)
2450 		{
2451 		    handle->nMarkedItems = nInv;
2452 		    handle->type = IC_ALL_MARKED;
2453 		}
2454 		else if (v == DATA_VALID)
2455 		{
2456 		    handle->nMarkedItems = 0;
2457 		    handle->type = IC_ALL_UNMARKED;
2458 		}
2459 		else
2460 		{
2461 		    DXSetError(ERROR_DATA_INVALID,
2462 			    "invalid component array");
2463 		    goto error;
2464 		}
2465 
2466 	    }
2467 	    else
2468 	    {
2469 		handle->type = IC_DEP_ARRAY;
2470 
2471 		handle->array  = (Array)DXReference((Object)iarray);
2472 		handle->data   = (byte *)DXGetArrayData(iarray);
2473 
2474 		handle->nMarkedItems = 0;
2475 		dPtr = (ubyte *)(handle->data);
2476 		for (i = 0; i < nInv; i++)
2477 		    if (*dPtr++ == DATA_INVALID)
2478 			 handle->nMarkedItems ++;
2479 	    }
2480 	}
2481 	else if (DXGetAttribute((Object)iarray, "ref"))
2482 	{
2483 	    int *iPtr, i;
2484 
2485 	    if ((type != TYPE_INT && type != TYPE_UINT) ||
2486 		cat  != CATEGORY_REAL 			||
2487 		rank != 0)
2488 	    {
2489 		DXSetError(ERROR_DATA_INVALID,
2490 		    "referential invalid data component is wrong type, %s",
2491 		    "category, or not scalar");
2492 		goto error;
2493 	    }
2494 
2495 	    DXGetArrayInfo(iarray, &nInv, NULL, NULL, NULL, NULL);
2496 
2497 	    if (nInv == 0)
2498 	    {
2499 		handle->type = IC_ALL_UNMARKED;
2500 		handle->nMarkedItems = 0;
2501 	    }
2502 	    else
2503 	    {
2504 		/*  Accessing the elements of a large IC_SORTED_LIST via   */
2505 		/*    binary search is hideously slow.  Use a HASH or DEP  */
2506 		/*    internally.                                          */
2507 		if (handle->nItems != -1 &&
2508 		    nInv >= DEP_MEM_THRESHOLD(handle->nItems))
2509 		{
2510 		    ubyte *data = (ubyte *)DXAllocate(
2511 			                     handle->nItems*sizeof(ubyte));
2512 		    if (!data)
2513 			goto error;
2514 		    memset(data, IC_ELEMENT_UNMARKED, handle->nItems);
2515 
2516 		    handle->nMarkedItems = 0;
2517 		    iPtr = (int *)DXGetArrayData(iarray);
2518 		    for (i = 0; i < nInv; i++, iPtr++)
2519 		    {
2520 			if (data[*iPtr] == IC_ELEMENT_UNMARKED)
2521 			    handle->nMarkedItems++;
2522 			data[*iPtr] = IC_ELEMENT_MARKED;
2523 		    }
2524 
2525 		    handle->type         = IC_DEP_ARRAY;
2526 		    handle->data         = data;
2527 		}
2528 		else
2529 		{
2530 		    long      li;
2531 		    HashTable hash = DXCreateHash(sizeof(long), NULL, NULL);
2532 		    if (!hash)
2533 			goto error;
2534 
2535 		    iPtr = (int *)DXGetArrayData(iarray);
2536 		    for (i = 0; i < nInv; i++, iPtr++) {
2537 			li = *iPtr;
2538 			if (! DXInsertHashElement(hash, (Element)&li))
2539 			    goto error;
2540 		    }
2541 
2542 		    handle->nMarkedItems = 0;
2543 		    DXInitGetNextHashElement(hash);
2544 		    while (DXGetNextHashElement(hash))
2545 		        handle->nMarkedItems++;
2546 
2547 		    handle->type         = IC_HASH;
2548 		    handle->hash         = hash;
2549 		}
2550 	    }
2551 	}
2552 	else
2553 	{
2554 	    DXSetError(ERROR_DATA_INVALID,
2555 		"invalid component has neither dep nor ref attribute");
2556 	    goto error;
2557 	}
2558     }
2559     else
2560     {
2561 	/*
2562 	 * Otherwise, the everything so far is assumed to be valid.
2563 	 */
2564         handle->type = IC_ALL_UNMARKED;
2565     }
2566 
2567     return handle;
2568 
2569 error:
2570     DXFreeInvalidComponentHandle(handle);
2571     return NULL;
2572 }
2573 
2574 Error
DXFreeInvalidComponentHandle(InvalidComponentHandle handle)2575 DXFreeInvalidComponentHandle(InvalidComponentHandle handle)
2576 {
2577     if (handle)
2578     {
2579 	if (handle->iName)
2580 	    DXFree((Pointer)handle->iName);
2581 	if (handle->array)
2582 	    DXDelete((Object)handle->array);
2583 	if (handle->hash)
2584 	    DXDestroyHash(handle->hash);
2585 	if (handle->data && !handle->array)
2586 	    DXFree((Pointer)handle->data);
2587 	if (handle->seglist)
2588 	    DXDeleteSegList(handle->seglist);
2589 	DXFree((Pointer)handle->sortList);
2590 
2591 	DXFree((Pointer)handle);
2592     }
2593 
2594     return OK;
2595 }
2596 
2597 Error
DXSaveInvalidComponent(Field field,InvalidComponentHandle handle)2598 DXSaveInvalidComponent(Field field, InvalidComponentHandle handle)
2599 {
2600     Array array;
2601     char  sbuf[128];
2602 
2603     if (! handle->iName)
2604     {
2605 	DXSetError(ERROR_INTERNAL, "unknown invalid component name");
2606 	return ERROR;
2607     }
2608 
2609     sprintf(sbuf, "invalid %s", handle->iName);
2610 
2611     if (DXGetComponentValue(field, sbuf))
2612 	DXDeleteComponent(field, sbuf);
2613 
2614     if (handle->type  == IC_ALL_UNMARKED &&
2615 	handle->sense == IC_MARKS_INDICATE_INVALID)
2616     {
2617 	return OK;
2618     }
2619 
2620     if (handle->type  == IC_ALL_MARKED &&
2621 	handle->sense == IC_MARKS_INDICATE_VALID)
2622     {
2623 	return OK;
2624     }
2625 
2626     array = DXGetInvalidComponentArray(handle);
2627     if (! array)
2628 	return ERROR;
2629 
2630     if (! DXSetComponentValue(field, sbuf, (Object)array))
2631 	return ERROR;
2632 
2633     return OK;
2634 }
2635 
2636 #define DEP_ARRAY 1
2637 #define REF_ARRAY 2
2638 
2639 Array
DXGetInvalidComponentArray(InvalidComponentHandle handle)2640 DXGetInvalidComponentArray(InvalidComponentHandle handle)
2641 {
2642     Array  array = NULL;
2643     Object attr;
2644     int    nInvalid;
2645     int    type = 0;
2646     long   li;
2647 
2648     if (! handle)
2649 	goto error;
2650 
2651     if (handle->array)
2652 	return handle->array;
2653 
2654     if (handle->sense == IC_MARKS_INDICATE_VALID)
2655 	nInvalid = handle->nItems - handle->nMarkedItems;
2656     else
2657 	nInvalid = handle->nMarkedItems;
2658 
2659     if ((nInvalid == handle->nItems)				             ||
2660 	((handle->type == IC_ALL_MARKED &&
2661 		handle->sense == IC_MARKS_INDICATE_INVALID)) 		     ||
2662 	((handle->type == IC_ALL_UNMARKED &&
2663 		handle->sense == IC_MARKS_INDICATE_VALID)))
2664     {
2665 	ubyte value = DATA_INVALID;
2666 
2667 	type = DEP_ARRAY;
2668 
2669 	array = (Array)DXNewConstantArray(handle->nItems, &value,
2670 					    TYPE_UBYTE, CATEGORY_REAL, 0);
2671 	if (! array)
2672 	    goto error;
2673     }
2674     else if (nInvalid == 0						     ||
2675 	((handle->type == IC_ALL_MARKED &&
2676 		handle->sense == IC_MARKS_INDICATE_VALID)) 		     ||
2677 	((handle->type == IC_ALL_UNMARKED &&
2678 		handle->sense == IC_MARKS_INDICATE_INVALID)))
2679     {
2680 	ubyte value = DATA_VALID;
2681 
2682 	type = DEP_ARRAY;
2683 
2684 	array = (Array)DXNewConstantArray(handle->nItems, &value,
2685 					    TYPE_UBYTE, CATEGORY_REAL, 0);
2686 	if (! array)
2687 	    goto error;
2688     }
2689     else if (handle->type == IC_DEP_ARRAY)
2690     {
2691 
2692 	/*
2693 	 * If there are enough actually invalid, output a dep array.
2694 	 * Otherwise, create a sort list.
2695 	 */
2696 	if (handle->nItems != -1 &&
2697 	    nInvalid >= DEP_STORAGE_THRESHOLD(handle->nItems))
2698 	{
2699 	    type = DEP_ARRAY;
2700 
2701 	    array = DXNewArray(TYPE_UBYTE, CATEGORY_REAL, 0);
2702 	    if (! array)
2703 		goto error;
2704 
2705 	    /*
2706 	     * We may have to invert the byte vector to get the right sense.
2707 	     */
2708 	    if (handle->sense == IC_MARKS_INDICATE_VALID)
2709 	    {
2710 		int i;
2711 		ubyte *ptr;
2712 
2713 		ptr = (ubyte *)handle->data;
2714 		for (i = 0; i < handle->nItems; i++, ptr++)
2715 		    if (*ptr == IC_ELEMENT_MARKED)
2716 			*ptr = IC_ELEMENT_UNMARKED;
2717 		    else
2718 			*ptr = IC_ELEMENT_MARKED;
2719 
2720 		handle->sense = IC_MARKS_INDICATE_INVALID;
2721 	    }
2722 
2723 	    if (! DXAddArrayData(array, 0, handle->nItems, handle->data))
2724 		goto error;
2725 	}
2726 	else
2727 	{
2728 	    ubyte target;
2729 	    int i;
2730 	    ubyte *bptr;
2731 	    int *iptr;
2732 
2733 	    type = REF_ARRAY;
2734 
2735 	    array = DXNewArray(TYPE_INT, CATEGORY_REAL, 0);
2736 	    if (! array)
2737 		goto error;
2738 
2739 	    if (!DXAddArrayData(array, 0, nInvalid, NULL))
2740 		goto error;
2741 
2742 	    if (handle->sense == IC_MARKS_INDICATE_VALID)
2743 	        target = IC_ELEMENT_UNMARKED;
2744 	    else
2745 	        target = IC_ELEMENT_MARKED;
2746 
2747 	    iptr = (int *)DXGetArrayData(array);
2748 	    bptr = (ubyte *)handle->data;
2749 	    for (i = 0; i < handle->nItems; i++)
2750 		if (*bptr++ == target)
2751 		   *iptr++ = i;
2752 	}
2753     }
2754     else if (handle->type == IC_SORTED_LIST)
2755     {
2756 	type = REF_ARRAY;
2757 
2758 	array = DXNewArray(TYPE_INT, CATEGORY_REAL, 0);
2759 	if (! array)
2760 	    goto error;
2761 
2762 	if (!DXAddArrayData(array, 0, nInvalid, handle->data))
2763 	    goto error;
2764     }
2765     else if (handle->type == IC_HASH)
2766     {
2767 	/*
2768 	 * If its a hash table, then we may return either a dep
2769 	 * or ref result, depending on which will be larger.
2770 	 * This depends on the number actually invalid, regardless
2771 	 * of the sense of the hash table.
2772 	 */
2773 	int *dPtr;
2774 
2775 	if (handle->nItems != -1 &&
2776 	    nInvalid >= DEP_STORAGE_THRESHOLD(handle->nItems))
2777 	{
2778 	    ubyte *data;
2779 	    long *sPtr;
2780 
2781 	    type = DEP_ARRAY;
2782 
2783 	    array = DXNewArray(TYPE_UBYTE, CATEGORY_REAL, 0);
2784 	    if (! array)
2785 		goto error;
2786 
2787 	    if (! DXAddArrayData(array, 0, handle->nItems, NULL))
2788 		goto error;
2789 
2790 	    data = (ubyte *)DXGetArrayData(array);
2791 
2792 	    /*
2793 	     * If marks indicate invalid, then initialize the array
2794 	     * to valid, then traverse the hash list setting the
2795 	     * array entries corresponding to the hash table
2796 	     * contents to INVALID.  Otherwise, do it the opposite
2797 	     * way.
2798 	     */
2799 	    if (handle->sense == IC_MARKS_INDICATE_INVALID)
2800 	    {
2801 		memset(data, DATA_VALID, handle->nItems*sizeof(ubyte));
2802 
2803 		DXInitGetNextHashElement(handle->hash);
2804 		while(NULL !=
2805 		   	  (sPtr = (long *)DXGetNextHashElement(handle->hash)))
2806 		{
2807 		    data[*sPtr] = DATA_INVALID;
2808 		}
2809 	    }
2810 	    else
2811 	    {
2812 		memset(data, DATA_INVALID, handle->nItems*sizeof(ubyte));
2813 
2814 		DXInitGetNextHashElement(handle->hash);
2815 		while(NULL !=
2816 		   	  (sPtr = (long *)DXGetNextHashElement(handle->hash)))
2817 		{
2818 		    data[*sPtr] = DATA_VALID;
2819 		}
2820 	    }
2821 	}
2822 	else
2823 	{
2824 	    long *sPtr;
2825 
2826 	    type = REF_ARRAY;
2827 
2828 	    array = DXNewArray(TYPE_INT, CATEGORY_REAL, 0);
2829 	    if (! array)
2830 		goto error;
2831 
2832 	    if (! DXAddArrayData(array, 0, nInvalid, NULL))
2833 		goto error;
2834 
2835 	    dPtr = (int *)DXGetArrayData(array);
2836 
2837 	    /*
2838 	     * If the marks indicate valid, then we need to
2839 	     * determine the elements that DO NOT reside in the
2840 	     * hash table.  We do this by trying all of them.
2841 	     * This ain't great, but nothing better comes to
2842 	     * mind.  If the marks indicate invalid, then we have
2843 	     * the easy case.
2844 	     */
2845 	    if (handle->sense == IC_MARKS_INDICATE_VALID)
2846 	    {
2847 		for (li = 0; li < handle->nItems; li++)
2848 		{
2849 		    if (! DXQueryHashElement(handle->hash, (Key)&li))
2850 			*dPtr++ = li;
2851 		}
2852 	    }
2853 	    else
2854 	    {
2855 		DXInitGetNextHashElement(handle->hash);
2856 		while(NULL !=
2857 			  (sPtr = (long *)DXGetNextHashElement(handle->hash)))
2858 		{
2859 		    *dPtr++ = *sPtr;
2860 		}
2861 	    }
2862 	}
2863     }
2864     else
2865     {
2866 	DXSetError(ERROR_INTERNAL, "bad invalid component handle");
2867 	goto error;
2868     }
2869 
2870     if (handle->iName)
2871     {
2872 	attr = (Object)DXNewString(handle->iName);
2873 	if (! attr)
2874 	     goto error;
2875 
2876 	if (type == DEP_ARRAY)
2877 	    DXSetAttribute((Object)array, "dep", attr);
2878 	else if (type == REF_ARRAY)
2879 	    DXSetAttribute((Object)array, "ref", attr);
2880 	else
2881 	{
2882 	    DXSetError(ERROR_INTERNAL, "unknown invalid array type");
2883 	    goto error;
2884 	}
2885     }
2886 
2887     return array;
2888 
2889 error:
2890     DXDelete((Object)array);
2891     return NULL;
2892 }
2893 
2894 int
DXIsElementInvalid(InvalidComponentHandle handle,int index)2895 DXIsElementInvalid(InvalidComponentHandle handle, int index)
2896 {
2897     if (handle->sense == IC_MARKS_INDICATE_VALID)
2898 	return ! IsElementMarked(handle, index);
2899     else
2900 	return IsElementMarked(handle, index);
2901 }
2902 
2903 int
DXIsElementValid(InvalidComponentHandle handle,int index)2904 DXIsElementValid(InvalidComponentHandle handle, int index)
2905 {
2906     if (handle->sense == IC_MARKS_INDICATE_INVALID)
2907 	return ! IsElementMarked(handle, index);
2908     else
2909 	return IsElementMarked(handle, index);
2910 }
2911 
2912 static int
IsElementMarked(InvalidComponentHandle handle,int index)2913 IsElementMarked(InvalidComponentHandle handle, int index)
2914 {
2915     switch(handle->type)
2916     {
2917 	case IC_ALL_MARKED:
2918 	{
2919 	    return TRUE;
2920 	}
2921 
2922 	case IC_ALL_UNMARKED:
2923 	{
2924 	    return FALSE;
2925 	}
2926 
2927 	case IC_DEP_ARRAY:
2928 	{
2929 	    if (((ubyte *)(handle->data))[index] == IC_ELEMENT_MARKED)
2930 		return TRUE;
2931 	    else
2932 		return FALSE;
2933 	}
2934 
2935 	case IC_HASH:
2936 	{
2937 	    long li = index;
2938 
2939 	    if (DXQueryHashElement(handle->hash, (Key)&li))
2940 		return TRUE;
2941 	    else
2942 		return FALSE;
2943 	}
2944 
2945 	case IC_SORTED_LIST:
2946 	{
2947 	    int *base = (int *)handle->data;
2948 	    int max = handle->nMarkedItems-1;
2949 	    int min = 0, mid;
2950 
2951 	    if (handle->nMarkedItems == 0 	||
2952 		base[0] > index 		||
2953 		base[max] < index)
2954 	    {
2955 		return FALSE;
2956 	    }
2957 
2958 	    for (mid = (max + min) >> 1; mid != min; mid = (min + max) >> 1)
2959 		if (base[mid] > index)
2960 		    max = mid;
2961 		else if (base[mid] < index)
2962 		    min = mid;
2963 		else
2964 		    return TRUE;
2965 
2966 	    if (base[min] == index || base[max] == index)
2967 		return TRUE;
2968 	    else
2969 		return FALSE;
2970 	}
2971     }
2972     /* Function should always short circuit, but just incase */
2973     return FALSE;
2974 }
2975 
2976 Error
DXSetElementInvalid(InvalidComponentHandle handle,int index)2977 DXSetElementInvalid(InvalidComponentHandle handle, int index)
2978 {
2979     if (handle->sense == IC_MARKS_INDICATE_VALID)
2980 	return RemoveMark(handle, index);
2981     else
2982 	return SetMark(handle, index);
2983 }
2984 
2985 Error
DXSetElementValid(InvalidComponentHandle handle,int index)2986 DXSetElementValid(InvalidComponentHandle handle, int index)
2987 {
2988     if (handle->sense == IC_MARKS_INDICATE_VALID)
2989 	return SetMark(handle, index);
2990     else
2991 	return RemoveMark(handle, index);
2992 }
2993 
2994 static Error
SetMark(InvalidComponentHandle handle,int index)2995 SetMark(InvalidComponentHandle handle, int index)
2996 {
2997     long li;
2998 
2999     if (handle->type == IC_ALL_MARKED)
3000 	return OK;
3001 
3002     /*
3003      * If this is the first invalidation, then we need to set up
3004      * a hash table to swallow invalidations until the threshold
3005      */
3006     if (handle->type == IC_ALL_UNMARKED)
3007     {
3008 	handle->nMarkedItems = 0;
3009 
3010 	handle->type = IC_HASH;
3011 
3012 	/*
3013 	 * Hashing will use a straight key
3014 	 */
3015 	handle->hash = DXCreateHash(sizeof(long), NULL, NULL);
3016 	if (! handle->hash)
3017 	    goto error;
3018     }
3019 
3020     /*
3021      * Now save the invalidation
3022      */
3023     switch(handle->type)
3024     {
3025 	case IC_DEP_ARRAY:
3026 	{
3027 	    if (handle->array)
3028 	    {
3029 		ubyte *tmp = DXAllocate(handle->nItems*sizeof(ubyte));
3030 		if (! tmp)
3031 		    goto error;
3032 
3033 		memcpy(tmp, handle->data, handle->nItems*sizeof(ubyte));
3034 
3035 		DXDelete((Object)handle->array);
3036 		handle->array = NULL;
3037 		handle->data = tmp;
3038 	    }
3039 
3040 	    if (((ubyte *)(handle->data))[index] != IC_ELEMENT_MARKED)
3041 	    {
3042 		((ubyte *)(handle->data))[index] = IC_ELEMENT_MARKED;
3043 		handle->nMarkedItems ++;
3044 	    }
3045 	    break;
3046 	}
3047 
3048 	case IC_HASH:
3049 	{
3050 	    li = index;
3051 
3052 	    if (! DXQueryHashElement(handle->hash, (Key)&li))
3053 	    {
3054 		if (! DXInsertHashElement(handle->hash, (Element)&li))
3055 		    goto error;
3056 		handle->nMarkedItems ++;
3057 	    }
3058 	    break;
3059 	}
3060 
3061 	case IC_SORTED_LIST:
3062 	{
3063 	    /*
3064 	     * If the thing is currently a sorted list and we are
3065 	     * doing an insert, transform to a hash table
3066 	     */
3067 	    int i, *iPtr;
3068 	    HashTable hash = DXCreateHash(sizeof(long), NULL, NULL);
3069 	    if (! hash)
3070 		goto error;
3071 
3072 	    for (i = 0, iPtr = (int *)handle->data; i < handle->nMarkedItems; i++)
3073 	    {
3074 		li = *iPtr++;
3075 
3076 		if (! DXInsertHashElement(hash, (Element)&li))
3077 		    goto error;
3078 	    }
3079 
3080 	    if (handle->array)
3081 	    {
3082 		DXDelete((Object)handle->array);
3083 		handle->array = NULL;
3084 		handle->data  = NULL;
3085 	    }
3086 	    else
3087 	    {
3088 		DXFree((Pointer)handle->data);
3089 		handle->data = NULL;
3090 	    }
3091 
3092 	    handle->hash = hash;
3093 	    handle->type = IC_HASH;
3094 
3095 	    /*
3096 	     * Now add to hash table
3097 	     */
3098 	    li = index;
3099 	    if (! DXQueryHashElement(handle->hash, (Key)&li))
3100 	    {
3101 		if (! DXInsertHashElement(handle->hash, (Element)&li))
3102 		    goto error;
3103 		handle->nMarkedItems ++;
3104 	    }
3105 	    break;
3106 	}
3107 
3108 	default:
3109 	{
3110 	    DXSetError(ERROR_INTERNAL, "unknown handle type");
3111 	    goto error;
3112 	}
3113     }
3114 
3115     /*
3116      * If not already a dependent array and we have passed the threshold,
3117      * convert to a dependent array. IF we know the overall size.
3118      */
3119     if ((handle->type != IC_DEP_ARRAY) && (handle->nItems != -1) &&
3120 	(handle->nMarkedItems >= DEP_MEM_THRESHOLD(handle->nItems)))
3121     {
3122 	ubyte *depArray = (ubyte *)DXAllocate(handle->nItems*sizeof(ubyte));
3123 	if (! depArray)
3124 	    goto error;
3125 
3126 	memset(depArray, IC_ELEMENT_UNMARKED, handle->nItems);
3127 
3128 	/*
3129 	 * At this point, if we came in with a sorted list we will already
3130 	 * have converted to a hash table, so if its not dependent, it
3131 	 * must be hash.
3132 	 */
3133 	if (handle->type == IC_HASH)
3134 	{
3135 	    long *iPtr;
3136 
3137 	    DXInitGetNextHashElement(handle->hash);
3138 	    while(NULL != (iPtr = (long *)DXGetNextHashElement(handle->hash)))
3139 	       depArray[*iPtr] = IC_ELEMENT_MARKED;
3140 
3141 	    DXDestroyHash(handle->hash);
3142 	    handle->hash = NULL;
3143 	}
3144 	else
3145 	{
3146 	    DXSetError(ERROR_INTERNAL,
3147 		"attempting to expand an invalid type of invalid component");
3148 	    goto error;
3149 	}
3150 
3151 	handle->data = depArray;
3152 	handle->array = NULL;
3153 	handle->type = IC_DEP_ARRAY;
3154     }
3155 
3156     return OK;
3157 
3158 error:
3159     return ERROR;
3160 }
3161 
3162 static Error
RemoveMark(InvalidComponentHandle handle,int index)3163 RemoveMark(InvalidComponentHandle handle, int index)
3164 {
3165     if (handle->type == IC_ALL_UNMARKED)
3166 	return OK;
3167 
3168     /*
3169      * If this is the first invalidation, then we need to set up
3170      * a hash table to swallow invalidations until the threshold
3171      */
3172     if (handle->type == IC_ALL_MARKED)
3173     {
3174 	handle->type = IC_HASH;
3175 	handle->nMarkedItems = 0;
3176 	handle->sense = !handle->sense;
3177 
3178 	/*
3179 	 * Hashing will use a straight key
3180 	 */
3181 	handle->hash = DXCreateHash(sizeof(long), NULL, NULL);
3182 	if (! handle->hash)
3183 	    goto error;
3184 
3185 	if (! SetMark(handle, index))
3186 	    goto error;
3187 
3188 	return OK;
3189     }
3190 
3191     /*
3192      * Now save the invalidation
3193      */
3194     switch(handle->type)
3195     {
3196 	case IC_DEP_ARRAY:
3197 	{
3198 	    if (handle->array)
3199 	    {
3200 		ubyte *tmp = DXAllocate(handle->nItems*sizeof(ubyte));
3201 		if (! tmp)
3202 		    goto error;
3203 
3204 		memcpy(tmp, handle->data, handle->nItems*sizeof(ubyte));
3205 
3206 		DXDelete((Object)handle->array);
3207 		handle->array = NULL;
3208 		handle->data = tmp;
3209 	    }
3210 
3211 	    if (((ubyte *)(handle->data))[index] != IC_ELEMENT_UNMARKED)
3212 	    {
3213 		((ubyte *)(handle->data))[index] = IC_ELEMENT_UNMARKED;
3214 		handle->nMarkedItems --;
3215 	    }
3216 	    break;
3217 	}
3218 
3219 	case IC_HASH:
3220 	{
3221 	    long li = index;
3222 
3223 	    if (DXQueryHashElement(handle->hash, (Key)&li))
3224 	    {
3225 		if (! DXDeleteHashElement(handle->hash, (Element)&li))
3226 		    goto error;
3227 		handle->nMarkedItems --;
3228 	    }
3229 	    break;
3230 	}
3231 
3232 	case IC_SORTED_LIST:
3233 	{
3234 	    /*
3235 	     * If the thing is currently a sorted list and we are
3236 	     * doing an deletion, transform to a hash table
3237 	     */
3238 	    int i, *iPtr;
3239 	    long li;
3240 
3241 	    HashTable hash = DXCreateHash(sizeof(long), NULL, NULL);
3242 	    if (! hash)
3243 		goto error;
3244 
3245 	    iPtr = (int *)handle->data;
3246 	    for (i = 0; i < handle->nMarkedItems; i++)
3247 	    {
3248 		li = *iPtr++;
3249 		if (! DXInsertHashElement(hash, (Element)&li))
3250 		    goto error;
3251 	    }
3252 
3253 	    if (handle->array)
3254 	    {
3255 		DXDelete((Object)handle->array);
3256 		handle->array = NULL;
3257 		handle->data  = NULL;
3258 	    }
3259 	    else
3260 	    {
3261 		DXFree((Pointer)handle->data);
3262 		handle->data = NULL;
3263 	    }
3264 
3265 	    handle->hash = hash;
3266 	    handle->type = IC_HASH;
3267 
3268 	    /*
3269 	     * Now add to hash table
3270 	     */
3271 	    li = index;
3272 	    if (DXQueryHashElement(handle->hash, (Key)&li))
3273 	    {
3274 		if (! DXDeleteHashElement(handle->hash, (Element)&li))
3275 		    goto error;
3276 		handle->nMarkedItems --;
3277 	    }
3278 	    break;
3279 	}
3280 
3281 	default:
3282 	{
3283 	    DXSetError(ERROR_INTERNAL, "unknown handle type");
3284 	    goto error;
3285 	}
3286     }
3287 
3288     /*
3289      * If not already a dependent array and we have passed the threshold,
3290      * convert to a dependent array.
3291      */
3292     if ((handle->type != IC_DEP_ARRAY) && (handle->nItems != -1) &&
3293 	(handle->nMarkedItems >= DEP_MEM_THRESHOLD(handle->nItems)))
3294     {
3295 	ubyte *depArray = (ubyte *)DXAllocate(handle->nItems*sizeof(ubyte));
3296 	if (! depArray)
3297 	    goto error;
3298 
3299 	memset(depArray, IC_ELEMENT_UNMARKED, handle->nItems);
3300 
3301 	/*
3302 	 * At this point, if we came in with a sorted list we will already
3303 	 * have converted to a hash table, so if its not dependent, it
3304 	 * must be hash.
3305 	 */
3306 	if (handle->type == IC_HASH)
3307 	{
3308 	    long *lPtr;
3309 
3310 	    DXInitGetNextHashElement(handle->hash);
3311 	    while(NULL != (lPtr = (long *)DXGetNextHashElement(handle->hash)))
3312 	       depArray[*lPtr] = IC_ELEMENT_MARKED;
3313 
3314 	    DXDestroyHash(handle->hash);
3315 	    handle->hash = NULL;
3316 	}
3317 	else
3318 	{
3319 	    DXSetError(ERROR_INTERNAL,
3320 		"attempting to expand an invalid type of invalid component");
3321 	    goto error;
3322 	}
3323 
3324 	handle->data = depArray;
3325 	handle->array = NULL;
3326 	handle->type = IC_DEP_ARRAY;
3327     }
3328 
3329     return OK;
3330 
3331 error:
3332     return ERROR;
3333 }
3334 
3335 int
DXIsElementInvalidSequential(InvalidComponentHandle handle,int index)3336 DXIsElementInvalidSequential(InvalidComponentHandle handle, int index)
3337 {
3338     /*
3339     if (handle->type == IC_ALL_UNMARKED)
3340 	return FALSE;
3341     else if (handle->type == IC_ALL_MARKED)
3342 	return TRUE;
3343     else if (handle->type == IC_SORTED_LIST)
3344     {
3345 	int *data;
3346 
3347 	if (index == 0)
3348 	    handle->next = 0;
3349 
3350 	if (handle->next >= handle->nMarkedItems)
3351 	    return FALSE;
3352 
3353 	data = (int *)(handle->data);
3354 
3355 	do
3356 	{
3357 	    if (index < data[handle->next])
3358 		return FALSE;
3359 	    if (index == data[handle->next])
3360 		return TRUE;
3361 	}
3362 	while (++(handle->next) < handle->nMarkedItems);
3363 
3364 	return FALSE;
3365     }
3366     else
3367     */
3368 	if(handle)
3369 		return DXIsElementInvalid(handle, index);
3370 	return 0;
3371 }
3372 
3373 
3374 int
DXIsElementValidSequential(InvalidComponentHandle handle,int index)3375 DXIsElementValidSequential(InvalidComponentHandle handle, int index)
3376 {
3377     /*
3378     if (handle->type == IC_ALL_UNMARKED)
3379 	return FALSE;
3380     else if (handle->type == IC_ALL_MARKED)
3381 	return TRUE;
3382     else if (handle->type == IC_SORTED_LIST)
3383     {
3384 	int *data;
3385 
3386 	if (index == 0)
3387 	    handle->next = 0;
3388 
3389 	if (handle->next >= handle->nMarkedItems)
3390 	    return FALSE;
3391 
3392 	data = (int *)(handle->data);
3393 
3394 	do
3395 	{
3396 	    if (index < data[handle->next])
3397 		return FALSE;
3398 	    if (index == data[handle->next])
3399 		return TRUE;
3400 	}
3401 	while (++(handle->next) < handle->nMarkedItems);
3402 
3403 	return FALSE;
3404     }
3405     else
3406     */
3407 	return DXIsElementValid(handle, index);
3408 }
3409 
3410 int
DXGetInvalidCount(InvalidComponentHandle handle)3411 DXGetInvalidCount(InvalidComponentHandle handle)
3412 {
3413     if (handle->sense == IC_MARKS_INDICATE_VALID)
3414 	return handle->nItems - handle->nMarkedItems;
3415     else
3416 	return handle->nMarkedItems;
3417 }
3418 
3419 int
DXGetValidCount(InvalidComponentHandle handle)3420 DXGetValidCount(InvalidComponentHandle handle)
3421 {
3422     if (handle->sense == IC_MARKS_INDICATE_INVALID)
3423 	return handle->nItems - handle->nMarkedItems;
3424     else
3425 	return handle->nMarkedItems;
3426 }
3427 
3428 static Field
DeleteFieldContents(Field f)3429 DeleteFieldContents(Field f)
3430 {
3431     char *cNames[1000];
3432     int  n;
3433 
3434     for (n = 0; DXGetEnumeratedComponentValue(f, n, cNames+n); n++);
3435 
3436     while (--n >= 0)
3437 	DXDeleteComponent(f, cNames[n]);
3438 
3439     return DXEndField(f);
3440 }
3441 
3442 Error
DXSetAllValid(InvalidComponentHandle handle)3443 DXSetAllValid(InvalidComponentHandle handle)
3444 {
3445     if (! RemoveContents(handle))
3446 	return ERROR;
3447 
3448     handle->type  = IC_ALL_UNMARKED;
3449     handle->sense = IC_MARKS_INDICATE_INVALID;
3450 
3451     return OK;
3452 }
3453 
3454 Error
DXSetAllInvalid(InvalidComponentHandle handle)3455 DXSetAllInvalid(InvalidComponentHandle handle)
3456 {
3457     if (! RemoveContents(handle))
3458 	return ERROR;
3459 
3460     handle->type  = IC_ALL_UNMARKED;
3461     handle->sense = IC_MARKS_INDICATE_VALID;
3462 
3463     return OK;
3464 }
3465 
3466 static Error
RemoveContents(InvalidComponentHandle handle)3467 RemoveContents(InvalidComponentHandle handle)
3468 {
3469     switch(handle->type)
3470     {
3471 	case IC_ALL_UNMARKED:
3472 	case IC_ALL_MARKED:
3473 	{
3474 	    break;
3475 	}
3476 
3477 	case IC_DEP_ARRAY:
3478 	case IC_SORTED_LIST:
3479 	{
3480 	    if (handle->array)
3481 	    {
3482 		DXDelete((Object)handle->array);
3483 		handle->array = NULL;
3484 		handle->data = NULL;
3485 	    }
3486 	    else
3487 	    {
3488 		DXFree((Pointer)handle->data);
3489 		handle->data = NULL;
3490 	    }
3491 
3492 	    break;
3493 	}
3494 
3495 	case IC_HASH:
3496 	{
3497 	    DXDestroyHash(handle->hash);
3498 	    handle->hash = NULL;
3499 
3500 	    break;
3501 	}
3502 
3503 	default:
3504 	    DXSetError(ERROR_INTERNAL,
3505 		"unknown invalid component handle type");
3506 	    goto error;
3507     }
3508 
3509     return OK;
3510 
3511 error:
3512     return ERROR;
3513 }
3514 
3515 Error
DXInitGetNextInvalidElementIndex(InvalidComponentHandle handle)3516 DXInitGetNextInvalidElementIndex(InvalidComponentHandle handle)
3517 {
3518     handle->nextCand  = 0;
3519     handle->nextSlot  = 0;
3520     handle->nextMarkI = -1;
3521 
3522     if (handle->type == IC_HASH)
3523 	if (! MakeSortList(handle))
3524 	    goto error;
3525 
3526     handle->nextMark = GetNextMarked(handle);
3527 
3528     return OK;
3529 
3530 error:
3531     return ERROR;
3532 }
3533 
3534 Error
DXInitGetNextValidElementIndex(InvalidComponentHandle handle)3535 DXInitGetNextValidElementIndex(InvalidComponentHandle handle)
3536 {
3537     return DXInitGetNextInvalidElementIndex(handle);
3538 }
3539 
3540 int
DXGetNextValidElementIndex(InvalidComponentHandle handle)3541 DXGetNextValidElementIndex(InvalidComponentHandle handle)
3542 {
3543     if (handle->sense == IC_MARKS_INDICATE_VALID)
3544     {
3545 	int next = handle->nextMark;
3546 	handle->nextMark = GetNextMarked(handle);
3547 	return next;
3548     }
3549     else
3550     {
3551 
3552 	/*
3553 	 * While there remain marks and our next candidate is marked, bump
3554 	 * them both.
3555 	 */
3556 	while (handle->nextMark != -1 && handle->nextCand == handle->nextMark)
3557 	{
3558 	    handle->nextCand ++;
3559 	    handle->nextMark = GetNextMarked(handle);
3560 	}
3561 
3562 	/*
3563 	 * If there are no remaining marks and we are not done...
3564 	 */
3565 	if (handle->nextCand < handle->nItems)
3566 	    return handle->nextCand++;
3567 	else
3568 	    return -1;
3569     }
3570 }
3571 
3572 
3573 int
DXGetNextInvalidElementIndex(InvalidComponentHandle handle)3574 DXGetNextInvalidElementIndex(InvalidComponentHandle handle)
3575 {
3576     if (handle->sense == IC_MARKS_INDICATE_INVALID)
3577     {
3578 	int next = handle->nextMark;
3579 	handle->nextMark = GetNextMarked(handle);
3580 	return next;
3581     }
3582     else
3583     {
3584 
3585 	/*
3586 	 * While there remain marks and our next candidate is marked, bump
3587 	 * them both.
3588 	 */
3589 	while (handle->nextMark != -1 && handle->nextCand == handle->nextMark)
3590 	{
3591 	    handle->nextCand ++;
3592 	    handle->nextMark = GetNextMarked(handle);
3593 	}
3594 
3595 	/*
3596 	 * If there are no remaining marks and we are not done...
3597 	 */
3598 	if (handle->nextCand < handle->nItems)
3599 	    return handle->nextCand++;
3600 	else
3601 	    return -1;
3602     }
3603 }
3604 
3605 Error
DXInvertValidity(InvalidComponentHandle handle)3606 DXInvertValidity(InvalidComponentHandle handle)
3607 {
3608     if (handle->sense == IC_MARKS_INDICATE_INVALID)
3609 	handle->sense = IC_MARKS_INDICATE_VALID;
3610     else
3611 	handle->sense = IC_MARKS_INDICATE_INVALID;
3612 
3613     return OK;
3614 }
3615 
3616 static Error
MakeSortList(InvalidComponentHandle handle)3617 MakeSortList(InvalidComponentHandle handle)
3618 {
3619     int i;
3620     long *p;
3621 
3622     if (handle->sortListSize != handle->nMarkedItems)
3623     {
3624 	DXFree((int *)handle->sortList);
3625 	handle->sortList = (int *)DXAllocate(handle->nMarkedItems*sizeof(int));
3626 	if (! handle->sortList)
3627 	    goto error;
3628 	handle->sortListSize = handle->nMarkedItems;
3629     }
3630 
3631     DXInitGetNextHashElement(handle->hash); i = 0;
3632     while (NULL != (p = (long *)DXGetNextHashElement(handle->hash)))
3633     {
3634 	if (i == handle->sortListSize)
3635 	{
3636 	    DXSetError(ERROR_INTERNAL, "sort list too short!");
3637 	    goto error;
3638 	}
3639 
3640 	handle->sortList[i++] = *p;
3641     }
3642 
3643     if (i != handle->sortListSize)
3644     {
3645 	DXSetError(ERROR_INTERNAL, "sort list wrong size!");
3646 	goto error;
3647     }
3648 
3649     refsort(handle->sortList, handle->sortListSize);
3650 
3651     return OK;
3652 
3653 error:
3654     return ERROR;
3655 }
3656 
3657 static int
GetNextMarked(InvalidComponentHandle handle)3658 GetNextMarked(InvalidComponentHandle handle)
3659 {
3660     if (handle->nextMarkI >= handle->nItems)
3661 	return -1;
3662 
3663     switch(handle->type)
3664     {
3665 	case IC_ALL_MARKED:
3666 	{
3667 	    if (handle->nextMarkI >= handle->nItems - 1)
3668 		return -1;
3669 	    else
3670 	        return (++(handle->nextMarkI));
3671 	}
3672 
3673 	case IC_ALL_UNMARKED:
3674 	{
3675 	    return -1;
3676 	}
3677 
3678 	case IC_SORTED_LIST:
3679 	{
3680 	    if (handle->nextSlot == handle->nMarkedItems)
3681 		return -1;
3682 	    else
3683 		return ((int *)(handle->data))[handle->nextSlot++];
3684 	}
3685 
3686 	case IC_HASH:
3687 	{
3688 	    if (handle->nextSlot == handle->sortListSize)
3689 		return -1;
3690 	    else
3691 		return ((int *)(handle->sortList))[handle->nextSlot++];
3692 	}
3693 
3694 	case IC_DEP_ARRAY:
3695 	{
3696 	    int i;
3697 	    ubyte *ptr = (ubyte *)handle->data + handle->nextMarkI + 1;
3698 
3699 	    for (i = handle->nextMarkI+1; i < handle->nItems; i++)
3700 		if (*ptr++ == IC_ELEMENT_MARKED)
3701 		{
3702 		    handle->nextMarkI = i;
3703 		    return i;
3704 		}
3705 
3706 	    return -1;
3707 	}
3708     }
3709     /* Function should be already returned, but just incase */
3710    return -1;
3711 }
3712 
3713 
3714 static int
GridSize(Array grid)3715 GridSize(Array grid)
3716 {
3717     switch(DXGetArrayClass(grid))
3718     {
3719 	case CLASS_PATHARRAY:
3720 	{
3721 	    int count;
3722 
3723 	    DXGetPathArrayInfo((PathArray)grid, &count);
3724 	    return count;
3725 	}
3726 
3727 	case CLASS_ARRAY:
3728 	{
3729 	    byte *map = NULL;
3730 	    int max, i, n, *elts, *e, nElements, nVerts, r;
3731 	    Type t;
3732 	    Category c;
3733 
3734 	    DXGetArrayInfo((Array)grid, &nElements, &t, &c, &r, &nVerts);
3735 
3736 	    if (t != TYPE_INT || c != CATEGORY_REAL || r != 1)
3737 	    {
3738 	        DXSetError(ERROR_DATA_INVALID, "connections");
3739 		return -1;
3740 	    }
3741 
3742 	    elts = (int *)DXGetArrayData(grid);
3743 
3744 	    n = nElements*nVerts;
3745 
3746 	    for (i = 0, e = elts, max = -1; i < n; i++, e++)
3747 		if (*e > max)
3748 		    max = *e;
3749 
3750 	    map = (byte *)DXAllocateZero((max+1)*sizeof(byte));
3751 	    if (! map)
3752 		return ERROR_OCCURRED;
3753 
3754 	    for (i = 0, e = elts; i < n; i++, e++)
3755 		if (*e >= 0)
3756 		    map[*e] = 1;
3757 
3758 	    for (i = 0; i < max; i++)
3759 		if (map[i] == 0)
3760 		{
3761 		    DXFree((Pointer)map);
3762 		    return HOLES_FOUND;
3763 		}
3764 
3765 	    DXFree((Pointer)map);
3766 	    return max + 1;
3767 	}
3768 
3769 	case CLASS_MESHARRAY:
3770 	{
3771 	    int nTerms, i, max;
3772 	    Array terms[100];
3773 	    int rtn;
3774 
3775 	    DXGetMeshArrayInfo((MeshArray)grid, &nTerms, terms);
3776 
3777 	    for (max = 1, i = 0; i < nTerms; i++)
3778 	    {
3779 		rtn = GridSize(terms[i]);
3780 		if (rtn < 0)
3781 		    return rtn;
3782 		max *= rtn;
3783 	    }
3784 
3785 	    return max;
3786 	}
3787 
3788 	default:
3789 	{
3790 	    DXSetError(ERROR_DATA_INVALID, "connections component");
3791 	    return ERROR_OCCURRED;
3792 	}
3793     }
3794 }
3795