Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
Go
Haskell
HLSL
Hook
Hylo
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Nim
Objective-C
Objective-C++
OCaml
OpenCL C
Pascal
Pony
Python
Racket
Ruby
Rust
Snowball
Scala
Solidity
Spice
Swift
LLVM TableGen
Toit
TypeScript Native
V
Vala
Visual Basic
WASM
Zig
Javascript
GIMPLE
c++ source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
6502-c++ 11.1.0
ARM GCC 10.2.0
ARM GCC 10.3.0
ARM GCC 10.4.0
ARM GCC 10.5.0
ARM GCC 11.1.0
ARM GCC 11.2.0
ARM GCC 11.3.0
ARM GCC 11.4.0
ARM GCC 12.1.0
ARM GCC 12.2.0
ARM GCC 12.3.0
ARM GCC 12.4.0
ARM GCC 13.1.0
ARM GCC 13.2.0
ARM GCC 13.2.0 (unknown-eabi)
ARM GCC 13.3.0
ARM GCC 13.3.0 (unknown-eabi)
ARM GCC 14.1.0
ARM GCC 14.1.0 (unknown-eabi)
ARM GCC 14.2.0
ARM GCC 14.2.0 (unknown-eabi)
ARM GCC 4.5.4
ARM GCC 4.6.4
ARM GCC 5.4
ARM GCC 6.3.0
ARM GCC 6.4.0
ARM GCC 7.3.0
ARM GCC 7.5.0
ARM GCC 8.2.0
ARM GCC 8.5.0
ARM GCC 9.3.0
ARM GCC 9.4.0
ARM GCC 9.5.0
ARM GCC trunk
ARM gcc 10.2.1 (none)
ARM gcc 10.3.1 (2021.07 none)
ARM gcc 10.3.1 (2021.10 none)
ARM gcc 11.2.1 (none)
ARM gcc 5.4.1 (none)
ARM gcc 7.2.1 (none)
ARM gcc 8.2 (WinCE)
ARM gcc 8.3.1 (none)
ARM gcc 9.2.1 (none)
ARM msvc v19.0 (WINE)
ARM msvc v19.10 (WINE)
ARM msvc v19.14 (WINE)
ARM64 Morello gcc 10.1 Alpha 2
ARM64 gcc 10.2
ARM64 gcc 10.3
ARM64 gcc 10.4
ARM64 gcc 10.5.0
ARM64 gcc 11.1
ARM64 gcc 11.2
ARM64 gcc 11.3
ARM64 gcc 11.4.0
ARM64 gcc 12.1
ARM64 gcc 12.2.0
ARM64 gcc 12.3.0
ARM64 gcc 12.4.0
ARM64 gcc 13.1.0
ARM64 gcc 13.2.0
ARM64 gcc 13.3.0
ARM64 gcc 14.1.0
ARM64 gcc 14.2.0
ARM64 gcc 4.9.4
ARM64 gcc 5.4
ARM64 gcc 5.5.0
ARM64 gcc 6.3
ARM64 gcc 6.4
ARM64 gcc 7.3
ARM64 gcc 7.5
ARM64 gcc 8.2
ARM64 gcc 8.5
ARM64 gcc 9.3
ARM64 gcc 9.4
ARM64 gcc 9.5
ARM64 gcc trunk
ARM64 msvc v19.14 (WINE)
AVR gcc 10.3.0
AVR gcc 11.1.0
AVR gcc 12.1.0
AVR gcc 12.2.0
AVR gcc 12.3.0
AVR gcc 12.4.0
AVR gcc 13.1.0
AVR gcc 13.2.0
AVR gcc 13.3.0
AVR gcc 14.1.0
AVR gcc 14.2.0
AVR gcc 4.5.4
AVR gcc 4.6.4
AVR gcc 5.4.0
AVR gcc 9.2.0
AVR gcc 9.3.0
Arduino Mega (1.8.9)
Arduino Uno (1.8.9)
BPF clang (trunk)
BPF clang 13.0.0
BPF clang 14.0.0
BPF clang 15.0.0
BPF clang 16.0.0
BPF clang 17.0.1
BPF clang 18.1.0
BPF clang 19.1.0
BPF gcc 13.1.0
BPF gcc 13.2.0
BPF gcc 13.3.0
BPF gcc trunk
EDG (experimental reflection)
EDG 6.5
EDG 6.5 (GNU mode gcc 13)
EDG 6.6
EDG 6.6 (GNU mode gcc 13)
FRC 2019
FRC 2020
FRC 2023
HPPA gcc 14.2.0
KVX ACB 4.1.0 (GCC 7.5.0)
KVX ACB 4.1.0-cd1 (GCC 7.5.0)
KVX ACB 4.10.0 (GCC 10.3.1)
KVX ACB 4.11.1 (GCC 10.3.1)
KVX ACB 4.12.0 (GCC 11.3.0)
KVX ACB 4.2.0 (GCC 7.5.0)
KVX ACB 4.3.0 (GCC 7.5.0)
KVX ACB 4.4.0 (GCC 7.5.0)
KVX ACB 4.6.0 (GCC 9.4.1)
KVX ACB 4.8.0 (GCC 9.4.1)
KVX ACB 4.9.0 (GCC 9.4.1)
KVX ACB 5.0.0 (GCC 12.2.1)
LoongArch64 clang (trunk)
LoongArch64 clang 17.0.1
LoongArch64 clang 18.1.0
LoongArch64 clang 19.1.0
M68K gcc 13.1.0
M68K gcc 13.2.0
M68K gcc 13.3.0
M68K gcc 14.1.0
M68K gcc 14.2.0
M68k clang (trunk)
MRISC32 gcc (trunk)
MSP430 gcc 4.5.3
MSP430 gcc 5.3.0
MSP430 gcc 6.2.1
MinGW clang 14.0.3
MinGW clang 14.0.6
MinGW clang 15.0.7
MinGW clang 16.0.0
MinGW clang 16.0.2
MinGW gcc 11.3.0
MinGW gcc 12.1.0
MinGW gcc 12.2.0
MinGW gcc 13.1.0
RISC-V (32-bits) gcc (trunk)
RISC-V (32-bits) gcc 10.2.0
RISC-V (32-bits) gcc 10.3.0
RISC-V (32-bits) gcc 11.2.0
RISC-V (32-bits) gcc 11.3.0
RISC-V (32-bits) gcc 11.4.0
RISC-V (32-bits) gcc 12.1.0
RISC-V (32-bits) gcc 12.2.0
RISC-V (32-bits) gcc 12.3.0
RISC-V (32-bits) gcc 12.4.0
RISC-V (32-bits) gcc 13.1.0
RISC-V (32-bits) gcc 13.2.0
RISC-V (32-bits) gcc 13.3.0
RISC-V (32-bits) gcc 14.1.0
RISC-V (32-bits) gcc 14.2.0
RISC-V (32-bits) gcc 8.2.0
RISC-V (32-bits) gcc 8.5.0
RISC-V (32-bits) gcc 9.4.0
RISC-V (64-bits) gcc (trunk)
RISC-V (64-bits) gcc 10.2.0
RISC-V (64-bits) gcc 10.3.0
RISC-V (64-bits) gcc 11.2.0
RISC-V (64-bits) gcc 11.3.0
RISC-V (64-bits) gcc 11.4.0
RISC-V (64-bits) gcc 12.1.0
RISC-V (64-bits) gcc 12.2.0
RISC-V (64-bits) gcc 12.3.0
RISC-V (64-bits) gcc 12.4.0
RISC-V (64-bits) gcc 13.1.0
RISC-V (64-bits) gcc 13.2.0
RISC-V (64-bits) gcc 13.3.0
RISC-V (64-bits) gcc 14.1.0
RISC-V (64-bits) gcc 14.2.0
RISC-V (64-bits) gcc 8.2.0
RISC-V (64-bits) gcc 8.5.0
RISC-V (64-bits) gcc 9.4.0
RISC-V rv32gc clang (trunk)
RISC-V rv32gc clang 10.0.0
RISC-V rv32gc clang 10.0.1
RISC-V rv32gc clang 11.0.0
RISC-V rv32gc clang 11.0.1
RISC-V rv32gc clang 12.0.0
RISC-V rv32gc clang 12.0.1
RISC-V rv32gc clang 13.0.0
RISC-V rv32gc clang 13.0.1
RISC-V rv32gc clang 14.0.0
RISC-V rv32gc clang 15.0.0
RISC-V rv32gc clang 16.0.0
RISC-V rv32gc clang 17.0.1
RISC-V rv32gc clang 18.1.0
RISC-V rv32gc clang 19.1.0
RISC-V rv32gc clang 9.0.0
RISC-V rv32gc clang 9.0.1
RISC-V rv64gc clang (trunk)
RISC-V rv64gc clang 10.0.0
RISC-V rv64gc clang 10.0.1
RISC-V rv64gc clang 11.0.0
RISC-V rv64gc clang 11.0.1
RISC-V rv64gc clang 12.0.0
RISC-V rv64gc clang 12.0.1
RISC-V rv64gc clang 13.0.0
RISC-V rv64gc clang 13.0.1
RISC-V rv64gc clang 14.0.0
RISC-V rv64gc clang 15.0.0
RISC-V rv64gc clang 16.0.0
RISC-V rv64gc clang 17.0.1
RISC-V rv64gc clang 18.1.0
RISC-V rv64gc clang 19.1.0
RISC-V rv64gc clang 9.0.0
RISC-V rv64gc clang 9.0.1
Raspbian Buster
Raspbian Stretch
SPARC LEON gcc 12.2.0
SPARC LEON gcc 12.3.0
SPARC LEON gcc 12.4.0
SPARC LEON gcc 13.1.0
SPARC LEON gcc 13.2.0
SPARC LEON gcc 13.3.0
SPARC LEON gcc 14.1.0
SPARC LEON gcc 14.2.0
SPARC gcc 12.2.0
SPARC gcc 12.3.0
SPARC gcc 12.4.0
SPARC gcc 13.1.0
SPARC gcc 13.2.0
SPARC gcc 13.3.0
SPARC gcc 14.1.0
SPARC gcc 14.2.0
SPARC64 gcc 12.2.0
SPARC64 gcc 12.3.0
SPARC64 gcc 12.4.0
SPARC64 gcc 13.1.0
SPARC64 gcc 13.2.0
SPARC64 gcc 13.3.0
SPARC64 gcc 14.1.0
SPARC64 gcc 14.2.0
TI C6x gcc 12.2.0
TI C6x gcc 12.3.0
TI C6x gcc 12.4.0
TI C6x gcc 13.1.0
TI C6x gcc 13.2.0
TI C6x gcc 13.3.0
TI C6x gcc 14.1.0
TI C6x gcc 14.2.0
TI CL430 21.6.1
VAX gcc NetBSDELF 10.4.0
VAX gcc NetBSDELF 10.5.0 (Nov 15 03:50:22 2023)
WebAssembly clang (trunk)
Xtensa ESP32 gcc 11.2.0 (2022r1)
Xtensa ESP32 gcc 12.2.0 (20230208)
Xtensa ESP32 gcc 8.2.0 (2019r2)
Xtensa ESP32 gcc 8.2.0 (2020r1)
Xtensa ESP32 gcc 8.2.0 (2020r2)
Xtensa ESP32 gcc 8.4.0 (2020r3)
Xtensa ESP32 gcc 8.4.0 (2021r1)
Xtensa ESP32 gcc 8.4.0 (2021r2)
Xtensa ESP32-S2 gcc 11.2.0 (2022r1)
Xtensa ESP32-S2 gcc 12.2.0 (20230208)
Xtensa ESP32-S2 gcc 8.2.0 (2019r2)
Xtensa ESP32-S2 gcc 8.2.0 (2020r1)
Xtensa ESP32-S2 gcc 8.2.0 (2020r2)
Xtensa ESP32-S2 gcc 8.4.0 (2020r3)
Xtensa ESP32-S2 gcc 8.4.0 (2021r1)
Xtensa ESP32-S2 gcc 8.4.0 (2021r2)
Xtensa ESP32-S3 gcc 11.2.0 (2022r1)
Xtensa ESP32-S3 gcc 12.2.0 (20230208)
Xtensa ESP32-S3 gcc 8.4.0 (2020r3)
Xtensa ESP32-S3 gcc 8.4.0 (2021r1)
Xtensa ESP32-S3 gcc 8.4.0 (2021r2)
arm64 msvc v19.20 VS16.0
arm64 msvc v19.21 VS16.1
arm64 msvc v19.22 VS16.2
arm64 msvc v19.23 VS16.3
arm64 msvc v19.24 VS16.4
arm64 msvc v19.25 VS16.5
arm64 msvc v19.27 VS16.7
arm64 msvc v19.28 VS16.8
arm64 msvc v19.28 VS16.9
arm64 msvc v19.29 VS16.10
arm64 msvc v19.29 VS16.11
arm64 msvc v19.30 VS17.0
arm64 msvc v19.31 VS17.1
arm64 msvc v19.32 VS17.2
arm64 msvc v19.33 VS17.3
arm64 msvc v19.34 VS17.4
arm64 msvc v19.35 VS17.5
arm64 msvc v19.36 VS17.6
arm64 msvc v19.37 VS17.7
arm64 msvc v19.38 VS17.8
arm64 msvc v19.39 VS17.9
arm64 msvc v19.40 VS17.10
arm64 msvc v19.latest
armv7-a clang (trunk)
armv7-a clang 10.0.0
armv7-a clang 10.0.1
armv7-a clang 11.0.0
armv7-a clang 11.0.1
armv7-a clang 12.0.0
armv7-a clang 12.0.1
armv7-a clang 13.0.0
armv7-a clang 13.0.1
armv7-a clang 14.0.0
armv7-a clang 15.0.0
armv7-a clang 16.0.0
armv7-a clang 17.0.1
armv7-a clang 18.1.0
armv7-a clang 19.1.0
armv7-a clang 9.0.0
armv7-a clang 9.0.1
armv8-a clang (all architectural features, trunk)
armv8-a clang (trunk)
armv8-a clang 10.0.0
armv8-a clang 10.0.1
armv8-a clang 11.0.0
armv8-a clang 11.0.1
armv8-a clang 12.0.0
armv8-a clang 13.0.0
armv8-a clang 14.0.0
armv8-a clang 15.0.0
armv8-a clang 16.0.0
armv8-a clang 17.0.1
armv8-a clang 18.1.0
armv8-a clang 19.1.0
armv8-a clang 9.0.0
armv8-a clang 9.0.1
ellcc 0.1.33
ellcc 0.1.34
ellcc 2017-07-16
hexagon-clang 16.0.5
llvm-mos atari2600-3e
llvm-mos atari2600-4k
llvm-mos atari2600-common
llvm-mos atari5200-supercart
llvm-mos atari8-cart-megacart
llvm-mos atari8-cart-std
llvm-mos atari8-cart-xegs
llvm-mos atari8-common
llvm-mos atari8-dos
llvm-mos c128
llvm-mos c64
llvm-mos commodore
llvm-mos cpm65
llvm-mos cx16
llvm-mos dodo
llvm-mos eater
llvm-mos mega65
llvm-mos nes
llvm-mos nes-action53
llvm-mos nes-cnrom
llvm-mos nes-gtrom
llvm-mos nes-mmc1
llvm-mos nes-mmc3
llvm-mos nes-nrom
llvm-mos nes-unrom
llvm-mos nes-unrom-512
llvm-mos osi-c1p
llvm-mos pce
llvm-mos pce-cd
llvm-mos pce-common
llvm-mos pet
llvm-mos rp6502
llvm-mos rpc8e
llvm-mos supervision
llvm-mos vic20
loongarch64 gcc 12.2.0
loongarch64 gcc 12.3.0
loongarch64 gcc 12.4.0
loongarch64 gcc 13.1.0
loongarch64 gcc 13.2.0
loongarch64 gcc 13.3.0
loongarch64 gcc 14.1.0
loongarch64 gcc 14.2.0
mips clang 13.0.0
mips clang 14.0.0
mips clang 15.0.0
mips clang 16.0.0
mips clang 17.0.1
mips clang 18.1.0
mips clang 19.1.0
mips gcc 11.2.0
mips gcc 12.1.0
mips gcc 12.2.0
mips gcc 12.3.0
mips gcc 12.4.0
mips gcc 13.1.0
mips gcc 13.2.0
mips gcc 13.3.0
mips gcc 14.1.0
mips gcc 14.2.0
mips gcc 4.9.4
mips gcc 5.4
mips gcc 5.5.0
mips gcc 9.3.0 (codescape)
mips gcc 9.5.0
mips64 (el) gcc 12.1.0
mips64 (el) gcc 12.2.0
mips64 (el) gcc 12.3.0
mips64 (el) gcc 12.4.0
mips64 (el) gcc 13.1.0
mips64 (el) gcc 13.2.0
mips64 (el) gcc 13.3.0
mips64 (el) gcc 14.1.0
mips64 (el) gcc 14.2.0
mips64 (el) gcc 4.9.4
mips64 (el) gcc 5.4.0
mips64 (el) gcc 5.5.0
mips64 (el) gcc 9.5.0
mips64 clang 13.0.0
mips64 clang 14.0.0
mips64 clang 15.0.0
mips64 clang 16.0.0
mips64 clang 17.0.1
mips64 clang 18.1.0
mips64 clang 19.1.0
mips64 gcc 11.2.0
mips64 gcc 12.1.0
mips64 gcc 12.2.0
mips64 gcc 12.3.0
mips64 gcc 12.4.0
mips64 gcc 13.1.0
mips64 gcc 13.2.0
mips64 gcc 13.3.0
mips64 gcc 14.1.0
mips64 gcc 14.2.0
mips64 gcc 4.9.4
mips64 gcc 5.4.0
mips64 gcc 5.5.0
mips64 gcc 9.5.0
mips64el clang 13.0.0
mips64el clang 14.0.0
mips64el clang 15.0.0
mips64el clang 16.0.0
mips64el clang 17.0.1
mips64el clang 18.1.0
mips64el clang 19.1.0
mipsel clang 13.0.0
mipsel clang 14.0.0
mipsel clang 15.0.0
mipsel clang 16.0.0
mipsel clang 17.0.1
mipsel clang 18.1.0
mipsel clang 19.1.0
mipsel gcc 12.1.0
mipsel gcc 12.2.0
mipsel gcc 12.3.0
mipsel gcc 12.4.0
mipsel gcc 13.1.0
mipsel gcc 13.2.0
mipsel gcc 13.3.0
mipsel gcc 14.1.0
mipsel gcc 14.2.0
mipsel gcc 4.9.4
mipsel gcc 5.4.0
mipsel gcc 5.5.0
mipsel gcc 9.5.0
nanoMIPS gcc 6.3.0 (mtk)
power gcc 11.2.0
power gcc 12.1.0
power gcc 12.2.0
power gcc 12.3.0
power gcc 12.4.0
power gcc 13.1.0
power gcc 13.2.0
power gcc 13.3.0
power gcc 14.1.0
power gcc 14.2.0
power gcc 4.8.5
power64 AT12.0 (gcc8)
power64 AT13.0 (gcc9)
power64 gcc 11.2.0
power64 gcc 12.1.0
power64 gcc 12.2.0
power64 gcc 12.3.0
power64 gcc 12.4.0
power64 gcc 13.1.0
power64 gcc 13.2.0
power64 gcc 13.3.0
power64 gcc 14.1.0
power64 gcc 14.2.0
power64 gcc trunk
power64le AT12.0 (gcc8)
power64le AT13.0 (gcc9)
power64le clang (trunk)
power64le gcc 11.2.0
power64le gcc 12.1.0
power64le gcc 12.2.0
power64le gcc 12.3.0
power64le gcc 12.4.0
power64le gcc 13.1.0
power64le gcc 13.2.0
power64le gcc 13.3.0
power64le gcc 14.1.0
power64le gcc 14.2.0
power64le gcc 6.3.0
power64le gcc trunk
powerpc64 clang (trunk)
s390x gcc 11.2.0
s390x gcc 12.1.0
s390x gcc 12.2.0
s390x gcc 12.3.0
s390x gcc 12.4.0
s390x gcc 13.1.0
s390x gcc 13.2.0
s390x gcc 13.3.0
s390x gcc 14.1.0
s390x gcc 14.2.0
sh gcc 12.2.0
sh gcc 12.3.0
sh gcc 12.4.0
sh gcc 13.1.0
sh gcc 13.2.0
sh gcc 13.3.0
sh gcc 14.1.0
sh gcc 14.2.0
sh gcc 4.9.4
sh gcc 9.5.0
vast (trunk)
x64 msvc v19.0 (WINE)
x64 msvc v19.10 (WINE)
x64 msvc v19.14 (WINE)
x64 msvc v19.20 VS16.0
x64 msvc v19.21 VS16.1
x64 msvc v19.22 VS16.2
x64 msvc v19.23 VS16.3
x64 msvc v19.24 VS16.4
x64 msvc v19.25 VS16.5
x64 msvc v19.27 VS16.7
x64 msvc v19.28 VS16.8
x64 msvc v19.28 VS16.9
x64 msvc v19.29 VS16.10
x64 msvc v19.29 VS16.11
x64 msvc v19.30 VS17.0
x64 msvc v19.31 VS17.1
x64 msvc v19.32 VS17.2
x64 msvc v19.33 VS17.3
x64 msvc v19.34 VS17.4
x64 msvc v19.35 VS17.5
x64 msvc v19.36 VS17.6
x64 msvc v19.37 VS17.7
x64 msvc v19.38 VS17.8
x64 msvc v19.39 VS17.9
x64 msvc v19.40 VS17.10
x64 msvc v19.latest
x86 djgpp 4.9.4
x86 djgpp 5.5.0
x86 djgpp 6.4.0
x86 djgpp 7.2.0
x86 msvc v19.0 (WINE)
x86 msvc v19.10 (WINE)
x86 msvc v19.14 (WINE)
x86 msvc v19.20 VS16.0
x86 msvc v19.21 VS16.1
x86 msvc v19.22 VS16.2
x86 msvc v19.23 VS16.3
x86 msvc v19.24 VS16.4
x86 msvc v19.25 VS16.5
x86 msvc v19.27 VS16.7
x86 msvc v19.28 VS16.8
x86 msvc v19.28 VS16.9
x86 msvc v19.29 VS16.10
x86 msvc v19.29 VS16.11
x86 msvc v19.30 VS17.0
x86 msvc v19.31 VS17.1
x86 msvc v19.32 VS17.2
x86 msvc v19.33 VS17.3
x86 msvc v19.34 VS17.4
x86 msvc v19.35 VS17.5
x86 msvc v19.36 VS17.6
x86 msvc v19.37 VS17.7
x86 msvc v19.38 VS17.8
x86 msvc v19.39 VS17.9
x86 msvc v19.40 VS17.10
x86 msvc v19.latest
x86 nvc++ 22.11
x86 nvc++ 22.7
x86 nvc++ 22.9
x86 nvc++ 23.1
x86 nvc++ 23.11
x86 nvc++ 23.3
x86 nvc++ 23.5
x86 nvc++ 23.7
x86 nvc++ 23.9
x86 nvc++ 24.1
x86 nvc++ 24.3
x86 nvc++ 24.5
x86 nvc++ 24.7
x86-64 Zapcc 190308
x86-64 clang (EricWF contracts)
x86-64 clang (amd-staging)
x86-64 clang (assertions trunk)
x86-64 clang (clangir)
x86-64 clang (dascandy contracts)
x86-64 clang (experimental -Wlifetime)
x86-64 clang (experimental P1061)
x86-64 clang (experimental P1144)
x86-64 clang (experimental P1221)
x86-64 clang (experimental P2996)
x86-64 clang (experimental P3068)
x86-64 clang (experimental P3309)
x86-64 clang (experimental P3367)
x86-64 clang (experimental P3372)
x86-64 clang (experimental metaprogramming - P2632)
x86-64 clang (old concepts branch)
x86-64 clang (p1974)
x86-64 clang (pattern matching - P2688)
x86-64 clang (reflection)
x86-64 clang (resugar)
x86-64 clang (thephd.dev)
x86-64 clang (trunk)
x86-64 clang (variadic friends - P2893)
x86-64 clang (widberg)
x86-64 clang 10.0.0
x86-64 clang 10.0.0 (assertions)
x86-64 clang 10.0.1
x86-64 clang 11.0.0
x86-64 clang 11.0.0 (assertions)
x86-64 clang 11.0.1
x86-64 clang 12.0.0
x86-64 clang 12.0.0 (assertions)
x86-64 clang 12.0.1
x86-64 clang 13.0.0
x86-64 clang 13.0.0 (assertions)
x86-64 clang 13.0.1
x86-64 clang 14.0.0
x86-64 clang 14.0.0 (assertions)
x86-64 clang 15.0.0
x86-64 clang 15.0.0 (assertions)
x86-64 clang 16.0.0
x86-64 clang 16.0.0 (assertions)
x86-64 clang 17.0.1
x86-64 clang 17.0.1 (assertions)
x86-64 clang 18.1.0
x86-64 clang 18.1.0 (assertions)
x86-64 clang 19.1.0
x86-64 clang 19.1.0 (assertions)
x86-64 clang 2.6.0 (assertions)
x86-64 clang 2.7.0 (assertions)
x86-64 clang 2.8.0 (assertions)
x86-64 clang 2.9.0 (assertions)
x86-64 clang 3.0.0
x86-64 clang 3.0.0 (assertions)
x86-64 clang 3.1
x86-64 clang 3.1 (assertions)
x86-64 clang 3.2
x86-64 clang 3.2 (assertions)
x86-64 clang 3.3
x86-64 clang 3.3 (assertions)
x86-64 clang 3.4 (assertions)
x86-64 clang 3.4.1
x86-64 clang 3.5
x86-64 clang 3.5 (assertions)
x86-64 clang 3.5.1
x86-64 clang 3.5.2
x86-64 clang 3.6
x86-64 clang 3.6 (assertions)
x86-64 clang 3.7
x86-64 clang 3.7 (assertions)
x86-64 clang 3.7.1
x86-64 clang 3.8
x86-64 clang 3.8 (assertions)
x86-64 clang 3.8.1
x86-64 clang 3.9.0
x86-64 clang 3.9.0 (assertions)
x86-64 clang 3.9.1
x86-64 clang 4.0.0
x86-64 clang 4.0.0 (assertions)
x86-64 clang 4.0.1
x86-64 clang 5.0.0
x86-64 clang 5.0.0 (assertions)
x86-64 clang 5.0.1
x86-64 clang 5.0.2
x86-64 clang 6.0.0
x86-64 clang 6.0.0 (assertions)
x86-64 clang 6.0.1
x86-64 clang 7.0.0
x86-64 clang 7.0.0 (assertions)
x86-64 clang 7.0.1
x86-64 clang 7.1.0
x86-64 clang 8.0.0
x86-64 clang 8.0.0 (assertions)
x86-64 clang 8.0.1
x86-64 clang 9.0.0
x86-64 clang 9.0.0 (assertions)
x86-64 clang 9.0.1
x86-64 clang rocm-4.5.2
x86-64 clang rocm-5.0.2
x86-64 clang rocm-5.1.3
x86-64 clang rocm-5.2.3
x86-64 clang rocm-5.3.3
x86-64 clang rocm-5.7.0
x86-64 clang rocm-6.0.2
x86-64 clang rocm-6.1.2
x86-64 gcc (contract labels)
x86-64 gcc (contracts natural syntax)
x86-64 gcc (contracts)
x86-64 gcc (coroutines)
x86-64 gcc (modules)
x86-64 gcc (trunk)
x86-64 gcc 10.1
x86-64 gcc 10.2
x86-64 gcc 10.3
x86-64 gcc 10.4
x86-64 gcc 10.5
x86-64 gcc 11.1
x86-64 gcc 11.2
x86-64 gcc 11.3
x86-64 gcc 11.4
x86-64 gcc 12.1
x86-64 gcc 12.2
x86-64 gcc 12.3
x86-64 gcc 12.4
x86-64 gcc 13.1
x86-64 gcc 13.2
x86-64 gcc 13.3
x86-64 gcc 14.1
x86-64 gcc 14.2
x86-64 gcc 3.4.6
x86-64 gcc 4.0.4
x86-64 gcc 4.1.2
x86-64 gcc 4.4.7
x86-64 gcc 4.5.3
x86-64 gcc 4.6.4
x86-64 gcc 4.7.1
x86-64 gcc 4.7.2
x86-64 gcc 4.7.3
x86-64 gcc 4.7.4
x86-64 gcc 4.8.1
x86-64 gcc 4.8.2
x86-64 gcc 4.8.3
x86-64 gcc 4.8.4
x86-64 gcc 4.8.5
x86-64 gcc 4.9.0
x86-64 gcc 4.9.1
x86-64 gcc 4.9.2
x86-64 gcc 4.9.3
x86-64 gcc 4.9.4
x86-64 gcc 5.1
x86-64 gcc 5.2
x86-64 gcc 5.3
x86-64 gcc 5.4
x86-64 gcc 5.5
x86-64 gcc 6.1
x86-64 gcc 6.2
x86-64 gcc 6.3
x86-64 gcc 6.4
x86-64 gcc 6.5
x86-64 gcc 7.1
x86-64 gcc 7.2
x86-64 gcc 7.3
x86-64 gcc 7.4
x86-64 gcc 7.5
x86-64 gcc 8.1
x86-64 gcc 8.2
x86-64 gcc 8.3
x86-64 gcc 8.4
x86-64 gcc 8.5
x86-64 gcc 9.1
x86-64 gcc 9.2
x86-64 gcc 9.3
x86-64 gcc 9.4
x86-64 gcc 9.5
x86-64 icc 13.0.1
x86-64 icc 16.0.3
x86-64 icc 17.0.0
x86-64 icc 18.0.0
x86-64 icc 19.0.0
x86-64 icc 19.0.1
x86-64 icc 2021.1.2
x86-64 icc 2021.10.0
x86-64 icc 2021.2.0
x86-64 icc 2021.3.0
x86-64 icc 2021.4.0
x86-64 icc 2021.5.0
x86-64 icc 2021.6.0
x86-64 icc 2021.7.0
x86-64 icc 2021.7.1
x86-64 icc 2021.8.0
x86-64 icc 2021.9.0
x86-64 icx (latest)
x86-64 icx 2021.1.2
x86-64 icx 2021.2.0
x86-64 icx 2021.3.0
x86-64 icx 2021.4.0
x86-64 icx 2022.0.0
x86-64 icx 2022.1.0
x86-64 icx 2022.2.0
x86-64 icx 2022.2.1
x86-64 icx 2023.0.0
x86-64 icx 2023.1.0
x86-64 icx 2023.2.1
x86-64 icx 2024.0.0
x86-64 icx 2024.1.0
x86-64 icx 2024.2.0
zig c++ 0.10.0
zig c++ 0.11.0
zig c++ 0.12.0
zig c++ 0.12.1
zig c++ 0.13.0
zig c++ 0.6.0
zig c++ 0.7.0
zig c++ 0.7.1
zig c++ 0.8.0
zig c++ 0.9.0
zig c++ trunk
Options
Source code
// HACK: #define __cpp_lib_mdspan 202207L #define __cpp_lib_submdspan 202306L /////////////////////////////// // <mdspan> -*- C++ -*- // Copyright (C) 2024 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // Under Section 7 of GPL version 3, you are granted additional // permissions described in the GCC Runtime Library Exception, version // 3.1, as published by the Free Software Foundation. // You should have received a copy of the GNU General Public License and // a copy of the GCC Runtime Library Exception along with this program; // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // <http://www.gnu.org/licenses/>. /** @file include/mdspan * This is a Standard C++ Library header. */ #ifndef _GLIBCXX_MDSPAN #define _GLIBCXX_MDSPAN 1 // #pragma GCC system_header #define __glibcxx_want_mdspan #define __glibcxx_want_submdspan // #include <bits/version.h> #ifdef __cpp_lib_mdspan // C++ >= 23 #include <span> #include <type_traits> #include <concepts> #include <utility> #include <ext/numeric_traits.h> #ifdef __cpp_lib_submdspan // C++ >= 26 #include <tuple> #endif namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION // < // note: implementing 'concepts-only' for c++23 // may be defined somewhere else other than <mdspan> template<typename> inline constexpr bool __enable_tuple_like = false; template<typename _Tp> concept __tuple_like = __enable_tuple_like<remove_cvref_t<_Tp>>; template<typename _Tp> concept __pair_like = __tuple_like<_Tp> && tuple_size_v<remove_cvref_t<_Tp>> == 2; // specialization of __tuple_like for pair template<typename _T1, typename _T2> inline constexpr bool __enable_tuple_like<pair<_T1, _T2>> = true; // specialization of __tuple_like for tuple template<typename... _Ts> inline constexpr bool __enable_tuple_like<tuple<_Ts...>> = true; // specialization of __tuple_like for complex (c++26), ranges::subrange // will be defined somewhere else // > // < // note: adding '_Nth_type_t' after '_Nth_type' on <bits/utility.h> template<size_t _I, typename... _Ts> using _Nth_type_t = _Nth_type<_I, _Ts...>::type; // > namespace __mdspan { template <typename _Tp> struct _EmptyArray { // Indexing is undefined. __attribute__((__always_inline__,__noreturn__)) _Tp& operator[](size_t) const noexcept { __builtin_trap(); } static constexpr size_t size() noexcept { return 0; } }; template<typename _Tp, size_t _Nm> using __maybe_empty_array = __conditional_t<_Nm != 0, array<_Tp, _Nm>, _EmptyArray<_Tp>>; template<size_t... _Extents> consteval auto __generate_dyn_idx_map() { constexpr size_t __rank = sizeof...(_Extents); __maybe_empty_array<size_t, __rank> __from_extents { _Extents ... }; __maybe_empty_array<size_t, __rank> __result; for (size_t __r = 0, __i = 0; __r < __rank; ++__r) { __result[__r] = __i; if (__from_extents[__r] == dynamic_extent) ++__i; } return __result; } template<size_t... _Extents> consteval auto __generate_dyn_idx_inv_map() { constexpr size_t __rank = sizeof...(_Extents); constexpr size_t __rank_dyn = ((_Extents == dynamic_extent) + ... + 0); __maybe_empty_array<size_t, __rank> __from_extents { _Extents ... }; __maybe_empty_array<size_t, __rank_dyn> __result; for (size_t __r = 0, __i = 0; __r < __rank; ++__r) if (__from_extents[__r] == dynamic_extent) __result[__i++] = __r; return __result; } template<typename _IndexType, typename _From> constexpr auto __index_cast(_From&& __from) noexcept { if constexpr (is_integral_v<_From> && !is_same_v<_From, bool>) return __from; else return static_cast<_IndexType>(__from); } // simplfy the use of integer packs with common patterns template<size_t _Nm, typename _F> __attribute__((always_inline)) constexpr decltype(auto) __apply_index_pack(_F&& __f) { return [&]<size_t... _Is>(index_sequence<_Is...>) -> decltype(auto) { // expects to have a lambda as an argument return __f.template operator()<_Is...>(); }(make_index_sequence<_Nm>{}); } template<typename _To, typename _From> constexpr bool __is_repr_as(_From __val) { return in_range<_To>(__val); } template<typename _To, typename... _From> constexpr bool __are_repr_as(_From... __vals) { return (__mdspan::__is_repr_as<_To>(__vals) && ... && true); } template<typename _To, typename _From, size_t _Nm> constexpr bool __are_repr_as(span<_From, _Nm> __vals) { for (size_t __i = 0; __i < _Nm; ++__i) if (!__mdspan::__is_repr_as<_To>(__vals[__i])) return false; return true; } template<typename _IndexType, typename _From> constexpr bool __is_index_in_extent(_IndexType __ext, _From __val) { if constexpr (is_signed_v<_From>) if (__val < 0) return false; using _Tp = common_type_t<_IndexType, _From>; return static_cast<_Tp>(__val) < static_cast<_Tp>(__ext); } template<typename _Extents, typename... _From> constexpr bool __is_multidim_index_in(const _Extents& __ext, _From... __vals) { static_assert(_Extents::rank() == sizeof...(_From)); return __mdspan::__apply_index_pack<_Extents::rank()>([&]<size_t... _Is> { return (__mdspan::__is_index_in_extent(__ext.extent(_Is), __vals) && ...); }); } // fwd decl. template<typename _Mapping> constexpr typename _Mapping::index_type __mapping_offset(const _Mapping&); #ifdef __cpp_lib_submdspan template<typename _Tp> concept __integral_constant_like = is_integral_v<_Tp> && !is_same_v<bool, remove_const_t<decltype(_Tp::value)>> && convertible_to<_Tp, decltype(_Tp::value)> && equality_comparable_with<_Tp, decltype(_Tp::value)> && bool_constant<_Tp() == _Tp::value>::value && bool_constant<static_cast<decltype(_Tp::value)>(_Tp()) == _Tp::value>::value; // prerequisite of implementing submdspan // - implement c++23 tuple-like interactions template<typename _Tp, typename _IndexType> concept __index_pair_like = __pair_like<_Tp> && convertible_to<tuple_element_t<0, _Tp>, _IndexType> && convertible_to<tuple_element_t<1, _Tp>, _IndexType>; template<typename _Tp> constexpr auto __de_ice(_Tp __val) { if constexpr (__mdspan::__integral_constant_like<_Tp>) return _Tp::value; else return __val; } template<typename... _Ts> __attribute__((always_inline)) constexpr void __for_each_types(auto&& __f) { // expects to have a lambda as an argument (__f.template operator()<_Ts>(), ...); } template<size_t _Nm, typename... _Ts> requires (sizeof...(_Ts) == _Nm) __attribute__((always_inline)) constexpr void __for_each_index_pack_and_types(auto&& __f) { [&]<size_t... _Is>(index_sequence<_Is...>) { (__f.template operator()<_Is, _Ts>(), ...); }(make_index_sequence<_Nm>{}); } template<size_t _Nm, typename... _Args> requires (sizeof...(_Args) == _Nm) __attribute__((always_inline)) constexpr void __for_each_index_pack_and_args(auto&& __f, _Args... __args) { [&]<size_t... _Is>(index_sequence<_Is...>) { (__f.template operator()<_Is, _Args>(__args), ...); }(make_index_sequence<_Nm>{}); } template<size_t _Idx, typename... _Args> __attribute__((always_inline)) constexpr decltype(auto) __get_element_at(_Args&&... __args) noexcept { #ifdef __cpp_pack_indexing return std::forward<_Args...[_Idx]>(__args...[_Idx]); #else return std::get<_Idx>(std::forward_as_tuple(std::forward<_Args>(__args)...)); #endif } // fwd decl. template<typename _Extents, typename _LayoutMapping, typename... _Slicers> constexpr auto __submdspan_mapping_impl(const _LayoutMapping&, _Slicers...); #endif } template<typename _IndexType, size_t... _Extents> class extents { static_assert(is_integral_v<_IndexType> && !is_same_v<_IndexType, bool>); static_assert(((__mdspan::__is_repr_as<_IndexType>(_Extents) || _Extents == dynamic_extent) && ...)); struct _Impl { static constexpr size_t _S_rank = sizeof...(_Extents); static constexpr size_t _S_rank_dyn = ((_Extents == dynamic_extent) + ... + 0); static constexpr bool _S_req_size_is_always_zero = ((_Extents == 0) || ...); using _DynamicVals = __mdspan::__maybe_empty_array<_IndexType, _S_rank_dyn>; using _StaticVals = __mdspan::__maybe_empty_array<size_t, _S_rank>; static constexpr auto _S_dyn_idx_map = __mdspan::__generate_dyn_idx_map<_Extents...>(); static constexpr auto _S_dyn_idx_inv_map = __mdspan::__generate_dyn_idx_inv_map<_Extents...>(); static constexpr _StaticVals _S_static_vals { _Extents ... }; [[no_unique_address]] _DynamicVals _M_dyn_vals; template <size_t... _Is> static constexpr _DynamicVals _S_dyn_vals_zeros(index_sequence<_Is...>) noexcept { return _DynamicVals { ((void) _Is, 0) ... }; } // ctor constexpr _Impl() noexcept requires (_S_rank_dyn == 0) = default; constexpr _Impl() noexcept requires (_S_rank_dyn != 0) : _M_dyn_vals(_S_dyn_vals_zeros(make_index_sequence<_S_rank_dyn> {})) {} template<typename... _DynVals> requires (sizeof...(_DynVals) == _S_rank_dyn) constexpr _Impl(_DynVals... __vals) : _M_dyn_vals{static_cast<_IndexType>(__vals)...} {} template<typename _Tp, size_t _Nm> requires (_Nm == _S_rank_dyn) constexpr _Impl(const span<_Tp, _Nm>& __vals) { if constexpr (_Nm > 0) { for (size_t __i = 0; __i < _Nm; ++__i) _M_dyn_vals[__i] = static_cast<_IndexType>(__vals[__i]); } } template<typename... _DynVals> requires (sizeof...(_DynVals) != _S_rank_dyn && sizeof...(_DynVals) == _S_rank) constexpr _Impl(_DynVals... __vals) { __mdspan::__maybe_empty_array<_IndexType, _S_rank> __vals_list { static_cast<_IndexType>(__vals) ... }; for (size_t __i = 0; __i < _S_rank; ++__i) { auto __static_val = _S_static_vals[__i]; if (__static_val == dynamic_extent) _M_dyn_vals[_S_dyn_idx_map[__i]] = __vals_list[__i]; else __glibcxx_assert(__vals_list[__i] == static_cast<_IndexType>(__static_val)); } } template<typename _Tp, size_t _Nm> requires (_Nm != _S_rank_dyn && (_Nm == _S_rank || _Nm == dynamic_extent)) constexpr _Impl(const span<_Tp, _Nm>& __vals) { if constexpr (_Nm > 0) { for (size_t __i = 0; __i < _Nm; ++__i) { auto __static_val = _S_static_vals[__i]; if (__static_val == dynamic_extent) _M_dyn_vals[_S_dyn_idx_map[__i]] = static_cast<_IndexType>(__vals[__i]); else __glibcxx_assert(static_cast<_IndexType>(__vals[__i]) == static_cast<_IndexType>(__static_val)); } } } constexpr _Impl(const _DynamicVals& __vals) : _Impl(span(__vals)) { } constexpr _IndexType _M_extent(size_t __r) const noexcept { __glibcxx_assert(__r < _S_rank); return _S_static_vals[__r] == dynamic_extent ? _M_dyn_vals[_S_dyn_idx_map[__r]] : static_cast<_IndexType>(_S_static_vals[__r]); } }; [[no_unique_address]] _Impl _M_impl; public: using index_type = _IndexType; using size_type = make_unsigned_t<_IndexType>; using rank_type = size_t; // observers static constexpr rank_type rank() noexcept { return _Impl::_S_rank; } static constexpr rank_type rank_dynamic() noexcept { return _Impl::_S_rank_dyn; } static constexpr size_t static_extent(rank_type __r) noexcept { __glibcxx_assert(__r < rank()); return _Impl::_S_static_vals[__r]; } constexpr index_type extent(rank_type __r) const noexcept { __glibcxx_assert(__r < rank()); return _M_impl._M_extent(__r); } private: // exposition-only observers constexpr index_type _M_fwd_prod_of_extents(rank_type __r) const noexcept { index_type __s = 1; for (rank_type __i = 0; __i < __r; ++__i) __s *= extent(__i); return __s; } constexpr index_type _M_rev_prod_of_extents(rank_type __r) const noexcept { index_type __s = 1; for (rank_type __i = rank() - 1; __i > __r; --__i) __s *= extent(__i); return __s; } constexpr index_type _M_size() const noexcept { if constexpr (_Impl::_S_req_size_is_always_zero) return 0; else return _M_fwd_prod_of_extents(rank()); } friend struct layout_left; friend struct layout_right; friend struct layout_stride; template<typename _Mapping> friend constexpr typename _Mapping::index_type __mdspan::__mapping_offset(const _Mapping&); template<typename _Up, typename _OtherExtents, typename _OtherLayout, typename _OtherAccessor> friend class mdspan; template<typename _OtherExtents> static constexpr typename _Impl::_DynamicVals _S_x_vals_from_extents(const _OtherExtents& __other) noexcept { using _Result = _Impl::_DynamicVals; return __mdspan::__apply_index_pack<rank_dynamic()>([&]<size_t... _Idx> { return _Result { __other.extent(_Impl::_S_dyn_idx_inv_map[_Idx]) ... }; }); } public: // ctor constexpr extents() noexcept = default; template<typename... _OtherIndexTypes> requires (is_convertible_v<_OtherIndexTypes, index_type> && ...) && (is_nothrow_constructible_v<index_type, _OtherIndexTypes> && ...) && (sizeof...(_OtherIndexTypes) == rank() || sizeof...(_OtherIndexTypes) == rank_dynamic()) constexpr explicit extents(_OtherIndexTypes... __exts) noexcept : _M_impl(static_cast<index_type>(__exts)...) { __glibcxx_assert(__mdspan::__are_repr_as<index_type>(__exts...)); } template<typename _OtherIndexType, size_t _Nm> requires is_convertible_v<_OtherIndexType, index_type> && is_nothrow_constructible_v<index_type, _OtherIndexType> && (_Nm == rank() || _Nm == rank_dynamic()) constexpr explicit(_Nm != rank_dynamic()) extents(const span<_OtherIndexType, _Nm>& __exts) noexcept : _M_impl(__exts) { __glibcxx_assert(__mdspan::__are_repr_as<index_type>(__exts)); } template<typename _OtherIndexType, size_t _Nm> requires is_convertible_v<_OtherIndexType, index_type> && is_nothrow_constructible_v<index_type, _OtherIndexType> && (_Nm == rank() || _Nm == rank_dynamic()) constexpr explicit(_Nm != rank_dynamic()) extents(const array<_OtherIndexType, _Nm>& __exts) noexcept : _M_impl(span(__exts)) { __glibcxx_assert(__mdspan::__are_repr_as<index_type>(span(__exts))); } template<typename _OtherIndexType, size_t... _OtherExtents> requires (sizeof...(_OtherExtents) == rank()) && ((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ...) constexpr explicit (((_Extents != dynamic_extent && _OtherExtents == dynamic_extent) || ...) || (static_cast<make_unsigned_t<index_type>>(__gnu_cxx::__int_traits<index_type>::__max) < static_cast<make_unsigned_t<_OtherIndexType>>(__gnu_cxx::__int_traits<_OtherIndexType>::__max))) extents(const extents<_OtherIndexType, _OtherExtents...>& __other) noexcept : _M_impl(_S_x_vals_from_extents(__other)) { if constexpr (rank() > 0) { for (size_t __r = 0; __r < rank(); ++__r) { if constexpr (static_cast<make_unsigned_t<index_type>>(__gnu_cxx::__int_traits<index_type>::__max) < static_cast<make_unsigned_t<_OtherIndexType>>(__gnu_cxx::__int_traits<_OtherIndexType>::__max)) __glibcxx_assert(__mdspan::__is_repr_as<index_type>(__other.extent(__r))); __glibcxx_assert(static_extent(__r) == dynamic_extent || static_cast<index_type>(__other.extent(__r)) == static_cast<index_type>(static_extent(__r))); } } } template <typename _OtherIndexType, std::size_t... _OtherExtents> friend constexpr bool operator==(const extents& __lhs, const extents<_OtherIndexType, _OtherExtents...>& __rhs) noexcept { if constexpr (rank() != sizeof...(_OtherExtents)) { return false; } else { for (rank_type __r = 0; __r < rank(); ++__r) { using _CommonT = common_type_t<index_type, _OtherIndexType>; if (static_cast<_CommonT>(__lhs.extent(__r)) != static_cast<_CommonT>(__rhs.extent(__r))) return false; } return true; } } }; template<typename... _IndexTypes> requires (is_convertible_v<_IndexTypes, size_t> && ...) extents(_IndexTypes...) -> extents<size_t, (_IndexTypes(0), dynamic_extent)...>; namespace __mdspan { template<typename _IndexType, size_t _Rank> consteval auto __dextents_impl() { return __mdspan::__apply_index_pack<_Rank>([]<size_t... _Is> { return extents <_IndexType, (_Is, dynamic_extent) ...> {}; }); } } template<typename _IndexType, size_t _Rank> using dextents = decltype(__mdspan::__dextents_impl<_IndexType, _Rank>()); struct layout_left { template<typename _Extents> class mapping; }; struct layout_right { template<typename _Extents> class mapping; }; struct layout_stride { template<typename _Extents> class mapping; }; namespace __mdspan { template<typename> inline constexpr bool __is_extents = false; template<typename _IndexType, size_t... _Extents> inline constexpr bool __is_extents<extents<_IndexType, _Extents...>> = true; template<typename _Layout, typename _Mapping> concept __is_mapping_of = is_same_v<_Mapping, typename _Layout::template mapping<typename _Mapping::extents_type>>; template<typename _Mapping> concept __layout_mapping_alike = requires { requires __is_extents<typename _Mapping::extents_type>; { _Mapping::is_always_strided() } -> same_as<bool>; { _Mapping::is_always_exhaustive() } -> same_as<bool>; { _Mapping::is_always_unique() } -> same_as<bool>; bool_constant<_Mapping::is_always_strided()>::value; bool_constant<_Mapping::is_always_exhaustive()>::value; bool_constant<_Mapping::is_always_unique()>::value; }; template<typename _Mapping> constexpr typename _Mapping::index_type __mapping_offset(const _Mapping& __m) { constexpr size_t __rank = _Mapping::extents_type::rank(); if constexpr (__rank == 0) return __m(); else if constexpr (_Mapping::extents_type::_Impl::_S_req_size_is_always_zero) return 0; else { if (__m.extents()._M_size() == 0) return 0; else return __mdspan::__apply_index_pack<__rank>([&]<size_t... _Idx> { return __m((_Idx, 0)...); }); } } } template<typename _Extents> class layout_left::mapping { static constexpr bool _S_req_span_size_is_repr(const _Extents& __ext) { using extents_type = _Extents; using index_type = _Extents::index_type; using rank_type = _Extents::rank_type; if constexpr (extents_type::rank() == 0) return true; index_type __prod = __ext.extent(0); for (rank_type __r = 1; __r < extents_type::rank(); ++__r) if (__builtin_mul_overflow(__prod, __ext.extent(__r), &__prod)) return false; return true; } public: using extents_type = _Extents; using index_type = extents_type::index_type; using size_type = extents_type::size_type; using rank_type = extents_type::rank_type; using layout_type = layout_left; static_assert(__mdspan::__is_extents<_Extents>, "extents_type must be a specialization of std::extents"); static_assert(extents_type::rank_dynamic() > 0 || _S_req_span_size_is_repr(extents_type())); constexpr mapping() noexcept = default; constexpr mapping(const mapping&) noexcept = default; constexpr mapping(const extents_type& __ext) noexcept : _M_extents(__ext) { __glibcxx_assert(_S_req_span_size_is_repr(__ext)); } template<typename _OtherExtents> requires is_constructible_v<extents_type, _OtherExtents> constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const mapping<_OtherExtents>& __other) noexcept : _M_extents(__other.extents()) { __glibcxx_assert(__mdspan::__is_repr_as<index_type>(__other.required_span_size())); } template<typename _OtherExtents> requires is_constructible_v<extents_type, _OtherExtents> && (extents_type::rank() <= 1) constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const layout_right::mapping<_OtherExtents>& __other) noexcept : _M_extents(__other.extents()) { __glibcxx_assert(__mdspan::__is_repr_as<index_type>(__other.required_span_size())); } template<typename _OtherExtents> requires is_constructible_v<extents_type, _OtherExtents> constexpr explicit(extents_type::rank() > 0) mapping(const layout_stride::mapping<_OtherExtents>& __other) noexcept : _M_extents(__other.extents()) { __glibcxx_assert(__mdspan::__is_repr_as<index_type>(__other.required_span_size())); if constexpr (extents_type::rank() > 0) { for (rank_type __r = 0; __r < extents_type::rank(); ++__r) __glibcxx_assert(__other.stride(__r) == __other.extents()._M_fwd_prod_of_extents(__r)); } } constexpr mapping& operator=(const mapping&) noexcept = default; constexpr const extents_type& extents() const noexcept { return _M_extents; } constexpr index_type required_span_size() const noexcept { return _M_extents._M_size(); } template<typename... _Idx> requires (sizeof...(_Idx) == extents_type::rank()) && (is_convertible_v<_Idx, index_type> && ...) && (is_nothrow_constructible_v<index_type, _Idx> && ...) constexpr index_type operator()(_Idx... __idx) const noexcept { __glibcxx_assert(__mdspan::__is_multidim_index_in(_M_extents, __mdspan::__index_cast<index_type>(__idx)...)); return __mdspan::__apply_index_pack<extents_type::rank()>([&]<size_t... _P> -> index_type { return ((static_cast<index_type>(__idx) * stride(_P)) + ... + 0); }); } static constexpr bool is_always_unique() noexcept { return true; } static constexpr bool is_always_exhaustive() noexcept { return true; } static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } static constexpr bool is_exhaustive() noexcept { return true; } static constexpr bool is_strided() noexcept { return true; } constexpr index_type stride(rank_type __r) const noexcept requires (extents_type::rank() > 0) { __glibcxx_assert(__r < extents_type::rank()); return _M_extents._M_fwd_prod_of_extents(__r); } template <typename _OtherExtents> requires (_OtherExtents::rank() == extents_type::rank()) friend constexpr bool operator==(const mapping& __lhs, const mapping<_OtherExtents>& __rhs) noexcept { return __lhs.extents() == __rhs.extents(); } private: [[no_unique_address]] extents_type _M_extents {}; #ifdef __cpp_lib_submdspan template<typename... _Slicers> friend constexpr auto submdspan_mapping(const mapping& __src, _Slicers... __slices) { return __mdspan::__submdspan_mapping_impl<_Extents>(__src, __slices...); } #endif }; template<typename _Extents> class layout_right::mapping { static constexpr bool _S_req_span_size_is_repr(const _Extents& __ext) { using extents_type = _Extents; using index_type = _Extents::index_type; using rank_type = _Extents::rank_type; if constexpr (extents_type::rank() == 0) return true; index_type __prod = __ext.extent(0); for (rank_type __r = 1; __r < extents_type::rank(); ++__r) if (__builtin_mul_overflow(__prod, __ext.extent(__r), &__prod)) return false; return true; } public: using extents_type = _Extents; using index_type = extents_type::index_type; using size_type = extents_type::size_type; using rank_type = extents_type::rank_type; using layout_type = layout_right; static_assert(__mdspan::__is_extents<_Extents>, "extents_type must be a specialization of std::extents"); static_assert(extents_type::rank_dynamic() > 0 || _S_req_span_size_is_repr(extents_type())); constexpr mapping() noexcept = default; constexpr mapping(const mapping&) noexcept = default; constexpr mapping(const extents_type& __ext) noexcept : _M_extents(__ext) { __glibcxx_assert(_S_req_span_size_is_repr(__ext)); } template<typename _OtherExtents> requires is_constructible_v<extents_type, _OtherExtents> constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const mapping<_OtherExtents>& __other) noexcept : _M_extents(__other.extents()) { __glibcxx_assert(__mdspan::__is_repr_as<index_type>(__other.required_span_size())); } template<typename _OtherExtents> requires is_constructible_v<extents_type, _OtherExtents> && (extents_type::rank() <= 1) constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const layout_left::mapping<_OtherExtents>& __other) noexcept : _M_extents(__other.extents()) { __glibcxx_assert(__mdspan::__is_repr_as<index_type>(__other.required_span_size())); } template<typename _OtherExtents> requires is_constructible_v<extents_type, _OtherExtents> constexpr explicit(extents_type::rank() > 0) mapping(const layout_stride::mapping<_OtherExtents>& __other) noexcept : _M_extents(__other.extents()) { __glibcxx_assert(__mdspan::__is_repr_as<index_type>(__other.required_span_size())); if constexpr (extents_type::rank() > 0) { for (rank_type __r = 0; __r < extents_type::rank(); ++__r) __glibcxx_assert(__other.stride(__r) == __other.extents()._M_rev_prod_of_extents(__r)); } } constexpr mapping& operator=(const mapping&) noexcept = default; constexpr const extents_type& extents() const noexcept { return _M_extents; } constexpr index_type required_span_size() const noexcept { return _M_extents._M_size(); } template<typename... _Idx> requires (sizeof...(_Idx) == extents_type::rank()) && (is_convertible_v<_Idx, index_type> && ...) && (is_nothrow_constructible_v<index_type, _Idx> && ...) constexpr index_type operator()(_Idx... __idx) const noexcept { __glibcxx_assert(__mdspan::__is_multidim_index_in(_M_extents, __mdspan::__index_cast<index_type>(__idx)...)); return __mdspan::__apply_index_pack<extents_type::rank()>([&]<size_t... _P> -> index_type { return ((static_cast<index_type>(__idx) * stride(_P)) + ... + 0); }); } static constexpr bool is_always_unique() noexcept { return true; } static constexpr bool is_always_exhaustive() noexcept { return true; } static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } static constexpr bool is_exhaustive() noexcept { return true; } static constexpr bool is_strided() noexcept { return true; } constexpr index_type stride(rank_type __r) const noexcept requires (extents_type::rank() > 0) { __glibcxx_assert(__r < extents_type::rank()); return _M_extents._M_rev_prod_of_extents(__r); } template <typename _OtherExtents> requires (_OtherExtents::rank() == extents_type::rank()) friend constexpr bool operator==(const mapping& __lhs, const mapping<_OtherExtents>& __rhs) noexcept { return __lhs.extents() == __rhs.extents(); } private: [[no_unique_address]] extents_type _M_extents {}; #ifdef __cpp_lib_submdspan template<typename... _Slicers> friend constexpr auto submdspan_mapping(const mapping& __src, _Slicers... __slices) { return __mdspan::__submdspan_mapping_impl<_Extents>(__src, __slices...); } #endif }; template<typename _Extents> class layout_stride::mapping { static constexpr bool _S_req_span_size_is_repr(const _Extents& __ext) { using extents_type = _Extents; using index_type = _Extents::index_type; using rank_type = _Extents::rank_type; if constexpr (extents_type::rank() == 0) return true; index_type __prod = __ext.extent(0); for (rank_type __r = 1; __r < extents_type::rank(); ++__r) if (__builtin_mul_overflow(__prod, __ext.extent(__r), &__prod)) return false; return true; } public: using extents_type = _Extents; using index_type = extents_type::index_type; using size_type = extents_type::size_type; using rank_type = extents_type::rank_type; using layout_type = layout_stride; static_assert(__mdspan::__is_extents<_Extents>, "extents_type must be a specialization of std::extents"); static_assert(extents_type::rank_dynamic() > 0 || _S_req_span_size_is_repr(extents_type())); private: static constexpr rank_type _S_rank = extents_type::rank(); using _StrideStorage = __mdspan::__maybe_empty_array<index_type, _S_rank>; template<typename _OtherMapping> static constexpr _StrideStorage _S_fill_strides(const _OtherMapping& __m) { return __mdspan::__apply_index_pack<_S_rank>([&]<size_t... _Idx> { return _StrideStorage { static_cast<index_type>(__m.stride(_Idx)) ... }; }); } static constexpr const _StrideStorage& _S_fill_strides(const _StrideStorage& __strides) { return __strides; } template<typename _OtherIndexType> static constexpr _StrideStorage _S_fill_strides(span<_OtherIndexType, _S_rank> __strides) { return __mdspan::__apply_index_pack<_S_rank>([&]<size_t... _Idx> { return _StrideStorage { static_cast<index_type>(__strides[_Idx]) ... }; }); } template<typename _OtherIndexType, size_t _Nm> static constexpr index_type _S_req_span_size(const extents_type& __e, span<_OtherIndexType, _Nm> __strides) { if constexpr (_S_rank == 0) return 1; else if constexpr (extents_type::_Impl::_S_req_size_is_always_zero) return 0; else { if (__e._M_size() == 0) return 0; else return __mdspan::__apply_index_pack<_S_rank>([&]<size_t... _Idx> { return 1 + (((__e.extent(_Idx) - 1) * __mdspan::__index_cast<index_type>(__strides[_Idx])) + ...); }); } } static constexpr index_type _S_req_span_size(const extents_type& __e, const _StrideStorage& __strides) { return _S_req_span_size(__e, span(__strides)); } constexpr auto _M_permutated_by_strides() const noexcept requires (_S_rank > 1) { array<size_t, _S_rank> __permute = __mdspan::__apply_index_pack<_S_rank>([]<size_t... _Idx> { return array<size_t, _S_rank> { _Idx ... }; }); for (rank_type __i = _S_rank - 1; __i > 0; --__i) { for (rank_type __r = 0; __r < __i; ++__r) { if (_M_strides[__permute[__r]] > _M_strides[__permute[__r + 1]]) std::swap(__permute[__r], __permute[__r + 1]); else { if (_M_strides[__permute[__r]] == _M_strides[__permute[__r + 1]] && _M_extents.extent(__permute[__r]) > 1) std::swap(__permute[__r], __permute[__r + 1]); } } } return __permute; } public: constexpr mapping() noexcept : _M_extents(extents_type()), _M_strides(_S_fill_strides(layout_right::mapping<extents_type>())) { __glibcxx_assert( __mdspan::__is_repr_as<index_type>(layout_right::mapping<extents_type>().required_span_size()) ); } constexpr mapping(const mapping&) noexcept = default; template<typename _OtherIndexType> requires is_convertible_v<const _OtherIndexType&, index_type> && is_nothrow_constructible_v<index_type, const _OtherIndexType&> constexpr mapping(const extents_type& __e, span<_OtherIndexType, _S_rank> __strides) noexcept : _M_extents(__e), _M_strides(_S_fill_strides(__strides)) { if constexpr (_S_rank > 0) { for (rank_type __r = 0; __r < _S_rank; ++__r) __glibcxx_assert(__strides[__r] > 0); __glibcxx_assert(__mdspan::__is_repr_as<index_type>(_S_req_span_size(__e, __strides))); if constexpr (_S_rank > 1) { const auto __permute = _M_permutated_by_strides(); for (rank_type __r = 1; __r < _S_rank; ++__r) __glibcxx_assert(__strides[__permute[__r]] >= __strides[__permute[__r - 1]] * __e.extent(__permute[__r - 1])); } } } template<typename _OtherIndexType> requires is_convertible_v<const _OtherIndexType&, index_type> && is_nothrow_constructible_v<index_type, const _OtherIndexType&> constexpr mapping(const extents_type& __e, const array<_OtherIndexType, _S_rank>& __strides) noexcept : mapping(__e, span(__strides)) { } template<__mdspan::__layout_mapping_alike _StridedLayoutMapping> requires is_constructible_v<extents_type, typename _StridedLayoutMapping::extents_type> && (_StridedLayoutMapping::is_always_unique() && _StridedLayoutMapping::is_always_strided()) constexpr explicit(!(is_convertible_v<typename _StridedLayoutMapping::extents_type, extents_type> && (__mdspan::__is_mapping_of<layout_left, _StridedLayoutMapping> || __mdspan::__is_mapping_of<layout_right, _StridedLayoutMapping> || __mdspan::__is_mapping_of<layout_stride, _StridedLayoutMapping>))) mapping(const _StridedLayoutMapping& __other) noexcept : _M_extents(__other.extents()), _M_strides(_S_fill_strides(__other)) { if constexpr (_S_rank > 0) { for (rank_type __r = 0; __r < _S_rank; ++__r) __glibcxx_assert(__other.stride(__r) > 0); __glibcxx_assert(__mdspan::__is_repr_as<index_type>(__other.required_span_size())); __glibcxx_assert(__mdspan::__mapping_offset(__other) == 0); } } constexpr mapping& operator=(const mapping&) noexcept = default; constexpr const extents_type& extents() const noexcept { return _M_extents; } constexpr _StrideStorage strides() const noexcept { return _M_strides; } constexpr index_type required_span_size() const noexcept { return _S_req_span_size(_M_extents, _M_strides); } template<typename... _Idx> requires (sizeof...(_Idx) == _S_rank) && (is_convertible_v<_Idx, index_type> && ...) && (is_nothrow_constructible_v<index_type, _Idx> && ...) constexpr index_type operator()(_Idx... __idx) const noexcept { __glibcxx_assert(__mdspan::__is_multidim_index_in(_M_extents, __mdspan::__index_cast<index_type>(__idx)...)); return __mdspan::__apply_index_pack<_S_rank>([&]<size_t... _P> -> index_type { return ((static_cast<index_type>(__idx) * stride(_P)) + ... + 0); }); } static constexpr bool is_always_unique() noexcept { return true; } static constexpr bool is_always_exhaustive() noexcept { return false; } static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } constexpr bool is_exhaustive() const noexcept { if constexpr (_S_rank == 0) return true; else { const index_type __span_size = required_span_size(); if (__span_size != 0) return __span_size == _M_extents._M_size(); else { if constexpr (_S_rank == 1) return _M_strides[0] == 1; else { rank_type __largest_at_r = 0; for (rank_type __r = 1; __r < _S_rank; ++__r) { if (_M_strides[__r] > _M_strides[__largest_at_r]) __largest_at_r = __r; } for (rank_type __r = 0; __r < _S_rank; ++__r) { if (_M_extents.extent(__r) == 0 && __r != __largest_at_r) return false; } return true; } } } } static constexpr bool is_strided() noexcept { return true; } constexpr index_type stride(rank_type __r) const noexcept requires (_S_rank > 0) { __glibcxx_assert(__r < _S_rank); return _M_strides[__r]; } template<__mdspan::__layout_mapping_alike _OtherMapping> requires (_OtherMapping::extents_type::rank() == _S_rank) && (_OtherMapping::is_always_strided()) friend constexpr bool operator==(const mapping& __lhs, const _OtherMapping& __rhs) noexcept { if (__lhs.extents() != __rhs.extents() || __mdspan::__mapping_offset(__rhs) != 0) return false; for (rank_type __r = 0; __r < _S_rank; ++__r) if (__lhs.stride(__r) != __rhs.stride(__r)) return false; return true; } private: [[no_unique_address]] extents_type _M_extents; [[no_unique_address]] _StrideStorage _M_strides; #ifdef __cpp_lib_submdspan template<typename... _Slicers> friend constexpr auto submdspan_mapping(const mapping& __src, _Slicers... __slices) { return __mdspan::__submdspan_mapping_impl<_Extents>(__src, __slices...); } #endif }; template<typename _Tp> struct default_accessor { using offset_policy = default_accessor; using element_type = _Tp; using reference = element_type&; using data_handle_type = element_type*; static_assert(sizeof(_Tp) > 0, "element_type must be a complete type"); static_assert(!is_abstract_v<_Tp>, "element_type cannot be an abstract type"); static_assert(!is_array_v<_Tp>, "element_type cannot be an array type"); constexpr default_accessor() noexcept = default; template<typename _Up> requires is_convertible_v<_Up(*)[], _Tp(*)[]> constexpr default_accessor(default_accessor<_Up>) noexcept { } constexpr reference access(data_handle_type __p, size_t __i) const noexcept { return __p[__i]; } constexpr data_handle_type offset(data_handle_type __p, size_t __i) const noexcept { return __p + __i; } }; template<typename _Tp, typename _Extents, typename _LayoutPolicy = layout_right, typename _AccessorPolicy = default_accessor<_Tp>> class mdspan { public: using extents_type = _Extents; using layout_type = _LayoutPolicy; using accessor_type = _AccessorPolicy; using mapping_type = layout_type::template mapping<extents_type>; using element_type = _Tp; using value_type = remove_cv_t<_Tp>; using index_type = extents_type::index_type; using size_type = extents_type::size_type; using rank_type = extents_type::rank_type; using data_handle_type = accessor_type::data_handle_type; using reference = accessor_type::reference; static_assert(sizeof(_Tp) > 0, "element_type must be a complete type"); static_assert(!is_abstract_v<_Tp>, "element_type cannot be an abstract type"); static_assert(!is_array_v<_Tp>, "element_type cannot be an array type"); static_assert(__mdspan::__is_extents<_Extents>, "extents_type must be a specialization of std::extents"); static_assert(is_same_v<_Tp, typename _AccessorPolicy::element_type>); static constexpr rank_type rank() noexcept { return extents_type::rank(); } static constexpr rank_type rank_dynamic() noexcept { return extents_type::rank_dynamic(); } static constexpr size_t static_extent(rank_type __r) noexcept { return extents_type::static_extent(__r); } constexpr index_type extent(rank_type __r) const noexcept { return extents().extent(__r); } private: [[no_unique_address]] accessor_type _M_acc; [[no_unique_address]] mapping_type _M_map; [[no_unique_address]] data_handle_type _M_ptr; template <typename _Up, typename _OtherExtents, typename _OtherLayoutPolicy, typename _OtherAccessor> friend class mdspan; public: constexpr mdspan() requires (rank_dynamic() > 0) && is_default_constructible_v<data_handle_type> && is_default_constructible_v<mapping_type> && is_default_constructible_v<accessor_type> : _M_acc(), _M_map(), _M_ptr() { } constexpr mdspan(const mdspan&) = default; constexpr mdspan(mdspan&&) = default; template<typename... _OtherIndexTypes> requires (is_convertible_v<_OtherIndexTypes, index_type> && ...) && (is_nothrow_constructible_v<index_type, _OtherIndexTypes> && ...) && (sizeof...(_OtherIndexTypes) == rank() || sizeof...(_OtherIndexTypes) == rank_dynamic()) && is_constructible_v<mapping_type, extents_type> && is_default_constructible_v<accessor_type> constexpr explicit mdspan(data_handle_type __p, _OtherIndexTypes... __exts) : _M_acc(), _M_map(extents_type(static_cast<index_type>(std::move(__exts))...)), _M_ptr(std::move(__p)) { } template<typename _OtherIndexType, size_t _Nm> requires is_convertible_v<const _OtherIndexType&, index_type> && is_nothrow_constructible_v<index_type, const _OtherIndexType&> && (_Nm == rank() || _Nm == rank_dynamic()) && is_constructible_v<mapping_type, extents_type> && is_default_constructible_v<accessor_type> constexpr explicit(_Nm != rank_dynamic()) mdspan(data_handle_type __p, std::span<_OtherIndexType, _Nm> __exts) : _M_acc(), _M_map(extents_type(__exts)), _M_ptr(std::move(__p)) { } template<typename _OtherIndexType, size_t _Nm> requires is_convertible_v<const _OtherIndexType&, index_type> && is_nothrow_constructible_v<index_type, const _OtherIndexType&> && (_Nm == rank() || _Nm == rank_dynamic()) && is_constructible_v<mapping_type, extents_type> && is_default_constructible_v<accessor_type> constexpr explicit(_Nm != rank_dynamic()) mdspan(data_handle_type __p, const std::array<_OtherIndexType, _Nm>& __exts) : _M_acc(), _M_map(extents_type(__exts)), _M_ptr(std::move(__p)) { } constexpr mdspan(data_handle_type __p, const extents_type& __ext) requires is_constructible_v<mapping_type, const extents_type&> && is_default_constructible_v<accessor_type> : _M_acc(), _M_map(__ext), _M_ptr(std::move(__p)) { } constexpr mdspan(data_handle_type __p, const mapping_type& __m) requires is_default_constructible_v<accessor_type> : _M_acc(), _M_map(__m), _M_ptr(std::move(__p)) { } constexpr mdspan(data_handle_type __p, const mapping_type& __m, const accessor_type& __a) : _M_acc(__a), _M_map(__m), _M_ptr(std::move(__p)) { } template<typename _Up, typename _OtherExtents, typename _OtherLayoutPolicy, typename _OtherAccessor> requires is_constructible_v<mapping_type, const typename _OtherLayoutPolicy::template mapping<_OtherExtents>&> && is_constructible_v<accessor_type, const _OtherAccessor&> && is_constructible_v<data_handle_type, const typename _OtherAccessor::data_handle_type&> && is_constructible_v<extents_type, _OtherExtents> constexpr explicit(!is_convertible_v<const typename _OtherLayoutPolicy::template mapping<_OtherExtents>&, mapping_type> || !is_convertible_v<const _OtherAccessor&, accessor_type>) mdspan(const mdspan<_Up, _OtherExtents, _OtherLayoutPolicy, _OtherAccessor>& __other) : _M_acc(__other._M_acc), _M_map(__other._M_map), _M_ptr(__other._M_ptr) { if constexpr (rank() > 0) { for (size_t __r = 0; __r < rank(); ++__r) __glibcxx_assert(static_extent(__r) == dynamic_extent || static_cast<index_type>(__other.extent(__r)) == static_cast<index_type>(static_extent(__r))); } } constexpr mdspan& operator=(const mdspan&) = default; constexpr mdspan& operator=(mdspan&&) = default; // element access template<typename... _Idx> requires (is_convertible_v<_Idx, index_type> && ...) && (is_nothrow_constructible_v<index_type, _Idx> && ...) && (sizeof...(_Idx) == rank()) constexpr reference operator[](_Idx... __idx) const { __glibcxx_assert(__mdspan::__is_multidim_index_in(extents(), __mdspan::__index_cast<index_type>(__idx)...)); return _M_acc.access(_M_ptr, _M_map(static_cast<index_type>(std::move(__idx))...)); } template<typename _OtherIndexType> constexpr reference operator[](span<_OtherIndexType, rank()> __idx) const { return __mdspan::__apply_index_pack<rank()>([&]<size_t... _Is> -> reference { return operator[](static_cast<const _OtherIndexType&>(__idx[_Is])...); }); } template<typename _OtherIndexType> constexpr reference operator[](const array<_OtherIndexType, rank()>& __idx) const { return operator[](span(__idx)); } // observers constexpr size_type size() const noexcept { return _M_map.extents()._M_size(); } [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; } friend constexpr void swap(mdspan& __lhs, mdspan& __rhs) noexcept { std::swap(__lhs._M_acc, __rhs._M_acc); std::swap(__lhs._M_map, __rhs._M_map); std::swap(__lhs._M_ptr, __rhs._M_ptr); } constexpr const extents_type& extents() const noexcept { return _M_map.extents(); } constexpr const data_handle_type& data_handle() const noexcept { return _M_ptr; } constexpr const mapping_type& mapping() const noexcept { return _M_map; } constexpr const accessor_type& accessor() const noexcept { return _M_acc; } static constexpr bool is_always_unique() noexcept { return mapping_type::is_always_unique(); } static constexpr bool is_always_exhaustive() noexcept { return mapping_type::is_always_exhaustive(); } static constexpr bool is_always_strided() noexcept { return mapping_type::is_always_strided(); } constexpr bool is_unique() const noexcept { return _M_map.is_unique(); } constexpr bool is_exhaustive() const noexcept { return _M_map.is_exhaustive(); } constexpr bool is_strided() const noexcept { return _M_map.is_strided(); } constexpr index_type stride(rank_type __r) const { return _M_map.stride(__r); } }; template<typename _CArray> requires is_array_v<_CArray> && (rank_v<_CArray> == 1) mdspan(_CArray&) -> mdspan<remove_all_extents_t<_CArray>, extents<size_t, extent_v<_CArray, 0>>>; template<typename _P> requires is_pointer_v<remove_reference_t<_P>> mdspan(_P&&) -> mdspan<remove_pointer_t<remove_reference_t<_P>>, extents<size_t>>; template<typename _Tp, typename... _Extents> requires (is_convertible_v<_Extents, size_t> && ...) && (sizeof...(_Extents) > 0) explicit mdspan(_Tp*, _Extents...) -> mdspan<_Tp, dextents<size_t, sizeof...(_Extents)>>; template<typename _Tp, typename _OtherIndexType, size_t _Nm> mdspan(_Tp*, span<_OtherIndexType, _Nm>) -> mdspan<_Tp, dextents<size_t, _Nm>>; template<typename _Tp, typename _OtherIndexType, size_t _Nm> mdspan(_Tp*, const array<_OtherIndexType, _Nm>&) -> mdspan<_Tp, dextents<size_t, _Nm>>; template<typename _Tp, typename _IndexType, size_t... _Extents> mdspan(_Tp*, const extents<_IndexType, _Extents...>&) -> mdspan<_Tp, extents<_IndexType, _Extents...>>; template<typename _Tp, typename _Mapping> mdspan(_Tp*, const _Mapping&) -> mdspan<_Tp, typename _Mapping::extents_type, typename _Mapping::layout_type>; template<typename _Mapping, typename _Accessor> mdspan(const typename _Accessor::data_handle_type&, const _Mapping&, const _Accessor&) -> mdspan<typename _Accessor::element_type, typename _Mapping::extents_type, typename _Mapping::layout_type, _Accessor>; #ifdef __cpp_lib_submdspan // C++ >= 26 template<typename _Offset, typename _Extent, typename _Stride> struct strided_slice { using offset_type = _Offset; using extent_type = _Extent; using stride_type = _Stride; [[no_unique_address]] offset_type offset {}; [[no_unique_address]] extent_type extent {}; [[no_unique_address]] stride_type stride {}; static_assert(is_integral_v<_Offset> || __mdspan::__integral_constant_like<_Offset>); static_assert(is_integral_v<_Extent> || __mdspan::__integral_constant_like<_Extent>); static_assert(is_integral_v<_Stride> || __mdspan::__integral_constant_like<_Stride>); }; template<typename _LayoutMapping> struct submdspan_mapping_result { [[no_unique_address]] _LayoutMapping mapping = _LayoutMapping(); size_t offset; }; struct full_extent_t { explicit full_extent_t() = default; }; inline constexpr full_extent_t full_extent {}; namespace __mdspan { template<typename> inline constexpr bool __is_strided_slice = false; template<typename _Offset, typename _Extent, typename _Stride> inline constexpr bool __is_strided_slice<strided_slice<_Offset, _Extent, _Stride>> = true; template<typename _Slice, typename _IndexType = size_t> concept __slice_specifier = convertible_to<_Slice, _IndexType> || __mdspan::__index_pair_like<_Slice, _IndexType> || is_convertible_v<_Slice, full_extent_t> || __mdspan::__is_strided_slice<_Slice>; template<typename _IndexType, size_t _Kp, typename... _Slicers> constexpr _IndexType __first_of_extent_slice(_Slicers... __slices) { static_assert(is_integral_v<_IndexType>); using _Slicer = _Nth_type_t<_Kp, _Slicers...>; auto& __slice = __mdspan::__get_element_at<_Kp>(__slices...); if constexpr (convertible_to<_Slicer, _IndexType>) return __mdspan::__index_cast<_IndexType>(__slice); else if constexpr (__mdspan::__index_pair_like<_Slicer, _IndexType>) return __mdspan::__index_cast<_IndexType>(std::get<0>(__slice)); else if constexpr (__mdspan::__is_strided_slice<_Slicer>) return __mdspan::__index_cast<_IndexType>(__mdspan::__de_ice(__slice.offset)); else return 0; } template<size_t _Kp, typename _Extents, typename... _Slicers> constexpr auto __last_of_extent_slice(const _Extents& __src, _Slicers... __slices) { static_assert(__mdspan::__is_extents<_Extents>); using _IndexType = _Extents::index_type; using _Slicer = _Nth_type_t<_Kp, _Slicers...>; auto& __slice = __mdspan::__get_element_at<_Kp>(__slices...); if constexpr (convertible_to<_Slicer, _IndexType>) return __mdspan::__index_cast<_IndexType>(__mdspan::__de_ice(__slice) + 1); else if constexpr (__mdspan::__index_pair_like<_Slicer, _IndexType>) return __mdspan::__index_cast<_IndexType>(std::get<1>(__slice)); else if constexpr (__mdspan::__is_strided_slice<_Slicer>) return __mdspan::__index_cast<_IndexType>(__mdspan::__de_ice(__slice.offset) + __mdspan::__de_ice(__slice.extent)); else return __mdspan::__index_cast<_IndexType>(__src.extent(_Kp)); } template<typename _IndexType, typename... _Slicers> consteval auto __generate_map_ranks() { constexpr size_t __rank = sizeof...(_Slicers); array<size_t, __rank> __result; __mdspan::__for_each_types<_Slicers...>([&, __k = 0, __j = 0]<typename _Slice> mutable { if constexpr (convertible_to<_Slice, _IndexType>) __result[__k] = dynamic_extent; else __result[__k] = __j++; ++__k; }); return __result; } // TODO: add '__mdspan::__src_indices' template<typename _Extents, typename... _Slicers> consteval auto __subextents() { using _IndexType = _Extents::index_type; static constexpr size_t __subrank = ((!convertible_to<_Slicers, _IndexType>) + ... + 0); static constexpr auto __map_rank = __mdspan::__generate_map_ranks<_IndexType, _Slicers...>(); __mdspan::__maybe_empty_array<size_t, __subrank> __result; if constexpr (__subrank != 0) { __mdspan::__for_each_index_pack_and_types<_Extents::rank(), _Slicers...>( [&]<size_t _Kp, typename _Slicer> { if constexpr (__map_rank[_Kp] != dynamic_extent) { if constexpr (is_convertible_v<_Slicer, full_extent_t>) __result[__map_rank[_Kp]] = _Extents::static_extent(_Kp); else if constexpr (requires { // allows short-circuit evaluation requires __mdspan::__index_pair_like<_Slicer, _IndexType>; requires __mdspan::__integral_constant_like<tuple_element_t<0, _Slicer>>; requires __mdspan::__integral_constant_like<tuple_element_t<1, _Slicer>>; }) __result[__map_rank[_Kp]] = __mdspan::__de_ice(tuple_element_t<1, _Slicer>()) - __mdspan::__de_ice(tuple_element_t<0, _Slicer>()); else if constexpr (requires { requires __mdspan::__is_strided_slice<_Slicer>; requires __mdspan::__integral_constant_like<typename _Slicer::extent_type>; requires typename _Slicer::extent_type() == 0; }) __result[__map_rank[_Kp]] = 0; else if constexpr (requires { requires __mdspan::__is_strided_slice<_Slicer>; requires __mdspan::__integral_constant_like<typename _Slicer::extent_type>; requires __mdspan::__integral_constant_like<typename _Slicer::stride_type>; }) __result[__map_rank[_Kp]] = 1 + (__mdspan::__de_ice(_Slicer::extent_type()) - 1) / __mdspan::__de_ice(_Slicer::stride_type()); else __result[__map_rank[_Kp]] = dynamic_extent; } }); } return __result; } template<typename _Extents, typename... _Slicers> consteval auto __submdspan_extents_result_impl() { static constexpr auto __subextents_result = __mdspan::__subextents<_Extents, _Slicers...>(); return __mdspan::__apply_index_pack<__subextents_result.size()>([]<size_t... _Idx> { return extents<typename _Extents::index_type, __subextents_result[_Idx]...> {}; }); } } template<typename _Extents, typename... _Slicers> requires __mdspan::__is_extents<_Extents> && (_Extents::rank() == sizeof...(_Slicers)) && (__mdspan::__slice_specifier<_Slicers, typename _Extents::index_type> && ...) constexpr auto submdspan_extents(const _Extents& __src, _Slicers... __slices) { // TODO: add preconditions // preconditions: // for each rank index k of __src.extents(), all of the following are true: // * if _Slicers ... [k] is a specialization of strided_slice: // * __slices ... [k].extent == 0 // * __slices ... [k].stride > 0 // * 0 <= __first_of_extent_slice<_IndexType, k>(__slices...) // <= __last_of_extent_slice<k>(__src, __slices...) // <= __src.extent(k) using _Result = decltype(__mdspan::__submdspan_extents_result_impl<_Extents, _Slicers...>()); if constexpr (_Result::rank() == 0) return _Result {}; else { using _IndexType = _Extents::index_type; static constexpr auto __map_rank = __mdspan::__generate_map_ranks<_IndexType, _Slicers...>(); array<_IndexType, _Result::rank()> __result_args; __mdspan::__for_each_index_pack_and_args<_Extents::rank()>( [&]<size_t _Kp, typename _Slicer>(type_identity_t<_Slicer> __slice) { if constexpr (__map_rank[_Kp] != dynamic_extent) { if constexpr (__mdspan::__is_strided_slice<_Slicer>) __result_args[__map_rank[_Kp]] = __slice.extent == 0 ? 0 : 1 + (__mdspan::__de_ice(__slice.extent) - 1) / __mdspan::__de_ice(__slice.stride); else __result_args[__map_rank[_Kp]] = __mdspan::__last_of_extent_slice<_Kp>(__src, __slices...) - __mdspan::__first_of_extent_slice<_IndexType, _Kp>(__slices...); } }, __slices...); return _Result { __result_args }; } } namespace __mdspan { template<typename _Extents, typename _Subextents, typename _LayoutMapping, typename... _Slicers> constexpr auto __submdspan_strides(const _LayoutMapping& __mapping, _Slicers... __slices) { using _IndexType = _Extents::index_type; static constexpr auto __map_rank = __mdspan::__generate_map_ranks<_IndexType, _Slicers...>(); array<_IndexType, _Subextents::rank()> __result; if constexpr (_Subextents::rank() != 0) { __mdspan::__for_each_index_pack_and_args<_Extents::rank()>( [&]<size_t _Kp, typename _Slicer>(type_identity_t<_Slicer> __slice){ if constexpr (__map_rank[_Kp] != dynamic_extent) { if constexpr (__mdspan::__is_strided_slice<_Slicer>) __result[__map_rank[_Kp]] = __mapping.stride(_Kp) * (__slice.stride < __slice.extent ? __mdspan::__de_ice(__slice.stride) : 1); else __result[__map_rank[_Kp]] = __mapping.stride(_Kp); } }, __slices...); } return __result; } template<typename _IndexType, typename _Extents, typename _Subextents, typename... _Slicers> consteval bool __layout_left_submdspan_mapping_conds() { if constexpr (_Subextents::rank() == 0 || _Subextents::rank() - 1 >= sizeof...(_Slicers)) return false; else { using _LastSlicer = _Nth_type_t<_Subextents::rank() - 1, _Slicers...>; return __mdspan::__apply_index_pack<_Subextents::rank() - 1>([]<size_t... _Ks>{ return (is_convertible_v<_Nth_type_t<_Ks, _Slicers...>, full_extent_t> && ...); }) && (__mdspan::__index_pair_like<_LastSlicer, _IndexType> || is_convertible_v<_LastSlicer, full_extent_t>); } } template<typename _IndexType, typename _Extents, typename _Subextents, typename... _Slicers> consteval bool __layout_right_submdspan_mapping_conds() { if constexpr (_Extents::rank() < _Subextents::rank() || _Extents::rank() - _Subextents::rank() >= sizeof...(_Slicers)) return false; else { using _FirstSlicer = _Nth_type_t<_Extents::rank() - _Subextents::rank(), _Slicers...>; return __mdspan::__apply_index_pack<_Subextents::rank() - 1>([]<size_t... _Ks>{ constexpr auto __apply_offset = [](size_t _Kp) -> size_t { return _Kp + _Extents::rank() - _Subextents::rank() + 1; }; return (is_convertible_v<_Nth_type_t<__apply_offset(_Ks), _Slicers...>, full_extent_t> && ...); }) && (__mdspan::__index_pair_like<_FirstSlicer, _IndexType> || is_convertible_v<_FirstSlicer, full_extent_t>); } } // TODO: add constraints and preconditions template<typename _Extents, typename _LayoutMapping, typename... _Slicers> constexpr auto __submdspan_mapping_impl(const _LayoutMapping& __mapping, _Slicers... __slices) { using _IndexType = _Extents::index_type; const auto __subexts = std::submdspan_extents(__mapping.extents(), __slices...); using _Subextents = remove_cv_t<decltype(__subexts)>; const auto __substrides = __mdspan::__submdspan_strides<_Extents, _Subextents>(__mapping, __slices...); return __mdspan::__apply_index_pack<_LayoutMapping::extents_type::rank()>([&]<size_t... _Idx>{ const size_t __offset = __mapping(__mdspan::__first_of_extent_slice<_IndexType, _Idx>(__slices...)...); if constexpr (_Extents::rank() == 0) return submdspan_mapping_result { __mapping, 0 }; else if constexpr (is_same_v<layout_left, typename _LayoutMapping::layout_type> && __mdspan::__layout_left_submdspan_mapping_conds<_IndexType, _Extents, _Subextents, _Slicers...>()) return submdspan_mapping_result { layout_left::mapping(__subexts), __offset }; else if constexpr (is_same_v<layout_right, typename _LayoutMapping::layout_type> && __mdspan::__layout_right_submdspan_mapping_conds<_IndexType, _Extents, _Subextents, _Slicers...>()) return submdspan_mapping_result { layout_right::mapping(__subexts), __offset }; else return submdspan_mapping_result { layout_stride::mapping(__subexts, __substrides), __offset }; }); } } // TODO: add constraints and preconditions template<typename _Tp, typename _Extents, typename _Layout, typename _Accessor, typename... _Slicers> constexpr auto submdspan(const mdspan<_Tp, _Extents, _Layout, _Accessor>& __src, _Slicers... __slices) { auto __sub_map_offset = submdspan_mapping(__src.mapping(), __slices...); return mdspan (__src.accessor().offset(__src.data_handle(), __sub_map_offset.offset), __sub_map_offset.mapping, typename _Accessor::offset_policy(__src.accessor())); } #endif // C++26 _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // __cpp_lib_mdspan #endif // _GLIBCXX_MDSPAN ////////////////////////////////////////// /// Basic Tests ////////////////////////////////////////// namespace gold { void assume_failure() { } constexpr void assume(bool b) noexcept { if consteval { if (!b) assume_failure(); } else { if (!b) [[unlikely]] #ifndef NDEBUG __builtin_trap(); #else __builtin_unreachable(); #endif // NDEBUG } } } template <int = 0> consteval void test_extents0() { using Extents0 = std::extents<std::size_t, 6, 4, 2>; static_assert(std::is_same_v<typename Extents0::index_type, std::size_t>); static_assert(std::is_same_v<typename Extents0::size_type, std::size_t>); static_assert(std::is_same_v<typename Extents0::rank_type, std::size_t>); static_assert(Extents0::rank() == 3); static_assert(Extents0::rank_dynamic() == 0); static_assert(Extents0::static_extent(0) == 6); static_assert(Extents0::static_extent(1) == 4); static_assert(Extents0::static_extent(2) == 2); static_assert(sizeof(Extents0) == 1); Extents0 ext0; gold::assume(ext0.extent(0) == 6); gold::assume(ext0.extent(1) == 4); gold::assume(ext0.extent(2) == 2); //// using Extents1 = std::extents<std::size_t, std::dynamic_extent, std::dynamic_extent>; static_assert(Extents1::rank() == 2); static_assert(Extents1::rank_dynamic() == 2); static_assert(Extents1::static_extent(0) == std::dynamic_extent); static_assert(Extents1::static_extent(1) == std::dynamic_extent); static_assert(sizeof(Extents1) == sizeof(std::size_t) * Extents1::rank_dynamic()); Extents1 ext1 (6, 9); gold::assume(ext1.extent(0) == 6); gold::assume(ext1.extent(1) == 9); //// using Extents2 = std::extents<std::size_t, 2, 3, std::dynamic_extent>; static_assert(Extents2::rank() == 3); static_assert(Extents2::rank_dynamic() == 1); static_assert(Extents2::static_extent(0) == 2); static_assert(Extents2::static_extent(1) == 3); static_assert(Extents2::static_extent(2) == std::dynamic_extent); Extents2 ext2 (5); gold::assume(ext2.extent(0) == 2); gold::assume(ext2.extent(1) == 3); gold::assume(ext2.extent(2) == 5); //// using Extents3 = std::extents<int, std::dynamic_extent, 3, std::dynamic_extent, 5>; static_assert(std::is_same_v<typename Extents3::index_type, int>); static_assert(std::is_same_v<typename Extents3::size_type, unsigned int>); static_assert(std::is_same_v<typename Extents3::rank_type, std::size_t>); static_assert(Extents3::rank() == 4); static_assert(Extents3::rank_dynamic() == 2); static_assert(Extents3::static_extent(0) == std::dynamic_extent); static_assert(Extents3::static_extent(1) == 3); static_assert(Extents3::static_extent(2) == std::dynamic_extent); static_assert(Extents3::static_extent(3) == 5); Extents3 ext3 (6, 9); gold::assume(ext3.extent(0) == 6); gold::assume(ext3.extent(1) == 3); gold::assume(ext3.extent(2) == 9); gold::assume(ext3.extent(3) == 5); } template <int = 0> consteval void test_extents1() { using T0 = std::extents<std::size_t, std::dynamic_extent, std::dynamic_extent>; using T0 = std::dextents<std::size_t, 2>; static_assert(std::regular<T0>); static_assert(std::is_trivially_copyable_v<T0>); using T1 = std::extents<signed char, 1, 5, 3, 4>; static_assert(std::regular<T1>); static_assert(std::is_trivially_copyable_v<T1>); } template <int = 0> consteval void test_extents2() { using StaticExtents = std::extents<std::size_t, 3, 6, 9>; StaticExtents static_exts; static_assert(StaticExtents::rank() == 3); static_assert(StaticExtents::rank_dynamic() == 0); static_assert(StaticExtents::static_extent(0) == 3); static_assert(StaticExtents::static_extent(1) == 6); static_assert(StaticExtents::static_extent(2) == 9); // ... using DynamicExtents = std::dextents<std::size_t, 3>; // decay to dynamic extents DynamicExtents runtime_exts = static_exts; static_assert(DynamicExtents::rank() == 3); static_assert(DynamicExtents::rank_dynamic() == 3); static_assert(DynamicExtents::static_extent(0) == std::dynamic_extent); static_assert(DynamicExtents::static_extent(1) == std::dynamic_extent); static_assert(DynamicExtents::static_extent(2) == std::dynamic_extent); gold::assume(runtime_exts.extent(0) == 3); gold::assume(runtime_exts.extent(1) == 6); gold::assume(runtime_exts.extent(2) == 9); gold::assume(static_exts == runtime_exts); } template <int = 0> consteval void test_layout_right() { // layout-right // + row-major layout type // + rightmost stride is 1 { using Extents = std::extents<std::size_t>; static_assert(Extents::rank() == 0); static_assert(Extents::rank_dynamic() == 0); Extents exts; using Mapping = std::layout_right::mapping<Extents>; Mapping m (exts); gold::assume(m.required_span_size() == 1); gold::assume(m() == 0); static_assert(Mapping::is_always_unique()); static_assert(Mapping::is_always_exhaustive()); static_assert(Mapping::is_always_strided()); static_assert(Mapping::is_unique()); static_assert(Mapping::is_exhaustive()); static_assert(Mapping::is_strided()); } { using Extents = std::extents<std::size_t>; static_assert(Extents::rank() == 0); static_assert(Extents::rank_dynamic() == 0); Extents exts; using Mapping = std::layout_right::mapping<Extents>; Mapping m (exts); gold::assume(m.required_span_size() == 1); gold::assume(m() == 0); } { using Extents = std::extents<std::size_t, 4>; static_assert(Extents::rank() == 1); static_assert(Extents::rank_dynamic() == 0); static_assert(Extents::static_extent(0) == 4); Extents exts; using Mapping = std::layout_right::mapping<Extents>; static_assert(std::is_same_v<typename Mapping::layout_type, std::layout_right>); static_assert(std::is_same_v<typename Mapping::extents_type, Extents>); Mapping m (exts); gold::assume(m.required_span_size() == 4); gold::assume(m.stride(0) == 1); gold::assume(m(0) == 0); gold::assume(m(1) == 1); gold::assume(m(2) == 2); gold::assume(m(3) == 3); } { using Extents = std::extents<std::size_t, 4, 3>; static_assert(Extents::rank() == 2); static_assert(Extents::rank_dynamic() == 0); static_assert(Extents::static_extent(0) == 4); static_assert(Extents::static_extent(1) == 3); Extents exts; using Mapping = std::layout_right::mapping<Extents>; Mapping m (exts); gold::assume(m.required_span_size() == 12); gold::assume(m.stride(1) == 1); gold::assume(m.stride(0) == 3 * 1); gold::assume(m(0, 0) == 0); gold::assume(m(0, 1) == 1); gold::assume(m(0, 2) == 2); gold::assume(m(1, 0) == 3); gold::assume(m(1, 1) == 4); gold::assume(m(1, 2) == 5); gold::assume(m(2, 0) == 6); gold::assume(m(2, 1) == 7); gold::assume(m(2, 2) == 8); gold::assume(m(3, 0) == 9); gold::assume(m(3, 1) == 10); gold::assume(m(3, 2) == 11); } { using Extents = std::extents<std::size_t, 4, 3, 2>; static_assert(Extents::rank() == 3); static_assert(Extents::rank_dynamic() == 0); static_assert(Extents::static_extent(0) == 4); static_assert(Extents::static_extent(1) == 3); static_assert(Extents::static_extent(2) == 2); Extents exts; using Mapping = std::layout_right::mapping<Extents>; Mapping m (exts); gold::assume(m.required_span_size() == 24); gold::assume(m.stride(2) == 1); gold::assume(m.stride(1) == 2 * 1); gold::assume(m.stride(0) == 3 * 2 * 1 /* 6 */); gold::assume(m(0, 0, 0) == 0); gold::assume(m(0, 0, 1) == 1); gold::assume(m(0, 1, 0) == 2); gold::assume(m(0, 1, 1) == 3); gold::assume(m(0, 2, 0) == 4); gold::assume(m(0, 2, 1) == 5); gold::assume(m(1, 0, 0) == 6); gold::assume(m(1, 0, 1) == 7); gold::assume(m(1, 1, 0) == 8); gold::assume(m(1, 1, 1) == 9); gold::assume(m(1, 2, 0) == 10); gold::assume(m(1, 2, 1) == 11); gold::assume(m(2, 0, 0) == 12); gold::assume(m(2, 0, 1) == 13); gold::assume(m(2, 1, 0) == 14); gold::assume(m(2, 1, 1) == 15); gold::assume(m(2, 2, 0) == 16); gold::assume(m(2, 2, 1) == 17); gold::assume(m(3, 0, 0) == 18); gold::assume(m(3, 0, 1) == 19); gold::assume(m(3, 1, 0) == 20); gold::assume(m(3, 1, 1) == 21); gold::assume(m(3, 2, 0) == 22); gold::assume(m(3, 2, 1) == 23); } } template <int = 0> consteval void test_layout_left() { // layout-left // + column-major layout type // + leftmost stride is 1 { using Extents = std::extents<std::size_t>; static_assert(Extents::rank() == 0); static_assert(Extents::rank_dynamic() == 0); Extents exts; using Mapping = std::layout_left::mapping<Extents>; Mapping m (exts); gold::assume(m.required_span_size() == 1); gold::assume(m() == 0); static_assert(Mapping::is_always_unique()); static_assert(Mapping::is_always_exhaustive()); static_assert(Mapping::is_always_strided()); static_assert(Mapping::is_unique()); static_assert(Mapping::is_exhaustive()); static_assert(Mapping::is_strided()); } { using Extents = std::extents<std::size_t, 4>; static_assert(Extents::rank() == 1); static_assert(Extents::rank_dynamic() == 0); static_assert(Extents::static_extent(0) == 4); Extents exts; using Mapping = std::layout_left::mapping<Extents>; static_assert(std::is_same_v<typename Mapping::layout_type, std::layout_left>); static_assert(std::is_same_v<typename Mapping::extents_type, Extents>); Mapping m (exts); gold::assume(m.required_span_size() == 4); gold::assume(m.stride(0) == 1); gold::assume(m(0) == 0); gold::assume(m(1) == 1); gold::assume(m(2) == 2); gold::assume(m(3) == 3); } { using Extents = std::extents<std::size_t, 4, 3>; static_assert(Extents::rank() == 2); static_assert(Extents::rank_dynamic() == 0); static_assert(Extents::static_extent(0) == 4); static_assert(Extents::static_extent(1) == 3); Extents exts; using Mapping = std::layout_left::mapping<Extents>; Mapping m (exts); gold::assume(m.required_span_size() == 12); gold::assume(m.stride(0) == 1); gold::assume(m.stride(1) == 1 * 4); gold::assume(m(0, 0) == 0); gold::assume(m(1, 0) == 1); gold::assume(m(2, 0) == 2); gold::assume(m(3, 0) == 3); gold::assume(m(0, 1) == 4); gold::assume(m(1, 1) == 5); gold::assume(m(2, 1) == 6); gold::assume(m(3, 1) == 7); gold::assume(m(0, 2) == 8); gold::assume(m(1, 2) == 9); gold::assume(m(2, 2) == 10); gold::assume(m(3, 2) == 11); } { using Extents = std::extents<std::size_t, 4, 3, 2>; static_assert(Extents::rank() == 3); static_assert(Extents::rank_dynamic() == 0); static_assert(Extents::static_extent(0) == 4); static_assert(Extents::static_extent(1) == 3); static_assert(Extents::static_extent(2) == 2); Extents exts; using Mapping = std::layout_left::mapping<Extents>; Mapping m (exts); gold::assume(m.required_span_size() == 24); gold::assume(m.stride(0) == 1); gold::assume(m.stride(1) == 1 * 4 /* 4 */); gold::assume(m.stride(2) == 1 * 4 * 3 /* 12 */); gold::assume(m(0, 0, 0) == 0); gold::assume(m(1, 0, 0) == 1); gold::assume(m(2, 0, 0) == 2); gold::assume(m(3, 0, 0) == 3); gold::assume(m(0, 1, 0) == 4); gold::assume(m(1, 1, 0) == 5); gold::assume(m(2, 1, 0) == 6); gold::assume(m(3, 1, 0) == 7); gold::assume(m(0, 2, 0) == 8); gold::assume(m(1, 2, 0) == 9); gold::assume(m(2, 2, 0) == 10); gold::assume(m(3, 2, 0) == 11); gold::assume(m(0, 0, 1) == 12); gold::assume(m(1, 0, 1) == 13); gold::assume(m(2, 0, 1) == 14); gold::assume(m(3, 0, 1) == 15); gold::assume(m(0, 1, 1) == 16); gold::assume(m(1, 1, 1) == 17); gold::assume(m(2, 1, 1) == 18); gold::assume(m(3, 1, 1) == 19); gold::assume(m(0, 2, 1) == 20); gold::assume(m(1, 2, 1) == 21); gold::assume(m(2, 2, 1) == 22); gold::assume(m(3, 2, 1) == 23); } } template <int = 0> consteval void test_layout_stride() { // layout-stride // + user-defined strided layout type { using Extents = std::extents<std::size_t, 4>; static_assert(Extents::rank() == 1); static_assert(Extents::rank_dynamic() == 0); static_assert(Extents::static_extent(0) == 4); Extents exts; using Mapping = std::layout_stride::mapping<Extents>; static_assert(std::is_same_v<typename Mapping::layout_type, std::layout_stride>); static_assert(std::is_same_v<typename Mapping::extents_type, Extents>); static_assert(Mapping::is_always_unique()); static_assert(!Mapping::is_always_exhaustive()); static_assert(Mapping::is_always_strided()); Mapping m_1 (exts, std::array{1}); gold::assume(m_1.is_unique()); gold::assume(m_1.is_exhaustive()); gold::assume(m_1.is_strided()); gold::assume(m_1.required_span_size() == 4); gold::assume(m_1.stride(0) == 1); gold::assume(m_1(0) == 0); gold::assume(m_1(1) == 1); gold::assume(m_1(2) == 2); gold::assume(m_1(3) == 3); Mapping m_2 (exts, std::array{2}); gold::assume(m_2.required_span_size() == 7); gold::assume(!m_2.is_exhaustive()); gold::assume(m_2.stride(0) == 2); gold::assume(m_2(0) == 0); gold::assume(m_2(1) == 2); gold::assume(m_2(2) == 4); gold::assume(m_2(3) == 6); } { using Extents = std::extents<std::size_t, 2, 3>; using LayoutLeftMapping = std::layout_left::mapping<Extents>; using LayoutRightMapping = std::layout_right::mapping<Extents>; using LayoutStrideMapping = std::layout_stride::mapping<Extents>; Extents exts; LayoutStrideMapping m_left = LayoutLeftMapping(exts); gold::assume(m_left.required_span_size() == 6); gold::assume(m_left.stride(0) == 1); gold::assume(m_left.stride(1) == 2); LayoutStrideMapping m_right = LayoutRightMapping(exts); gold::assume(m_right.required_span_size() == 6); gold::assume(m_right.stride(1) == 1); gold::assume(m_right.stride(0) == 3); } } template <int = 0> consteval void test_mdspan0() { { using Span = std::mdspan<int, std::extents<int>>; static_assert(std::is_same_v<typename Span::element_type, int>); static_assert(std::is_same_v<typename Span::reference, int&>); static_assert(std::is_same_v<typename Span::data_handle_type, int*>); static_assert(std::is_same_v<typename Span::extents_type, std::extents<int>>); static_assert(std::is_same_v<typename Span::layout_type, std::layout_right>); static_assert(std::is_same_v<typename Span::accessor_type, std::default_accessor<int>>); static_assert(Span::rank() == 0); static_assert(Span::rank_dynamic() == 0); int elem = 101; Span sp (&elem); gold::assume(sp[] == 101); gold::assume(*sp.data_handle() == 101); } { using matrix_3x3 = std::mdspan<char, std::extents<std::size_t, 3, 3>>; using Span = matrix_3x3; static_assert(std::is_same_v<typename Span::element_type, char>); static_assert(std::is_same_v<typename Span::reference, char&>); static_assert(std::is_same_v<typename Span::data_handle_type, char*>); static_assert(std::is_same_v<typename Span::extents_type, std::extents<std::size_t, 3, 3>>); static_assert(std::is_same_v<typename Span::layout_type, std::layout_right>); static_assert(std::is_same_v<typename Span::accessor_type, std::default_accessor<char>>); static_assert(Span::rank() == 2); static_assert(Span::rank_dynamic() == 0); static_assert(Span::static_extent(0) == 3); static_assert(Span::static_extent(1) == 3); char chars [] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I' }; // [ A B C ] // [ D E F ] // [ G H I ] // scan as left to right (by row each), then top to bottom matrix_3x3 mat (chars); gold::assume(mat.size() == 9); gold::assume(*mat.data_handle() == 'A'); gold::assume(mat.stride(1) == 1); gold::assume(mat.stride(0) == 3 * 1); gold::assume(mat[0, 0] == 'A'); gold::assume(mat[0, 1] == 'B'); gold::assume(mat[0, 2] == 'C'); gold::assume(mat[1, 0] == 'D'); gold::assume(mat[1, 1] == 'E'); gold::assume(mat[1, 2] == 'F'); gold::assume(mat[2, 0] == 'G'); gold::assume(mat[2, 1] == 'H'); gold::assume(mat[2, 2] == 'I'); using matrix_3x3_transposed = std::mdspan<char, std::extents<std::size_t, 3, 3>, std::layout_left>; // [ A B C ] // [ D E F ] // [ G H I ] // scan as top to bottom (by column each), then left to right matrix_3x3_transposed mat_trans (chars); gold::assume(mat_trans.size() == 9); gold::assume(*mat_trans.data_handle() == 'A'); gold::assume(mat_trans.stride(0) == 1); gold::assume(mat_trans.stride(1) == 1 * 3); gold::assume(mat_trans[0, 0] == 'A'); gold::assume(mat_trans[0, 1] == 'D'); gold::assume(mat_trans[0, 2] == 'G'); gold::assume(mat_trans[1, 0] == 'B'); gold::assume(mat_trans[1, 1] == 'E'); gold::assume(mat_trans[1, 2] == 'H'); gold::assume(mat_trans[2, 0] == 'C'); gold::assume(mat_trans[2, 1] == 'F'); gold::assume(mat_trans[2, 2] == 'I'); } } namespace linalg { template <typename NestedAccessor, typename Scalar> struct scaled_accessor { using element_type = std::add_const_t<decltype(std::declval<Scalar>() * std::declval<typename NestedAccessor::element_type>())>; using reference = std::remove_const_t<element_type>; using data_handle_type = NestedAccessor::data_handle_type; using offset_policy = scaled_accessor<typename NestedAccessor::offset_policy, Scalar>; NestedAccessor m_acc_ {}; Scalar m_scale_ {}; constexpr reference access(data_handle_type p, std::size_t i) const noexcept { return m_scale_ * typename NestedAccessor::element_type(m_acc_.access(p, i)); } constexpr offset_policy::data_handle_type offset(data_handle_type p, std::size_t i) const noexcept { return m_acc_.offset(p, i); } }; template <typename ScalingFactor, typename T, typename Extents, typename Layout, typename Accessor> constexpr auto scaled(std::mdspan<T, Extents, Layout, Accessor> md, ScalingFactor alpha) { using new_accessor = scaled_accessor<Accessor, ScalingFactor>; using new_mdspan = std::mdspan<typename new_accessor::element_type, Extents, Layout, new_accessor>; return new_mdspan(md.data_handle(), md.mapping(), new_accessor(md.accessor(), alpha)); } } template <int = 0> consteval void test_mdspan1() { { int data [] { 3, 1, 5, 2, 6, 2 }; using ScaledAccessor = linalg::scaled_accessor<std::default_accessor<int>, int>; auto md0 = std::mdspan<int, std::extents<std::size_t>>(data + 2); gold::assume(md0[] == 5); auto md0_s = std::mdspan<const int, std::extents<std::size_t>, std::layout_right, ScaledAccessor>(data + 2, {}, ScaledAccessor({}, 10)); gold::assume(md0_s[] == 50); auto md0_s2 = linalg::scaled(md0, 3); gold::assume(md0_s2[] == 15); auto md1 = std::mdspan(data, std::extents(6)); gold::assume(md1[0] == 3); gold::assume(md1[1] == 1); gold::assume(md1[2] == 5); gold::assume(md1[3] == 2); gold::assume(md1[4] == 6); gold::assume(md1[5] == 2); auto md1_s = linalg::scaled(md1, 2); gold::assume(md1_s[0] == 6); gold::assume(md1_s[1] == 2); gold::assume(md1_s[2] == 10); gold::assume(md1_s[3] == 4); gold::assume(md1_s[4] == 12); gold::assume(md1_s[5] == 4); } } template <int = 0> consteval void test_submdspan_extents0() { // TODO } template <int = 0> consteval void test_submdspan0() { char data[] { 'D', 'R', 'A', 'G', 'O', 'N' }; // idx: 0 1 2 3 4 5 { auto md = std::mdspan(data, 6); static_assert(md.rank() == 1); // sub_md0 = ['D', 'R', 'A', 'G', 'O', 'N'] auto sub_md0 = std::submdspan(md, std::full_extent); static_assert(std::is_same_v<typename decltype(sub_md0)::layout_type, std::layout_right>); static_assert(sub_md0.rank() == 1); gold::assume(sub_md0.stride(0) == 1); gold::assume(sub_md0.extent(0) == 6); gold::assume(sub_md0.size() == 6); gold::assume(md[0] == sub_md0[0] && sub_md0[0] == 'D'); gold::assume(md[1] == sub_md0[1] && sub_md0[1] == 'R'); gold::assume(md[2] == sub_md0[2] && sub_md0[2] == 'A'); gold::assume(md[3] == sub_md0[3] && sub_md0[3] == 'G'); gold::assume(md[4] == sub_md0[4] && sub_md0[4] == 'O'); gold::assume(md[5] == sub_md0[5] && sub_md0[5] == 'N'); // sub_md1 = 'A' auto sub_md1 = std::submdspan(md, 2); static_assert(sub_md1.rank() == 0); gold::assume(sub_md1.size() == 1); gold::assume(sub_md1.data_handle() == data + 2); gold::assume(sub_md1[] == md[2] && sub_md1[] == 'A'); // sub_md2 = ['R, 'A', 'G'] auto sub_md2 = std::submdspan(md, std::pair(1, 4)); static_assert(sub_md2.rank() == 1); gold::assume(sub_md2.stride(0) == 1); gold::assume(sub_md2.extent(0) == 3); gold::assume(sub_md2.size() == 3); gold::assume(sub_md2.data_handle() == data + 1); gold::assume(sub_md2[0] == md[1] && sub_md2[0] == 'R'); gold::assume(sub_md2[1] == md[2] && sub_md2[1] == 'A'); gold::assume(sub_md2[2] == md[3] && sub_md2[2] == 'G'); // sub_md3 = ['D', 'A', 'O'] auto sub_md3 = std::submdspan(md, std::strided_slice{.offset = 0, .extent = md.extent(0), .stride = 2}); static_assert(sub_md3.rank() == 1); gold::assume(sub_md3.stride(0) == 2); gold::assume(sub_md3.extent(0) == 3); gold::assume(sub_md3.size() == 3); gold::assume(sub_md3[0] == md[0] && sub_md3[0] == 'D'); gold::assume(sub_md3[1] == md[2] && sub_md3[1] == 'A'); gold::assume(sub_md3[2] == md[4] && sub_md3[2] == 'O'); } { auto md = std::mdspan(data, 2, 3); // [ D R A ] // [ G O N ] static_assert(md.rank() == 2); gold::assume(std::submdspan(md, 0, 0)[] == md[0, 0] && md[0, 0] == 'D'); gold::assume(std::submdspan(md, 1, 2)[] == md[1, 2] && md[1, 2] == 'N'); // take 2nd row // [ - - - ] // [ G O N ] auto sub_md0 = std::submdspan(md, 1, std::full_extent); static_assert(sub_md0.rank() == 1); gold::assume(sub_md0[0] == md[1, 0] && md[1, 0] == 'G'); gold::assume(sub_md0[1] == md[1, 1] && md[1, 1] == 'O'); gold::assume(sub_md0[2] == md[1, 2] && md[1, 2] == 'N'); // take 3rd column // [ - - A ] // [ - - N ] auto sub_md1 = std::submdspan(md, std::full_extent, 2); gold::assume(sub_md1[0] == md[0, 2] && md[0, 2] == 'A'); gold::assume(sub_md1[1] == md[1, 2] && md[1, 2] == 'N'); // take a square "matrix" on // [ - R A ] // [ - O N ] auto sub_md2 = std::submdspan(md, std::full_extent, std::pair(1, 3)); gold::assume(sub_md2[0, 0] == md[0, 1] && md[0, 1] == 'R'); gold::assume(sub_md2[0, 1] == md[0, 2] && md[0, 2] == 'A'); gold::assume(sub_md2[1, 0] == md[1, 1] && md[1, 1] == 'O'); gold::assume(sub_md2[1, 1] == md[1, 2] && md[1, 2] == 'N'); } } #include <cstdio> template <int = 0> void test_submdspan1() { auto print_matrix = []<typename M>(M md) { static_assert(std::is_same_v<char, typename M::element_type>); static_assert(M::rank() == 2); for (std::size_t i = 0; i < md.extent(0); ++i) { for (std::size_t j = 0; j < md.extent(1); ++j) std::printf("%c ", md[i, j]); std::printf("\n"); } std::printf("\n"); }; auto fill_view = []<typename M>(M md, char c) { static_assert(std::is_same_v<char, typename M::element_type>); if constexpr (M::rank() == 0) { md[] = c; } else if constexpr (M::rank() == 1) { for (std::size_t i = 0; i < md.extent(0); ++i) md[i] = c; } else if constexpr (M::rank() == 2) { for (std::size_t i = 0; i < md.extent(0); ++i) { for (std::size_t j = 0; j < md.extent(1); ++j) md[i, j] = c; } } }; auto clear_view = [fill_view](auto md) { fill_view(md, '\0'); }; char buffer [25] {}; auto md = std::mdspan(buffer, 5, 5); // draw a square { // [ - - - - - ] // [ - X X X - ] // [ - X X X - ] // [ - X X X - ] // [ - - - - - ] auto interior_md = std::submdspan(md, std::pair(1, md.extent(0) - 1), std::pair(1, md.extent(1) - 1)); // [ X X X X X ] // [ - - - - - ] // [ - - - - - ] // [ - - - - - ] // [ - - - - - ] auto border_top = std::submdspan(md, 0, std::full_extent); // [ - - - - - ] // [ - - - - - ] // [ - - - - - ] // [ - - - - - ] // [ X X X X X ] auto border_bottom = std::submdspan(md, md.extent(0) - 1, std::full_extent); // [ - - - - - ] // [ X - - - - ] // [ X - - - - ] // [ X - - - - ] // [ - - - - - ] auto border_left = std::submdspan(md, std::pair(1, md.extent(0) - 1), 0); // [ - - - - - ] // [ - - - - X ] // [ - - - - X ] // [ - - - - X ] // [ - - - - - ] auto border_right = std::submdspan(md, std::pair(1, md.extent(0) - 1), md.extent(1) - 1); fill_view(interior_md, ' '); fill_view(border_top, '+'); fill_view(border_bottom, '+'); fill_view(border_left, '+'); fill_view(border_right, '+'); print_matrix(md); // expected output: // + + + + + // + + // + + // + + // + + + + + clear_view(md); } // draw a cross { // [ - - - - - ] // [ - - - - - ] // [ X X X X X ] // [ - - - - - ] // [ - - - - - ] auto cross_horizontal = std::submdspan(md, 2, std::full_extent); // [ - - X - - ] // [ - - X - - ] // [ - - X - - ] // [ - - X - - ] // [ - - X - - ] auto cross_vertical = std::submdspan(md, std::full_extent, 2); // [ X X - - - ] // [ X X - - - ] // [ - - - - - ] // [ - - - - - ] // [ - - - - - ] auto void_top_left = std::submdspan(md, std::pair(0, 2), std::pair(0, 2)); // [ - - - X X ] // [ - - - X X ] // [ - - - - - ] // [ - - - - - ] // [ - - - - - ] auto void_top_right = std::submdspan(md, std::pair(0, 2), std::pair(md.extent(1) - 2, md.extent(1))); // [ - - - - - ] // [ - - - - - ] // [ - - - - - ] // [ X X - - - ] // [ X X - - - ] auto void_bottom_left = std::submdspan(md, std::pair(md.extent(0) - 2, md.extent(0)), std::pair(0, 2)); // [ - - - - - ] // [ - - - - - ] // [ - - - - - ] // [ - - - X X ] // [ - - - X X ] auto void_bottom_right = std::submdspan(md, std::pair(md.extent(0) - 2, md.extent(0)), std::pair(md.extent(1) - 2, md.extent(1))); fill_view(cross_horizontal, '+'); fill_view(cross_vertical, '+'); fill_view(void_top_left, ' '); fill_view(void_top_right, ' '); fill_view(void_bottom_left, ' '); fill_view(void_bottom_right, ' '); print_matrix(md); // expected output: // + // + // + + + + + // + // + clear_view(md); } } int main() { test_extents0(); test_extents1(); test_extents2(); test_layout_left(); test_layout_right(); test_layout_stride(); test_mdspan0(); test_mdspan1(); test_submdspan0(); test_submdspan1(); }
Become a Patron
Sponsor on GitHub
Donate via PayPal
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
About the author
Statistics
Changelog
Version tree