// File: dsharlet[P]array/test/readme.cpp
// Function: nda::test_readme_body()
TEST(readme) {
  // Define a 3 dimensional shape, and an array of this shape.
  using my_3d_shape_type = shape<dim<>, dim<>, dim<>>;
  constexpr int width = 16;
  constexpr int height = 10;
  constexpr int depth = 3;
  my_3d_shape_type my_3d_shape(width, height, depth);
  array<int, my_3d_shape_type> my_array(my_3d_shape);

  // Access elements of this array.
  for (int z = 0; z < depth; z++) {
    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {
        my_array(x, y, z) = 5;
      }
    }
  }

  // Use for_each_value helper to access this array.
  my_array.for_each_value([](int& value) { value = 5; });

  // Use for_all_indices/for_each_index helper to access this array.
  for_all_indices(my_3d_shape, [&](int x, int y, int z) { my_array(x, y, z) = 5; });
  for_each_index(my_3d_shape, [&](my_3d_shape_type::index_type i) { my_array[i] = 5; });

  // This shows the default iteration order of for_all_indices.
  my_3d_shape_type my_shape(2, 2, 2);
  for_all_indices(
      my_shape, [](int x, int y, int z) { std::cout << x << ", " << y << ", " << z << std::endl; });
  // Output:
  // 0, 0, 0
  // 1, 0, 0
  // 0, 1, 0
  // 1, 1, 0
  // 0, 0, 1
  // 1, 0, 1
  // 0, 1, 1
  // 1, 1, 1

  // This shows the iteration order of for_all_indices with
  // a permutation.
  for_all_indices<2, 0, 1>(
      my_shape, [](int x, int y, int z) { std::cout << x << ", " << y << ", " << z << std::endl; });
  // Output:
  // 0, 0, 0
  // 0, 0, 1
  // 1, 0, 0
  // 1, 0, 1
  // 0, 1, 0
  // 0, 1, 1
  // 1, 1, 0
  // 1, 1, 1

  index_t y = 0;
  index_t z = 0;

  // Define a compile-time dense 3 dimensional shape.
  using my_dense_3d_shape_type =
      shape<dim</*Min=*/dynamic, /*Extent=*/dynamic, /*Stride=*/1>, dim<>, dim<>>;
  array<char, my_dense_3d_shape_type> my_dense_array({16, 3, 3});
  for (auto x : my_dense_array.x()) {
    // The compiler knows that each loop iteration accesses
    // elements that are contiguous in memory for contiguous x.
    my_dense_array(x, y, z) = 0;
  }

  // Define a matrix type with row, column indices.
  using matrix_shape = shape<dim<>, dense_dim<>>;
  array<double, matrix_shape> my_matrix({10, 4});
  for (auto i : my_matrix.i()) {
    for (auto j : my_matrix.j()) {
      // This loop ordering is efficient for this type.
      my_matrix(i, j) = 0.0;
    }
  }

  // Demonstrate slicing an array.
  // Slicing
  array_ref_of_rank<int, 2> channel1 = my_array(_, _, 1);
  array_ref_of_rank<int, 1> row4_channel2 = my_array(_, 4, 2);

  // Cropping
  array_ref_of_rank<int, 3> top_left = my_array(interval<>{0, 2}, interval<>{0, 4}, _);
  array_ref_of_rank<int, 2> center_channel0 = my_array(interval<>{1, 2}, interval<>{2, 4}, 0);

  assert_used(channel1);
  assert_used(row4_channel2);
  assert_used(top_left);
  assert_used(center_channel0);

  // Demonstrate iterating over an array in tiles using split.
  constexpr index_t x_split_factor = 3;
  const index_t y_split_factor = 5;
  for (auto yo : split(my_array.y(), y_split_factor)) {
    for (auto xo : split<x_split_factor>(my_array.x())) {
      auto tile = my_array(xo, yo, _);
      for (auto x : tile.x()) {
        // The compiler knows this loop has a fixed extent x_split_factor!
        tile(x, y, z) = x;
      }
    }
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x740, %rsp            # imm = 0x740
movl $0x10, -0x84(%rbp)
movl $0xa, -0x88(%rbp)
movl $0x3, -0x8c(%rbp)
leaq -0xd8(%rbp), %rdi
movl $0x10, %esi
movl $0xa, %edx
movl $0x3, %ecx
callq 0x34ec0
leaq -0x140(%rbp), %rdi
leaq -0xd8(%rbp), %rsi
callq 0x34f10
movl $0x0, -0x144(%rbp)
cmpl $0x3, -0x144(%rbp)
jge 0x150640
movl $0x0, -0x148(%rbp)
cmpl $0xa, -0x148(%rbp)
jge 0x15062a
movl $0x0, -0x14c(%rbp)
cmpl $0x10, -0x14c(%rbp)
jge 0x150614
movl -0x14c(%rbp), %esi
movl -0x148(%rbp), %edx
movl -0x144(%rbp), %ecx
leaq -0x140(%rbp), %rdi
callq 0x35b40
movq %rax, -0x640(%rbp)
jmp 0x1505df
movq -0x640(%rbp), %rax
movl $0x5, (%rax)
movl -0x14c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14c(%rbp)
jmp 0x1505af
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x158(%rbp)
movl %eax, -0x15c(%rbp)
jmp 0x150f93
jmp 0x150616
movl -0x148(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x148(%rbp)
jmp 0x150598
jmp 0x15062c
movl -0x144(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x144(%rbp)
jmp 0x150581
leaq -0x140(%rbp), %rdi
leaq -0x15d(%rbp), %rsi
callq 0x150fb0
jmp 0x150655
leaq -0x140(%rbp), %rax
movq %rax, -0x168(%rbp)
leaq -0xd8(%rbp), %rdi
leaq -0x168(%rbp), %rsi
callq 0x150fe0
jmp 0x150678
leaq -0x140(%rbp), %rax
movq %rax, -0x170(%rbp)
leaq -0xd8(%rbp), %rdi
leaq -0x170(%rbp), %rsi
callq 0x151010
jmp 0x15069b
leaq -0x1b8(%rbp), %rdi
movl $0x2, %ecx
movl %ecx, %esi
movl %ecx, %edx
callq 0x34ec0
jmp 0x1506b2
leaq -0x1b8(%rbp), %rdi
leaq -0x1b9(%rbp), %rsi
callq 0x151040
jmp 0x1506c7
leaq -0x1b8(%rbp), %rdi
leaq -0x1ba(%rbp), %rsi
callq 0x151070
jmp 0x1506dc
movq $0x0, -0x1c8(%rbp)
movq $0x0, -0x1d0(%rbp)
leaq -0x280(%rbp), %rdi
movl $0x10, %esi
movl $0x3, %ecx
movl %ecx, %edx
callq 0x34640
jmp 0x15070c
leaq -0x238(%rbp), %rdi
leaq -0x280(%rbp), %rsi
callq 0x1624d0
jmp 0x150721
leaq -0x238(%rbp), %rdi
callq 0x162570
movq %rax, -0x648(%rbp)
jmp 0x150736
movq -0x648(%rbp), %rax
movq %rax, -0x288(%rbp)
movq -0x288(%rbp), %rdi
callq 0x366c0
movq %rax, -0x650(%rbp)
jmp 0x150759
movq -0x650(%rbp), %rax
movq %rax, -0x290(%rbp)
movq -0x288(%rbp), %rdi
callq 0x366f0
movq %rax, -0x658(%rbp)
jmp 0x15077c
movq -0x658(%rbp), %rax
movq %rax, -0x298(%rbp)
leaq -0x290(%rbp), %rax
movq %rax, -0x48(%rbp)
leaq -0x298(%rbp), %rax
movq %rax, -0x50(%rbp)
movq -0x48(%rbp), %rax
movq (%rax), %rax
movq -0x50(%rbp), %rcx
cmpq (%rcx), %rax
setne %al
movb %al, -0x659(%rbp)
movb -0x659(%rbp), %al
testb $0x1, %al
jne 0x1507c6
jmp 0x150856
leaq -0x290(%rbp), %rax
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x668(%rbp)
movq -0x668(%rbp), %rax
movq %rax, -0x2a0(%rbp)
movq -0x2a0(%rbp), %rsi
movq -0x1c8(%rbp), %rdx
movq -0x1d0(%rbp), %rcx
leaq -0x238(%rbp), %rdi
callq 0x162590
movq %rax, -0x670(%rbp)
jmp 0x150817
movq -0x670(%rbp), %rax
movb $0x0, (%rax)
leaq -0x290(%rbp), %rax
movq %rax, -0x8(%rbp)
movq -0x8(%rbp), %rax
movq (%rax), %rcx
addq $0x1, %rcx
movq %rcx, (%rax)
jmp 0x15078a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x158(%rbp)
movl %eax, -0x15c(%rbp)
jmp 0x150f87
leaq -0x320(%rbp), %rdi
movl $0xa, %esi
movl $0x4, %edx
callq 0x149bd0
jmp 0x15086e
leaq -0x2f0(%rbp), %rdi
leaq -0x320(%rbp), %rsi
callq 0x1625e0
jmp 0x150883
leaq -0x2f0(%rbp), %rdi
callq 0x162670
movq %rax, -0x678(%rbp)
jmp 0x150898
movq -0x678(%rbp), %rax
movq %rax, -0x328(%rbp)
movq -0x328(%rbp), %rdi
callq 0x366c0
movq %rax, -0x680(%rbp)
jmp 0x1508bb
movq -0x680(%rbp), %rax
movq %rax, -0x330(%rbp)
movq -0x328(%rbp), %rdi
callq 0x366f0
movq %rax, -0x688(%rbp)
jmp 0x1508de
movq -0x688(%rbp), %rax
movq %rax, -0x338(%rbp)
leaq -0x330(%rbp), %rax
movq %rax, -0x58(%rbp)
leaq -0x338(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x58(%rbp), %rax
movq (%rax), %rax
movq -0x60(%rbp), %rcx
cmpq (%rcx), %rax
setne %al
movb %al, -0x689(%rbp)
movb -0x689(%rbp), %al
testb $0x1, %al
jne 0x150928
jmp 0x150aad
leaq -0x330(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x698(%rbp)
movq -0x698(%rbp), %rax
movq %rax, -0x340(%rbp)
leaq -0x2f0(%rbp), %rdi
callq 0x162690
movq %rax, -0x6a0(%rbp)
jmp 0x150964
movq -0x6a0(%rbp), %rax
movq %rax, -0x348(%rbp)
movq -0x348(%rbp), %rdi
callq 0x366c0
movq %rax, -0x6a8(%rbp)
jmp 0x150987
movq -0x6a8(%rbp), %rax
movq %rax, -0x350(%rbp)
movq -0x348(%rbp), %rdi
callq 0x366f0
movq %rax, -0x6b0(%rbp)
jmp 0x1509aa
movq -0x6b0(%rbp), %rax
movq %rax, -0x358(%rbp)
leaq -0x350(%rbp), %rax
movq %rax, -0x68(%rbp)
leaq -0x358(%rbp), %rax
movq %rax, -0x70(%rbp)
movq -0x68(%rbp), %rax
movq (%rax), %rax
movq -0x70(%rbp), %rcx
cmpq (%rcx), %rax
setne %al
movb %al, -0x6b1(%rbp)
movb -0x6b1(%rbp), %al
testb $0x1, %al
jne 0x1509f4
jmp 0x150a8d
leaq -0x350(%rbp), %rax
movq %rax, -0x38(%rbp)
movq -0x38(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x6c0(%rbp)
movq -0x6c0(%rbp), %rax
movq %rax, -0x360(%rbp)
movq -0x340(%rbp), %rsi
movq -0x360(%rbp), %rdx
leaq -0x2f0(%rbp), %rdi
callq 0x1626b0
movq %rax, -0x6c8(%rbp)
jmp 0x150a3e
movq -0x6c8(%rbp), %rax
xorps %xmm0, %xmm0
movsd %xmm0, (%rax)
leaq -0x350(%rbp), %rax
movq %rax, -0x10(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rcx
addq $0x1, %rcx
movq %rcx, (%rax)
jmp 0x1509b8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x158(%rbp)
movl %eax, -0x15c(%rbp)
leaq -0x2f0(%rbp), %rdi
callq 0x162cd0
jmp 0x150f87
jmp 0x150a8f
leaq -0x330(%rbp), %rax
movq %rax, -0x18(%rbp)
movq -0x18(%rbp), %rax
movq (%rax), %rcx
addq $0x1, %rcx
movq %rcx, (%rax)
jmp 0x1508ec
movw 0x1418de(%rip), %ax     # 0x292392
movw %ax, -0x39a(%rbp)
movw 0x1418d0(%rip), %ax     # 0x292392
movw %ax, -0x39c(%rbp)
leaq -0x398(%rbp), %rdi
leaq -0x140(%rbp), %rsi
movl $0x1, %edx
callq 0x162700
jmp 0x150ae3
movw 0x1418a8(%rip), %ax     # 0x292392
movw %ax, -0x3c2(%rbp)
leaq -0x3c0(%rbp), %rdi
leaq -0x140(%rbp), %rsi
movl $0x4, %edx
movl $0x2, %ecx
callq 0x162770
jmp 0x150b10
xorl %eax, %eax
movl %eax, %esi
leaq -0x428(%rbp), %rdi
movl $0x2, %edx
callq 0x13e90
jmp 0x150b27
xorl %eax, %eax
movl %eax, %esi
leaq -0x438(%rbp), %rdi
movl $0x4, %edx
callq 0x13e90
jmp 0x150b3e
movw 0x14184d(%rip), %ax     # 0x292392
movw %ax, -0x43a(%rbp)
movq -0x428(%rbp), %rdx
movq -0x420(%rbp), %rcx
movq -0x438(%rbp), %r8
movq -0x430(%rbp), %r9
leaq -0x418(%rbp), %rdi
leaq -0x140(%rbp), %rsi
callq 0x1627e0
jmp 0x150b7d
leaq -0x488(%rbp), %rdi
movl $0x1, %esi
movl $0x2, %edx
callq 0x13e90
jmp 0x150b95
leaq -0x498(%rbp), %rdi
movl $0x2, %esi
movl $0x4, %edx
callq 0x13e90
jmp 0x150bad
movq -0x488(%rbp), %rdx
movq -0x480(%rbp), %rcx
movq -0x498(%rbp), %r8
movq -0x490(%rbp), %r9
movq %rsp, %rax
movl $0x0, (%rax)
leaq -0x478(%rbp), %rdi
leaq -0x140(%rbp), %rsi
callq 0x162860
jmp 0x150be7
leaq -0x398(%rbp), %rdi
callq 0x1628e0
jmp 0x150bf5
leaq -0x3c0(%rbp), %rdi
callq 0x1628f0
jmp 0x150c03
leaq -0x418(%rbp), %rdi
callq 0x162900
jmp 0x150c11
leaq -0x478(%rbp), %rdi
callq 0x1628e0
jmp 0x150c1f
movq $0x3, -0x4a0(%rbp)
movq $0x5, -0x4a8(%rbp)
leaq -0x140(%rbp), %rdi
callq 0x36740
movq %rax, -0x6d0(%rbp)
jmp 0x150c4a
movq -0x6d0(%rbp), %rsi
leaq -0x4e0(%rbp), %rdi
movl $0x5, %edx
callq 0x162910
jmp 0x150c64
leaq -0x4e0(%rbp), %rax
movq %rax, -0x4b0(%rbp)
movq -0x4b0(%rbp), %rsi
leaq -0x4f8(%rbp), %rdi
callq 0x162980
jmp 0x150c87
movq -0x4b0(%rbp), %rsi
leaq -0x510(%rbp), %rdi
callq 0x1629b0
jmp 0x150c9c
jmp 0x150c9e
leaq -0x4f8(%rbp), %rdi
leaq -0x510(%rbp), %rsi
callq 0x1629e0
movb %al, -0x6d1(%rbp)
jmp 0x150cb9
movb -0x6d1(%rbp), %al
testb $0x1, %al
jne 0x150cc8
jmp 0x150f5a
leaq -0x4f8(%rbp), %rdi
callq 0x162a30
movq %rdx, -0x6e8(%rbp)
movq %rax, -0x6e0(%rbp)
jmp 0x150ce4
movq -0x6e8(%rbp), %rax
movq -0x6e0(%rbp), %rcx
movq %rcx, -0x520(%rbp)
movq %rax, -0x518(%rbp)
leaq -0x140(%rbp), %rdi
callq 0x36760
movq %rax, -0x6f0(%rbp)
jmp 0x150d15
movq -0x6f0(%rbp), %rsi
leaq -0x558(%rbp), %rdi
callq 0x162a50
jmp 0x150d2a
leaq -0x558(%rbp), %rax
movq %rax, -0x528(%rbp)
movq -0x528(%rbp), %rsi
leaq -0x570(%rbp), %rdi
callq 0x162ac0
jmp 0x150d4d
movq -0x528(%rbp), %rsi
leaq -0x588(%rbp), %rdi
callq 0x162af0
jmp 0x150d62
jmp 0x150d64
leaq -0x570(%rbp), %rdi
leaq -0x588(%rbp), %rsi
callq 0x162b20
movb %al, -0x6f1(%rbp)
jmp 0x150d7f
movb -0x6f1(%rbp), %al
testb $0x1, %al
jne 0x150d8e
jmp 0x150f45
leaq -0x570(%rbp), %rdi
callq 0x162b70
movq %rax, -0x700(%rbp)
jmp 0x150da3
movq -0x700(%rbp), %rax
movq %rax, -0x598(%rbp)
movups -0x598(%rbp), %xmm0
movaps %xmm0, -0x600(%rbp)
movups -0x520(%rbp), %xmm0
movaps %xmm0, -0x610(%rbp)
movw 0x1415be(%rip), %ax     # 0x292392
movw %ax, -0x612(%rbp)
movq -0x600(%rbp), %rdx
movq -0x610(%rbp), %rcx
movq -0x608(%rbp), %r8
leaq -0x5e8(%rbp), %rdi
leaq -0x140(%rbp), %rsi
callq 0x162ba0
jmp 0x150e05
leaq -0x5e8(%rbp), %rdi
callq 0x162c20
movq %rax, -0x708(%rbp)
jmp 0x150e1a
movq -0x708(%rbp), %rax
movq %rax, -0x620(%rbp)
movq -0x620(%rbp), %rdi
callq 0xd5d50
movq %rax, -0x710(%rbp)
jmp 0x150e3d
movq -0x710(%rbp), %rax
movq %rax, -0x628(%rbp)
movq -0x620(%rbp), %rdi
callq 0xd5d80
movq %rax, -0x718(%rbp)
jmp 0x150e60
movq -0x718(%rbp), %rax
movq %rax, -0x630(%rbp)
leaq -0x628(%rbp), %rax
movq %rax, -0x78(%rbp)
leaq -0x630(%rbp), %rax
movq %rax, -0x80(%rbp)
movq -0x78(%rbp), %rax
movq (%rax), %rax
movq -0x80(%rbp), %rcx
cmpq (%rcx), %rax
setne %al
movb %al, -0x719(%rbp)
movb -0x719(%rbp), %al
testb $0x1, %al
jne 0x150eaa
jmp 0x150f30
leaq -0x628(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x728(%rbp)
movq -0x728(%rbp), %rax
movq %rax, -0x638(%rbp)
movq -0x638(%rbp), %rsi
movl %esi, %eax
movl %eax, -0x734(%rbp)
movq -0x1c8(%rbp), %rdx
movq -0x1d0(%rbp), %rcx
leaq -0x5e8(%rbp), %rdi
callq 0x162c40
movq %rax, -0x730(%rbp)
jmp 0x150f03
movq -0x730(%rbp), %rax
movl -0x734(%rbp), %ecx
movl %ecx, (%rax)
leaq -0x628(%rbp), %rax
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rax
movq (%rax), %rcx
addq $0x1, %rcx
movq %rcx, (%rax)
jmp 0x150e6e
jmp 0x150f32
leaq -0x570(%rbp), %rdi
callq 0x162c90
jmp 0x150f40
jmp 0x150d64
jmp 0x150f47
leaq -0x4f8(%rbp), %rdi
callq 0x162cb0
jmp 0x150f55
jmp 0x150c9e
leaq -0x2f0(%rbp), %rdi
callq 0x162cd0
leaq -0x238(%rbp), %rdi
callq 0x162d10
leaq -0x140(%rbp), %rdi
callq 0x35160
addq $0x740, %rsp            # imm = 0x740
popq %rbp
retq
leaq -0x238(%rbp), %rdi
callq 0x162d10
leaq -0x140(%rbp), %rdi
callq 0x35160
movq -0x158(%rbp), %rdi
callq 0x33a0
nopl (%rax,%rax)