70 const RightColumns_ right_columns,
71 GetRightColumn_ get_right_column,
72 Output_*
const output,
75 const auto left_NR = left.
nrow();
76 const auto common_dim = left.
ncol();
80 std::fill_n(output, sanisizer::product_unsafe<std::size_t>(left_NR, right_columns), 0);
83 std::optional<std::vector<std::optional<std::vector<Output_> > > > tmp_results;
85 tmp_results.emplace(sanisizer::cast<I<
decltype(tmp_results->size())> >(options.
num_threads - 1));
88 const auto num_used =
tatami::parallelize([&](
int t, LeftIndex_ start, LeftIndex_ length) ->
void {
91 std::optional<std::vector<Output_> > tmp_output;
93 if (!do_parallel || t == 0) {
96 tmp_output.emplace(sanisizer::product<I<
decltype(tmp_output->size())> >(left_NR, right_columns));
97 outptr = tmp_output->data();
102 for (LeftIndex_ cd = 0; cd < length; ++cd) {
103 const auto ptr = ext->fetch(buffer.data());
104 for (RightColumns_ rc = 0; rc < right_columns; ++rc) {
105 const Output_ mult = get_right_column(rc)[start + cd];
106 for (LeftIndex_ lr = 0; lr < left_NR; ++lr) {
107 outptr[sanisizer::nd_offset<std::size_t>(lr, left_NR, rc)] += mult *
static_cast<Output_
>(ptr[lr]);
113 std::vector<std::vector<LeftValue_> > left_buffers;
114 std::vector<const LeftValue_*> left_ptrs;
117 left_buffers.reserve(max_block_cols);
118 for (LeftIndex_ cd = 0; cd < max_block_cols; ++cd) {
121 sanisizer::resize(left_ptrs, max_block_cols);
125 while (cd < length) {
127 for (LeftIndex_ cd_counter = 0; cd_counter < cd_num; ++cd_counter) {
128 left_ptrs[cd_counter] = ext->fetch(left_buffers[cd_counter].data());
131 RightColumns_ rc = 0;
132 while (rc < right_columns) {
133 const RightColumns_ rc_end = rc + sanisizer::min(options.
primary_block_size, right_columns - rc);
135 while (lr < left_NR) {
138 for (LeftIndex_ cd_counter = 0; cd_counter < cd_num; ++cd_counter) {
139 const auto matcol = left_ptrs[cd_counter];
140 for (
auto rc_copy = rc; rc_copy < rc_end; ++rc_copy) {
141 const Output_ mult = get_right_column(rc_copy)[start + cd + cd_counter];
142 for (
auto lr_copy = lr; lr_copy < lr_end; ++lr_copy) {
143 outptr[sanisizer::nd_offset<std::size_t>(lr_copy, left_NR, rc_copy)] += mult *
static_cast<Output_
>(matcol[lr_copy]);
156 if (do_parallel && t > 0) {
157 (*tmp_results)[t - 1] = std::move(tmp_output);
162 for (
int u = 1; u < num_used; ++u) {
163 const auto& tmp = *((*tmp_results)[u - 1]);
164 const auto N = tmp.size();
165 for (I<
decltype(N)> x = 0; x < N; ++x) {