std::mdspan


Introduction

std::mdspan is a powerful addition to the C++23 standard library that provides a multidimensional view over contiguous memory. It allows for efficient and flexible handling of multidimensional data without owning the underlying storage. This feature is particularly useful in scientific computing, image processing, and other domains that deal with multi-dimensional data structures.

Example 1: Basic Usage of std::mdspan

#include <iostream>
#include <vector>
#include <mdspan>

int main() {
    std::vector<int> data = {1, 2, 3, 4, 5, 6};

    // Create a 2x3 mdspan view over the vector
    std::mdspan<int, std::extents<std::size_t, 2, 3>> matrix(data.data());

    // Access and print elements
    for (std::size_t i = 0; i < matrix.extent(0); ++i) {
        for (std::size_t j = 0; j < matrix.extent(1); ++j) {
            std::cout << matrix[i, j] << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

Explanation

This example demonstrates the basic usage of std::mdspan: - We create a std::vector to hold our data. - We then create a 2x3 std::mdspan view over this data. - The mdspan allows us to access the data as if it were a 2D matrix. - We use nested loops to iterate over the elements and print them.

Example 2: Dynamic Extents with std::mdspan

#include <iostream>
#include <vector>
#include <mdspan>

int main() {
    std::vector<double> data(24);
    for (int i = 0; i < 24; ++i) {
        data[i] = i * 1.1;
    }

    // Create a 3D mdspan with dynamic extents
    std::mdspan<double, std::dextents<std::size_t, 3>> volume(data.data(), 2, 3, 4);

    // Access and print elements
    for (std::size_t i = 0; i < volume.extent(0); ++i) {
        for (std::size_t j = 0; j < volume.extent(1); ++j) {
            for (std::size_t k = 0; k < volume.extent(2); ++k) {
                std::cout << volume[i, j, k] << " ";
            }
            std::cout << std::endl;
        }
        std::cout << std::endl;
    }

    return 0;
}

Explanation

This example showcases the use of dynamic extents with std::mdspan: - We create a std::vector with 24 elements. - We use std::dextents to create a 3D std::mdspan with dynamic extents. - The dimensions (2x3x4) are specified at runtime. - We then access and print the elements as a 3D volume.

Example 3: Custom Layout with std::mdspan

#include <iostream>
#include <vector>
#include <mdspan>

int main() {
    std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9};

    // Create a 3x3 mdspan with column-major layout
    std::mdspan<int, std::extents<std::size_t, 3, 3>, std::layout_left> matrix(data.data());

    // Access and print elements
    for (std::size_t i = 0; i < matrix.extent(0); ++i) {
        for (std::size_t j = 0; j < matrix.extent(1); ++j) {
            std::cout << matrix[i, j] << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

Explanation

This example demonstrates the use of custom layouts with std::mdspan: - We create a 3x3 std::mdspan view over a vector of 9 elements. - We use std::layout_left to specify a column-major layout. - In column-major layout, elements in the same column are stored contiguously. - This can be useful for interoperability with libraries that expect column-major data.

Example 4: Strided std::mdspan

#include <iostream>
#include <vector>
#include <mdspan>

int main() {
    std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

    // Create a 2x2 mdspan with strides
    std::mdspan<int, std::extents<std::size_t, 2, 2>, 
                std::layout_stride> matrix(data.data(), 
                std::extents<std::size_t, 2, 2>{}, 
                std::array<std::size_t, 2>{1, 3});

    // Access and print elements
    for (std::size_t i = 0; i < matrix.extent(0); ++i) {
        for (std::size_t j = 0; j < matrix.extent(1); ++j) {
            std::cout << matrix[i, j] << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

Explanation

This example shows how to use strided std::mdspan: - We create a 2x2 std::mdspan view over a vector of 12 elements. - We use std::layout_stride to specify custom strides. - The strides {1, 3} mean that we move 1 element for each row and 3 elements for each column. - This results in a view that selects elements {1, 4, 7, 10} from the original data. - Strided views are useful for subsampling or working with non-contiguous slices of data.

Summary

std::mdspan is a versatile feature in C++23 that provides a view over multidimensional data. It offers several advantages:

  1. Non-owning view: It doesn't manage memory, allowing efficient access to existing data.
  2. Compile-time and runtime dimensionality: Supports both static and dynamic extents.
  3. Custom layouts: Allows for different memory layouts like row-major, column-major, or custom strides.
  4. Performance: Provides a zero-overhead abstraction for multidimensional data access.

These examples demonstrate the basic usage, dynamic extents, custom layouts, and strided views with std::mdspan. This feature is particularly useful in scientific computing, image processing, and other fields that work with multidimensional data structures. By providing a flexible and efficient way to work with such data, std::mdspan can significantly simplify code and improve performance in these domains.

Related

Previous Page | Course Schedule | Course Content