1/*********************************************************************
2 *   Copyright 1993, UCAR/Unidata
3 *   See netcdf/COPYRIGHT filey for copying and redistribution conditions.
4 *********************************************************************/
5
6#include "ncdap.h"
7#include "dceparselex.h"
8#include "dceconstraints.h"
9#include "dapdump.h"
10
11static void completesegments(NClistfullpathNClistsegments);
12static NCerror qualifyprojectionnames(DCEprojectionproj);
13static NCerror qualifyprojectionsizes(DCEprojectionproj);
14static NCerror qualifyprojectionnames(DCEprojectionproj);
15static NCerror matchpartialname(NClistnodesNClistsegmentsCDFnode** nodep);
16static int matchsuffix(NClistmatchpathNClistsegments);
17static int iscontainer(CDFnodenode);
18static DCEprojectionprojectify(CDFnodefieldDCEprojectioncontainer);
19static int slicematch(NClistseglist1NClistseglist2);
20
21/* Parse incoming url constraints, if any,
22   to check for syntactic correctness */
23NCerror
24dapparsedapconstraints(NCDAPCOMMONdapcomm, char* constraints,
25     DCEconstraintdceconstraint)
26{
27    NCerror ncstat = NC_NOERR;
28    char* errmsg = NULL;
29
30    ASSERT(dceconstraint != NULL);
31    nclistclear(dceconstraint->projections);
32    nclistclear(dceconstraint->selections);
33
34    ncstat = dapceparse(constraints,dceconstraint,&errmsg);
35    if(ncstat) {
36      nclog(NCLOGWARN,"DCE constraint parse failure: %s",errmsg);
37      nclistclear(dceconstraint->projections);
38      nclistclear(dceconstraint->selections);
39    }
40    /* errmsg is freed whether ncstat or not. */
41    nullfree(errmsg);
42    return ncstat;
43}
44
45/* Map constraint paths to CDFnode paths in specified tree and fill
46   in the declsizes.
47
48   Two things to watch out for:
49   1. suffix paths are legal (i.e. incomplete paths)
50   2. nc_virtual nodes (via restruct)
51
52*/
53
54NCerror
55dapmapconstraints(DCEconstraintconstraint,
56 CDFnoderoot)
57{
58    int i;
59    NCerror ncstat = NC_NOERR;
60    NClistnodes = root->tree->nodes;
61    NClistdceprojections = constraint->projections;
62
63    /* Convert the projection paths to leaves in the dds tree */
64    for(i=0;i<nclistlength(dceprojections);i++) {
65 CDFnodecdfmatch = NULL;
66 DCEprojectionproj = (DCEprojection*)nclistget(dceprojections,i);
67 if(proj->discrim != CES_VAR) continue; /* ignore functions */
68 ncstat = matchpartialname(nodes,proj->var->segments,&cdfmatch);
69 if(ncstat) goto done;
70 /* Cross links */
71 assert(cdfmatch != NULL);
72 proj->var->annotation = (void*)cdfmatch;
73    }
74
75done:
76    return THROW(ncstat);
77}
78
79
80/* Fill in:
81    1. projection segments
82    2. projection segment slices declsize
83    3. selection path
84*/
85NCerror
86dapqualifyconstraints(DCEconstraintconstraint)
87{
88    NCerror ncstat = NC_NOERR;
89    int i;
90#ifdef DEBUG
91fprintf(stderr,"ncqualifyconstraints.before: %s\n",
92 dumpconstraint(constraint));
93#endif
94    if(constraint != NULL) {
95        for(i=0;i<nclistlength(constraint->projections);i++) {
96            DCEprojectionp = (DCEprojection*)nclistget(constraint->projections,i);
97            ncstat = qualifyprojectionnames(p);
98            ncstat = qualifyprojectionsizes(p);
99        }
100    }
101#ifdef DEBUG
102fprintf(stderr,"ncqualifyconstraints.after: %s\n",
103 dumpconstraint(constraint));
104#endif
105    return ncstat;
106}
107
108/* convert all names in projections in paths to be fully qualified
109   by adding prefix segment objects.
110*/
111static NCerror
112qualifyprojectionnames(DCEprojectionproj)
113{
114    NCerror ncstat = NC_NOERR;
115    NClistfullpath = nclistnew();
116
117    ASSERT((proj->discrim == CES_VAR
118            && proj->var->annotation != NULL
119            && ((CDFnode*)proj->var->annotation)->ocnode != NULL));
120    collectnodepath((CDFnode*)proj->var->annotation,fullpath,!WITHDATASET);
121#ifdef DEBUG
122fprintf(stderr,"qualify: %s -> ",
123 dumpprojection(proj));
124#endif
125    /* Now add path nodes to create full path */
126    completesegments(fullpath,proj->var->segments);
127
128#ifdef DEBUG
129fprintf(stderr,"%s\n",
130 dumpprojection(proj));
131#endif
132    nclistfree(fullpath);
133    return ncstat;
134}
135
136/* Make sure that the slice declsizes are all defined for this projection */
137static NCerror
138qualifyprojectionsizes(DCEprojectionproj)
139{
140    int i,j;
141    ASSERT(proj->discrim == CES_VAR);
142#ifdef DEBUG
143fprintf(stderr,"qualifyprojectionsizes.before: %s\n",
144 dumpprojection(proj));
145#endif
146    for(i=0;i<nclistlength(proj->var->segments);i++) {
147        DCEsegmentseg = (DCEsegment*)nclistget(proj->var->segments,i);
148 NClistdimset = NULL;
149 CDFnodecdfnode = (CDFnode*)seg->annotation;
150 ASSERT(cdfnode != NULL);
151        dimset = cdfnode->array.dimsetplus;
152        seg->rank = nclistlength(dimset);
153 /* For this, we do not want any string dimensions */
154 if(cdfnode->array.stringdim != NULLseg->rank--;
155        for(j=0;j<seg->rank;j++) {
156     CDFnodedim = (CDFnode*)nclistget(dimset,j);
157     if(dim->dim.basedim != NULLdim = dim->dim.basedim;
158            ASSERT(dim != null);
159     if(seg->slicesdefined)
160         seg->slices[j].declsize = dim->dim.declsize;
161     else
162         dcemakewholeslice(seg->slices+j,dim->dim.declsize);
163 }
164        seg->slicesdefined = 1;
165        seg->slicesdeclized = 1;
166    }
167#ifdef DEBUG
168fprintf(stderr,"qualifyprojectionsizes.after: %s\n",
169 dumpprojection(proj));
170#endif
171    return NC_NOERR;
172}
173
174static void
175completesegments(NClistfullpathNClistsegments)
176{
177    int i,delta;
178    /* add path nodes to segments to create full path */
179    delta = (nclistlength(fullpath) - nclistlength(segments));
180    ASSERT((delta >= 0));
181    for(i=0;i<delta;i++) {
182        DCEsegmentseg = (DCEsegment*)dcecreate(CES_SEGMENT);
183        CDFnodenode = (CDFnode*)nclistget(fullpath,i);
184        seg->name = nulldup(node->ocname);
185        seg->annotation = (void*)node;
186 seg->rank = nclistlength(node->array.dimset0);
187        nclistinsert(segments,i,(void*)seg);
188    }
189    /* Now modify the segments to point to the appropriate node
190       and fill in the slices.
191    */
192    for(i=delta;i<nclistlength(segments);i++) {
193        DCEsegmentseg = (DCEsegment*)nclistget(segments,i);
194        CDFnodenode = (CDFnode*)nclistget(fullpath,i);
195 seg->annotation = (void*)node;
196    }
197}
198
199/*
200We are given a set of segments (in path)
201representing a partial path for a CDFnode variable.
202Our goal is to locate all matching
203variables for which the path of that
204variable has a suffix matching
205the given partial path.
206If one node matches exactly, then use that one;
207otherwise there had better be exactly one
208match else ambiguous.
209Additional constraints (4/12/2010):
2101. if a segment is dimensioned, then use that info
211   to distinguish e.g a grid node from a possible
212   grid array within it of the same name.
213   Treat sequences as of rank 1.
2142. if there are two matches, and one is the grid
215   and the other is the grid array within that grid,
216   then choose the grid array.
2173. If there are multiple matches choose the one with the
218   shortest path
2194. otherwise complain about ambiguity
220*/
221
222/**
223 * Given a path as segments,
224 * try to locate the CDFnode
225 * instance (from a given set)
226 * that corresponds to the path.
227 * The key difficulty is that the
228 * path may only be a suffix of the
229 * complete path.
230 */
231
232static NCerror
233matchpartialname(NClistnodesNClistsegmentsCDFnode** nodep)
234{
235    int i,nsegs;
236    NCerror ncstat = NC_NOERR;
237    DCEsegmentlastseg = NULL;
238    NClistnamematches = nclistnew();
239    NClistmatches = nclistnew();
240    NClistmatchpath = nclistnew();
241
242    /* Locate all nodes with the same name
243       as the last element in the segment path
244    */
245    nsegs = nclistlength(segments);
246    lastseg = (DCEsegment*)nclistget(segments,nsegs-1);
247    for(i=0;i<nclistlength(nodes);i++) {
248        CDFnodenode = (CDFnode*)nclistget(nodes,i);
249 if(node->ocname == null)
250     continue;
251 /* Path names come from oc space */
252        if(strcmp(node->ocname,lastseg->name) != 0)
253     continue;
254 /* Only look at selected kinds of nodes */
255 if(node->nctype != NC_Sequence
256               && node->nctype != NC_Structure
257               && node->nctype != NC_Grid
258               && node->nctype != NC_Atomic
259          )
260     continue;
261 nclistpush(namematches,(void*)node);
262    }
263    if(nclistlength(namematches)==0) {
264        nclog(NCLOGERR,"No match for projection name: %s",lastseg->name);
265        ncstat = NC_EDDS;
266 goto done;
267    }
268
269    /* Now, collect and compare paths of the matching nodes */
270    for(i=0;i<nclistlength(namematches);i++) {
271        CDFnodematchnode = (CDFnode*)nclistget(namematches,i);
272 nclistclear(matchpath);
273 collectnodepath(matchnode,matchpath,0);
274 /* Do a suffix match */
275        if(matchsuffix(matchpath,segments)) {
276     nclistpush(matches,(void*)matchnode);
277#ifdef DEBUG
278fprintf(stderr,"matchpartialname: pathmatch: %s :: %s\n",
279matchnode->ncfullname,dumpsegments(segments));
280#endif
281 }
282    }
283    /* |matches|==0 => no match; |matches|>1 => ambiguity */
284    switch (nclistlength(matches)) {
285    case 0:
286        nclog(NCLOGERR,"No match for projection name: %s",lastseg->name);
287        ncstat = NC_EDDS;
288 break;
289    case 1:
290        if(nodep)
291     *nodep = (CDFnode*)nclistget(matches,0);
292 break;
293    default: {
294 CDFnodeminnode = NULL;
295 int minpath = 0;
296 int nmin = 0; /* to catch multiple ones with same short path */
297 /* ok, see if one of the matches has a path that is shorter
298           then all the others */
299 for(i=0;i<nclistlength(matches);i++) {
300     CDFnodecandidate = (CDFnode*)nclistget(matches,i);
301     nclistclear(matchpath);
302     collectnodepath(candidate,matchpath,0);
303     if(minpath == 0) {
304 minpath = nclistlength(matchpath);
305 minnode = candidate;
306     } else if(nclistlength(matchpath) == minpath) {
307         nmin++;
308     } else if(nclistlength(matchpath) < minpath) {
309 minpath = nclistlength(matchpath);
310 minnode = candidate;
311 nmin = 1;
312     }
313 } /*for*/
314 if(minnode == NULL || nmin > 1) {
315     nclog(NCLOGERR,"Ambiguous match for projection name: %s",
316 lastseg->name);
317            ncstat = NC_EDDS;
318 } else if(nodep)
319     *nodep = minnode;
320 } break;
321    }
322#ifdef DEBUG
323fprintf(stderr,"matchpartialname: choice: %s %s for %s\n",
324(nclistlength(matches) > 1?"":"forced"),
325(*nodep)->ncfullname,dumpsegments(segments));
326#endif
327
328done:
329    nclistfree(namematches);
330    nclistfree(matches);
331    nclistfree(matchpath);
332    return THROW(ncstat);
333}
334
335static int
336matchsuffix(NClistmatchpathNClistsegments)
337{
338    int i,pathstart;
339    int nsegs = nclistlength(segments);
340    int pathlen = nclistlength(matchpath);
341    int segmatch;
342
343    /* try to match the segment list as a suffix of the path list */
344
345    /* Find the maximal point in the path s.t. |suffix of path|
346       == |segments|
347    */
348    pathstart = (pathlen - nsegs);
349    if(pathstart < 0)
350 return 0; /* pathlen <nsegs => no match possible */
351
352    /* Walk the suffix of the path and the segments and
353       matching as we go
354    */
355    for(i=0;i<nsegs;i++) {
356 CDFnodenode = (CDFnode*)nclistget(matchpath,pathstart+i);
357 DCEsegmentseg = (DCEsegment*)nclistget(segments,i);
358 int rank = seg->rank;
359 segmatch = 1; /* until proven otherwise */
360 /* Do the names match (in oc name space) */
361 if(strcmp(seg->name,node->ocname) != 0) {
362     segmatch = 0;
363 } else {
364     /* Do the ranks match (watch out for sequences) */
365     if(node->nctype == NC_Sequence)
366 rank--; /* remove sequence pseudo-rank */
367     if(rank > 0
368 && rank != nclistlength(node->array.dimset0))
369 segmatch = 0; /* rank mismatch */
370 }
371 if(!segmatch)
372     return 0;
373   }
374   return 1; /* all segs matched */
375}
376
377/* Given the arguments to vara
378   construct a corresponding projection
379   with any pseudo dimensions removed
380*/
381NCerror
382dapbuildvaraprojection(CDFnodevar,
383      const size_t* startp, const size_t* countp, const ptrdiff_tstridep,
384      DCEprojection** projectionp)
385{
386    int i,j;
387    NCerror ncstat = NC_NOERR;
388    DCEprojectionprojection = NULL;
389    NClistpath = nclistnew();
390    NClistsegments = NULL;
391    int dimindex;
392
393    /* Build a skeleton projection that has 1 segment for
394       every cdfnode from root to the variable of interest.
395       Each segment has the slices from its corresponding node
396       in the path, including pseudo-dims
397    */
398    ncstat = dapvar2projection(var,&projection);
399
400#ifdef DEBUG
401fprintf(stderr,"buildvaraprojection: skeleton: %s\n",dumpprojection(projection));
402#endif
403
404    /* Now, modify the projection to reflect the corresponding
405       start/count/stride from the nc_get_vara arguments.
406    */
407    segments = projection->var->segments;
408    dimindex = 0;
409    for(i=0;i<nclistlength(segments);i++) {
410 DCEsegmentsegment = (DCEsegment*)nclistget(segments,i);
411        for(j=0;j<segment->rank;j++) {
412     size_t count = 0;
413     DCEsliceslice = &segment->slices[j];
414     /* make each slice represent the corresponding
415               start/count/stride */
416     slice->first = startp[dimindex+j];
417     slice->stride = stridep[dimindex+j];
418     count = countp[dimindex+j];
419     slice->count = count;
420     slice->length = count * slice->stride;
421     slice->last = (slice->first + slice->length) - 1;
422     if(slice->last >= slice->declsize) {
423 slice->last = slice->declsize - 1;
424 /* reverse compute the new length */
425 slice->length = (slice->last - slice->first) + 1;
426     }
427 }
428 dimindex += segment->rank;
429    }
430#ifdef DEBUG
431fprintf(stderr,"buildvaraprojection.final: %s\n",dumpprojection(projection));
432#endif
433
434#ifdef DEBUG
435fprintf(stderr,"buildvaraprojection3: final: projection=%s\n",
436        dumpprojection(projection));
437#endif
438
439    if(projectionp) *projectionp = projection;
440
441    nclistfree(path);
442    if(ncstatdcefree((DCEnode*)projection);
443    return ncstat;
444}
445
446int
447dapiswholeslice(DCEslicesliceCDFnodedim)
448{
449    if(slice->first != 0 || slice->stride != 1) return 0;
450    if(dim != NULL) {
451 if(slice->length != dim->dim.declsize) return 0;
452    } else if(dim == NULL) {
453 size_t count = slice->count;
454 if(slice->declsize == 0
455    || count != slice->declsize) return 0;
456    }
457    return 1;
458}
459
460int
461dapiswholesegment(DCEsegmentseg)
462{
463    int i,whole;
464    NClistdimset = NULL;
465    unsigned int rank;
466
467    if(seg->rank == 0) return 1;
468    if(!seg->slicesdefined) return 0;
469    if(seg->annotation == NULL) return 0;
470    dimset = ((CDFnode*)seg->annotation)->array.dimset0;
471    rank = nclistlength(dimset);
472    whole = 1; /* assume so */
473    for(i=0;i<rank;i++) {
474 CDFnodedim = (CDFnode*)nclistget(dimset,i);
475 if(!dapiswholeslice(&seg->slices[i],dim)) {whole = 0; break;}
476    }
477    return whole;
478}
479
480int
481dapiswholeprojection(DCEprojectionproj)
482{
483    int i,whole;
484
485    ASSERT((proj->discrim == CES_VAR));
486
487    whole = 1; /* assume so */
488    for(i=0;i<nclistlength(proj->var->segments);i++) {
489        DCEsegmentsegment = (DCEsegment*)nclistget(proj->var->segments,i);
490 if(!dapiswholesegment(segment)) {whole = 0; break;}
491    }
492    return whole;
493}
494
495int
496dapiswholeconstraint(DCEconstraintcon)
497{
498    int i;
499    if(con == NULL) return 1;
500    if(con->projections != NULL) {
501 for(i=0;i<nclistlength(con->projections);i++) {
502  if(!dapiswholeprojection((DCEprojection*)nclistget(con->projections,i)))
503     return 0;
504 }
505    }
506    if(con->selections != NULL)
507 return 0;
508    return 1;
509}
510
511
512/*
513Given a set of projections, we need to produce
514an expanded, correct, and equivalent set of projections.
515The term "correct" means we must fix the following cases:
5161. Multiple occurrences of the same leaf variable
517   with differing projection slices. Fix is to complain.
5182. Occurrences of container and one or more of its fields.
519   Fix is to suppress the container.
520The term "expanded" means
5211. Expand all occurrences of only a container by
522   replacing it with all of its fields.
523*/
524
525NCerror
526dapfixprojections(NClistlist)
527{
528    int i,j,k;
529    NCerror ncstat = NC_NOERR;
530    NClisttmp = nclistnew(); /* misc. uses */
531
532#ifdef DEBUG
533fprintf(stderr,"fixprojection: list = %s\n",dumpprojections(list));
534#endif
535
536    if(nclistlength(list) == 0) goto done;
537
538    /* Step 1: remove duplicates and complain about slice mismatches */
539    for(i=0;i<nclistlength(list);i++) {
540 DCEprojectionp1 = (DCEprojection*)nclistget(list,i);
541 if(p1 == NULL) continue;
542        if(p1->discrim != CES_VAR) continue; /* dont try to unify functions */
543        for(j=i;j<nclistlength(list);j++) {
544     DCEprojectionp2 = (DCEprojection*)nclistget(list,j);
545     if(p2 == NULL) continue;
546     if(p1 == p2) continue;
547     if(p2->discrim != CES_VAR) continue;
548     if(p1->var->annotation != p2->var->annotation) continue;
549     /* check for slice mismatches */
550     if(!slicematch(p1->var->segments,p2->var->segments)) {
551 /* complain */
552 nclog(NCLOGWARN,"Malformed projection: same variable with different slicing");
553     }
554     /* remove p32 */
555     nclistset(list,j,(void*)NULL);
556     dcefree((DCEnode*)p2);
557 }
558    }
559
560    /* Step 2: remove containers when a field is also present */
561    for(i=0;i<nclistlength(list);i++) {
562 DCEprojectionp1 = (DCEprojection*)nclistget(list,i);
563 if(p1 == NULL) continue;
564        if(p1->discrim != CES_VAR) continue; /* dont try to unify functions */
565 if(!iscontainer((CDFnode*)p1->var->annotation))
566     continue;
567        for(j=i;j<nclistlength(list);j++) {
568     DCEprojectionp2 = (DCEprojection*)nclistget(list,j);
569     if(p2 == NULL) continue;
570     if(p2->discrim != CES_VAR) continue;
571     nclistclear(tmp);
572     collectnodepath((CDFnode*)p2->var->annotation,tmp,WITHDATASET);
573     for(k=0;k<nclistlength(tmp);k++) {
574 void* candidate = (void*)nclistget(tmp,k);
575         if(candidate == p1->var->annotation) {
576     nclistset(list,i,(void*)NULL);
577             dcefree((DCEnode*)p1);
578     goto next;
579 }
580     }
581 }
582next:   continue;
583    }
584
585    /* Step 3: expand all containers recursively down to the leaf nodes */
586    for(;;) {
587 nclistclear(tmp);
588        for(i=0;i<nclistlength(list);i++) {
589            DCEprojectiontarget = (DCEprojection*)nclistget(list,i);
590            CDFnodeleaf;
591            if(target == NULL) continue;
592            if(target->discrim != CES_VAR)
593                continue; /* dont try to unify functions */
594            leaf = (CDFnode*)target->var->annotation;
595            ASSERT(leaf != NULL);
596            if(iscontainer(leaf)) {/* capture container */
597 if(!nclistcontains(tmp,(void*)target))
598                    nclistpush(tmp,(void*)target);
599                nclistset(list,i,(void*)NULL);
600            }
601        }
602 if(nclistlength(tmp) == 0) break; /*done*/
603        /* Now explode the containers */
604        for(i=0;i<nclistlength(tmp);i++) {
605            DCEprojectioncontainer = (DCEprojection*)nclistget(tmp,i);
606     CDFnodeleaf = (CDFnode*)container->var->annotation;
607            for(j=0;i<nclistlength(leaf->subnodes);j++) {
608                CDFnodefield = (CDFnode*)nclistget(leaf->subnodes,j);
609 /* Convert field node to a proper constraint */
610 DCEprojectionproj = projectify(field,container);
611 nclistpush(list,(void*)proj);
612     }
613            /* reclaim the container */
614     dcefree((DCEnode*)container);
615 }
616    } /*for(;;)*/
617
618    /* remove all NULL elements */
619    for(i=nclistlength(list)-1;i>=0;i--) {
620        DCEprojectiontarget = (DCEprojection*)nclistget(list,i);
621 if(target == NULL)
622     nclistremove(list,i);
623    }
624
625done:
626#ifdef DEBUG
627fprintf(stderr,"fixprojection: exploded = %s\n",dumpprojections(list));
628#endif
629    nclistfree(tmp);
630    return ncstat;
631}
632
633static int
634iscontainer(CDFnodenode)
635{
636    return (node->nctype == NC_Dataset
637               || node->nctype == NC_Sequence
638               || node->nctype == NC_Structure
639               || node->nctype == NC_Grid);
640}
641
642static DCEprojection*
643projectify(CDFnodefieldDCEprojectioncontainer)
644{
645    DCEprojectionproj  = (DCEprojection*)dcecreate(CES_PROJECT);
646    DCEvarvar  = (DCEvar*)dcecreate(CES_VAR);
647    DCEsegmentseg  = (DCEsegment*)dcecreate(CES_SEGMENT);
648    proj->discrim = CES_VAR;
649    proj->var = var;
650    var->annotation = (void*)field;
651    /* Dup the segment list */
652    var->segments = dceclonelist(container->var->segments);
653    seg->rank = 0;
654    nclistpush(var->segments,(void*)seg);
655    return proj;
656}
657
658static int
659slicematch(NClistseglist1NClistseglist2)
660{
661    int i,j;
662    if((seglist1 == NULL || seglist2 == NULL) && seglist1 != seglist2)
663 return 0;
664    if(nclistlength(seglist1) != nclistlength(seglist2))
665 return 0;
666    for(i=0;i<nclistlength(seglist1);i++) {
667 DCEsegmentseg1 = (DCEsegment*)nclistget(seglist1,i);
668 DCEsegmentseg2 = (DCEsegment*)nclistget(seglist2,i);
669 if(seg1->rank != seg2->rank)
670     return 0;
671 for(j=0;j<seg1->rank;j++) {
672     DCEsliceslice1 = &seg1->slices[j];
673     DCEsliceslice2 = &seg2->slices[j];
674     size_t count1 = slice1->count;
675     size_t count2 = slice2->count;
676     if(slice1->first != slice2->first
677        || count1 != count2
678        || slice1->stride != slice2->stride)
679 return 0;
680 }
681    }
682    return 1;
683}
684
685/* Convert a CDFnode var to a projection; include
686   pseudodimensions; always whole variable.
687*/
688int
689dapvar2projection(CDFnodevarDCEprojection** projectionp)
690{
691    int i,j;
692    int ncstat = NC_NOERR;
693    NClistpath = nclistnew();
694    NClistsegments;
695    DCEprojectionprojection = NULL;
696    int dimindex;
697
698    /* Collect the nodes needed to construct the projection segments */
699    collectnodepath(var,path,!WITHDATASET);
700
701    segments = nclistnew();
702    dimindex = 0; /* point to next subset of slices */
703    nclistsetalloc(segments,nclistlength(path));
704    for(i=0;i<nclistlength(path);i++) {
705 DCEsegmentsegment = (DCEsegment*)dcecreate(CES_SEGMENT);
706 CDFnoden = (CDFnode*)nclistget(path,i);
707 int localrank;
708        NClistdimset;
709
710 segment->annotation = (void*)n;
711        segment->name = nulldup(n->ocname);
712        /* We need to assign whole slices to each segment */
713 localrank = nclistlength(n->array.dimsetplus);
714        segment->rank = localrank;
715 dimset = n->array.dimsetplus;
716        for(j=0;j<localrank;j++) {
717     DCEsliceslice;
718     CDFnodedim;
719     slice = &segment->slices[j];
720     dim = (CDFnode*)nclistget(dimset,j);
721     ASSERT(dim->dim.declsize0 > 0);
722     dcemakewholeslice(slice,dim->dim.declsize0);
723 }
724 segment->slicesdefined = 1;
725 segment->slicesdeclized = 1;
726 dimindex += localrank;
727 nclistpush(segments,(void*)segment);
728    }
729
730    projection = (DCEprojection*)dcecreate(CES_PROJECT);
731    projection->discrim = CES_VAR;
732    projection->var = (DCEvar*)dcecreate(CES_VAR);
733    projection->var->annotation = (void*)var;
734    projection->var->segments = segments;
735
736#ifdef DEBUG1
737fprintf(stderr,"dapvar2projection: projection=%s\n",
738        dumpprojection(projection));
739#endif
740
741    nclistfree(path);
742    if(ncstatdcefree((DCEnode*)projection);
743    else if(projectionp) *projectionp = projection;
744    return ncstat;
745}
746
747/*
748Given a set of projections and a projection
749representing a variable (from, say vara or prefetch)
750construct a single projection for fetching that variable
751with the proper constraints.
752*/
753int
754daprestrictprojection(NClistprojectionsDCEprojectionvarDCEprojection** resultp)
755{
756    int ncstat = NC_NOERR;
757    int i;
758    DCEprojectionresult = NULL;
759#ifdef DEBUG1
760fprintf(stderr,"restrictprojection.before: constraints=|%s| vara=|%s|\n",
761 dumpprojections(projections),
762 dumpprojection(var));
763#endif
764
765    ASSERT(var != NULL);
766
767    /* the projection list will contain at most 1 match for the var by construction */
768    for(result=null,i=0;i<nclistlength(projections);i++) {
769 DCEprojectionp1 = (DCEprojection*)nclistget(projections,i);
770 if(p1 == NULL || p1->discrim != CES_VAR) continue;
771 if(p1->var->annotation == var->var->annotation) {
772     result = p1;
773     break;
774 }
775    }
776    if(result == NULL) {
777 result = (DCEprojection*)dceclone((DCEnode*)var); /* use only the var projection */
778  goto done;
779    }
780    result = (DCEprojection*)dceclone((DCEnode*)result); /* so we can modify */
781
782#ifdef DEBUG1
783fprintf(stderr,"restrictprojection.choice: base=|%s| add=|%s|\n",
784 dumpprojection(result),dumpprojection(var));
785#endif
786    /* We need to merge the projection from the projection list
787       with the var projection
788    */
789    ncstat = dcemergeprojections(result,var); /* result will be modified */
790
791done:
792    if(resultp) *resultp = result;
793#ifdef DEBUG
794fprintf(stderr,"restrictprojection.after=|%s|\n",
795 dumpprojection(result));
796#endif
797    return ncstat;
798}
799
800/* Shift the slice so it runs from 0..count by step 1 */
801static void
802dapshiftslice(DCEsliceslice)
803{
804    size_t first = slice->first;
805    size_t stride = slice->stride;
806    if(first == 0 && stride == 1) return; /* no need to do anything */
807    slice->first = 0;
808    slice->stride = 1;
809    slice->length = slice->count;
810    slice->last = slice->length - 1;
811}
812
813int
814dapshiftprojection(DCEprojectionprojection)
815{
816    int ncstat = NC_NOERR;
817    int i,j;
818    NClistsegments;
819
820#ifdef DEBUG1
821fprintf(stderr,"dapshiftprojection.before: %s\n",dumpprojection(projection));
822#endif
823
824    ASSERT(projection->discrim == CES_VAR);
825    segments = projection->var->segments;
826    for(i=0;i<nclistlength(segments);i++) {
827 DCEsegmentseg = (DCEsegment*)nclistget(segments,i);
828        for(j=0;j<seg->rank;j++) {
829     DCEsliceslice = seg->slices+j;
830     dapshiftslice(slice);
831 }
832    }
833
834#ifdef DEBUG1
835fprintf(stderr,"dapshiftprojection.after: %s\n",dumpprojection(projection));
836#endif
837
838    return ncstat;
839}
840
841/* Compute the set of variables referenced in the projections
842   of the input constraint.
843*/
844NCerror
845dapcomputeprojectedvars(NCDAPCOMMONdapcommDCEconstraintconstraint)
846{
847    NCerror ncstat = NC_NOERR;
848    NClistvars = NULL;
849    int i;
850
851    vars = nclistnew();
852
853    if(dapcomm->cdf.projectedvars != NULL)
854 nclistfree(dapcomm->cdf.projectedvars);
855    dapcomm->cdf.projectedvars = vars;
856
857    if(constraint == NULL || constraint->projections == NULL)
858 goto done;
859
860    for(i=0;i<nclistlength(constraint->projections);i++) {
861 CDFnodenode;
862 DCEprojectionproj = (DCEprojection*)nclistget(constraint->projections,i);
863 if(proj->discrim == CES_FCN) continue; /* ignore these */
864 node = (CDFnode*)proj->var->annotation;
865 if(!nclistcontains(vars,(void*)node)) {
866     nclistpush(vars,(void*)node);
867 }
868    }
869
870done:
871    return ncstat;
872}


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed