66 my_original_seed(seed),
67 my_delayed_env(Rcpp::Environment::namespace_env(
"DelayedArray")),
68 my_sparse_env(Rcpp::Environment::namespace_env(
"SparseArray")),
69 my_dense_extractor(my_delayed_env[
"extract_array"]),
70 my_sparse_extractor(my_sparse_env[
"extract_sparse_array"])
77 const auto base = Rcpp::Environment::base_env();
78 const Rcpp::Function fun = base[
"dim"];
79 const Rcpp::RObject output = fun(seed);
80 if (output.sexp_type() != INTSXP) {
81 auto ctype = get_class_name(my_original_seed);
82 throw std::runtime_error(
"'dim(<" + ctype +
">)' should return an integer vector");
85 const Rcpp::IntegerVector dims(output);
86 if (dims.size() != 2 || dims[0] < 0 || dims[1] < 0) {
87 auto ctype = get_class_name(my_original_seed);
88 throw std::runtime_error(
"'dim(<" + ctype +
">)' should contain two non-negative integers");
94 my_nrow = sanisizer::cast<Index_>(dims[0]);
95 my_ncol = sanisizer::cast<Index_>(dims[1]);
103 const Rcpp::Function fun = my_delayed_env[
"is_sparse"];
104 const Rcpp::LogicalVector is_sparse = fun(seed);
105 if (is_sparse.size() != 1) {
106 auto ctype = get_class_name(my_original_seed);
107 throw std::runtime_error(
"'is_sparse(<" + ctype +
">)' should return a logical vector of length 1");
109 my_sparse = (is_sparse[0] != 0);
116 const Rcpp::Function fun = my_delayed_env[
"chunkGrid"];
117 const Rcpp::RObject grid = fun(seed);
119 if (grid == R_NilValue) {
120 my_row_max_chunk_size = 1;
121 my_col_max_chunk_size = 1;
122 std::iota(my_row_chunk_map.begin(), my_row_chunk_map.end(),
static_cast<Index_
>(0));
123 std::iota(my_col_chunk_map.begin(), my_col_chunk_map.end(),
static_cast<Index_
>(0));
124 my_row_chunk_ticks.resize(sanisizer::sum<
decltype(my_row_chunk_ticks.size())>(my_nrow, 1));
125 std::iota(my_row_chunk_ticks.begin(), my_row_chunk_ticks.end(),
static_cast<Index_
>(0));
126 my_col_chunk_ticks.resize(sanisizer::sum<
decltype(my_col_chunk_ticks.size())>(my_ncol, 1));
127 std::iota(my_col_chunk_ticks.begin(), my_col_chunk_ticks.end(),
static_cast<Index_
>(0));
132 my_prefer_rows =
false;
135 auto grid_cls = get_class_name(grid);
137 if (grid_cls ==
"RegularArrayGrid") {
138 const Rcpp::IntegerVector spacings(Rcpp::RObject(grid.slot(
"spacings")));
139 if (spacings.size() != 2) {
140 auto ctype = get_class_name(seed);
141 throw std::runtime_error(
"'chunkGrid(<" + ctype +
">)@spacings' should be an integer vector of length 2 with non-negative values");
144 const auto populate = [](
146 const Index_ spacing,
147 std::vector<Index_>& map,
148 std::vector<Index_>& ticks
153 ticks.reserve((extent / spacing) + (extent % spacing > 0) + 1);
155 ticks.push_back(start);
156 while (start != extent) {
157 auto to_fill = std::min(spacing, extent - start);
158 std::fill_n(map.begin() + start, to_fill, ticks.size() - 1);
160 ticks.push_back(start);
165 my_row_max_chunk_size = spacings[0];
166 populate(my_nrow, my_row_max_chunk_size, my_row_chunk_map, my_row_chunk_ticks);
167 my_col_max_chunk_size = spacings[1];
168 populate(my_ncol, my_col_max_chunk_size, my_col_chunk_map, my_col_chunk_ticks);
170 }
else if (grid_cls ==
"ArbitraryArrayGrid") {
171 const Rcpp::List ticks(Rcpp::RObject(grid.slot(
"tickmarks")));
172 if (ticks.size() != 2) {
173 auto ctype = get_class_name(seed);
174 throw std::runtime_error(
"'chunkGrid(<" + ctype +
">)@tickmarks' should return a list of length 2");
177 const auto populate = [](
179 const Rcpp::IntegerVector& ticks,
180 std::vector<Index_>& map,
181 std::vector<Index_>& new_ticks,
182 Index_& max_chunk_size
184 if (ticks.size() != 0 && ticks[ticks.size() - 1] !=
static_cast<int>(extent)) {
185 throw std::runtime_error(
"invalid ticks returned by 'chunkGrid'");
187 new_ticks.resize(sanisizer::sum<
decltype(new_ticks.size())>(ticks.size(), 1));
188 std::copy(ticks.begin(), ticks.end(), new_ticks.begin() + 1);
195 for (
auto t : ticks) {
197 throw std::runtime_error(
"invalid ticks returned by 'chunkGrid'");
199 Index_ to_fill = t - start;
200 if (to_fill > max_chunk_size) {
201 max_chunk_size = to_fill;
203 std::fill_n(map.begin() + start, to_fill, counter);
209 Rcpp::IntegerVector first(ticks[0]);
210 populate(my_nrow, first, my_row_chunk_map, my_row_chunk_ticks, my_row_max_chunk_size);
211 Rcpp::IntegerVector second(ticks[1]);
212 populate(my_ncol, second, my_col_chunk_map, my_col_chunk_ticks, my_col_max_chunk_size);
215 auto ctype = get_class_name(seed);
216 throw std::runtime_error(
"instance of unknown class '" + grid_cls +
"' returned by 'chunkGrid(<" + ctype +
">)");
220 const auto chunks_per_row = my_col_chunk_ticks.size() - 1;
221 const auto chunks_per_col = my_row_chunk_ticks.size() - 1;
222 my_prefer_rows = chunks_per_row <= chunks_per_col;
228 my_cache_size_in_bytes = *(opt.maximum_cache_size);
230 Rcpp::Function fun = my_delayed_env[
"getAutoBlockSize"];
231 Rcpp::NumericVector bsize = fun();
232 if (bsize.size() != 1 || bsize[0] < 0) {
233 throw std::runtime_error(
"'getAutoBlockSize()' should return a non-negative number of bytes");
235 my_cache_size_in_bytes = sanisizer::from_float<I<
decltype(my_cache_size_in_bytes)> >(bsize[0]);
248 Index_ my_nrow, my_ncol;
249 bool my_sparse, my_prefer_rows;
251 std::vector<Index_> my_row_chunk_map, my_col_chunk_map;
252 std::vector<Index_> my_row_chunk_ticks, my_col_chunk_ticks;
262 Index_ my_row_max_chunk_size, my_col_max_chunk_size;
264 std::size_t my_cache_size_in_bytes;
265 bool my_require_minimum_cache;
267 Rcpp::RObject my_original_seed;
268 Rcpp::Environment my_delayed_env, my_sparse_env;
269 Rcpp::Function my_dense_extractor, my_sparse_extractor;
272 Index_ nrow()
const {
276 Index_ ncol()
const {
280 bool is_sparse()
const {
284 double is_sparse_proportion()
const {
285 return static_cast<double>(my_sparse);
288 bool prefer_rows()
const {
289 return my_prefer_rows;
292 double prefer_rows_proportion()
const {
293 return static_cast<double>(my_prefer_rows);
296 bool uses_oracle(
bool)
const {
301 Index_ max_primary_chunk_length(
const bool row)
const {
302 return (row ? my_row_max_chunk_size : my_col_max_chunk_size);
305 Index_ primary_num_chunks(
const bool row,
const Index_ primary_chunk_length)
const {
306 auto primary_dim = (row ? my_nrow : my_ncol);
307 if (primary_chunk_length == 0) {
310 return primary_dim / primary_chunk_length;
314 Index_ secondary_dim(
const bool row)
const {
315 return (row ? my_ncol : my_nrow);
318 const std::vector<Index_>& chunk_ticks(
const bool row)
const {
320 return my_row_chunk_ticks;
322 return my_col_chunk_ticks;
326 const std::vector<Index_>& chunk_map(
const bool row)
const {
328 return my_row_chunk_map;
330 return my_col_chunk_map;
340 template <
bool,
bool,
typename,
typename,
typename>
class FromDense_,
341 template <
bool,
bool,
typename,
typename,
typename,
typename>
class FromSparse_,
344 std::unique_ptr<tatami::DenseExtractor<oracle_, Value_, Index_> > populate_dense_internal(
346 const Index_ non_target_length,
350 std::unique_ptr<tatami::DenseExtractor<oracle_, Value_, Index_> > output;
352 const Index_ max_target_chunk_length = max_primary_chunk_length(row);
353 tatami_chunked::SlabCacheStats<Index_> stats(
354 max_target_chunk_length,
356 primary_num_chunks(row, max_target_chunk_length),
357 my_cache_size_in_bytes,
358 sizeof(CachedValue_),
359 my_require_minimum_cache
362 const auto& map = chunk_map(row);
363 const auto& ticks = chunk_ticks(row);
364 const bool solo = (stats.max_slabs_in_cache == 0);
366#ifdef TATAMI_R_PARALLELIZE_UNKNOWN
369 mexec.run([&]() ->
void {
375 new FromDense_<true, oracle_, Value_, Index_, CachedValue_>(
380 std::forward<Args_>(args)...,
389 new FromDense_<false, oracle_, Value_, Index_, CachedValue_>(
394 std::forward<Args_>(args)...,
405 new FromSparse_<true, oracle_, Value_, Index_, CachedValue_, CachedIndex_>(
410 std::forward<Args_>(args)...,
411 max_target_chunk_length,
420 new FromSparse_<false, oracle_, Value_, Index_, CachedValue_, CachedIndex_>(
425 std::forward<Args_>(args)...,
426 max_target_chunk_length,
435#ifdef TATAMI_R_PARALLELIZE_UNKNOWN
442 template<
bool oracle_>
443 std::unique_ptr<tatami::DenseExtractor<oracle_, Value_, Index_> > populate_dense(
448 const Index_ non_target_dim = secondary_dim(row);
449 return populate_dense_internal<oracle_, DenseFull, DensifiedSparseFull>(
457 template<
bool oracle_>
458 std::unique_ptr<tatami::DenseExtractor<oracle_, Value_, Index_> > populate_dense(
461 const Index_ block_start,
462 const Index_ block_length,
465 return populate_dense_internal<oracle_, DenseBlock, DensifiedSparseBlock>(
474 template<
bool oracle_>
475 std::unique_ptr<tatami::DenseExtractor<oracle_, Value_, Index_> > populate_dense(
481 const Index_ nidx = indices_ptr->size();
482 return populate_dense_internal<oracle_, DenseIndexed, DensifiedSparseIndexed>(
486 std::move(indices_ptr)
491 std::unique_ptr<tatami::MyopicDenseExtractor<Value_, Index_> > dense(
495 return populate_dense<false>(row,
false, opt);
498 std::unique_ptr<tatami::MyopicDenseExtractor<Value_, Index_> > dense(
500 const Index_ block_start,
501 const Index_ block_length,
504 return populate_dense<false>(row,
false, block_start, block_length, opt);
507 std::unique_ptr<tatami::MyopicDenseExtractor<Value_, Index_> > dense(
512 return populate_dense<false>(row,
false, std::move(indices_ptr), opt);
519 std::unique_ptr<tatami::OracularDenseExtractor<Value_, Index_> > dense(
524 return populate_dense<true>(row, std::move(ora), opt);
527 std::unique_ptr<tatami::OracularDenseExtractor<Value_, Index_> > dense(
530 const Index_ block_start,
531 const Index_ block_length,
534 return populate_dense<true>(row, std::move(ora), block_start, block_length, opt);
537 std::unique_ptr<tatami::OracularDenseExtractor<Value_, Index_> > dense(
543 return populate_dense<true>(row, std::move(ora), std::move(indices_ptr), opt);
552 template<
bool,
bool,
typename,
typename,
typename,
typename>
class FromSparse_,
555 std::unique_ptr<tatami::SparseExtractor<oracle_, Value_, Index_> > populate_sparse_internal(
557 const Index_ non_target_length,
562 const Index_ max_target_chunk_length = max_primary_chunk_length(row);
563 tatami_chunked::SlabCacheStats<Index_> stats(
564 max_target_chunk_length,
566 primary_num_chunks(row, max_target_chunk_length),
567 my_cache_size_in_bytes,
569 my_require_minimum_cache
572 const auto& map = chunk_map(row);
573 const auto& ticks = chunk_ticks(row);
576 const bool solo = stats.max_slabs_in_cache == 0;
578 std::unique_ptr<tatami::SparseExtractor<oracle_, Value_, Index_> > output;
580#ifdef TATAMI_R_PARALLELIZE_UNKNOWN
583 mexec.run([&]() ->
void {
588 new FromSparse_<true, oracle_, Value_, Index_, CachedValue_, CachedIndex_>(
593 std::forward<Args_>(args)...,
594 max_target_chunk_length,
605 new FromSparse_<false, oracle_, Value_, Index_, CachedValue_, CachedIndex_>(
610 std::forward<Args_>(args)...,
611 max_target_chunk_length,
621#ifdef TATAMI_R_PARALLELIZE_UNKNOWN
628 template<
bool oracle_>
629 std::unique_ptr<tatami::SparseExtractor<oracle_, Value_, Index_> > populate_sparse(
634 const Index_ non_target_dim = secondary_dim(row);
635 return populate_sparse_internal<oracle_, SparseFull>(
644 template<
bool oracle_>
645 std::unique_ptr<tatami::SparseExtractor<oracle_, Value_, Index_> > populate_sparse(
648 const Index_ block_start,
649 const Index_ block_length,
652 return populate_sparse_internal<oracle_, SparseBlock>(
662 template<
bool oracle_>
663 std::unique_ptr<tatami::SparseExtractor<oracle_, Value_, Index_> > populate_sparse(
669 return populate_sparse_internal<oracle_, SparseIndexed>(
674 std::move(indices_ptr)
679 std::unique_ptr<tatami::MyopicSparseExtractor<Value_, Index_> > sparse(
684 return std::make_unique<tatami::FullSparsifiedWrapper<false, Value_, Index_> >(
690 return populate_sparse<false>(row,
false, opt);
694 std::unique_ptr<tatami::MyopicSparseExtractor<Value_, Index_> > sparse(
696 const Index_ block_start,
697 const Index_ block_length,
701 return std::make_unique<tatami::BlockSparsifiedWrapper<false, Value_, Index_> >(
702 dense(row, block_start, block_length, opt),
708 return populate_sparse<false>(row,
false, block_start, block_length, opt);
712 std::unique_ptr<tatami::MyopicSparseExtractor<Value_, Index_> > sparse(
718 auto index_copy = indices_ptr;
719 return std::make_unique<tatami::IndexSparsifiedWrapper<false, Value_, Index_> >(
720 dense(row, std::move(indices_ptr), opt),
721 std::move(index_copy),
725 return populate_sparse<false>(row,
false, std::move(indices_ptr), opt);
733 std::unique_ptr<tatami::OracularSparseExtractor<Value_, Index_> > sparse(
739 return std::make_unique<tatami::FullSparsifiedWrapper<true, Value_, Index_> >(
740 dense(row, std::move(ora), opt),
745 return populate_sparse<true>(row, std::move(ora), opt);
749 std::unique_ptr<tatami::OracularSparseExtractor<Value_, Index_> > sparse(
752 const Index_ block_start,
753 const Index_ block_length,
757 return std::make_unique<tatami::BlockSparsifiedWrapper<true, Value_, Index_> >(
758 dense(row, std::move(ora), block_start, block_length, opt),
764 return populate_sparse<true>(row, std::move(ora), block_start, block_length, opt);
768 std::unique_ptr<tatami::OracularSparseExtractor<Value_, Index_> > sparse(
775 auto index_copy = indices_ptr;
776 return std::make_unique<tatami::IndexSparsifiedWrapper<true, Value_, Index_> >(
777 dense(row, std::move(ora), std::move(indices_ptr), opt),
778 std::move(index_copy),
782 return populate_sparse<true>(row, std::move(ora), std::move(indices_ptr), opt);