constraints3.c 25 KB

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