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#
GLSL
Go
Haskell
HLSL
Hook
Hylo
IL
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
SPIR-V
Swift
LLVM TableGen
Toit
TypeScript Native
V
Vala
Visual Basic
WASM
Zig
Javascript
GIMPLE
Ygen
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)
KVX ACB 5.2.0 (GCC 13.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
clang-cl 18.1.0
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 nvc++ 24.9
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 (string interpolation - P3412)
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 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
x86-64 icx 2025.0.0
x86-64 icx 2025.0.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
#include <coroutine> #include <iterator> #include <ranges> // MPark.Variant // // Copyright Michael Park, 2015-2017 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) #ifndef MPARK_VARIANT_HPP #define MPARK_VARIANT_HPP /* variant synopsis namespace std { // 20.7.2, class template variant template <class... Types> class variant { public: // 20.7.2.1, constructors constexpr variant() noexcept(see below); variant(const variant&); variant(variant&&) noexcept(see below); template <class T> constexpr variant(T&&) noexcept(see below); template <class T, class... Args> constexpr explicit variant(in_place_type_t<T>, Args&&...); template <class T, class U, class... Args> constexpr explicit variant( in_place_type_t<T>, initializer_list<U>, Args&&...); template <size_t I, class... Args> constexpr explicit variant(in_place_index_t<I>, Args&&...); template <size_t I, class U, class... Args> constexpr explicit variant( in_place_index_t<I>, initializer_list<U>, Args&&...); // 20.7.2.2, destructor ~variant(); // 20.7.2.3, assignment variant& operator=(const variant&); variant& operator=(variant&&) noexcept(see below); template <class T> variant& operator=(T&&) noexcept(see below); // 20.7.2.4, modifiers template <class T, class... Args> T& emplace(Args&&...); template <class T, class U, class... Args> T& emplace(initializer_list<U>, Args&&...); template <size_t I, class... Args> variant_alternative<I, variant>& emplace(Args&&...); template <size_t I, class U, class... Args> variant_alternative<I, variant>& emplace(initializer_list<U>, Args&&...); // 20.7.2.5, value status constexpr bool valueless_by_exception() const noexcept; constexpr size_t index() const noexcept; // 20.7.2.6, swap void swap(variant&) noexcept(see below); }; // 20.7.3, variant helper classes template <class T> struct variant_size; // undefined template <class T> constexpr size_t variant_size_v = variant_size<T>::value; template <class T> struct variant_size<const T>; template <class T> struct variant_size<volatile T>; template <class T> struct variant_size<const volatile T>; template <class... Types> struct variant_size<variant<Types...>>; template <size_t I, class T> struct variant_alternative; // undefined template <size_t I, class T> using variant_alternative_t = typename variant_alternative<I, T>::type; template <size_t I, class T> struct variant_alternative<I, const T>; template <size_t I, class T> struct variant_alternative<I, volatile T>; template <size_t I, class T> struct variant_alternative<I, const volatile T>; template <size_t I, class... Types> struct variant_alternative<I, variant<Types...>>; constexpr size_t variant_npos = -1; // 20.7.4, value access template <class T, class... Types> constexpr bool holds_alternative(const variant<Types...>&) noexcept; template <size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>>& get(variant<Types...>&); template <size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>>&& get(variant<Types...>&&); template <size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>> const& get(const variant<Types...>&); template <size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>> const&& get(const variant<Types...>&&); template <class T, class... Types> constexpr T& get(variant<Types...>&); template <class T, class... Types> constexpr T&& get(variant<Types...>&&); template <class T, class... Types> constexpr const T& get(const variant<Types...>&); template <class T, class... Types> constexpr const T&& get(const variant<Types...>&&); template <size_t I, class... Types> constexpr add_pointer_t<variant_alternative_t<I, variant<Types...>>> get_if(variant<Types...>*) noexcept; template <size_t I, class... Types> constexpr add_pointer_t<const variant_alternative_t<I, variant<Types...>>> get_if(const variant<Types...>*) noexcept; template <class T, class... Types> constexpr add_pointer_t<T> get_if(variant<Types...>*) noexcept; template <class T, class... Types> constexpr add_pointer_t<const T> get_if(const variant<Types...>*) noexcept; // 20.7.5, relational operators template <class... Types> constexpr bool operator==(const variant<Types...>&, const variant<Types...>&); template <class... Types> constexpr bool operator!=(const variant<Types...>&, const variant<Types...>&); template <class... Types> constexpr bool operator<(const variant<Types...>&, const variant<Types...>&); template <class... Types> constexpr bool operator>(const variant<Types...>&, const variant<Types...>&); template <class... Types> constexpr bool operator<=(const variant<Types...>&, const variant<Types...>&); template <class... Types> constexpr bool operator>=(const variant<Types...>&, const variant<Types...>&); // 20.7.6, visitation template <class Visitor, class... Variants> constexpr see below visit(Visitor&&, Variants&&...); // 20.7.7, class monostate struct monostate; // 20.7.8, monostate relational operators constexpr bool operator<(monostate, monostate) noexcept; constexpr bool operator>(monostate, monostate) noexcept; constexpr bool operator<=(monostate, monostate) noexcept; constexpr bool operator>=(monostate, monostate) noexcept; constexpr bool operator==(monostate, monostate) noexcept; constexpr bool operator!=(monostate, monostate) noexcept; // 20.7.9, specialized algorithms template <class... Types> void swap(variant<Types...>&, variant<Types...>&) noexcept(see below); // 20.7.10, class bad_variant_access class bad_variant_access; // 20.7.11, hash support template <class T> struct hash; template <class... Types> struct hash<variant<Types...>>; template <> struct hash<monostate>; } // namespace std */ #include <cstddef> #include <exception> #include <functional> #include <initializer_list> #include <limits> #include <new> #include <type_traits> #include <utility> // MPark.Variant // // Copyright Michael Park, 2015-2017 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) #ifndef MPARK_CONFIG_HPP #define MPARK_CONFIG_HPP // MSVC 2015 Update 3. #if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_FULL_VER < 190024210) #error "MPark.Variant requires C++11 support." #endif #ifndef __has_attribute #define __has_attribute(x) 0 #endif #ifndef __has_builtin #define __has_builtin(x) 0 #endif #ifndef __has_include #define __has_include(x) 0 #endif #ifndef __has_feature #define __has_feature(x) 0 #endif #if __has_attribute(always_inline) || defined(__GNUC__) #define MPARK_ALWAYS_INLINE __attribute__((__always_inline__)) inline #elif defined(_MSC_VER) #define MPARK_ALWAYS_INLINE __forceinline #else #define MPARK_ALWAYS_INLINE inline #endif #if __has_builtin(__builtin_addressof) || \ (defined(__GNUC__) && __GNUC__ >= 7) || defined(_MSC_VER) #define MPARK_BUILTIN_ADDRESSOF #endif #if __has_builtin(__builtin_unreachable) || defined(__GNUC__) #define MPARK_BUILTIN_UNREACHABLE __builtin_unreachable() #elif defined(_MSC_VER) #define MPARK_BUILTIN_UNREACHABLE __assume(false) #else #define MPARK_BUILTIN_UNREACHABLE #endif #if __has_builtin(__type_pack_element) #define MPARK_TYPE_PACK_ELEMENT #endif #if defined(__cpp_constexpr) && __cpp_constexpr >= 200704 && \ !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 9) #define MPARK_CPP11_CONSTEXPR #endif #if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 #define MPARK_CPP14_CONSTEXPR #endif #if __has_feature(cxx_exceptions) || defined(__cpp_exceptions) || \ (defined(_MSC_VER) && defined(_CPPUNWIND)) #define MPARK_EXCEPTIONS #endif #if defined(__cpp_generic_lambdas) || defined(_MSC_VER) #define MPARK_GENERIC_LAMBDAS #endif #if defined(__cpp_lib_integer_sequence) #define MPARK_INTEGER_SEQUENCE #endif #if (defined(__cpp_decltype_auto) && defined(__cpp_return_type_deduction)) || defined(_MSC_VER) #define MPARK_RETURN_TYPE_DEDUCTION #endif #if defined(__cpp_lib_transparent_operators) || defined(_MSC_VER) #define MPARK_TRANSPARENT_OPERATORS #endif #if defined(__cpp_variable_templates) || defined(_MSC_VER) #define MPARK_VARIABLE_TEMPLATES #endif #if !defined(__GLIBCXX__) || __has_include(<codecvt>) // >= libstdc++-5 #define MPARK_TRIVIALITY_TYPE_TRAITS #define MPARK_INCOMPLETE_TYPE_TRAITS #endif #endif // MPARK_CONFIG_HPP // MPark.Variant // // Copyright Michael Park, 2015-2017 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) #ifndef MPARK_IN_PLACE_HPP #define MPARK_IN_PLACE_HPP #include <cstddef> namespace mpark { struct in_place_t { explicit in_place_t() = default; }; template <std::size_t I> struct in_place_index_t { explicit in_place_index_t() = default; }; template <typename T> struct in_place_type_t { explicit in_place_type_t() = default; }; #ifdef MPARK_VARIABLE_TEMPLATES constexpr in_place_t in_place{}; template <std::size_t I> constexpr in_place_index_t<I> in_place_index{}; template <typename T> constexpr in_place_type_t<T> in_place_type{}; #endif } // namespace mpark #endif // MPARK_IN_PLACE_HPP // MPark.Variant // // Copyright Michael Park, 2015-2017 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) #ifndef MPARK_LIB_HPP #define MPARK_LIB_HPP #include <memory> #include <functional> #include <type_traits> #include <utility> #define MPARK_RETURN(...) \ noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { return __VA_ARGS__; } namespace mpark { namespace lib { template <typename T> struct identity { using type = T; }; inline namespace cpp14 { template <typename T, std::size_t N> struct array { constexpr const T &operator[](std::size_t index) const { return data[index]; } T data[N == 0 ? 1 : N]; }; template <typename T> using add_pointer_t = typename std::add_pointer<T>::type; template <typename... Ts> using common_type_t = typename std::common_type<Ts...>::type; template <typename T> using decay_t = typename std::decay<T>::type; template <bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type; template <typename T> using remove_const_t = typename std::remove_const<T>::type; template <typename T> using remove_reference_t = typename std::remove_reference<T>::type; template <typename T> using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type; template <typename T> inline constexpr T &&forward(remove_reference_t<T> &t) noexcept { return static_cast<T &&>(t); } template <typename T> inline constexpr T &&forward(remove_reference_t<T> &&t) noexcept { static_assert(!std::is_lvalue_reference<T>::value, "can not forward an rvalue as an lvalue"); return static_cast<T &&>(t); } template <typename T> inline constexpr remove_reference_t<T> &&move(T &&t) noexcept { return static_cast<remove_reference_t<T> &&>(t); } #ifdef MPARK_INTEGER_SEQUENCE using std::integer_sequence; using std::index_sequence; using std::make_index_sequence; using std::index_sequence_for; #else template <typename T, T... Is> struct integer_sequence { using value_type = T; static constexpr std::size_t size() noexcept { return sizeof...(Is); } }; template <std::size_t... Is> using index_sequence = integer_sequence<std::size_t, Is...>; template <typename Lhs, typename Rhs> struct make_index_sequence_concat; template <std::size_t... Lhs, std::size_t... Rhs> struct make_index_sequence_concat<index_sequence<Lhs...>, index_sequence<Rhs...>> : identity<index_sequence<Lhs..., (sizeof...(Lhs) + Rhs)...>> {}; template <std::size_t N> struct make_index_sequence_impl; template <std::size_t N> using make_index_sequence = typename make_index_sequence_impl<N>::type; template <std::size_t N> struct make_index_sequence_impl : make_index_sequence_concat<make_index_sequence<N / 2>, make_index_sequence<N - (N / 2)>> {}; template <> struct make_index_sequence_impl<0> : identity<index_sequence<>> {}; template <> struct make_index_sequence_impl<1> : identity<index_sequence<0>> {}; template <typename... Ts> using index_sequence_for = make_index_sequence<sizeof...(Ts)>; #endif // <functional> #ifdef MPARK_TRANSPARENT_OPERATORS using equal_to = std::equal_to<>; #else struct equal_to { template <typename Lhs, typename Rhs> inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const MPARK_RETURN(lib::forward<Lhs>(lhs) == lib::forward<Rhs>(rhs)) }; #endif #ifdef MPARK_TRANSPARENT_OPERATORS using not_equal_to = std::not_equal_to<>; #else struct not_equal_to { template <typename Lhs, typename Rhs> inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const MPARK_RETURN(lib::forward<Lhs>(lhs) != lib::forward<Rhs>(rhs)) }; #endif #ifdef MPARK_TRANSPARENT_OPERATORS using less = std::less<>; #else struct less { template <typename Lhs, typename Rhs> inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const MPARK_RETURN(lib::forward<Lhs>(lhs) < lib::forward<Rhs>(rhs)) }; #endif #ifdef MPARK_TRANSPARENT_OPERATORS using greater = std::greater<>; #else struct greater { template <typename Lhs, typename Rhs> inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const MPARK_RETURN(lib::forward<Lhs>(lhs) > lib::forward<Rhs>(rhs)) }; #endif #ifdef MPARK_TRANSPARENT_OPERATORS using less_equal = std::less_equal<>; #else struct less_equal { template <typename Lhs, typename Rhs> inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const MPARK_RETURN(lib::forward<Lhs>(lhs) <= lib::forward<Rhs>(rhs)) }; #endif #ifdef MPARK_TRANSPARENT_OPERATORS using greater_equal = std::greater_equal<>; #else struct greater_equal { template <typename Lhs, typename Rhs> inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const MPARK_RETURN(lib::forward<Lhs>(lhs) >= lib::forward<Rhs>(rhs)) }; #endif } // namespace cpp14 inline namespace cpp17 { // <type_traits> template <bool B> using bool_constant = std::integral_constant<bool, B>; template <typename...> struct voider : identity<void> {}; template <typename... Ts> using void_t = typename voider<Ts...>::type; namespace detail { namespace swappable { using std::swap; template <typename T> struct is_swappable { private: template <typename U, typename = decltype(swap(std::declval<U &>(), std::declval<U &>()))> inline static std::true_type test(int); template <typename U> inline static std::false_type test(...); public: static constexpr bool value = decltype(test<T>(0))::value; }; template <bool IsSwappable, typename T> struct is_nothrow_swappable { static constexpr bool value = noexcept(swap(std::declval<T &>(), std::declval<T &>())); }; template <typename T> struct is_nothrow_swappable<false, T> : std::false_type {}; } // namespace swappable } // namespace detail using detail::swappable::is_swappable; template <typename T> using is_nothrow_swappable = detail::swappable::is_nothrow_swappable<is_swappable<T>::value, T>; // <functional> namespace detail { template <typename T> struct is_reference_wrapper : std::false_type {}; template <typename T> struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {}; template <bool, int> struct Invoke; template <> struct Invoke<true /* pmf */, 0 /* is_base_of */> { template <typename R, typename T, typename Arg, typename... Args> inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) MPARK_RETURN((lib::forward<Arg>(arg).*pmf)(lib::forward<Args>(args)...)) }; template <> struct Invoke<true /* pmf */, 1 /* is_reference_wrapper */> { template <typename R, typename T, typename Arg, typename... Args> inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) MPARK_RETURN((lib::forward<Arg>(arg).get().*pmf)(lib::forward<Args>(args)...)) }; template <> struct Invoke<true /* pmf */, 2 /* otherwise */> { template <typename R, typename T, typename Arg, typename... Args> inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) MPARK_RETURN(((*lib::forward<Arg>(arg)).*pmf)(lib::forward<Args>(args)...)) }; template <> struct Invoke<false /* pmo */, 0 /* is_base_of */> { template <typename R, typename T, typename Arg> inline static constexpr auto invoke(R T::*pmo, Arg &&arg) MPARK_RETURN(lib::forward<Arg>(arg).*pmo) }; template <> struct Invoke<false /* pmo */, 1 /* is_reference_wrapper */> { template <typename R, typename T, typename Arg> inline static constexpr auto invoke(R T::*pmo, Arg &&arg) MPARK_RETURN(lib::forward<Arg>(arg).get().*pmo) }; template <> struct Invoke<false /* pmo */, 2 /* otherwise */> { template <typename R, typename T, typename Arg> inline static constexpr auto invoke(R T::*pmo, Arg &&arg) MPARK_RETURN((*lib::forward<Arg>(arg)).*pmo) }; template <typename R, typename T, typename Arg, typename... Args> inline constexpr auto invoke(R T::*f, Arg &&arg, Args &&... args) MPARK_RETURN( Invoke<std::is_function<R>::value, (std::is_base_of<T, lib::decay_t<Arg>>::value ? 0 : is_reference_wrapper<lib::decay_t<Arg>>::value ? 1 : 2)>::invoke(f, lib::forward<Arg>(arg), lib::forward<Args>(args)...)) #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4100) #endif template <typename F, typename... Args> inline constexpr auto invoke(F &&f, Args &&... args) MPARK_RETURN(lib::forward<F>(f)(lib::forward<Args>(args)...)) #ifdef _MSC_VER #pragma warning(pop) #endif } // namespace detail template <typename F, typename... Args> inline constexpr auto invoke(F &&f, Args &&... args) MPARK_RETURN(detail::invoke(lib::forward<F>(f), lib::forward<Args>(args)...)) namespace detail { template <typename Void, typename, typename...> struct invoke_result {}; template <typename F, typename... Args> struct invoke_result<void_t<decltype(lib::invoke( std::declval<F>(), std::declval<Args>()...))>, F, Args...> : identity<decltype( lib::invoke(std::declval<F>(), std::declval<Args>()...))> {}; } // namespace detail template <typename F, typename... Args> using invoke_result = detail::invoke_result<void, F, Args...>; template <typename F, typename... Args> using invoke_result_t = typename invoke_result<F, Args...>::type; namespace detail { template <typename Void, typename, typename...> struct is_invocable : std::false_type {}; template <typename F, typename... Args> struct is_invocable<void_t<invoke_result_t<F, Args...>>, F, Args...> : std::true_type {}; template <typename Void, typename, typename, typename...> struct is_invocable_r : std::false_type {}; template <typename R, typename F, typename... Args> struct is_invocable_r<void_t<invoke_result_t<F, Args...>>, R, F, Args...> : std::is_convertible<invoke_result_t<F, Args...>, R> {}; } // namespace detail template <typename F, typename... Args> using is_invocable = detail::is_invocable<void, F, Args...>; template <typename R, typename F, typename... Args> using is_invocable_r = detail::is_invocable_r<void, R, F, Args...>; // <memory> #ifdef MPARK_BUILTIN_ADDRESSOF template <typename T> inline constexpr T *addressof(T &arg) noexcept { return __builtin_addressof(arg); } #else namespace detail { namespace has_addressof_impl { struct fail; template <typename T> inline fail operator&(T &&); template <typename T> inline static constexpr bool impl() { return (std::is_class<T>::value || std::is_union<T>::value) && !std::is_same<decltype(&std::declval<T &>()), fail>::value; } } // namespace has_addressof_impl template <typename T> using has_addressof = bool_constant<has_addressof_impl::impl<T>()>; template <typename T> inline constexpr T *addressof(T &arg, std::true_type) noexcept { return std::addressof(arg); } template <typename T> inline constexpr T *addressof(T &arg, std::false_type) noexcept { return &arg; } } // namespace detail template <typename T> inline constexpr T *addressof(T &arg) noexcept { return detail::addressof(arg, detail::has_addressof<T>{}); } #endif template <typename T> inline constexpr T *addressof(const T &&) = delete; } // namespace cpp17 template <typename T> struct remove_all_extents : identity<T> {}; template <typename T, std::size_t N> struct remove_all_extents<array<T, N>> : remove_all_extents<T> {}; template <typename T> using remove_all_extents_t = typename remove_all_extents<T>::type; template <std::size_t N> using size_constant = std::integral_constant<std::size_t, N>; template <std::size_t I, typename T> struct indexed_type : size_constant<I> { using type = T; }; template <bool... Bs> using all = std::is_same<integer_sequence<bool, true, Bs...>, integer_sequence<bool, Bs..., true>>; #ifdef MPARK_TYPE_PACK_ELEMENT template <std::size_t I, typename... Ts> using type_pack_element_t = __type_pack_element<I, Ts...>; #else template <std::size_t I, typename... Ts> struct type_pack_element_impl { private: template <typename> struct set; template <std::size_t... Is> struct set<index_sequence<Is...>> : indexed_type<Is, Ts>... {}; template <typename T> inline static std::enable_if<true, T> impl(indexed_type<I, T>); inline static std::enable_if<false> impl(...); public: using type = decltype(impl(set<index_sequence_for<Ts...>>{})); }; template <std::size_t I, typename... Ts> using type_pack_element = typename type_pack_element_impl<I, Ts...>::type; template <std::size_t I, typename... Ts> using type_pack_element_t = typename type_pack_element<I, Ts...>::type; #endif #ifdef MPARK_TRIVIALITY_TYPE_TRAITS using std::is_trivially_copy_constructible; using std::is_trivially_move_constructible; using std::is_trivially_copy_assignable; using std::is_trivially_move_assignable; #else template <typename T> struct is_trivially_copy_constructible : bool_constant< std::is_copy_constructible<T>::value && __has_trivial_copy(T)> {}; template <typename T> struct is_trivially_move_constructible : bool_constant<__is_trivial(T)> {}; template <typename T> struct is_trivially_copy_assignable : bool_constant< std::is_copy_assignable<T>::value && __has_trivial_assign(T)> {}; template <typename T> struct is_trivially_move_assignable : bool_constant<__is_trivial(T)> {}; #endif template <typename T, bool> struct dependent_type : T {}; template <typename Is, std::size_t J> struct push_back; template <typename Is, std::size_t J> using push_back_t = typename push_back<Is, J>::type; template <std::size_t... Is, std::size_t J> struct push_back<index_sequence<Is...>, J> { using type = index_sequence<Is..., J>; }; } // namespace lib } // namespace mpark #undef MPARK_RETURN #endif // MPARK_LIB_HPP namespace mpark { #ifdef MPARK_RETURN_TYPE_DEDUCTION #define AUTO auto #define AUTO_RETURN(...) { return __VA_ARGS__; } #define AUTO_REFREF auto && #define AUTO_REFREF_RETURN(...) { return __VA_ARGS__; } #define DECLTYPE_AUTO decltype(auto) #define DECLTYPE_AUTO_RETURN(...) { return __VA_ARGS__; } #else #define AUTO auto #define AUTO_RETURN(...) \ -> lib::decay_t<decltype(__VA_ARGS__)> { return __VA_ARGS__; } #define AUTO_REFREF auto #define AUTO_REFREF_RETURN(...) \ -> decltype((__VA_ARGS__)) { \ static_assert(std::is_reference<decltype((__VA_ARGS__))>::value, ""); \ return __VA_ARGS__; \ } #define DECLTYPE_AUTO auto #define DECLTYPE_AUTO_RETURN(...) \ -> decltype(__VA_ARGS__) { return __VA_ARGS__; } #endif class bad_variant_access : public std::exception { public: virtual const char *what() const noexcept override { return "bad_variant_access"; } }; [[noreturn]] inline void throw_bad_variant_access() { #ifdef MPARK_EXCEPTIONS throw bad_variant_access{}; #else std::terminate(); MPARK_BUILTIN_UNREACHABLE; #endif } template <typename... Ts> class variant; template <typename T> struct variant_size; #ifdef MPARK_VARIABLE_TEMPLATES template <typename T> constexpr std::size_t variant_size_v = variant_size<T>::value; #endif template <typename T> struct variant_size<const T> : variant_size<T> {}; template <typename T> struct variant_size<volatile T> : variant_size<T> {}; template <typename T> struct variant_size<const volatile T> : variant_size<T> {}; template <typename... Ts> struct variant_size<variant<Ts...>> : lib::size_constant<sizeof...(Ts)> {}; template <std::size_t I, typename T> struct variant_alternative; template <std::size_t I, typename T> using variant_alternative_t = typename variant_alternative<I, T>::type; template <std::size_t I, typename T> struct variant_alternative<I, const T> : std::add_const<variant_alternative_t<I, T>> {}; template <std::size_t I, typename T> struct variant_alternative<I, volatile T> : std::add_volatile<variant_alternative_t<I, T>> {}; template <std::size_t I, typename T> struct variant_alternative<I, const volatile T> : std::add_cv<variant_alternative_t<I, T>> {}; template <std::size_t I, typename... Ts> struct variant_alternative<I, variant<Ts...>> { static_assert(I < sizeof...(Ts), "index out of bounds in `std::variant_alternative<>`"); using type = lib::type_pack_element_t<I, Ts...>; }; constexpr std::size_t variant_npos = static_cast<std::size_t>(-1); namespace detail { constexpr std::size_t not_found = static_cast<std::size_t>(-1); constexpr std::size_t ambiguous = static_cast<std::size_t>(-2); #ifdef MPARK_CPP14_CONSTEXPR template <typename T, typename... Ts> inline constexpr std::size_t find_index() { constexpr lib::array<bool, sizeof...(Ts)> matches = { {std::is_same<T, Ts>::value...} }; std::size_t result = not_found; for (std::size_t i = 0; i < sizeof...(Ts); ++i) { if (matches[i]) { if (result != not_found) { return ambiguous; } result = i; } } return result; } #else inline constexpr std::size_t find_index_impl(std::size_t result, std::size_t) { return result; } template <typename... Bs> inline constexpr std::size_t find_index_impl(std::size_t result, std::size_t idx, bool b, Bs... bs) { return b ? (result != not_found ? ambiguous : find_index_impl(idx, idx + 1, bs...)) : find_index_impl(result, idx + 1, bs...); } template <typename T, typename... Ts> inline constexpr std::size_t find_index() { return find_index_impl(not_found, 0, std::is_same<T, Ts>::value...); } #endif template <std::size_t I> using find_index_sfinae_impl = lib::enable_if_t<I != not_found && I != ambiguous, lib::size_constant<I>>; template <typename T, typename... Ts> using find_index_sfinae = find_index_sfinae_impl<find_index<T, Ts...>()>; template <std::size_t I> struct find_index_checked_impl : lib::size_constant<I> { static_assert(I != not_found, "the specified type is not found."); static_assert(I != ambiguous, "the specified type is ambiguous."); }; template <typename T, typename... Ts> using find_index_checked = find_index_checked_impl<find_index<T, Ts...>()>; struct valueless_t {}; enum class Trait { TriviallyAvailable, Available, Unavailable }; template <typename T, template <typename> class IsTriviallyAvailable, template <typename> class IsAvailable> inline constexpr Trait trait() { return IsTriviallyAvailable<T>::value ? Trait::TriviallyAvailable : IsAvailable<T>::value ? Trait::Available : Trait::Unavailable; } #ifdef MPARK_CPP14_CONSTEXPR template <typename... Traits> inline constexpr Trait common_trait(Traits... traits_) { Trait result = Trait::TriviallyAvailable; lib::array<Trait, sizeof...(Traits)> traits = {{traits_...}}; for (std::size_t i = 0; i < sizeof...(Traits); ++i) { Trait t = traits[i]; if (static_cast<int>(t) > static_cast<int>(result)) { result = t; } } return result; } #else inline constexpr Trait common_trait_impl(Trait result) { return result; } template <typename... Traits> inline constexpr Trait common_trait_impl(Trait result, Trait t, Traits... ts) { return static_cast<int>(t) > static_cast<int>(result) ? common_trait_impl(t, ts...) : common_trait_impl(result, ts...); } template <typename... Traits> inline constexpr Trait common_trait(Traits... ts) { return common_trait_impl(Trait::TriviallyAvailable, ts...); } #endif template <typename... Ts> struct traits { static constexpr Trait copy_constructible_trait = common_trait(trait<Ts, lib::is_trivially_copy_constructible, std::is_copy_constructible>()...); static constexpr Trait move_constructible_trait = common_trait(trait<Ts, lib::is_trivially_move_constructible, std::is_move_constructible>()...); static constexpr Trait copy_assignable_trait = common_trait(copy_constructible_trait, trait<Ts, lib::is_trivially_copy_assignable, std::is_copy_assignable>()...); static constexpr Trait move_assignable_trait = common_trait(move_constructible_trait, trait<Ts, lib::is_trivially_move_assignable, std::is_move_assignable>()...); static constexpr Trait destructible_trait = common_trait(trait<Ts, std::is_trivially_destructible, std::is_destructible>()...); }; namespace access { struct recursive_union { #ifdef MPARK_RETURN_TYPE_DEDUCTION template <typename V> inline static constexpr auto &&get_alt(V &&v, in_place_index_t<0>) { return lib::forward<V>(v).head_; } template <typename V, std::size_t I> inline static constexpr auto &&get_alt(V &&v, in_place_index_t<I>) { return get_alt(lib::forward<V>(v).tail_, in_place_index_t<I - 1>{}); } #else template <std::size_t I, bool Dummy = true> struct get_alt_impl { template <typename V> inline constexpr AUTO_REFREF operator()(V &&v) const AUTO_REFREF_RETURN(get_alt_impl<I - 1>{}(lib::forward<V>(v).tail_)) }; template <bool Dummy> struct get_alt_impl<0, Dummy> { template <typename V> inline constexpr AUTO_REFREF operator()(V &&v) const AUTO_REFREF_RETURN(lib::forward<V>(v).head_) }; template <typename V, std::size_t I> inline static constexpr AUTO_REFREF get_alt(V &&v, in_place_index_t<I>) AUTO_REFREF_RETURN(get_alt_impl<I>{}(lib::forward<V>(v))) #endif }; struct base { template <std::size_t I, typename V> inline static constexpr AUTO_REFREF get_alt(V &&v) #ifdef _MSC_VER AUTO_REFREF_RETURN(recursive_union::get_alt( lib::forward<V>(v).data_, in_place_index_t<I>{})) #else AUTO_REFREF_RETURN(recursive_union::get_alt( data(lib::forward<V>(v)), in_place_index_t<I>{})) #endif }; struct variant { template <std::size_t I, typename V> inline static constexpr AUTO_REFREF get_alt(V &&v) AUTO_REFREF_RETURN(base::get_alt<I>(lib::forward<V>(v).impl_)) }; } // namespace access namespace visitation { #if defined(MPARK_CPP14_CONSTEXPR) && !defined(_MSC_VER) #define MPARK_VARIANT_SWITCH_VISIT #endif struct base { template <typename Visitor, typename... Vs> using dispatch_result_t = decltype( lib::invoke(std::declval<Visitor>(), access::base::get_alt<0>(std::declval<Vs>())...)); template <typename Expected> struct expected { template <typename Actual> inline static constexpr bool but_got() { return std::is_same<Expected, Actual>::value; } }; template <typename Expected, typename Actual> struct visit_return_type_check { static_assert( expected<Expected>::template but_got<Actual>(), "`visit` requires the visitor to have a single return type"); template <typename Visitor, typename... Alts> inline static constexpr DECLTYPE_AUTO invoke(Visitor &&visitor, Alts &&... alts) DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward<Visitor>(visitor), lib::forward<Alts>(alts)...)) }; #ifdef MPARK_VARIANT_SWITCH_VISIT template <bool B, typename R, typename... ITs> struct dispatcher; template <typename R, typename... ITs> struct dispatcher<false, R, ITs...> { template <std::size_t B, typename F, typename... Vs> MPARK_ALWAYS_INLINE static constexpr R dispatch( F &&, typename ITs::type &&..., Vs &&...) { MPARK_BUILTIN_UNREACHABLE; } template <std::size_t I, typename F, typename... Vs> MPARK_ALWAYS_INLINE static constexpr R dispatch_case(F &&, Vs &&...) { MPARK_BUILTIN_UNREACHABLE; } template <std::size_t B, typename F, typename... Vs> MPARK_ALWAYS_INLINE static constexpr R dispatch_at(std::size_t, F &&, Vs &&...) { MPARK_BUILTIN_UNREACHABLE; } }; template <typename R, typename... ITs> struct dispatcher<true, R, ITs...> { template <std::size_t B, typename F> MPARK_ALWAYS_INLINE static constexpr R dispatch( F &&f, typename ITs::type &&... visited_vs) { using Expected = R; using Actual = decltype(lib::invoke( lib::forward<F>(f), access::base::get_alt<ITs::value>( lib::forward<typename ITs::type>(visited_vs))...)); return visit_return_type_check<Expected, Actual>::invoke( lib::forward<F>(f), access::base::get_alt<ITs::value>( lib::forward<typename ITs::type>(visited_vs))...); } template <std::size_t B, typename F, typename V, typename... Vs> MPARK_ALWAYS_INLINE static constexpr R dispatch( F &&f, typename ITs::type &&... visited_vs, V &&v, Vs &&... vs) { #define MPARK_DISPATCH(I) \ dispatcher<(I < lib::decay_t<V>::size()), \ R, \ ITs..., \ lib::indexed_type<I, V>>:: \ template dispatch<0>(lib::forward<F>(f), \ lib::forward<typename ITs::type>(visited_vs)..., \ lib::forward<V>(v), \ lib::forward<Vs>(vs)...) #define MPARK_DEFAULT(I) \ dispatcher<(I < lib::decay_t<V>::size()), R, ITs...>::template dispatch<I>( \ lib::forward<F>(f), \ lib::forward<typename ITs::type>(visited_vs)..., \ lib::forward<V>(v), \ lib::forward<Vs>(vs)...) switch (v.index()) { case B + 0: return MPARK_DISPATCH(B + 0); case B + 1: return MPARK_DISPATCH(B + 1); case B + 2: return MPARK_DISPATCH(B + 2); case B + 3: return MPARK_DISPATCH(B + 3); case B + 4: return MPARK_DISPATCH(B + 4); case B + 5: return MPARK_DISPATCH(B + 5); case B + 6: return MPARK_DISPATCH(B + 6); case B + 7: return MPARK_DISPATCH(B + 7); case B + 8: return MPARK_DISPATCH(B + 8); case B + 9: return MPARK_DISPATCH(B + 9); case B + 10: return MPARK_DISPATCH(B + 10); case B + 11: return MPARK_DISPATCH(B + 11); case B + 12: return MPARK_DISPATCH(B + 12); case B + 13: return MPARK_DISPATCH(B + 13); case B + 14: return MPARK_DISPATCH(B + 14); case B + 15: return MPARK_DISPATCH(B + 15); case B + 16: return MPARK_DISPATCH(B + 16); case B + 17: return MPARK_DISPATCH(B + 17); case B + 18: return MPARK_DISPATCH(B + 18); case B + 19: return MPARK_DISPATCH(B + 19); case B + 20: return MPARK_DISPATCH(B + 20); case B + 21: return MPARK_DISPATCH(B + 21); case B + 22: return MPARK_DISPATCH(B + 22); case B + 23: return MPARK_DISPATCH(B + 23); case B + 24: return MPARK_DISPATCH(B + 24); case B + 25: return MPARK_DISPATCH(B + 25); case B + 26: return MPARK_DISPATCH(B + 26); case B + 27: return MPARK_DISPATCH(B + 27); case B + 28: return MPARK_DISPATCH(B + 28); case B + 29: return MPARK_DISPATCH(B + 29); case B + 30: return MPARK_DISPATCH(B + 30); case B + 31: return MPARK_DISPATCH(B + 31); default: return MPARK_DEFAULT(B + 32); } #undef MPARK_DEFAULT #undef MPARK_DISPATCH } template <std::size_t I, typename F, typename... Vs> MPARK_ALWAYS_INLINE static constexpr R dispatch_case(F &&f, Vs &&... vs) { using Expected = R; using Actual = decltype( lib::invoke(lib::forward<F>(f), access::base::get_alt<I>(lib::forward<Vs>(vs))...)); return visit_return_type_check<Expected, Actual>::invoke( lib::forward<F>(f), access::base::get_alt<I>(lib::forward<Vs>(vs))...); } template <std::size_t B, typename F, typename V, typename... Vs> MPARK_ALWAYS_INLINE static constexpr R dispatch_at(std::size_t index, F &&f, V &&v, Vs &&... vs) { static_assert(lib::all<(lib::decay_t<V>::size() == lib::decay_t<Vs>::size())...>::value, "all of the variants must be the same size."); #define MPARK_DISPATCH_AT(I) \ dispatcher<(I < lib::decay_t<V>::size()), R>::template dispatch_case<I>( \ lib::forward<F>(f), lib::forward<V>(v), lib::forward<Vs>(vs)...) #define MPARK_DEFAULT(I) \ dispatcher<(I < lib::decay_t<V>::size()), R>::template dispatch_at<I>( \ index, lib::forward<F>(f), lib::forward<V>(v), lib::forward<Vs>(vs)...) switch (index) { case B + 0: return MPARK_DISPATCH_AT(B + 0); case B + 1: return MPARK_DISPATCH_AT(B + 1); case B + 2: return MPARK_DISPATCH_AT(B + 2); case B + 3: return MPARK_DISPATCH_AT(B + 3); case B + 4: return MPARK_DISPATCH_AT(B + 4); case B + 5: return MPARK_DISPATCH_AT(B + 5); case B + 6: return MPARK_DISPATCH_AT(B + 6); case B + 7: return MPARK_DISPATCH_AT(B + 7); case B + 8: return MPARK_DISPATCH_AT(B + 8); case B + 9: return MPARK_DISPATCH_AT(B + 9); case B + 10: return MPARK_DISPATCH_AT(B + 10); case B + 11: return MPARK_DISPATCH_AT(B + 11); case B + 12: return MPARK_DISPATCH_AT(B + 12); case B + 13: return MPARK_DISPATCH_AT(B + 13); case B + 14: return MPARK_DISPATCH_AT(B + 14); case B + 15: return MPARK_DISPATCH_AT(B + 15); case B + 16: return MPARK_DISPATCH_AT(B + 16); case B + 17: return MPARK_DISPATCH_AT(B + 17); case B + 18: return MPARK_DISPATCH_AT(B + 18); case B + 19: return MPARK_DISPATCH_AT(B + 19); case B + 20: return MPARK_DISPATCH_AT(B + 20); case B + 21: return MPARK_DISPATCH_AT(B + 21); case B + 22: return MPARK_DISPATCH_AT(B + 22); case B + 23: return MPARK_DISPATCH_AT(B + 23); case B + 24: return MPARK_DISPATCH_AT(B + 24); case B + 25: return MPARK_DISPATCH_AT(B + 25); case B + 26: return MPARK_DISPATCH_AT(B + 26); case B + 27: return MPARK_DISPATCH_AT(B + 27); case B + 28: return MPARK_DISPATCH_AT(B + 28); case B + 29: return MPARK_DISPATCH_AT(B + 29); case B + 30: return MPARK_DISPATCH_AT(B + 30); case B + 31: return MPARK_DISPATCH_AT(B + 31); default: return MPARK_DEFAULT(B + 32); } #undef MPARK_DEFAULT #undef MPARK_DISPATCH_AT } }; #else template <typename T> inline static constexpr const T &at(const T &elem) noexcept { return elem; } template <typename T, std::size_t N, typename... Is> inline static constexpr const lib::remove_all_extents_t<T> &at( const lib::array<T, N> &elems, std::size_t i, Is... is) noexcept { return at(elems[i], is...); } template <typename F, typename... Fs> inline static constexpr lib::array<lib::decay_t<F>, sizeof...(Fs) + 1> make_farray(F &&f, Fs &&... fs) { return {{lib::forward<F>(f), lib::forward<Fs>(fs)...}}; } template <typename F, typename... Vs> struct make_fmatrix_impl { template <std::size_t... Is> inline static constexpr dispatch_result_t<F, Vs...> dispatch( F &&f, Vs &&... vs) { using Expected = dispatch_result_t<F, Vs...>; using Actual = decltype(lib::invoke( lib::forward<F>(f), access::base::get_alt<Is>(lib::forward<Vs>(vs))...)); return visit_return_type_check<Expected, Actual>::invoke( lib::forward<F>(f), access::base::get_alt<Is>(lib::forward<Vs>(vs))...); } #ifdef MPARK_RETURN_TYPE_DEDUCTION template <std::size_t... Is> inline static constexpr auto impl(lib::index_sequence<Is...>) { return &dispatch<Is...>; } template <typename Is, std::size_t... Js, typename... Ls> inline static constexpr auto impl(Is, lib::index_sequence<Js...>, Ls... ls) { return make_farray(impl(lib::push_back_t<Is, Js>{}, ls...)...); } #else template <typename...> struct impl; template <std::size_t... Is> struct impl<lib::index_sequence<Is...>> { inline constexpr AUTO operator()() const AUTO_RETURN(&dispatch<Is...>) }; template <typename Is, std::size_t... Js, typename... Ls> struct impl<Is, lib::index_sequence<Js...>, Ls...> { inline constexpr AUTO operator()() const AUTO_RETURN( make_farray(impl<lib::push_back_t<Is, Js>, Ls...>{}()...)) }; #endif }; #ifdef MPARK_RETURN_TYPE_DEDUCTION template <typename F, typename... Vs> inline static constexpr auto make_fmatrix() { return make_fmatrix_impl<F, Vs...>::impl( lib::index_sequence<>{}, lib::make_index_sequence<lib::decay_t<Vs>::size()>{}...); } #else template <typename F, typename... Vs> inline static constexpr AUTO make_fmatrix() AUTO_RETURN( typename make_fmatrix_impl<F, Vs...>::template impl< lib::index_sequence<>, lib::make_index_sequence<lib::decay_t<Vs>::size()>...>{}()) #endif template <typename F, typename... Vs> struct make_fdiagonal_impl { template <std::size_t I> inline static constexpr dispatch_result_t<F, Vs...> dispatch( F &&f, Vs &&... vs) { using Expected = dispatch_result_t<F, Vs...>; using Actual = decltype( lib::invoke(lib::forward<F>(f), access::base::get_alt<I>(lib::forward<Vs>(vs))...)); return visit_return_type_check<Expected, Actual>::invoke( lib::forward<F>(f), access::base::get_alt<I>(lib::forward<Vs>(vs))...); } template <std::size_t... Is> inline static constexpr AUTO impl(lib::index_sequence<Is...>) AUTO_RETURN(make_farray(&dispatch<Is>...)) }; template <typename F, typename V, typename... Vs> inline static constexpr auto make_fdiagonal() -> decltype(make_fdiagonal_impl<F, V, Vs...>::impl( lib::make_index_sequence<lib::decay_t<V>::size()>{})) { static_assert(lib::all<(lib::decay_t<V>::size() == lib::decay_t<Vs>::size())...>::value, "all of the variants must be the same size."); return make_fdiagonal_impl<F, V, Vs...>::impl( lib::make_index_sequence<lib::decay_t<V>::size()>{}); } #endif }; #if !defined(MPARK_VARIANT_SWITCH_VISIT) && \ (!defined(_MSC_VER) || _MSC_VER >= 1910) template <typename F, typename... Vs> using fmatrix_t = decltype(base::make_fmatrix<F, Vs...>()); template <typename F, typename... Vs> struct fmatrix { static constexpr fmatrix_t<F, Vs...> value = base::make_fmatrix<F, Vs...>(); }; template <typename F, typename... Vs> constexpr fmatrix_t<F, Vs...> fmatrix<F, Vs...>::value; template <typename F, typename... Vs> using fdiagonal_t = decltype(base::make_fdiagonal<F, Vs...>()); template <typename F, typename... Vs> struct fdiagonal { static constexpr fdiagonal_t<F, Vs...> value = base::make_fdiagonal<F, Vs...>(); }; template <typename F, typename... Vs> constexpr fdiagonal_t<F, Vs...> fdiagonal<F, Vs...>::value; #endif struct alt { template <typename Visitor, typename... Vs> inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, Vs &&... vs) #ifdef MPARK_VARIANT_SWITCH_VISIT DECLTYPE_AUTO_RETURN( base::dispatcher< true, base::dispatch_result_t<Visitor, decltype(as_base( lib::forward<Vs>(vs)))...>>:: template dispatch<0>(lib::forward<Visitor>(visitor), as_base(lib::forward<Vs>(vs))...)) #elif !defined(_MSC_VER) || _MSC_VER >= 1910 DECLTYPE_AUTO_RETURN(base::at( fmatrix<Visitor &&, decltype(as_base(lib::forward<Vs>(vs)))...>::value, vs.index()...)(lib::forward<Visitor>(visitor), as_base(lib::forward<Vs>(vs))...)) #else DECLTYPE_AUTO_RETURN(base::at( base::make_fmatrix<Visitor &&, decltype(as_base(lib::forward<Vs>(vs)))...>(), vs.index()...)(lib::forward<Visitor>(visitor), as_base(lib::forward<Vs>(vs))...)) #endif template <typename Visitor, typename... Vs> inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, Visitor &&visitor, Vs &&... vs) #ifdef MPARK_VARIANT_SWITCH_VISIT DECLTYPE_AUTO_RETURN( base::dispatcher< true, base::dispatch_result_t<Visitor, decltype(as_base( lib::forward<Vs>(vs)))...>>:: template dispatch_at<0>(index, lib::forward<Visitor>(visitor), as_base(lib::forward<Vs>(vs))...)) #elif !defined(_MSC_VER) || _MSC_VER >= 1910 DECLTYPE_AUTO_RETURN(base::at( fdiagonal<Visitor &&, decltype(as_base(lib::forward<Vs>(vs)))...>::value, index)(lib::forward<Visitor>(visitor), as_base(lib::forward<Vs>(vs))...)) #else DECLTYPE_AUTO_RETURN(base::at( base::make_fdiagonal<Visitor &&, decltype(as_base(lib::forward<Vs>(vs)))...>(), index)(lib::forward<Visitor>(visitor), as_base(lib::forward<Vs>(vs))...)) #endif }; struct variant { private: template <typename Visitor> struct visitor { template <typename... Values> inline static constexpr bool does_not_handle() { return lib::is_invocable<Visitor, Values...>::value; } }; template <typename Visitor, typename... Values> struct visit_exhaustiveness_check { static_assert(visitor<Visitor>::template does_not_handle<Values...>(), "`visit` requires the visitor to be exhaustive."); inline static constexpr DECLTYPE_AUTO invoke(Visitor &&visitor, Values &&... values) DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward<Visitor>(visitor), lib::forward<Values>(values)...)) }; template <typename Visitor> struct value_visitor { Visitor &&visitor_; template <typename... Alts> inline constexpr DECLTYPE_AUTO operator()(Alts &&... alts) const DECLTYPE_AUTO_RETURN( visit_exhaustiveness_check< Visitor, decltype((lib::forward<Alts>(alts).value))...>:: invoke(lib::forward<Visitor>(visitor_), lib::forward<Alts>(alts).value...)) }; template <typename Visitor> inline static constexpr AUTO make_value_visitor(Visitor &&visitor) AUTO_RETURN(value_visitor<Visitor>{lib::forward<Visitor>(visitor)}) public: template <typename Visitor, typename... Vs> inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN(alt::visit_alt(lib::forward<Visitor>(visitor), lib::forward<Vs>(vs).impl_...)) template <typename Visitor, typename... Vs> inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( alt::visit_alt_at(index, lib::forward<Visitor>(visitor), lib::forward<Vs>(vs).impl_...)) template <typename Visitor, typename... Vs> inline static constexpr DECLTYPE_AUTO visit_value(Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( visit_alt(make_value_visitor(lib::forward<Visitor>(visitor)), lib::forward<Vs>(vs)...)) template <typename Visitor, typename... Vs> inline static constexpr DECLTYPE_AUTO visit_value_at(std::size_t index, Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( visit_alt_at(index, make_value_visitor(lib::forward<Visitor>(visitor)), lib::forward<Vs>(vs)...)) }; } // namespace visitation template <std::size_t Index, typename T> struct alt { using value_type = T; #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4244) #endif template <typename... Args> inline explicit constexpr alt(in_place_t, Args &&... args) : value(lib::forward<Args>(args)...) {} #ifdef _MSC_VER #pragma warning(pop) #endif T value; }; template <Trait DestructibleTrait, std::size_t Index, typename... Ts> union recursive_union; template <Trait DestructibleTrait, std::size_t Index> union recursive_union<DestructibleTrait, Index> {}; #define MPARK_VARIANT_RECURSIVE_UNION(destructible_trait, destructor) \ template <std::size_t Index, typename T, typename... Ts> \ union recursive_union<destructible_trait, Index, T, Ts...> { \ public: \ inline explicit constexpr recursive_union(valueless_t) noexcept \ : dummy_{} {} \ \ template <typename... Args> \ inline explicit constexpr recursive_union(in_place_index_t<0>, \ Args &&... args) \ : head_(in_place_t{}, lib::forward<Args>(args)...) {} \ \ template <std::size_t I, typename... Args> \ inline explicit constexpr recursive_union(in_place_index_t<I>, \ Args &&... args) \ : tail_(in_place_index_t<I - 1>{}, lib::forward<Args>(args)...) {} \ \ recursive_union(const recursive_union &) = default; \ recursive_union(recursive_union &&) = default; \ \ destructor \ \ recursive_union &operator=(const recursive_union &) = default; \ recursive_union &operator=(recursive_union &&) = default; \ \ private: \ char dummy_; \ alt<Index, T> head_; \ recursive_union<destructible_trait, Index + 1, Ts...> tail_; \ \ friend struct access::recursive_union; \ } MPARK_VARIANT_RECURSIVE_UNION(Trait::TriviallyAvailable, ~recursive_union() = default;); MPARK_VARIANT_RECURSIVE_UNION(Trait::Available, ~recursive_union() {}); MPARK_VARIANT_RECURSIVE_UNION(Trait::Unavailable, ~recursive_union() = delete;); #undef MPARK_VARIANT_RECURSIVE_UNION template <typename... Ts> using index_t = typename std::conditional< sizeof...(Ts) < (std::numeric_limits<unsigned char>::max)(), unsigned char, typename std::conditional< sizeof...(Ts) < (std::numeric_limits<unsigned short>::max)(), unsigned short, unsigned int>::type >::type; template <Trait DestructibleTrait, typename... Ts> class base { public: inline explicit constexpr base(valueless_t tag) noexcept : data_(tag), index_(static_cast<index_t<Ts...>>(-1)) {} template <std::size_t I, typename... Args> inline explicit constexpr base(in_place_index_t<I>, Args &&... args) : data_(in_place_index_t<I>{}, lib::forward<Args>(args)...), index_(I) {} inline constexpr bool valueless_by_exception() const noexcept { return index_ == static_cast<index_t<Ts...>>(-1); } inline constexpr std::size_t index() const noexcept { return valueless_by_exception() ? variant_npos : index_; } protected: using data_t = recursive_union<DestructibleTrait, 0, Ts...>; friend inline constexpr base &as_base(base &b) { return b; } friend inline constexpr const base &as_base(const base &b) { return b; } friend inline constexpr base &&as_base(base &&b) { return lib::move(b); } friend inline constexpr const base &&as_base(const base &&b) { return lib::move(b); } friend inline constexpr data_t &data(base &b) { return b.data_; } friend inline constexpr const data_t &data(const base &b) { return b.data_; } friend inline constexpr data_t &&data(base &&b) { return lib::move(b).data_; } friend inline constexpr const data_t &&data(const base &&b) { return lib::move(b).data_; } inline static constexpr std::size_t size() { return sizeof...(Ts); } data_t data_; index_t<Ts...> index_; friend struct access::base; friend struct visitation::base; }; struct dtor { #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4100) #endif template <typename Alt> inline void operator()(Alt &alt) const noexcept { alt.~Alt(); } #ifdef _MSC_VER #pragma warning(pop) #endif }; #if !defined(_MSC_VER) || _MSC_VER >= 1910 #define MPARK_INHERITING_CTOR(type, base) using base::base; #else #define MPARK_INHERITING_CTOR(type, base) \ template <typename... Args> \ inline explicit constexpr type(Args &&... args) \ : base(lib::forward<Args>(args)...) {} #endif template <typename Traits, Trait = Traits::destructible_trait> class destructor; #define MPARK_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ template <typename... Ts> \ class destructor<traits<Ts...>, destructible_trait> \ : public base<destructible_trait, Ts...> { \ using super = base<destructible_trait, Ts...>; \ \ public: \ MPARK_INHERITING_CTOR(destructor, super) \ using super::operator=; \ \ destructor(const destructor &) = default; \ destructor(destructor &&) = default; \ definition \ destructor &operator=(const destructor &) = default; \ destructor &operator=(destructor &&) = default; \ \ protected: \ destroy \ } MPARK_VARIANT_DESTRUCTOR( Trait::TriviallyAvailable, ~destructor() = default;, inline void destroy() noexcept { this->index_ = static_cast<index_t<Ts...>>(-1); }); MPARK_VARIANT_DESTRUCTOR( Trait::Available, ~destructor() { destroy(); }, inline void destroy() noexcept { if (!this->valueless_by_exception()) { visitation::alt::visit_alt(dtor{}, *this); } this->index_ = static_cast<index_t<Ts...>>(-1); }); MPARK_VARIANT_DESTRUCTOR( Trait::Unavailable, ~destructor() = delete;, inline void destroy() noexcept = delete;); #undef MPARK_VARIANT_DESTRUCTOR template <typename Traits> class constructor : public destructor<Traits> { using super = destructor<Traits>; public: MPARK_INHERITING_CTOR(constructor, super) using super::operator=; protected: #ifndef MPARK_GENERIC_LAMBDAS struct ctor { template <typename LhsAlt, typename RhsAlt> inline void operator()(LhsAlt &lhs_alt, RhsAlt &&rhs_alt) const { constructor::construct_alt(lhs_alt, lib::forward<RhsAlt>(rhs_alt).value); } }; #endif template <std::size_t I, typename T, typename... Args> inline static T &construct_alt(alt<I, T> &a, Args &&... args) { auto *result = ::new (static_cast<void *>(lib::addressof(a))) alt<I, T>(in_place_t{}, lib::forward<Args>(args)...); return result->value; } template <typename Rhs> inline static void generic_construct(constructor &lhs, Rhs &&rhs) { lhs.destroy(); if (!rhs.valueless_by_exception()) { visitation::alt::visit_alt_at( rhs.index(), #ifdef MPARK_GENERIC_LAMBDAS [](auto &lhs_alt, auto &&rhs_alt) { constructor::construct_alt( lhs_alt, lib::forward<decltype(rhs_alt)>(rhs_alt).value); } #else ctor{} #endif , lhs, lib::forward<Rhs>(rhs)); lhs.index_ = rhs.index_; } } }; template <typename Traits, Trait = Traits::move_constructible_trait> class move_constructor; #define MPARK_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, definition) \ template <typename... Ts> \ class move_constructor<traits<Ts...>, move_constructible_trait> \ : public constructor<traits<Ts...>> { \ using super = constructor<traits<Ts...>>; \ \ public: \ MPARK_INHERITING_CTOR(move_constructor, super) \ using super::operator=; \ \ move_constructor(const move_constructor &) = default; \ definition \ ~move_constructor() = default; \ move_constructor &operator=(const move_constructor &) = default; \ move_constructor &operator=(move_constructor &&) = default; \ } MPARK_VARIANT_MOVE_CONSTRUCTOR( Trait::TriviallyAvailable, move_constructor(move_constructor &&that) = default;); MPARK_VARIANT_MOVE_CONSTRUCTOR( Trait::Available, move_constructor(move_constructor &&that) noexcept( lib::all<std::is_nothrow_move_constructible<Ts>::value...>::value) : move_constructor(valueless_t{}) { this->generic_construct(*this, lib::move(that)); }); MPARK_VARIANT_MOVE_CONSTRUCTOR( Trait::Unavailable, move_constructor(move_constructor &&) = delete;); #undef MPARK_VARIANT_MOVE_CONSTRUCTOR template <typename Traits, Trait = Traits::copy_constructible_trait> class copy_constructor; #define MPARK_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, definition) \ template <typename... Ts> \ class copy_constructor<traits<Ts...>, copy_constructible_trait> \ : public move_constructor<traits<Ts...>> { \ using super = move_constructor<traits<Ts...>>; \ \ public: \ MPARK_INHERITING_CTOR(copy_constructor, super) \ using super::operator=; \ \ definition \ copy_constructor(copy_constructor &&) = default; \ ~copy_constructor() = default; \ copy_constructor &operator=(const copy_constructor &) = default; \ copy_constructor &operator=(copy_constructor &&) = default; \ } MPARK_VARIANT_COPY_CONSTRUCTOR( Trait::TriviallyAvailable, copy_constructor(const copy_constructor &that) = default;); MPARK_VARIANT_COPY_CONSTRUCTOR( Trait::Available, copy_constructor(const copy_constructor &that) : copy_constructor(valueless_t{}) { this->generic_construct(*this, that); }); MPARK_VARIANT_COPY_CONSTRUCTOR( Trait::Unavailable, copy_constructor(const copy_constructor &) = delete;); #undef MPARK_VARIANT_COPY_CONSTRUCTOR template <typename Traits> class assignment : public copy_constructor<Traits> { using super = copy_constructor<Traits>; public: MPARK_INHERITING_CTOR(assignment, super) using super::operator=; template <std::size_t I, typename... Args> inline /* auto & */ auto emplace(Args &&... args) -> decltype(this->construct_alt(access::base::get_alt<I>(*this), lib::forward<Args>(args)...)) { this->destroy(); auto &result = this->construct_alt(access::base::get_alt<I>(*this), lib::forward<Args>(args)...); this->index_ = I; return result; } protected: #ifndef MPARK_GENERIC_LAMBDAS template <typename That> struct assigner { template <typename ThisAlt, typename ThatAlt> inline void operator()(ThisAlt &this_alt, ThatAlt &&that_alt) const { self->assign_alt(this_alt, lib::forward<ThatAlt>(that_alt).value); } assignment *self; }; #endif template <std::size_t I, typename T, typename Arg> inline void assign_alt(alt<I, T> &a, Arg &&arg) { if (this->index() == I) { #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4244) #endif a.value = lib::forward<Arg>(arg); #ifdef _MSC_VER #pragma warning(pop) #endif } else { struct { void operator()(std::true_type) const { this_->emplace<I>(lib::forward<Arg>(arg_)); } void operator()(std::false_type) const { this_->emplace<I>(T(lib::forward<Arg>(arg_))); } assignment *this_; Arg &&arg_; } impl{this, lib::forward<Arg>(arg)}; impl(lib::bool_constant< std::is_nothrow_constructible<T, Arg>::value || !std::is_nothrow_move_constructible<T>::value>{}); } } template <typename That> inline void generic_assign(That &&that) { if (this->valueless_by_exception() && that.valueless_by_exception()) { // do nothing. } else if (that.valueless_by_exception()) { this->destroy(); } else { visitation::alt::visit_alt_at( that.index(), #ifdef MPARK_GENERIC_LAMBDAS [this](auto &this_alt, auto &&that_alt) { this->assign_alt( this_alt, lib::forward<decltype(that_alt)>(that_alt).value); } #else assigner<That>{this} #endif , *this, lib::forward<That>(that)); } } }; template <typename Traits, Trait = Traits::move_assignable_trait> class move_assignment; #define MPARK_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ template <typename... Ts> \ class move_assignment<traits<Ts...>, move_assignable_trait> \ : public assignment<traits<Ts...>> { \ using super = assignment<traits<Ts...>>; \ \ public: \ MPARK_INHERITING_CTOR(move_assignment, super) \ using super::operator=; \ \ move_assignment(const move_assignment &) = default; \ move_assignment(move_assignment &&) = default; \ ~move_assignment() = default; \ move_assignment &operator=(const move_assignment &) = default; \ definition \ } MPARK_VARIANT_MOVE_ASSIGNMENT( Trait::TriviallyAvailable, move_assignment &operator=(move_assignment &&that) = default;); MPARK_VARIANT_MOVE_ASSIGNMENT( Trait::Available, move_assignment & operator=(move_assignment &&that) noexcept( lib::all<(std::is_nothrow_move_constructible<Ts>::value && std::is_nothrow_move_assignable<Ts>::value)...>::value) { this->generic_assign(lib::move(that)); return *this; }); MPARK_VARIANT_MOVE_ASSIGNMENT( Trait::Unavailable, move_assignment &operator=(move_assignment &&) = delete;); #undef MPARK_VARIANT_MOVE_ASSIGNMENT template <typename Traits, Trait = Traits::copy_assignable_trait> class copy_assignment; #define MPARK_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ template <typename... Ts> \ class copy_assignment<traits<Ts...>, copy_assignable_trait> \ : public move_assignment<traits<Ts...>> { \ using super = move_assignment<traits<Ts...>>; \ \ public: \ MPARK_INHERITING_CTOR(copy_assignment, super) \ using super::operator=; \ \ copy_assignment(const copy_assignment &) = default; \ copy_assignment(copy_assignment &&) = default; \ ~copy_assignment() = default; \ definition \ copy_assignment &operator=(copy_assignment &&) = default; \ } MPARK_VARIANT_COPY_ASSIGNMENT( Trait::TriviallyAvailable, copy_assignment &operator=(const copy_assignment &that) = default;); MPARK_VARIANT_COPY_ASSIGNMENT( Trait::Available, copy_assignment &operator=(const copy_assignment &that) { this->generic_assign(that); return *this; }); MPARK_VARIANT_COPY_ASSIGNMENT( Trait::Unavailable, copy_assignment &operator=(const copy_assignment &) = delete;); #undef MPARK_VARIANT_COPY_ASSIGNMENT template <typename... Ts> class impl : public copy_assignment<traits<Ts...>> { using super = copy_assignment<traits<Ts...>>; public: MPARK_INHERITING_CTOR(impl, super) using super::operator=; impl(const impl&) = default; impl(impl&&) = default; ~impl() = default; impl &operator=(const impl &) = default; impl &operator=(impl &&) = default; template <std::size_t I, typename Arg> inline void assign(Arg &&arg) { this->assign_alt(access::base::get_alt<I>(*this), lib::forward<Arg>(arg)); } inline void swap(impl &that) { if (this->valueless_by_exception() && that.valueless_by_exception()) { // do nothing. } else if (this->index() == that.index()) { visitation::alt::visit_alt_at(this->index(), #ifdef MPARK_GENERIC_LAMBDAS [](auto &this_alt, auto &that_alt) { using std::swap; swap(this_alt.value, that_alt.value); } #else swapper{} #endif , *this, that); } else { impl *lhs = this; impl *rhs = lib::addressof(that); if (lhs->move_nothrow() && !rhs->move_nothrow()) { std::swap(lhs, rhs); } impl tmp(lib::move(*rhs)); #ifdef MPARK_EXCEPTIONS // EXTENSION: When the move construction of `lhs` into `rhs` throws // and `tmp` is nothrow move constructible then we move `tmp` back // into `rhs` and provide the strong exception safety guarantee. try { this->generic_construct(*rhs, lib::move(*lhs)); } catch (...) { if (tmp.move_nothrow()) { this->generic_construct(*rhs, lib::move(tmp)); } throw; } #else this->generic_construct(*rhs, lib::move(*lhs)); #endif this->generic_construct(*lhs, lib::move(tmp)); } } private: #ifndef MPARK_GENERIC_LAMBDAS struct swapper { template <typename ThisAlt, typename ThatAlt> inline void operator()(ThisAlt &this_alt, ThatAlt &that_alt) const { using std::swap; swap(this_alt.value, that_alt.value); } }; #endif inline constexpr bool move_nothrow() const { return this->valueless_by_exception() || lib::array<bool, sizeof...(Ts)>{ {std::is_nothrow_move_constructible<Ts>::value...} }[this->index()]; } }; #undef MPARK_INHERITING_CTOR template <typename From, typename To> struct is_non_narrowing_convertible { template <typename T> static std::true_type test(T(&&)[1]); template <typename T> static auto impl(int) -> decltype(test<T>({std::declval<From>()})); template <typename> static auto impl(...) -> std::false_type; static constexpr bool value = decltype(impl<To>(0))::value; }; template <typename Arg, std::size_t I, typename T, bool = std::is_arithmetic<T>::value, typename = void> struct overload_leaf {}; template <typename Arg, std::size_t I, typename T> struct overload_leaf<Arg, I, T, false> { using impl = lib::size_constant<I> (*)(T); operator impl() const { return nullptr; }; }; template <typename Arg, std::size_t I, typename T> struct overload_leaf< Arg, I, T, true #if defined(__clang__) || !defined(__GNUC__) || __GNUC__ >= 5 , lib::enable_if_t< std::is_same<lib::remove_cvref_t<T>, bool>::value ? std::is_same<lib::remove_cvref_t<Arg>, bool>::value : is_non_narrowing_convertible<Arg, T>::value> #endif > { using impl = lib::size_constant<I> (*)(T); operator impl() const { return nullptr; }; }; template <typename Arg, typename... Ts> struct overload_impl { private: template <typename> struct impl; template <std::size_t... Is> struct impl<lib::index_sequence<Is...>> : overload_leaf<Arg, Is, Ts>... {}; public: using type = impl<lib::index_sequence_for<Ts...>>; }; template <typename Arg, typename... Ts> using overload = typename overload_impl<Arg, Ts...>::type; template <typename Arg, typename... Ts> using best_match = lib::invoke_result_t<overload<Arg, Ts...>, Arg>; template <typename T> struct is_in_place_index : std::false_type {}; template <std::size_t I> struct is_in_place_index<in_place_index_t<I>> : std::true_type {}; template <typename T> struct is_in_place_type : std::false_type {}; template <typename T> struct is_in_place_type<in_place_type_t<T>> : std::true_type {}; } // detail template <typename... Ts> class variant { static_assert(0 < sizeof...(Ts), "variant must consist of at least one alternative."); static_assert(lib::all<!std::is_array<Ts>::value...>::value, "variant can not have an array type as an alternative."); static_assert(lib::all<!std::is_reference<Ts>::value...>::value, "variant can not have a reference type as an alternative."); static_assert(lib::all<!std::is_void<Ts>::value...>::value, "variant can not have a void type as an alternative."); public: template < typename Front = lib::type_pack_element_t<0, Ts...>, lib::enable_if_t<std::is_default_constructible<Front>::value, int> = 0> inline constexpr variant() noexcept( std::is_nothrow_default_constructible<Front>::value) : impl_(in_place_index_t<0>{}) {} variant(const variant &) = default; variant(variant &&) = default; template < typename Arg, typename Decayed = lib::decay_t<Arg>, lib::enable_if_t<!std::is_same<Decayed, variant>::value, int> = 0, lib::enable_if_t<!detail::is_in_place_index<Decayed>::value, int> = 0, lib::enable_if_t<!detail::is_in_place_type<Decayed>::value, int> = 0, std::size_t I = detail::best_match<Arg, Ts...>::value, typename T = lib::type_pack_element_t<I, Ts...>, lib::enable_if_t<std::is_constructible<T, Arg>::value, int> = 0> inline constexpr variant(Arg &&arg) noexcept( std::is_nothrow_constructible<T, Arg>::value) : impl_(in_place_index_t<I>{}, lib::forward<Arg>(arg)) {} template < std::size_t I, typename... Args, typename T = lib::type_pack_element_t<I, Ts...>, lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> inline explicit constexpr variant( in_place_index_t<I>, Args &&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value) : impl_(in_place_index_t<I>{}, lib::forward<Args>(args)...) {} template < std::size_t I, typename Up, typename... Args, typename T = lib::type_pack_element_t<I, Ts...>, lib::enable_if_t<std::is_constructible<T, std::initializer_list<Up> &, Args...>::value, int> = 0> inline explicit constexpr variant( in_place_index_t<I>, std::initializer_list<Up> il, Args &&... args) noexcept(std:: is_nothrow_constructible< T, std::initializer_list<Up> &, Args...>::value) : impl_(in_place_index_t<I>{}, il, lib::forward<Args>(args)...) {} template < typename T, typename... Args, std::size_t I = detail::find_index_sfinae<T, Ts...>::value, lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> inline explicit constexpr variant( in_place_type_t<T>, Args &&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value) : impl_(in_place_index_t<I>{}, lib::forward<Args>(args)...) {} template < typename T, typename Up, typename... Args, std::size_t I = detail::find_index_sfinae<T, Ts...>::value, lib::enable_if_t<std::is_constructible<T, std::initializer_list<Up> &, Args...>::value, int> = 0> inline explicit constexpr variant( in_place_type_t<T>, std::initializer_list<Up> il, Args &&... args) noexcept(std:: is_nothrow_constructible< T, std::initializer_list<Up> &, Args...>::value) : impl_(in_place_index_t<I>{}, il, lib::forward<Args>(args)...) {} ~variant() = default; variant &operator=(const variant &) = default; variant &operator=(variant &&) = default; template <typename Arg, lib::enable_if_t<!std::is_same<lib::decay_t<Arg>, variant>::value, int> = 0, std::size_t I = detail::best_match<Arg, Ts...>::value, typename T = lib::type_pack_element_t<I, Ts...>, lib::enable_if_t<(std::is_assignable<T &, Arg>::value && std::is_constructible<T, Arg>::value), int> = 0> inline variant &operator=(Arg &&arg) noexcept( (std::is_nothrow_assignable<T &, Arg>::value && std::is_nothrow_constructible<T, Arg>::value)) { impl_.template assign<I>(lib::forward<Arg>(arg)); return *this; } template < std::size_t I, typename... Args, typename T = lib::type_pack_element_t<I, Ts...>, lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> inline T &emplace(Args &&... args) { return impl_.template emplace<I>(lib::forward<Args>(args)...); } template < std::size_t I, typename Up, typename... Args, typename T = lib::type_pack_element_t<I, Ts...>, lib::enable_if_t<std::is_constructible<T, std::initializer_list<Up> &, Args...>::value, int> = 0> inline T &emplace(std::initializer_list<Up> il, Args &&... args) { return impl_.template emplace<I>(il, lib::forward<Args>(args)...); } template < typename T, typename... Args, std::size_t I = detail::find_index_sfinae<T, Ts...>::value, lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> inline T &emplace(Args &&... args) { return impl_.template emplace<I>(lib::forward<Args>(args)...); } template < typename T, typename Up, typename... Args, std::size_t I = detail::find_index_sfinae<T, Ts...>::value, lib::enable_if_t<std::is_constructible<T, std::initializer_list<Up> &, Args...>::value, int> = 0> inline T &emplace(std::initializer_list<Up> il, Args &&... args) { return impl_.template emplace<I>(il, lib::forward<Args>(args)...); } inline constexpr bool valueless_by_exception() const noexcept { return impl_.valueless_by_exception(); } inline constexpr std::size_t index() const noexcept { return impl_.index(); } template <bool Dummy = true, lib::enable_if_t< lib::all<Dummy, (lib::dependent_type<std::is_move_constructible<Ts>, Dummy>::value && lib::dependent_type<lib::is_swappable<Ts>, Dummy>::value)...>::value, int> = 0> inline void swap(variant &that) noexcept( lib::all<(std::is_nothrow_move_constructible<Ts>::value && lib::is_nothrow_swappable<Ts>::value)...>::value) { impl_.swap(that.impl_); } private: detail::impl<Ts...> impl_; friend struct detail::access::variant; friend struct detail::visitation::variant; }; template <std::size_t I, typename... Ts> inline constexpr bool holds_alternative(const variant<Ts...> &v) noexcept { return v.index() == I; } template <typename T, typename... Ts> inline constexpr bool holds_alternative(const variant<Ts...> &v) noexcept { return holds_alternative<detail::find_index_checked<T, Ts...>::value>(v); } namespace detail { template <std::size_t I, typename V> struct generic_get_impl { constexpr generic_get_impl(int) noexcept {} constexpr AUTO_REFREF operator()(V &&v) const AUTO_REFREF_RETURN( access::variant::get_alt<I>(lib::forward<V>(v)).value) }; template <std::size_t I, typename V> inline constexpr AUTO_REFREF generic_get(V &&v) AUTO_REFREF_RETURN(generic_get_impl<I, V>( holds_alternative<I>(v) ? 0 : (throw_bad_variant_access(), 0))( lib::forward<V>(v))) } // namespace detail template <std::size_t I, typename... Ts> inline constexpr variant_alternative_t<I, variant<Ts...>> &get( variant<Ts...> &v) { return detail::generic_get<I>(v); } template <std::size_t I, typename... Ts> inline constexpr variant_alternative_t<I, variant<Ts...>> &&get( variant<Ts...> &&v) { return detail::generic_get<I>(lib::move(v)); } template <std::size_t I, typename... Ts> inline constexpr const variant_alternative_t<I, variant<Ts...>> &get( const variant<Ts...> &v) { return detail::generic_get<I>(v); } template <std::size_t I, typename... Ts> inline constexpr const variant_alternative_t<I, variant<Ts...>> &&get( const variant<Ts...> &&v) { return detail::generic_get<I>(lib::move(v)); } template <typename T, typename... Ts> inline constexpr T &get(variant<Ts...> &v) { return get<detail::find_index_checked<T, Ts...>::value>(v); } template <typename T, typename... Ts> inline constexpr T &&get(variant<Ts...> &&v) { return get<detail::find_index_checked<T, Ts...>::value>(lib::move(v)); } template <typename T, typename... Ts> inline constexpr const T &get(const variant<Ts...> &v) { return get<detail::find_index_checked<T, Ts...>::value>(v); } template <typename T, typename... Ts> inline constexpr const T &&get(const variant<Ts...> &&v) { return get<detail::find_index_checked<T, Ts...>::value>(lib::move(v)); } namespace detail { template <std::size_t I, typename V> inline constexpr /* auto * */ AUTO generic_get_if(V *v) noexcept AUTO_RETURN(v && holds_alternative<I>(*v) ? lib::addressof(access::variant::get_alt<I>(*v).value) : nullptr) } // namespace detail template <std::size_t I, typename... Ts> inline constexpr lib::add_pointer_t<variant_alternative_t<I, variant<Ts...>>> get_if(variant<Ts...> *v) noexcept { return detail::generic_get_if<I>(v); } template <std::size_t I, typename... Ts> inline constexpr lib::add_pointer_t< const variant_alternative_t<I, variant<Ts...>>> get_if(const variant<Ts...> *v) noexcept { return detail::generic_get_if<I>(v); } template <typename T, typename... Ts> inline constexpr lib::add_pointer_t<T> get_if(variant<Ts...> *v) noexcept { return get_if<detail::find_index_checked<T, Ts...>::value>(v); } template <typename T, typename... Ts> inline constexpr lib::add_pointer_t<const T> get_if(const variant<Ts...> *v) noexcept { return get_if<detail::find_index_checked<T, Ts...>::value>(v); } namespace detail { template <typename RelOp> struct convert_to_bool { template <typename Lhs, typename Rhs> inline constexpr bool operator()(Lhs &&lhs, Rhs &&rhs) const { static_assert(std::is_convertible<lib::invoke_result_t<RelOp, Lhs, Rhs>, bool>::value, "relational operators must return a type" " implicitly convertible to bool"); return lib::invoke( RelOp{}, lib::forward<Lhs>(lhs), lib::forward<Rhs>(rhs)); } }; } // namespace detail template <typename... Ts> inline constexpr bool operator==(const variant<Ts...> &lhs, const variant<Ts...> &rhs) { using detail::visitation::variant; using equal_to = detail::convert_to_bool<lib::equal_to>; #ifdef MPARK_CPP14_CONSTEXPR if (lhs.index() != rhs.index()) return false; if (lhs.valueless_by_exception()) return true; return variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs); #else return lhs.index() == rhs.index() && (lhs.valueless_by_exception() || variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); #endif } template <typename... Ts> inline constexpr bool operator!=(const variant<Ts...> &lhs, const variant<Ts...> &rhs) { using detail::visitation::variant; using not_equal_to = detail::convert_to_bool<lib::not_equal_to>; #ifdef MPARK_CPP14_CONSTEXPR if (lhs.index() != rhs.index()) return true; if (lhs.valueless_by_exception()) return false; return variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs); #else return lhs.index() != rhs.index() || (!lhs.valueless_by_exception() && variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); #endif } template <typename... Ts> inline constexpr bool operator<(const variant<Ts...> &lhs, const variant<Ts...> &rhs) { using detail::visitation::variant; using less = detail::convert_to_bool<lib::less>; #ifdef MPARK_CPP14_CONSTEXPR if (rhs.valueless_by_exception()) return false; if (lhs.valueless_by_exception()) return true; if (lhs.index() < rhs.index()) return true; if (lhs.index() > rhs.index()) return false; return variant::visit_value_at(lhs.index(), less{}, lhs, rhs); #else return !rhs.valueless_by_exception() && (lhs.valueless_by_exception() || lhs.index() < rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at(lhs.index(), less{}, lhs, rhs))); #endif } template <typename... Ts> inline constexpr bool operator>(const variant<Ts...> &lhs, const variant<Ts...> &rhs) { using detail::visitation::variant; using greater = detail::convert_to_bool<lib::greater>; #ifdef MPARK_CPP14_CONSTEXPR if (lhs.valueless_by_exception()) return false; if (rhs.valueless_by_exception()) return true; if (lhs.index() > rhs.index()) return true; if (lhs.index() < rhs.index()) return false; return variant::visit_value_at(lhs.index(), greater{}, lhs, rhs); #else return !lhs.valueless_by_exception() && (rhs.valueless_by_exception() || lhs.index() > rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at(lhs.index(), greater{}, lhs, rhs))); #endif } template <typename... Ts> inline constexpr bool operator<=(const variant<Ts...> &lhs, const variant<Ts...> &rhs) { using detail::visitation::variant; using less_equal = detail::convert_to_bool<lib::less_equal>; #ifdef MPARK_CPP14_CONSTEXPR if (lhs.valueless_by_exception()) return true; if (rhs.valueless_by_exception()) return false; if (lhs.index() < rhs.index()) return true; if (lhs.index() > rhs.index()) return false; return variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs); #else return lhs.valueless_by_exception() || (!rhs.valueless_by_exception() && (lhs.index() < rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs)))); #endif } template <typename... Ts> inline constexpr bool operator>=(const variant<Ts...> &lhs, const variant<Ts...> &rhs) { using detail::visitation::variant; using greater_equal = detail::convert_to_bool<lib::greater_equal>; #ifdef MPARK_CPP14_CONSTEXPR if (rhs.valueless_by_exception()) return true; if (lhs.valueless_by_exception()) return false; if (lhs.index() > rhs.index()) return true; if (lhs.index() < rhs.index()) return false; return variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs); #else return rhs.valueless_by_exception() || (!lhs.valueless_by_exception() && (lhs.index() > rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at( lhs.index(), greater_equal{}, lhs, rhs)))); #endif } struct monostate {}; inline constexpr bool operator<(monostate, monostate) noexcept { return false; } inline constexpr bool operator>(monostate, monostate) noexcept { return false; } inline constexpr bool operator<=(monostate, monostate) noexcept { return true; } inline constexpr bool operator>=(monostate, monostate) noexcept { return true; } inline constexpr bool operator==(monostate, monostate) noexcept { return true; } inline constexpr bool operator!=(monostate, monostate) noexcept { return false; } #ifdef MPARK_CPP14_CONSTEXPR namespace detail { inline constexpr bool any(std::initializer_list<bool> bs) { for (bool b : bs) { if (b) { return true; } } return false; } } // namespace detail template <typename Visitor, typename... Vs> inline constexpr decltype(auto) visit(Visitor &&visitor, Vs &&... vs) { return (!detail::any({vs.valueless_by_exception()...}) ? (void)0 : throw_bad_variant_access()), detail::visitation::variant::visit_value( lib::forward<Visitor>(visitor), lib::forward<Vs>(vs)...); } #else namespace detail { template <std::size_t N> inline constexpr bool all_impl(const lib::array<bool, N> &bs, std::size_t idx) { return idx >= N || (bs[idx] && all_impl(bs, idx + 1)); } template <std::size_t N> inline constexpr bool all(const lib::array<bool, N> &bs) { return all_impl(bs, 0); } } // namespace detail template <typename Visitor, typename... Vs> inline constexpr DECLTYPE_AUTO visit(Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( (detail::all( lib::array<bool, sizeof...(Vs)>{{!vs.valueless_by_exception()...}}) ? (void)0 : throw_bad_variant_access()), detail::visitation::variant::visit_value(lib::forward<Visitor>(visitor), lib::forward<Vs>(vs)...)) #endif template <typename... Ts> inline auto swap(variant<Ts...> &lhs, variant<Ts...> &rhs) noexcept(noexcept(lhs.swap(rhs))) -> decltype(lhs.swap(rhs)) { lhs.swap(rhs); } namespace detail { template <typename T, typename...> using enabled_type = T; namespace hash { template <typename H, typename K> constexpr bool meets_requirements() noexcept { return std::is_copy_constructible<H>::value && std::is_move_constructible<H>::value && lib::is_invocable_r<std::size_t, H, const K &>::value; } template <typename K> constexpr bool is_enabled() noexcept { using H = std::hash<K>; return meets_requirements<H, K>() && std::is_default_constructible<H>::value && std::is_copy_assignable<H>::value && std::is_move_assignable<H>::value; } } // namespace hash } // namespace detail #undef AUTO #undef AUTO_RETURN #undef AUTO_REFREF #undef AUTO_REFREF_RETURN #undef DECLTYPE_AUTO #undef DECLTYPE_AUTO_RETURN } // namespace mpark namespace std { template <typename... Ts> struct hash<mpark::detail::enabled_type< mpark::variant<Ts...>, mpark::lib::enable_if_t<mpark::lib::all<mpark::detail::hash::is_enabled< mpark::lib::remove_const_t<Ts>>()...>::value>>> { using argument_type = mpark::variant<Ts...>; using result_type = std::size_t; inline result_type operator()(const argument_type &v) const { using mpark::detail::visitation::variant; std::size_t result = v.valueless_by_exception() ? 299792458 // Random value chosen by the universe upon creation : variant::visit_alt( #ifdef MPARK_GENERIC_LAMBDAS [](const auto &alt) { using alt_type = mpark::lib::decay_t<decltype(alt)>; using value_type = mpark::lib::remove_const_t< typename alt_type::value_type>; return hash<value_type>{}(alt.value); } #else hasher{} #endif , v); return hash_combine(result, hash<std::size_t>{}(v.index())); } private: #ifndef MPARK_GENERIC_LAMBDAS struct hasher { template <typename Alt> inline std::size_t operator()(const Alt &alt) const { using alt_type = mpark::lib::decay_t<Alt>; using value_type = mpark::lib::remove_const_t<typename alt_type::value_type>; return hash<value_type>{}(alt.value); } }; #endif static std::size_t hash_combine(std::size_t lhs, std::size_t rhs) { return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2); } }; template <> struct hash<mpark::monostate> { using argument_type = mpark::monostate; using result_type = std::size_t; inline result_type operator()(const argument_type &) const noexcept { return 66740831; // return a fundamentally attractive random value. } }; } // namespace std #endif // MPARK_VARIANT_HPP /* SPDX-License-Identifier: GPL-3.0-or-later */ // std::generator is not implemented yet, so polyfill it more or less namespace gpp { template <typename Out, typename In> class generator { public: // Types used by the coroutine struct promise_type { Out current_command; In feedback_value; template<typename Ret> struct awaiter : std::suspend_always { friend promise_type; constexpr auto await_resume() const { return get<Ret>(p.feedback_value); } promise_type& p; }; generator get_return_object() { return generator{handle::from_promise(*this)}; } static std::suspend_always initial_suspend() noexcept { return {}; } static std::suspend_always final_suspend() noexcept { return {}; } template<typename T> auto yield_value(T value) noexcept { current_command = value; using ret = typename T::return_type; if constexpr(std::is_same_v<ret, void>) return std::suspend_always{}; else return awaiter<ret>{{}, *this}; } void return_void() noexcept { } // Disallow co_await in generator coroutines. void await_transform() = delete; [[noreturn]] static void unhandled_exception() { std::abort(); } }; using handle = std::coroutine_handle<promise_type>; // To enable begin / end class iterator { public: explicit iterator(const handle& coroutine) noexcept : m_coroutine{coroutine} { } void operator++() noexcept { m_coroutine.resume(); } auto& operator*() const noexcept { return m_coroutine.promise(); } bool operator==(std::default_sentinel_t) const noexcept { return !m_coroutine || m_coroutine.done(); } private: handle m_coroutine; }; // Constructors explicit generator(handle coroutine) : m_coroutine{std::move(coroutine)} { } generator() noexcept = default; generator(const generator&) = delete; generator& operator=(const generator&) = delete; generator(generator&& other) noexcept : m_coroutine{other.m_coroutine} { other.m_coroutine = {}; } generator& operator=(generator&& other) noexcept { if (this != &other) { if (m_coroutine) { m_coroutine.destroy(); } m_coroutine = other.m_coroutine; other.m_coroutine = {}; } return *this; } ~generator() { if (m_coroutine) { m_coroutine.destroy(); } } // Range-based for loop support. iterator begin() noexcept { if (m_coroutine) { m_coroutine.resume(); } return iterator{m_coroutine}; } std::default_sentinel_t end() const noexcept { return {}; } private: handle m_coroutine; }; template <typename Out> class generator<Out, void> { public: // Types used by the coroutine struct promise_type { Out current_command; generator get_return_object() { return generator{handle::from_promise(*this)}; } static std::suspend_always initial_suspend() noexcept { return {}; } static std::suspend_always final_suspend() noexcept { return {}; } template<typename T> std::suspend_always yield_value(T&& value) noexcept { current_command = std::move(value); return std::suspend_always{}; } void return_void() noexcept { } // Disallow co_await in generator coroutines. void await_transform() = delete; [[noreturn]] static void unhandled_exception() { std::abort(); } }; using handle = std::coroutine_handle<promise_type>; // To enable begin / end class iterator { public: explicit iterator(const handle& coroutine) noexcept : m_coroutine{coroutine} { } void operator++() noexcept { m_coroutine.resume(); } auto& operator*() const noexcept { return m_coroutine.promise(); } bool operator==(std::default_sentinel_t) const noexcept { return !m_coroutine || m_coroutine.done(); } private: handle m_coroutine; }; // Constructors explicit generator(handle coroutine) : m_coroutine{std::move(coroutine)} { } generator() noexcept = default; generator(const generator&) = delete; generator& operator=(const generator&) = delete; generator(generator&& other) noexcept : m_coroutine{other.m_coroutine} { other.m_coroutine = {}; } generator& operator=(generator&& other) noexcept { if (this != &other) { if (m_coroutine) { m_coroutine.destroy(); } m_coroutine = other.m_coroutine; other.m_coroutine = {}; } return *this; } ~generator() { if (m_coroutine) { m_coroutine.destroy(); } } // Range-based for loop support. iterator begin() noexcept { if (m_coroutine) { m_coroutine.resume(); } return iterator{m_coroutine}; } std::default_sentinel_t end() const noexcept { return {}; } private: handle m_coroutine; }; struct suspend { bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle<>) const noexcept { } void await_resume() const noexcept { } }; //static const constexpr auto qSuspend = QSuspend{}; template<typename Promise> class task { public: using promise_type = Promise; explicit task(std::coroutine_handle<Promise> handle) noexcept : m_handle{std::move(handle)} { } task(task&& other) noexcept : m_handle{std::exchange(other.m_handle, {})} { } task& operator=(task&& other) noexcept { m_handle = std::exchange(other.m_handle, {}); return *this; } ~task() { if (m_handle) m_handle.destroy(); } task(const task&) = delete; task& operator=(const task&) = delete; bool resume() { if (!m_handle.done()) m_handle.resume(); return !m_handle.done(); } private: std::coroutine_handle<Promise> m_handle; }; } // Multiple variants were tried - mpark given above yields the smallest code // #include <boost/variant2.hpp> // #include <variant> namespace bv2 = mpark; namespace gpp { struct buffer_handle_t; using buffer_handle = buffer_handle_t*; struct texture_handle_t; using texture_handle = texture_handle_t*; struct sampler_handle_t; using sampler_handle = sampler_handle_t*; // Define our commands struct static_allocation { enum { allocation, static_, storage }; using return_type = buffer_handle; int binding; int size; }; struct static_upload { enum { upload, static_ }; using return_type = void; buffer_handle handle; int offset; int size; void* data; }; struct dynamic_vertex_allocation { enum { allocation, dynamic, vertex }; using return_type = buffer_handle; int binding; int size; }; struct dynamic_vertex_upload { enum { upload, dynamic, vertex }; using return_type = void; buffer_handle handle; int offset; int size; void* data; }; struct dynamic_index_allocation { enum { allocation, dynamic, index }; using return_type = buffer_handle; int binding; int size; }; struct dynamic_index_upload { enum { upload, dynamic, index }; using return_type = void; buffer_handle handle; int offset; int size; void* data; }; struct dynamic_ubo_allocation { enum { allocation, dynamic, ubo }; using return_type = buffer_handle; int binding; int size; }; struct dynamic_ubo_upload { enum { upload, dynamic, ubo }; using return_type = void; buffer_handle handle; int offset; int size; void* data; }; struct sampler_allocation { enum { allocation, sampler }; using return_type = sampler_handle; }; struct texture_allocation { enum { allocation, texture }; using return_type = texture_handle; int binding; int width; int height; }; struct texture_upload { enum { upload, texture }; using return_type = void; texture_handle handle; int offset; int size; void* data; }; struct get_ubo_handle { enum { getter, ubo }; using return_type = buffer_handle; int binding; }; struct get_texture_handle { enum { getter, texture }; using return_type = texture_handle; int binding; }; struct buffer_release { enum { deallocation, vertex, index }; using return_type = void; buffer_handle handle; }; struct ubo_release { enum { deallocation, ubo }; using return_type = void; buffer_handle handle; }; struct sampler_release { enum { deallocation, texture }; using return_type = void; texture_handle handle; }; struct texture_release { enum { deallocation, texture }; using return_type = void; texture_handle handle; }; struct begin_compute_pass { enum { compute, begin }; using return_type = void; }; struct end_compute_pass { enum { compute, end }; using return_type = void; }; struct compute_dispatch { enum { compute, dispatch }; using return_type = void; int x, y, z; }; struct buffer_view { const char* data; std::size_t size; }; struct texture_view { const char* data; std::size_t size; }; struct buffer_readback_handle_t; struct texture_readback_handle_t; using buffer_readback_handle = buffer_readback_handle_t*; using texture_readback_handle = texture_readback_handle_t*; struct buffer_awaiter { enum { readback, await, buffer }; using return_type = buffer_view; buffer_readback_handle handle; }; struct texture_awaiter { enum { readback, await, texture }; using return_type = texture_view; texture_readback_handle handle; }; struct readback_buffer { enum { readback, request, buffer }; using return_type = buffer_awaiter; buffer_handle handle; int offset; int size; }; struct readback_texture { enum { readback, request, texture }; using return_type = texture_awaiter; texture_handle handle; }; // Define what the update() can do using update_action = bv2::variant< static_allocation, static_upload, dynamic_vertex_allocation, dynamic_vertex_upload, buffer_release, dynamic_index_allocation, dynamic_index_upload, dynamic_ubo_allocation, dynamic_ubo_upload, ubo_release, sampler_allocation, sampler_release, texture_allocation, texture_upload, texture_release, get_ubo_handle >; using update_handle = bv2::variant<bv2::monostate, buffer_handle, texture_handle, sampler_handle>; using co_update = gpp::generator<update_action, update_handle>; // Define what the release() can do using release_action = bv2::variant< buffer_release , ubo_release , sampler_release , texture_release >; using co_release = gpp::generator<release_action, void>; // Define what the dispatch(), for compute, can do using dispatch_action = bv2::variant< begin_compute_pass, end_compute_pass , compute_dispatch , readback_buffer, readback_texture , buffer_awaiter, texture_awaiter >; using dispatch_handle = bv2::variant< bv2::monostate , buffer_awaiter, texture_awaiter , buffer_view, texture_view >; using co_dispatch = gpp::generator<dispatch_action, dispatch_handle>; } #include <vector> #include <cmath> #include <cstdlib> void* gpu_allocate_buffer(int size) { printf("gpu_allocate_buffer: %d\n", size); return nullptr; } void* gpu_allocate_sampler() { printf("gpu_allocate_sampler\n"); return nullptr; } void* gpu_allocate_texture(int w, int h) { printf("gpu_allocate_texture: %d x %d\n", w, h); return nullptr; } void gpu_upload_buffer(void*, void*) { printf("gpu_upload_buffer\n"); } void gpu_upload_texture(void*, void*) { printf("gpu_upload_texture\n"); } struct handle_release { template <typename C> void operator()(C command) { if constexpr (requires { C::deallocation; }) { if constexpr ( requires { C::vertex; } || requires { C::index; } || requires { C::ubo; }) { } else if constexpr ( requires { C::sampler; }) { } else if constexpr ( requires { C::texture; }) { } else { static_assert(C::unhandled); } } else { static_assert(C::unhandled); } } }; template<typename Ret> struct handle_update { template <typename C> Ret operator()(const C& command) const noexcept { if constexpr (requires { C::allocation; }) { if constexpr (requires { C::vertex; } || requires { C::index; }) { auto buf = gpu_allocate_buffer(command.size); return reinterpret_cast<typename C::return_type>(buf); } else if constexpr ( requires { C::sampler; } ) { auto buf = gpu_allocate_sampler(); return reinterpret_cast<typename C::return_type>(buf); } else if constexpr ( requires { C::ubo; } || requires { C::storage; }) { auto buf = gpu_allocate_buffer(command.size); return reinterpret_cast<typename C::return_type>(buf); } else if constexpr ( requires { C::texture; }) { auto tex = gpu_allocate_texture(command.width, command.height); return reinterpret_cast<typename C::return_type>(tex); } else { return typename C::return_type{}; } } else if constexpr(requires { C::getter; }) { if constexpr( requires { C::ubo; }) { return typename C::return_type{}; } else { static_assert(C::unhandled); return {}; } } else if constexpr(requires { C::upload; }) { if constexpr (requires { C::ubo; } || requires { C::storage; }) { gpu_upload_buffer(command.handle, command.data); return {}; } else if constexpr ( requires { C::texture; }) { gpu_upload_texture(command.handle, command.data); return {}; } else { return {}; } } else { handle_release{}(command); return {}; } return {}; } }; struct MyNode { gpp::texture_handle tex_handle{}; std::vector<float> tex; gpp::co_update update() { // In this example we test the automatic UBO filling with the inputs declared above. // Here the surrounding environment makes sure that the UBO already has a handle auto ubo = co_yield gpp::get_ubo_handle{ .binding = 0 }; // Upload some data into it, using an input (non-uniform) of our node using namespace std; float xy[2] = {2.f * rand(), .5f * rand()}; co_yield gpp::dynamic_ubo_upload{ .handle = ubo, .offset = 0, .size = sizeof(xy), .data = &xy }; // The sampler is not used by the inputs block, so we have to allocate it ourselves int sz = 16*16*4; if(!tex_handle) { this->tex_handle = co_yield gpp::texture_allocation{ .binding = 1 , .width = 16 , .height = 16 }; } // And upload some data co_yield gpp::texture_upload{ .handle = tex_handle , .offset = 0 , .size = sz , .data = tex.data() }; } }; static void process(MyNode& node) { for (auto& promise : node.update()) { using ret_type = decltype(promise.feedback_value); handle_update<ret_type> handler{}; promise.feedback_value = visit(handler, promise.current_command); } } int main() { MyNode node; process(node); }
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