static int DLOOP_Dataloop_create_flattened_struct(DLOOP_Count count, const int *blklens, const MPI_Aint *disps, const DLOOP_Type *oldtypes, DLOOP_Dataloop **dlp_p, MPI_Aint *dlsz_p, int *dldepth_p, int flag) { /* arbitrary types, convert to bytes and use indexed */ int i, err, nr_blks = 0; DLOOP_Size *tmp_blklens; MPI_Aint *tmp_disps; /* since we're calling another fn that takes this type as an input parameter */ DLOOP_Offset bytes; DLOOP_Segment *segp; int first_ind; DLOOP_Size last_ind; segp = MPIR_Segment_alloc(); /* --BEGIN ERROR HANDLING-- */ if (!segp) { return DLOOP_Dataloop_create_struct_memory_error(); } /* --END ERROR HANDLING-- */ /* use segment code once to count contiguous regions */ for (i=0; i < count; i++) { int is_basic; /* ignore type elements with a zero blklen */ if (blklens[i] == 0) continue; is_basic = (DLOOP_Handle_hasloop_macro(oldtypes[i])) ? 0 : 1; if (is_basic && (oldtypes[i] != MPI_LB && oldtypes[i] != MPI_UB)) { nr_blks++; } else /* derived type; get a count of contig blocks */ { DLOOP_Count tmp_nr_blks, sz; DLOOP_Handle_get_size_macro(oldtypes[i], sz); /* if the derived type has some data to contribute, * add to flattened representation */ if (sz > 0) { err = MPIR_Segment_init(NULL, (DLOOP_Count) blklens[i], oldtypes[i], segp, flag); if (err) return err; bytes = SEGMENT_IGNORE_LAST; MPIR_Segment_count_contig_blocks(segp, 0, &bytes, &tmp_nr_blks); nr_blks += tmp_nr_blks; } } } /* it's possible for us to get to this point only to realize that * there isn't any data in this type. in that case do what we always * do: store a simple contig of zero ints and call it done. */ if (nr_blks == 0) { MPIR_Segment_free(segp); err = MPIR_Dataloop_create_contiguous(0, MPI_INT, dlp_p, dlsz_p, dldepth_p, flag); return err; } nr_blks += 2; /* safety measure */ tmp_blklens = (DLOOP_Size *) DLOOP_Malloc(nr_blks * sizeof(DLOOP_Size), MPL_MEM_DATATYPE); /* --BEGIN ERROR HANDLING-- */ if (!tmp_blklens) { MPIR_Segment_free(segp); return DLOOP_Dataloop_create_struct_memory_error(); } /* --END ERROR HANDLING-- */ tmp_disps = (MPI_Aint *) DLOOP_Malloc(nr_blks * sizeof(MPI_Aint), MPL_MEM_DATATYPE); /* --BEGIN ERROR HANDLING-- */ if (!tmp_disps) { DLOOP_Free(tmp_blklens); MPIR_Segment_free(segp); return DLOOP_Dataloop_create_struct_memory_error(); } /* --END ERROR HANDLING-- */ /* use segment code again to flatten the type */ first_ind = 0; for (i=0; i < count; i++) { int is_basic; DLOOP_Count sz = -1; is_basic = (DLOOP_Handle_hasloop_macro(oldtypes[i])) ? 0 : 1; if (!is_basic) DLOOP_Handle_get_size_macro(oldtypes[i], sz); /* we're going to use the segment code to flatten the type. * we put in our displacement as the buffer location, and use * the blocklength as the count value to get N contiguous copies * of the type. * * Note that we're going to get back values in bytes, so that will * be our new element type. */ if (oldtypes[i] != MPI_UB && oldtypes[i] != MPI_LB && blklens[i] != 0 && (is_basic || sz > 0)) { err = MPIR_Segment_init((char *) DLOOP_OFFSET_CAST_TO_VOID_PTR disps[i], (DLOOP_Count) blklens[i], oldtypes[i], segp, 0 /* homogeneous */); if (err) return err; last_ind = nr_blks - first_ind; bytes = SEGMENT_IGNORE_LAST; MPIR_Segment_mpi_flatten(segp, 0, &bytes, &tmp_blklens[first_ind], &tmp_disps[first_ind], &last_ind); if (err) return err; first_ind += last_ind; } } nr_blks = first_ind; #if 0 if (MPL_DBG_SELECTED(MPIR_DBG_DATATYPE,VERBOSE)) { MPL_DBG_OUT(MPIR_DBG_DATATYPE,"--- start of flattened type ---"); for (i=0; i < nr_blks; i++) { MPL_DBG_OUT_FMT(MPIR_DBG_DATATYPE,(MPL_DBG_FDEST, "a[%d] = (%d, " DLOOP_OFFSET_FMT_DEC_SPEC ")", i, tmp_blklens[i], tmp_disps[i])); } MPL_DBG_OUT(MPIR_DBG_DATATYPE,"--- end of flattened type ---"); } #endif MPIR_Segment_free(segp); err = MPIR_Dataloop_create_indexed(nr_blks, tmp_blklens, tmp_disps, 1, /* disp in bytes */ MPI_BYTE, dlp_p, dlsz_p, dldepth_p, flag); DLOOP_Free(tmp_blklens); DLOOP_Free(tmp_disps); return err; }
int MPIR_Unpack_impl(const void *inbuf, MPI_Aint insize, MPI_Aint * position, void *outbuf, int outcount, MPI_Datatype datatype) { int mpi_errno = MPI_SUCCESS; MPI_Aint first, last; MPIR_Segment *segp; int contig; MPI_Aint dt_true_lb; MPI_Aint data_sz; if (insize == 0) goto fn_exit; /* Handle contig case quickly */ if (HANDLE_GET_KIND(datatype) == HANDLE_KIND_BUILTIN) { contig = TRUE; dt_true_lb = 0; data_sz = outcount * MPIR_Datatype_get_basic_size(datatype); } else { MPIR_Datatype *dt_ptr; MPIR_Datatype_get_ptr(datatype, dt_ptr); MPIR_Datatype_is_contig(datatype, &contig); dt_true_lb = dt_ptr->true_lb; data_sz = outcount * dt_ptr->size; } if (contig) { MPIR_Memcpy((char *) outbuf + dt_true_lb, (char *) inbuf + *position, data_sz); *position = (int) ((MPI_Aint) * position + data_sz); goto fn_exit; } /* non-contig case */ segp = MPIR_Segment_alloc(); MPIR_ERR_CHKANDJUMP1(segp == NULL, mpi_errno, MPI_ERR_OTHER, "**nomem", "**nomem %s", "MPIR_Segment_alloc"); mpi_errno = MPIR_Segment_init(outbuf, outcount, datatype, segp); MPIR_Assert(mpi_errno == MPI_SUCCESS); /* NOTE: the use of buffer values and positions in MPI_Unpack and in * MPIR_Segment_unpack are quite different. See code or docs or something. */ first = 0; last = SEGMENT_IGNORE_LAST; /* Ensure that pointer increment fits in a pointer */ MPIR_Ensure_Aint_fits_in_pointer((MPIR_VOID_PTR_CAST_TO_MPI_AINT inbuf) + (MPI_Aint) * position); MPIR_Segment_unpack(segp, first, &last, (void *) ((char *) inbuf + *position)); /* Ensure that calculation fits into an int datatype. */ MPIR_Ensure_Aint_fits_in_int((MPI_Aint) * position + last); *position = (int) ((MPI_Aint) * position + last); MPIR_Segment_free(segp); fn_exit: return mpi_errno; fn_fail: goto fn_exit; }