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