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);
}
|