1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
 int
 saf_describe_collection(SAF_ParMode  pmode,             /* The parallel mode. */
                         SAF_Set *containing_set,        /* The containing set of the desired collection. In SAF_ONE() parallel
                                                          * mode, all processes except the process identified by the rank
                                                          * argument of the SAF_ONE() macro are free to pass SAF_NULL with the
                                                          * set's database handle. */
                         SAF_Cat *cat,                   /* The collection category of the desired collection. */
                         SAF_CellType *t,                /* [OUT] The cell-type of the members of the collection. Pass NULL if
                                                          * this return value is not desired. */
                         int *count,                     /* [OUT] The returned count of the collection.  Pass NULL if this
                                                          * return value is not desired. */
                         SAF_IndexSpec *ispec,           /* [OUT] The returned indexing specification for the collection. Pass
                                                          * NULL if this return value is not desired. */
                         SAF_DecompMode *is_decomp,      /* [OUT] Whether the collection is a decomposition of the containing
                                                          * set. Pass NULL if this return value is not desired. */
                         SAF_Set **member_sets           /* If the collection is non-primitive, this argument is used to return
                                                          * the specific set handles for the sets that are in the collection.
                                                          * Pass NULL if this return value is not desired. Otherwise, if
                                                          * MEMBER_SETS points to NULL, the library will allocate space for the
                                                          * returned set handles. Otherwise the caller allocates the space and
                                                          * the input value of COUNT indicates the size of the space in
                                                          * number of set handles. */
                         )
 {
     SAF_ENTER(saf_describe_collection, SAF_PRECONDITION_ERROR);
     SAF_Collection      coll = SS_COLLECTION_NULL;
     ss_indexspec_t      idx  = SS_INDEXSPEC_NULL;
     int                 i;

     SAF_REQUIRE(_saf_valid_pmode(pmode), SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("PMODE must be valid"));
     if (!_saf_is_participating_proc(pmode)) SAF_RETURN(-1);

     SAF_REQUIRE(SS_SET(containing_set), SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("the CONTAINING_SET must be valid for all participating processes"));
     SAF_REQUIRE(SS_CAT(cat), SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("CAT must be a valid category handle for participating processes"));

     /* Issue: having both arguments NULL will cause _saf_valid_memhints to return false, but in this particular case, having both
     *        arguments NULL is ok, so we dont call _saf_valid_memhints if both are 0. */
     SAF_REQUIRE((!count && !member_sets) || _saf_valid_memhints(count, (void**)member_sets),
                 SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("NUM_SETS and MEMBER_SETS must be compatible for return value allocation"));

     /* Special case for the "self" collection, which isn't always instantiated as a first-class collection. */
     if (_saf_is_self_decomp(cat)) {
         if (t) *t = SAF_CELLTYPE_SET;
         if (is_decomp) *is_decomp = SAF_DECOMP_TRUE;
         if (ispec) {
             memset(ispec, 0, sizeof *ispec);
             ispec->ndims = 1;
             ispec->sizes[0] = 1;
         }
         if (member_sets) {
             if (!*member_sets) *member_sets = malloc(sizeof(**member_sets));
             (*member_sets)[0] = *containing_set;
         }
         if (count) *count = 1;
         goto done;
     }

     /* Obtain the collection given the containing set and collection category. If a collection is not defined on the
      * containing set for the specified category then fill in return values appropriately. */
     if (NULL==_saf_getCollection_set(containing_set, cat, &coll)) {
         if (t) *t = SAF_CELLTYPE_SET;
         if (is_decomp) *is_decomp = SAF_DECOMP_FALSE;
         if (ispec) memset(ispec, 0, sizeof *ispec);
         if (count) *count = 0;
         goto done;
     }

     /* The default index spec */
     ss_array_get(SS_COLLECTION_P(&coll,indexing), ss_pers_tm, (size_t)0, (size_t)1, &idx);

     SAF_ASSERT(SS_COLLECTION(&coll)->cell_type==SAF_CELLTYPE_SET || !member_sets, SAF_LOW_CHK_COST, SAF_ASSERTION_ERROR,
                _saf_errmsg("MEMBER_SETS must be NULL for a primitive collection for participating processes"));

     /* fill in return info as requested by the client */
     if (t) *t = SS_COLLECTION(&coll)->cell_type;
     if (is_decomp) *is_decomp = SS_COLLECTION(&coll)->is_decomp ? SAF_DECOMP_TRUE : SAF_DECOMP_FALSE;
     if (ispec) {
         memset(ispec, 0, sizeof *ispec);
         if (!SS_PERS_ISNULL(&idx)) {
             ispec->ndims = SS_INDEXSPEC(&idx)->ndims;
             for (i=0; i<SS_INDEXSPEC(&idx)->ndims; i++) {
                 ispec->sizes[i] = SS_INDEXSPEC(&idx)->sizes[i];
                 ispec->origins[i] = SS_INDEXSPEC(&idx)->origins[i];
                 ispec->order[i] = SS_INDEXSPEC(&idx)->order[i];
             }
         }
     }

     /* fill in the member sets, if requested */
     if (member_sets) {
         if (ss_array_nelmts(SS_COLLECTION_P(&coll,members))<(size_t)(SS_COLLECTION(&coll)->count))
             SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("attempt to read member list before it's been completely filled"));
         if (!*member_sets) {
             /* Library allocates results and returns all member sets */
             *member_sets = malloc(SS_COLLECTION(&coll)->count * sizeof(**member_sets));
         } else {
             /* Client allocated result buffer and COUNT incoming value is the array size */
             SAF_ASSERT(count && *count>=SS_COLLECTION(&coll)->count, SAF_LOW_CHK_COST, SAF_ASSERTION_ERROR,
                        _saf_errmsg("client allocated mem is too small %i", count));
         }
         ss_array_get(SS_COLLECTION_P(&coll,members), 0, 0, SS_NOSIZE, *member_sets);
     }

     /* finally, the count */
     if (count) *count = SS_COLLECTION(&coll)->count;

 done:
     SAF_LEAVE(SAF_SUCCESS);
 }