tatami_r
R bindings to tatami matrices
Loading...
Searching...
No Matches
UnknownMatrix.hpp
Go to the documentation of this file.
1#ifndef TATAMI_R_UNKNOWNMATRIX_HPP
2#define TATAMI_R_UNKNOWNMATRIX_HPP
3
4#include "Rcpp.h"
5#include "tatami/tatami.hpp"
6#include "sanisizer/sanisizer.hpp"
7
8#include "parallelize.hpp"
9#include "dense_extractor.hpp"
10#include "sparse_extractor.hpp"
11
12#include <vector>
13#include <memory>
14#include <string>
15#include <stdexcept>
16#include <optional>
17#include <cstddef>
18
24namespace tatami_r {
25
34 std::optional<std::size_t> maximum_cache_size;
35
42};
43
56template<typename Value_, typename Index_, typename CachedValue_ = Value_, typename CachedIndex_ = Index_>
57class UnknownMatrix : public tatami::Matrix<Value_, Index_> {
58public:
65 UnknownMatrix(Rcpp::RObject seed, const UnknownMatrixOptions& opt) :
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"])
71 {
72 // We assume the constructor only occurs on the main thread, so we
73 // won't bother locking things up. I'm also not sure that the
74 // operations in the initialization list are thread-safe.
75
76 {
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");
83 }
84
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");
89 }
90
91 // If this cast is okay, all subsequent casts from 'int' to 'Index_' will be okay.
92 // This is because all subsequent casts will involve values that are smaller than 'dims', e.g., chunk extents.
93 // For example, an ArbitraryArrayGrid is restricted by the ticks, while a RegularArrayGrid must have chunkdim <= refdim.
94 my_nrow = sanisizer::cast<Index_>(dims[0]);
95 my_ncol = sanisizer::cast<Index_>(dims[1]);
96
97 // Checking that we can safely create an Rcpp::IntegerVector without overfllow.
98 // We do it here once, so that we don't need to check in each call to consecutive_indices() or increment_indices() or whatever.
100 }
101
102 {
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");
108 }
109 my_sparse = (is_sparse[0] != 0);
110 }
111
112 {
113 tatami::resize_container_to_Index_size(my_row_chunk_map, my_nrow);
114 tatami::resize_container_to_Index_size(my_col_chunk_map, my_ncol);
115
116 const Rcpp::Function fun = my_delayed_env["chunkGrid"];
117 const Rcpp::RObject grid = fun(seed);
118
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));
128
129 // Both dense and sparse inputs are implicitly column-major, so
130 // if there isn't chunking information to the contrary, we'll
131 // favor extraction of the columns.
132 my_prefer_rows = false;
133
134 } else {
135 auto grid_cls = get_class_name(grid);
136
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");
142 }
143
144 const auto populate = [](
145 const Index_ extent,
146 const Index_ spacing,
147 std::vector<Index_>& map,
148 std::vector<Index_>& ticks
149 ) -> void {
150 if (spacing == 0) {
151 ticks.push_back(0);
152 } else {
153 ticks.reserve((extent / spacing) + (extent % spacing > 0) + 1);
154 Index_ start = 0;
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);
159 start += to_fill;
160 ticks.push_back(start);
161 }
162 }
163 };
164
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);
169
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");
175 }
176
177 const auto populate = [](
178 const Index_ extent,
179 const Rcpp::IntegerVector& ticks,
180 std::vector<Index_>& map,
181 std::vector<Index_>& new_ticks,
182 Index_& max_chunk_size
183 ) -> void {
184 if (ticks.size() != 0 && ticks[ticks.size() - 1] != static_cast<int>(extent)) {
185 throw std::runtime_error("invalid ticks returned by 'chunkGrid'");
186 }
187 new_ticks.resize(sanisizer::sum<decltype(new_ticks.size())>(ticks.size(), 1));
188 std::copy(ticks.begin(), ticks.end(), new_ticks.begin() + 1);
189
190 max_chunk_size = 0;
191 int start = 0;
193 Index_ counter = 0;
194
195 for (auto t : ticks) {
196 if (t < start) {
197 throw std::runtime_error("invalid ticks returned by 'chunkGrid'");
198 }
199 Index_ to_fill = t - start;
200 if (to_fill > max_chunk_size) {
201 max_chunk_size = to_fill;
202 }
203 std::fill_n(map.begin() + start, to_fill, counter);
204 ++counter;
205 start = t;
206 }
207 };
208
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);
213
214 } else {
215 auto ctype = get_class_name(seed);
216 throw std::runtime_error("instance of unknown class '" + grid_cls + "' returned by 'chunkGrid(<" + ctype + ">)");
217 }
218
219 // Choose the dimension that requires pulling out fewer chunks.
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;
223 }
224 }
225
226 my_require_minimum_cache = opt.require_minimum_cache;
227 if (opt.maximum_cache_size.has_value()) {
228 my_cache_size_in_bytes = *(opt.maximum_cache_size);
229 } else {
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");
234 }
235 my_cache_size_in_bytes = sanisizer::from_float<I<decltype(my_cache_size_in_bytes)> >(bsize[0]);
236 }
237 }
238
245 UnknownMatrix(Rcpp::RObject seed) : UnknownMatrix(std::move(seed), UnknownMatrixOptions()) {}
246
247private:
248 Index_ my_nrow, my_ncol;
249 bool my_sparse, my_prefer_rows;
250
251 std::vector<Index_> my_row_chunk_map, my_col_chunk_map;
252 std::vector<Index_> my_row_chunk_ticks, my_col_chunk_ticks;
253
254 // To decide how many chunks to store in the cache, we pretend the largest
255 // chunk is a good representative. This is a bit suboptimal for irregular
256 // chunks but the LruSlabCache class doesn't have a good way of dealing
257 // with this right now. The fundamental problem is that variable slabs will
258 // either (i) all reach the maximum allocation eventually, if slabs are
259 // reused, or (ii) require lots of allocations, if slabs are not reused, or
260 // (iii) require manual defragmentation, if slabs are reused in a manner
261 // that avoids inflation to the maximum allocation.
262 Index_ my_row_max_chunk_size, my_col_max_chunk_size;
263
264 std::size_t my_cache_size_in_bytes;
265 bool my_require_minimum_cache;
266
267 Rcpp::RObject my_original_seed;
268 Rcpp::Environment my_delayed_env, my_sparse_env;
269 Rcpp::Function my_dense_extractor, my_sparse_extractor;
270
271public:
272 Index_ nrow() const {
273 return my_nrow;
274 }
275
276 Index_ ncol() const {
277 return my_ncol;
278 }
279
280 bool is_sparse() const {
281 return my_sparse;
282 }
283
284 double is_sparse_proportion() const {
285 return static_cast<double>(my_sparse);
286 }
287
288 bool prefer_rows() const {
289 return my_prefer_rows;
290 }
291
292 double prefer_rows_proportion() const {
293 return static_cast<double>(my_prefer_rows);
294 }
295
296 bool uses_oracle(bool) const {
297 return true;
298 }
299
300private:
301 Index_ max_primary_chunk_length(const bool row) const {
302 return (row ? my_row_max_chunk_size : my_col_max_chunk_size);
303 }
304
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) {
308 return primary_dim;
309 } else {
310 return primary_dim / primary_chunk_length;
311 }
312 }
313
314 Index_ secondary_dim(const bool row) const {
315 return (row ? my_ncol : my_nrow);
316 }
317
318 const std::vector<Index_>& chunk_ticks(const bool row) const {
319 if (row) {
320 return my_row_chunk_ticks;
321 } else {
322 return my_col_chunk_ticks;
323 }
324 }
325
326 const std::vector<Index_>& chunk_map(const bool row) const {
327 if (row) {
328 return my_row_chunk_map;
329 } else {
330 return my_col_chunk_map;
331 }
332 }
333
334 /********************
335 *** Myopic dense ***
336 ********************/
337private:
338 template<
339 bool oracle_,
340 template <bool, bool, typename, typename, typename> class FromDense_,
341 template <bool, bool, typename, typename, typename, typename> class FromSparse_,
342 typename ... Args_
343 >
344 std::unique_ptr<tatami::DenseExtractor<oracle_, Value_, Index_> > populate_dense_internal(
345 const bool row,
346 const Index_ non_target_length,
348 Args_&& ... args
349 ) const {
350 std::unique_ptr<tatami::DenseExtractor<oracle_, Value_, Index_> > output;
351
352 const Index_ max_target_chunk_length = max_primary_chunk_length(row);
353 tatami_chunked::SlabCacheStats<Index_> stats(
354 /* target length = */ max_target_chunk_length,
355 /* non_target_length = */ non_target_length,
356 /* target_num_slabs = */ primary_num_chunks(row, max_target_chunk_length),
357 /* cache_size_in_bytes = */ my_cache_size_in_bytes,
358 /* element_size = */ sizeof(CachedValue_),
359 /* require_minimum_cache = */ my_require_minimum_cache
360 );
361
362 const auto& map = chunk_map(row);
363 const auto& ticks = chunk_ticks(row);
364 const bool solo = (stats.max_slabs_in_cache == 0);
365
366#ifdef TATAMI_R_PARALLELIZE_UNKNOWN
367 // This involves some Rcpp initializations, so we lock it just in case.
368 auto& mexec = executor();
369 mexec.run([&]() -> void {
370#endif
371
372 if (!my_sparse) {
373 if (solo) {
374 output.reset(
375 new FromDense_<true, oracle_, Value_, Index_, CachedValue_>(
376 my_original_seed,
377 my_dense_extractor,
378 row,
379 std::move(oracle),
380 std::forward<Args_>(args)...,
381 ticks,
382 map,
383 stats
384 )
385 );
386
387 } else {
388 output.reset(
389 new FromDense_<false, oracle_, Value_, Index_, CachedValue_>(
390 my_original_seed,
391 my_dense_extractor,
392 row,
393 std::move(oracle),
394 std::forward<Args_>(args)...,
395 ticks,
396 map,
397 stats
398 )
399 );
400 }
401
402 } else {
403 if (solo) {
404 output.reset(
405 new FromSparse_<true, oracle_, Value_, Index_, CachedValue_, CachedIndex_>(
406 my_original_seed,
407 my_sparse_extractor,
408 row,
409 std::move(oracle),
410 std::forward<Args_>(args)...,
411 max_target_chunk_length,
412 ticks,
413 map,
414 stats
415 )
416 );
417
418 } else {
419 output.reset(
420 new FromSparse_<false, oracle_, Value_, Index_, CachedValue_, CachedIndex_>(
421 my_original_seed,
422 my_sparse_extractor,
423 row,
424 std::move(oracle),
425 std::forward<Args_>(args)...,
426 max_target_chunk_length,
427 ticks,
428 map,
429 stats
430 )
431 );
432 }
433 }
434
435#ifdef TATAMI_R_PARALLELIZE_UNKNOWN
436 });
437#endif
438
439 return output;
440 }
441
442 template<bool oracle_>
443 std::unique_ptr<tatami::DenseExtractor<oracle_, Value_, Index_> > populate_dense(
444 const bool row,
446 const tatami::Options&
447 ) const {
448 const Index_ non_target_dim = secondary_dim(row);
449 return populate_dense_internal<oracle_, DenseFull, DensifiedSparseFull>(
450 row,
451 non_target_dim,
452 std::move(ora),
453 non_target_dim
454 );
455 }
456
457 template<bool oracle_>
458 std::unique_ptr<tatami::DenseExtractor<oracle_, Value_, Index_> > populate_dense(
459 const bool row,
461 const Index_ block_start,
462 const Index_ block_length,
463 const tatami::Options&
464 ) const {
465 return populate_dense_internal<oracle_, DenseBlock, DensifiedSparseBlock>(
466 row,
467 block_length,
468 std::move(ora),
469 block_start,
470 block_length
471 );
472 }
473
474 template<bool oracle_>
475 std::unique_ptr<tatami::DenseExtractor<oracle_, Value_, Index_> > populate_dense(
476 const bool row,
478 tatami::VectorPtr<Index_> indices_ptr,
479 const tatami::Options&
480 ) const {
481 const Index_ nidx = indices_ptr->size();
482 return populate_dense_internal<oracle_, DenseIndexed, DensifiedSparseIndexed>(
483 row,
484 nidx,
485 std::move(ora),
486 std::move(indices_ptr)
487 );
488 }
489
490public:
491 std::unique_ptr<tatami::MyopicDenseExtractor<Value_, Index_> > dense(
492 const bool row,
493 const tatami::Options& opt
494 ) const {
495 return populate_dense<false>(row, false, opt);
496 }
497
498 std::unique_ptr<tatami::MyopicDenseExtractor<Value_, Index_> > dense(
499 const bool row,
500 const Index_ block_start,
501 const Index_ block_length,
502 const tatami::Options& opt
503 ) const {
504 return populate_dense<false>(row, false, block_start, block_length, opt);
505 }
506
507 std::unique_ptr<tatami::MyopicDenseExtractor<Value_, Index_> > dense(
508 const bool row,
509 tatami::VectorPtr<Index_> indices_ptr,
510 const tatami::Options& opt
511 ) const {
512 return populate_dense<false>(row, false, std::move(indices_ptr), opt);
513 }
514
515 /**********************
516 *** Oracular dense ***
517 **********************/
518public:
519 std::unique_ptr<tatami::OracularDenseExtractor<Value_, Index_> > dense(
520 const bool row,
521 std::shared_ptr<const tatami::Oracle<Index_> > ora,
522 const tatami::Options& opt
523 ) const {
524 return populate_dense<true>(row, std::move(ora), opt);
525 }
526
527 std::unique_ptr<tatami::OracularDenseExtractor<Value_, Index_> > dense(
528 const bool row,
529 std::shared_ptr<const tatami::Oracle<Index_> > ora,
530 const Index_ block_start,
531 const Index_ block_length,
532 const tatami::Options& opt
533 ) const {
534 return populate_dense<true>(row, std::move(ora), block_start, block_length, opt);
535 }
536
537 std::unique_ptr<tatami::OracularDenseExtractor<Value_, Index_> > dense(
538 const bool row,
539 std::shared_ptr<const tatami::Oracle<Index_> > ora,
540 tatami::VectorPtr<Index_> indices_ptr,
541 const tatami::Options& opt
542 ) const {
543 return populate_dense<true>(row, std::move(ora), std::move(indices_ptr), opt);
544 }
545
546 /*********************
547 *** Myopic sparse ***
548 *********************/
549public:
550 template<
551 bool oracle_,
552 template<bool, bool, typename, typename, typename, typename> class FromSparse_,
553 typename ... Args_
554 >
555 std::unique_ptr<tatami::SparseExtractor<oracle_, Value_, Index_> > populate_sparse_internal(
556 const bool row,
557 const Index_ non_target_length,
559 const tatami::Options& opt,
560 Args_&& ... args
561 ) const {
562 const Index_ max_target_chunk_length = max_primary_chunk_length(row);
563 tatami_chunked::SlabCacheStats<Index_> stats(
564 /* target_length = */ max_target_chunk_length,
565 /* non_target_length = */ non_target_length,
566 /* target_num_slabs = */ primary_num_chunks(row, max_target_chunk_length),
567 /* cache_size_in_bytes = */ my_cache_size_in_bytes,
568 /* element_size = */ (opt.sparse_extract_index ? sizeof(CachedIndex_) : 0) + (opt.sparse_extract_value ? sizeof(CachedValue_) : 0),
569 /* require_minimum_cache = */ my_require_minimum_cache
570 );
571
572 const auto& map = chunk_map(row);
573 const auto& ticks = chunk_ticks(row);
574 const bool needs_value = opt.sparse_extract_value;
575 const bool needs_index = opt.sparse_extract_index;
576 const bool solo = stats.max_slabs_in_cache == 0;
577
578 std::unique_ptr<tatami::SparseExtractor<oracle_, Value_, Index_> > output;
579
580#ifdef TATAMI_R_PARALLELIZE_UNKNOWN
581 // This involves some Rcpp initializations, so we lock it just in case.
582 auto& mexec = executor();
583 mexec.run([&]() -> void {
584#endif
585
586 if (solo) {
587 output.reset(
588 new FromSparse_<true, oracle_, Value_, Index_, CachedValue_, CachedIndex_>(
589 my_original_seed,
590 my_sparse_extractor,
591 row,
592 std::move(oracle),
593 std::forward<Args_>(args)...,
594 max_target_chunk_length,
595 ticks,
596 map,
597 stats,
598 needs_value,
599 needs_index
600 )
601 );
602
603 } else {
604 output.reset(
605 new FromSparse_<false, oracle_, Value_, Index_, CachedValue_, CachedIndex_>(
606 my_original_seed,
607 my_sparse_extractor,
608 row,
609 std::move(oracle),
610 std::forward<Args_>(args)...,
611 max_target_chunk_length,
612 ticks,
613 map,
614 stats,
615 needs_value,
616 needs_index
617 )
618 );
619 }
620
621#ifdef TATAMI_R_PARALLELIZE_UNKNOWN
622 });
623#endif
624
625 return output;
626 }
627
628 template<bool oracle_>
629 std::unique_ptr<tatami::SparseExtractor<oracle_, Value_, Index_> > populate_sparse(
630 const bool row,
632 const tatami::Options& opt
633 ) const {
634 const Index_ non_target_dim = secondary_dim(row);
635 return populate_sparse_internal<oracle_, SparseFull>(
636 row,
637 non_target_dim,
638 std::move(ora),
639 opt,
640 non_target_dim
641 );
642 }
643
644 template<bool oracle_>
645 std::unique_ptr<tatami::SparseExtractor<oracle_, Value_, Index_> > populate_sparse(
646 const bool row,
648 const Index_ block_start,
649 const Index_ block_length,
650 const tatami::Options& opt
651 ) const {
652 return populate_sparse_internal<oracle_, SparseBlock>(
653 row,
654 block_length,
655 std::move(ora),
656 opt,
657 block_start,
658 block_length
659 );
660 }
661
662 template<bool oracle_>
663 std::unique_ptr<tatami::SparseExtractor<oracle_, Value_, Index_> > populate_sparse(
664 const bool row,
666 tatami::VectorPtr<Index_> indices_ptr,
667 const tatami::Options& opt
668 ) const {
669 return populate_sparse_internal<oracle_, SparseIndexed>(
670 row,
671 indices_ptr->size(),
672 std::move(ora),
673 opt,
674 std::move(indices_ptr)
675 );
676 }
677
678public:
679 std::unique_ptr<tatami::MyopicSparseExtractor<Value_, Index_> > sparse(
680 const bool row,
681 const tatami::Options& opt
682 ) const {
683 if (!my_sparse) {
684 return std::make_unique<tatami::FullSparsifiedWrapper<false, Value_, Index_> >(
685 dense(row, opt),
686 secondary_dim(row),
687 opt
688 );
689 } else {
690 return populate_sparse<false>(row, false, opt);
691 }
692 }
693
694 std::unique_ptr<tatami::MyopicSparseExtractor<Value_, Index_> > sparse(
695 const bool row,
696 const Index_ block_start,
697 const Index_ block_length,
698 const tatami::Options& opt
699 ) const {
700 if (!my_sparse) {
701 return std::make_unique<tatami::BlockSparsifiedWrapper<false, Value_, Index_> >(
702 dense(row, block_start, block_length, opt),
703 block_start,
704 block_length,
705 opt
706 );
707 } else {
708 return populate_sparse<false>(row, false, block_start, block_length, opt);
709 }
710 }
711
712 std::unique_ptr<tatami::MyopicSparseExtractor<Value_, Index_> > sparse(
713 const bool row,
714 tatami::VectorPtr<Index_> indices_ptr,
715 const tatami::Options& opt
716 ) const {
717 if (!my_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),
722 opt
723 );
724 } else {
725 return populate_sparse<false>(row, false, std::move(indices_ptr), opt);
726 }
727 }
728
729 /**********************
730 *** Oracular sparse ***
731 **********************/
732public:
733 std::unique_ptr<tatami::OracularSparseExtractor<Value_, Index_> > sparse(
734 const bool row,
735 std::shared_ptr<const tatami::Oracle<Index_> > ora,
736 const tatami::Options& opt
737 ) const {
738 if (!my_sparse) {
739 return std::make_unique<tatami::FullSparsifiedWrapper<true, Value_, Index_> >(
740 dense(row, std::move(ora), opt),
741 secondary_dim(row),
742 opt
743 );
744 } else {
745 return populate_sparse<true>(row, std::move(ora), opt);
746 }
747 }
748
749 std::unique_ptr<tatami::OracularSparseExtractor<Value_, Index_> > sparse(
750 const bool row,
751 std::shared_ptr<const tatami::Oracle<Index_> > ora,
752 const Index_ block_start,
753 const Index_ block_length,
754 const tatami::Options& opt
755 ) const {
756 if (!my_sparse) {
757 return std::make_unique<tatami::BlockSparsifiedWrapper<true, Value_, Index_> >(
758 dense(row, std::move(ora), block_start, block_length, opt),
759 block_start,
760 block_length,
761 opt
762 );
763 } else {
764 return populate_sparse<true>(row, std::move(ora), block_start, block_length, opt);
765 }
766 }
767
768 std::unique_ptr<tatami::OracularSparseExtractor<Value_, Index_> > sparse(
769 const bool row,
770 std::shared_ptr<const tatami::Oracle<Index_> > ora,
771 tatami::VectorPtr<Index_> indices_ptr,
772 const tatami::Options& opt
773 ) const {
774 if (!my_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),
779 opt
780 );
781 } else {
782 return populate_sparse<true>(row, std::move(ora), std::move(indices_ptr), opt);
783 }
784 }
785};
786
787}
788
789#endif
Unknown matrix-like object in R.
Definition UnknownMatrix.hpp:57
UnknownMatrix(Rcpp::RObject seed, const UnknownMatrixOptions &opt)
Definition UnknownMatrix.hpp:65
UnknownMatrix(Rcpp::RObject seed)
Definition UnknownMatrix.hpp:245
tatami bindings for arbitrary R matrices.
manticore::Executor & executor()
Definition parallelize.hpp:46
std::shared_ptr< const std::vector< Index_ > > VectorPtr
Index_ can_cast_Index_to_container_size(const Index_ x)
void resize_container_to_Index_size(Container_ &container, const Index_ x, Args_ &&... args)
typename std::conditional< oracle_, std::shared_ptr< const Oracle< Index_ > >, bool >::type MaybeOracle
Safely parallelize for unknown matrices.
bool sparse_extract_index
bool sparse_extract_value
Options for data extraction from an UnknownMatrix.
Definition UnknownMatrix.hpp:29
bool require_minimum_cache
Definition UnknownMatrix.hpp:41
std::optional< std::size_t > maximum_cache_size
Definition UnknownMatrix.hpp:34