
/*
Klaudia Niedziałkowska 331133

std::mdspan to widok tablicy wielowymiarowej, który przyporządkowuje indeks
wielowymiarowy do elementu tablicy.

Typ zdeklarowany jest w następujący sposób:
template<
    class T,
    class Extents,
    class LayoutPolicy = std::layout_right,
    class AccessorPolicy = std::default_accessor<T>
> class mdspan;


Jest on pochodną wprowadzonego w C++ 20 std::span, który umożliwia czytanie
ciągłej tablicy. Np. mając obiekt typu std::vector można nad nim utworzyć obiekt
typu span i wykonywać operacje  bez kopiowania danych.

Różnicą jednak w std::mdspan jest że tablica bazowa nie musi być
ciągła ani nawet w ogóle istnieć w pamięci. Zasady przyporządkowania i
dostępu do elementów można konfigurować.


Parametry szablonu:
- T - typ elementu, nie jest typem klasy abstrakcyjnej, ani typem tablicy
- Extents - liczba wymiarów, ich rozmiary (określa też te wymiary, które są
    znane w czasie kompilacji) musi być typem std::extents
- LayoutPolicy (opcjonalny)
    LayoutPolicy określa sposób przekształcania indeksu wielowymiarowego na
     bazowy indeks jednowymiarowy:
    1. layout_right - kolejność wierszowa, indeks znajdujący się najbardziej po
prawej stronie zapewnia dostęp o kroku 1 do pamięci bazowej;
    2. layout_left - kolejność kolumnowza, ndeks znajdujący się najbardziej po
lewej stronie zapewnia dostęp o kroku 1 do pamięci bazowej;
    3. layout_stride - mapowanie układu krokami zdefiniowanymi przez
użytkownika;
- AccessorPolicy (opcjonalny) - określa sposób konwersji podstawowego indeksu 1D
na odwołanie do T. Decyduje o typie zwracanym, sposobie odczytu i lokalizacji
danych. Umożliwa on np. Sprawdzanie zakresu, stosowanie przekształceń (np.
skalowanie, przesunięcie lub konwersje typów), wdrażanie dostępu tylko do
odczytu lub tylko do zapisu.
*/

#include <cstddef>
#include <mdspan>
#include <print>
#include <vector>

int main() {
  std::vector v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};

  // Reprezentacja danych jako 4 wiersze po 4 elementy
  auto example2D = std::mdspan(v.data(), 4, 4);
  std::print(
      "Example2D sizeof: {}, liczba wymiarów: {}, wymiar 0: {}, wymiar 1: {}\n",
      sizeof(example2D), example2D.rank(), example2D.extent(0),
      example2D.extent(1));

  // Reprezentacja danych jako macierz 3D
  auto example3D = std::mdspan(v.data(), 2, 4, 2);
  std::print(
      "Example3D sizeof: {}, liczba wymiarów: {}, wymiar 0: {}, wymiar 1: {}, "
      "wymiar 2: {}\n",
      sizeof(example3D), example3D.rank(), example3D.extent(0),
      example3D.extent(1), example3D.extent(2));

  // Zapisywanie do macierzy 2D
  for (std::size_t i = 0; i != example2D.extent(0); i++)
    for (std::size_t j = 0; j != example2D.extent(1); j++)
      example2D[i, j] = i * 100 + j;

  // Odczytywanie tablicy 2D
  std::println();
  std::print("Odczytywanie macierzy 2D:\n");
  for (size_t i = 0; i < example2D.extent(0); ++i) {
    for (size_t j = 0; j < example2D.extent(1); ++j)
      std::print("{} ", example2D[i, j]);
    std::println();
  }

  std::println();
  // Odczytywanie macierzy 3D
  std::print("Odczytytwanie macierzy 3D po zapisie do tablicy 2D:\n");
  for (std::size_t i = 0; i != example3D.extent(0); i++) {
    std::println("slice @ i = {}", i);
    for (std::size_t j = 0; j != example3D.extent(1); j++) {
      for (std::size_t k = 0; k != example3D.extent(2); k++)
        std::print("{} ", example3D[i, j, k]);
      std::println("");
    }
  }

  // Tworzenie tablicy z layout_stride
  std::println();
  std::print("Tablica z layout_stride:\n");
  std::array<std::size_t, 2> strides{4, 2};  // wiersz skacze o 4 a kolumna o 2
  auto layout =
      std::layout_stride::mapping(std::extents<std::size_t, 2, 2>{}, strides);

  auto ms_stride =
      std::mdspan<int, std::extents<std::size_t, 2, 2>, std::layout_stride>(
          v.data(), layout);

  for (std::size_t i = 0; i < ms_stride.extent(0); ++i) {
    for (std::size_t j = 0; j < ms_stride.extent(1); ++j) {
      std::print("{} ", ms_stride[i, j]);
    }
    std::println();
  }
}

/*
Źródła:
https://en.cppreference.com/cpp/container/mdspan
https://en.cppreference.com/cpp/named_req/AccessorPolicy
https://en.cppreference.com/cpp/container/span
*/