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 #2
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
/// \file /// /// Test for inline_vector /// /// Most of the tests below are adapted from libc++: https://libcxx.llvm.org /// under the following license: //===----------------------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "inplace_vector" #include <memory> #include <string> #include <vector> #include <iostream> #define CHECK(...) \ static_cast<void>((__VA_ARGS__) \ ? void(0) \ : ::std::__iv_detail::__assert_failure( \ static_cast<const char*>(__FILE__), __LINE__, \ "assertion failed: " #__VA_ARGS__)) #define CHECK_THROWS(EXPR, EXCEPT) \ if (auto e = [&] { try { (EXPR); return false; } catch (const EXCEPT &) { return true; } catch (...) { return false; } }(); !e) { \ ::std::__iv_detail::__assert_failure( static_cast<const char*>(__FILE__), __LINE__, "expression failed to throw " #EXCEPT ": " #EXPR); \ } template struct std::__iv_detail::__storage::__zero_sized<int>; template struct std::__iv_detail::__storage::__trivial<int, 10>; template struct std::__iv_detail::__storage::__non_trivial<std::unique_ptr<int>, 10>; template struct std::__iv_detail::__storage::__zero_sized<const int>; template struct std::__iv_detail::__storage::__trivial<const int, 10>; template struct std::__iv_detail::__storage::__non_trivial<const std::unique_ptr<int>, 10>; // empty: template struct std::inplace_vector<int, 0>; // trivial non-empty: template struct std::inplace_vector<int, 1>; template struct std::inplace_vector<int, 2>; template struct std::inplace_vector<const int, 3>; // non-trivial template struct std::inplace_vector<std::string, 3>; template struct std::inplace_vector<const std::string, 3>; // move-only: template struct std::inplace_vector<std::unique_ptr<int>, 3>; template struct std::inplace_vector<const std::unique_ptr<int>, 3>; struct tint { std::size_t i; tint() = default; constexpr tint(tint const&) = default; constexpr tint(tint &&) = default; constexpr tint& operator=(tint const&) = default; constexpr tint& operator=(tint&&) = default; // FIXME: ~tint() = default; // ^^^ adding this makes the class non-trivial in clang explicit constexpr tint(std::size_t j) : i(j) { } explicit operator std::size_t() { return i; } }; static_assert(std::is_trivial<tint>{} && std::is_copy_constructible<tint>{} && std::is_move_constructible<tint>{}, ""); // Explicit instantiations template struct std::inplace_vector<tint, 0>; // trivial empty template struct std::inplace_vector<tint, 1>; // trivial non-empty template struct std::inplace_vector<tint, 2>; // trivial non-empty template struct std::inplace_vector<tint, 3>; // trivial non-empty struct moint final { std::size_t i = 0; moint() = default; moint(moint const&) = delete; moint& operator=(moint const&) = delete; moint(moint&&) = default; moint& operator=(moint&&) = default; ~moint() = default; explicit operator std::size_t() { return i; } explicit constexpr moint(std::size_t j) : i(j) { } // it seems that deleting the copy constructor is not enough to make // this non-trivial using libstdc++: virtual void foo() { } bool operator==(moint b) { return i == b.i; } }; static_assert(!std::is_trivial<moint>{} and !std::is_copy_constructible<moint>{} and std::is_move_constructible<moint>{}, ""); // cannot explicitly instantiate the type for some types // // non-trivial empty: // template struct std::inplace_vector<moint, 0>; // // non-trivial non-empty: // template struct std::inplace_vector<moint, 1>; // template struct std::inplace_vector<moint, 2>; // template struct std::inplace_vector<moint, 3>; template <typename T, std::size_t N> using vector = std::inplace_vector<T, N>; class non_copyable { int i_; double d_; public: non_copyable(const non_copyable&) = delete; non_copyable& operator=(const non_copyable&) = delete; non_copyable(int i, double d) : i_(i), d_(d) { } non_copyable(non_copyable&& a) noexcept : i_(a.i_), d_(a.d_) { a.i_ = 0; a.d_ = 0; } non_copyable& operator=(non_copyable&& a) noexcept { i_ = a.i_; d_ = a.d_; a.i_ = 0; a.d_ = 0; return *this; } int geti() const { return i_; } double getd() const { return d_; } }; template <typename T, int N> struct vec { vec() = default; vec(std::initializer_list<T> /*il*/) { } }; template <typename T, std::size_t N> constexpr void test_il_constructor() { auto v = [] { switch(N) { case 0: { const vector<T, N> x{}; return x; } case 1: { const vector<T, N> x({0}); return x; } case 10: { const vector<T, N> x({0,1,2,3,4,5,6,7,8,9}); return x; } default: CHECK(false); } }(); CHECK(v.size() == N); for (size_t i = 0; i < N; ++i) CHECK(v[i] == T(i)); CHECK(11 > N); if !consteval { CHECK_THROWS(([&] { const vector<T, N> x({0,1,2,3,4,5,6,7,8,9,10}); }()), std::bad_alloc); } } template <typename T, std::size_t N> constexpr void test_il_assignment() { auto v = [] { switch(N) { case 0: { const vector<T, N> x = {}; return x; } case 1: { const vector<T, N> x = {0}; return x; } case 10: { const vector<T, N> x = {0,1,2,3,4,5,6,7,8,9}; return x; } default: CHECK(false); } }(); CHECK(v.size() == N); for (size_t i = 0; i < N; ++i) CHECK(v[i] == T(i)); if !consteval { CHECK_THROWS(([&] { const vector<T, N> x = {0,1,2,3,4,5,6,7,8,9,10}; }()), std::bad_alloc); } } template <typename T, std::size_t N> constexpr void test_default_constructor() { vector<T, N> v; CHECK(v.size() == 0); CHECK(v.empty()); CHECK(v.capacity() == N); } template <typename T, std::size_t N> constexpr void test_default_constructor_bounds_and_contiguous_iterators(std::size_t sz) { CHECK(sz <= N); vector<T, N> v(sz); CHECK(v.size() == sz); CHECK(v.max_size() == N); CHECK(v.capacity() == N); for (std::size_t i = 0; i != sz; ++i) { CHECK(v[i] == T{}); } for (std::size_t i = 0; i < v.size(); ++i) { // contiguous CHECK(*(v.begin() + i) == *(std::addressof(*v.begin()) + i)); CHECK(*(v.cbegin() + i) == *(std::addressof(*v.cbegin()) + i)); CHECK(*(v.rbegin() + i) == *(std::addressof(*v.rbegin()) - i)); CHECK(*(v.crbegin() + i) == *(std::addressof(*v.crbegin()) - i)); } // iterators if (v.size() == 0) { CHECK(v.empty()); CHECK(v.begin() == v.end()); CHECK(v.cbegin() == v.cend()); CHECK(v.rbegin() == v.rend()); CHECK(v.crbegin() == v.crend()); } else { CHECK(!v.empty()); CHECK(v.begin() != v.end()); CHECK(v.cbegin() != v.cend()); CHECK(v.rbegin() != v.rend()); CHECK(v.crbegin() != v.crend()); CHECK(std::distance(v.begin(), v.end()) == v.size()); CHECK(std::distance(v.cbegin(), v.cend()) == v.size()); CHECK(std::distance(v.rbegin(), v.rend()) == v.size()); CHECK(std::distance(v.crbegin(), v.crend()) == v.size()); CHECK(v.back() == T{}); CHECK(v.front() == T{}); } } template <typename T, std::size_t N> constexpr void test_iterators() { { // N3644 testing using C = vector<T, N>; typename C::iterator ii1{}, ii2{}; typename C::iterator ii4 = ii1; typename C::const_iterator cii{}; CHECK(ii1 == ii2); CHECK(ii1 == ii4); CHECK(!(ii1 != ii2)); CHECK((ii1 == cii)); CHECK((cii == ii1)); CHECK(!(ii1 != cii)); CHECK(!(cii != ii1)); CHECK(!(ii1 < cii)); CHECK(!(cii < ii1)); CHECK((ii1 <= cii)); CHECK((cii <= ii1)); CHECK(!(ii1 > cii)); CHECK(!(cii > ii1)); CHECK((ii1 >= cii)); CHECK((cii >= ii1)); CHECK((cii - ii1) == 0); CHECK((ii1 - cii) == 0); } } template <typename T, std::size_t N> constexpr void test_constructor_input_iterators() { CHECK(N < 11); const T t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; using C = vector<T, N>; C c(std::begin(t), std::begin(t) + N); CHECK(c.size() == N); CHECK(std::equal(std::begin(t), std::begin(t) + N, std::begin(c), std::end(c))); for (typename C::iterator i = c.begin(); i != c.end(); ++i) { auto idx = i - c.begin(); auto o = t[idx]; CHECK(*i == o); *i = 2 * o; CHECK(*i == (2*o)); CHECK(std::distance(c.begin(), i) == idx); CHECK(std::distance(i, c.end()) == c.size() - idx); } } template <typename T, std::size_t N> constexpr bool test_all_() { test_il_constructor<T, N>(); test_il_assignment<T, N>(); test_default_constructor<T, N>(); for (size_t i = 0; i < N; ++i) test_default_constructor_bounds_and_contiguous_iterators<T, N>(i); test_iterators<T, N>(); test_constructor_input_iterators<T, N>(); return true; } template <typename T, std::size_t N> void test_all() { constexpr bool ct = test_all_<T, N>(); static_assert(ct, "CONSTEXPR TESTS FAILED"); test_all_<T, N>(); } int main() { { // storage using std::__iv_detail::__storage::_t; using std::__iv_detail::__storage::__non_trivial; using std::__iv_detail::__storage::__trivial; using std::__iv_detail::__storage::__zero_sized; static_assert(std::is_same<_t<int, 0>, __zero_sized<int>>{}); static_assert(std::is_same<_t<int, 10>, __trivial<int, 10>>{}); static_assert(std::is_same<_t<std::unique_ptr<int>, 10>, __non_trivial<std::unique_ptr<int>, 10>>{}, ""); } test_all<int, 0>(); test_all<int, 1>(); test_all<int, 10>(); //test_all<const int, 0>(); { // capacity vector<int, 10> a; static_assert(a.capacity() == std::size_t(10)); CHECK(a.empty()); for (std::size_t i = 0; i != 10; ++i) { a.push_back(0); } static_assert(a.capacity() == std::size_t(10)); CHECK(a.size() == std::size_t(10)); CHECK(!a.empty()); CHECK_THROWS(a.push_back(0), std::bad_alloc); CHECK((uintptr_t)nullptr == (uintptr_t)a.try_push_back(0)); } { // resize copyable using Copyable = int; vector<Copyable, 10> a(std::size_t(10), 5); CHECK(a.size() == std::size_t(10)); static_assert(a.capacity() == std::size_t(10)); // test_contiguous(a); for (std::size_t i = 0; i != 10; ++i) { CHECK(a[i] == 5); } a.resize(5); CHECK(a.size() == std::size_t(5)); static_assert(a.capacity() == std::size_t(10)); // test_contiguous(a); a.resize(9); CHECK(a[4] == 5); for (std::size_t i = 5; i != 9; ++i) { CHECK(a[i] == 0); } CHECK(a.size() == std::size_t(9)); static_assert(a.capacity() == std::size_t(10)); // test_contiguous(a); a.resize(10, 3); CHECK(a[4] == 5); CHECK(a[8] == 0); CHECK(a[9] == 3); CHECK(a.size() == std::size_t(10)); static_assert(a.capacity() == std::size_t(10)); a.resize(5, 2); for (std::size_t i = 0; i != 5; ++i) { CHECK(a[i] == 5); } // test_contiguous(a); CHECK_THROWS(a.resize(12), std::bad_alloc); } { // resize move-only using MoveOnly = std::unique_ptr<int>; vector<MoveOnly, 10> a(10); CHECK(a.size() == std::size_t(10)); static_assert(a.capacity() == std::size_t(10)); a.resize(5); // test_contiguous(a); CHECK(a.size() == std::size_t(5)); static_assert(a.capacity() == std::size_t(10)); a.resize(9); CHECK(a.size() == std::size_t(9)); static_assert(a.capacity() == std::size_t(10)); } { // resize value: using Copyable = int; vector<Copyable, 10> a(std::size_t(10)); CHECK(a.size() == std::size_t(10)); static_assert(a.capacity() == std::size_t(10)); // test_contiguous(a); for (std::size_t i = 0; i != 10; ++i) { CHECK(a[i] == 0); } a.resize(5); CHECK(a.size() == std::size_t(5)); static_assert(a.capacity() == std::size_t(10)); // test_contiguous(a); for (std::size_t i = 0; i != 5; ++i) { CHECK(a[i] == 0); } a.resize(9, 5); for (std::size_t i = 0; i != 5; ++i) { CHECK(a[i] == 0); } for (std::size_t i = 5; i != 9; ++i) { CHECK(a[i] == 5); } CHECK(a.size() == std::size_t(9)); static_assert(a.capacity() == std::size_t(10)); // test_contiguous(a); a.resize(10, 3); for (std::size_t i = 0; i != 5; ++i) { CHECK(a[i] == 0); } for (std::size_t i = 5; i != 9; ++i) { CHECK(a[i] == 5); } CHECK(a[9] == 3); CHECK(a.size() == std::size_t(10)); static_assert(a.capacity() == std::size_t(10)); // test_contiguous(a); } { // assign copy vector<int, 3> z(3, 5); vector<int, 3> a = {0, 1, 2}; CHECK(a.size() == std::size_t{3}); vector<int, 3> b; CHECK(b.size() == std::size_t{0}); b = a; CHECK(b.size() == std::size_t{3}); CHECK( std::equal(std::begin(a), std::end(a), std::begin(b), std::end(b))); } { // copy construct vector<int, 3> a = {0, 1, 2}; CHECK(a.size() == std::size_t{3}); vector<int, 3> b(a); CHECK(b.size() == std::size_t{3}); CHECK( std::equal(std::begin(a), std::end(a), std::begin(b), std::end(b))); } { // assign move using MoveOnly = std::unique_ptr<int>; vector<MoveOnly, 3> a(3); CHECK(a.size() == std::size_t{3}); vector<MoveOnly, 3> b; CHECK(b.size() == std::size_t{0}); b = std::move(a); CHECK(b.size() == std::size_t{3}); CHECK(a.size() == std::size_t{3}); } { // move construct using MoveOnly = std::unique_ptr<int>; vector<MoveOnly, 3> a(3); CHECK(a.size() == std::size_t{3}); vector<MoveOnly, 3> b(std::move(a)); CHECK(b.size() == std::size_t{3}); CHECK(a.size() == std::size_t{3}); } { // old tests using vec_t = vector<int, 5>; vec_t vec1(5); vec1[0] = 0; vec1[1] = 1; vec1[2] = 2; vec1[3] = 3; vec1[4] = 4; { vec_t vec2; vec2.push_back(5); vec2.push_back(6); vec2.push_back(7); vec2.push_back(8); vec2.push_back(9); CHECK(vec1[0] == 0); CHECK(vec1[4] == 4); CHECK(vec2[0] == 5); CHECK(vec2[4] == 9); } { vec_t vec2; vec2.try_push_back(5); vec2.try_push_back(6); vec2.try_push_back(7); vec2.try_push_back(8); vec2.try_push_back(9); CHECK(vec1[0] == 0); CHECK(vec1[4] == 4); CHECK(vec2[0] == 5); CHECK(vec2[4] == 9); } { vec_t vec2; vec2.unchecked_push_back(5); vec2.unchecked_push_back(6); vec2.unchecked_push_back(7); vec2.unchecked_push_back(8); vec2.unchecked_push_back(9); CHECK(vec1[0] == 0); CHECK(vec1[4] == 4); CHECK(vec2[0] == 5); CHECK(vec2[4] == 9); } { auto vec2 = vec1; CHECK(vec2[0] == 0); CHECK(vec2[4] == 4); CHECK(vec1[0] == 0); CHECK(vec1[4] == 4); } { int count_ = 0; for (auto i : vec1) { CHECK(i == count_); count_++; } } { std::vector<int> vec2(5); vec2[0] = 4; vec2[1] = 3; vec2[2] = 2; vec2[3] = 1; vec2[4] = 0; vec_t vec(vec2.size()); copy(std::begin(vec2), std::end(vec2), std::begin(vec)); int count_ = 4; for (auto i : vec) { CHECK(i == count_); count_--; } } } { using vec_t = vector<int, 0>; static_assert(sizeof(vec_t) == 1, ""); constexpr auto a = vec_t{}; static_assert(a.size() == std::size_t{0}, ""); } { // back and front: using C = vector<int, 2>; C c(1); CHECK(c.back() == 0); CHECK(c.front() == 0); CHECK(c[0] == 0); c.clear(); int one = 1; c.push_back(one); CHECK(c.back() == 1); CHECK(c.front() == 1); CHECK(c[0] == 1); CHECK(c.size() == 1); c.push_back(2); CHECK(c.back() == 2); CHECK(c.front() == 1); CHECK(c[0] == 1); CHECK(c[1] == 2); CHECK(c.size() == 2); c.pop_back(); CHECK(c.front() == 1); CHECK(c[0] == 1); CHECK(c.back() == 1); c.pop_back(); CHECK(c.empty()); } { // const back: using C = vector<int, 2>; constexpr C c(1); static_assert(c.back() == 0); static_assert(c.front() == 0); static_assert(c[0] == 0); static_assert(c.size() == 1); } { // swap: same type using C = vector<int, 5>; C c0(3, 5); C c1(5, 1); C c2(0); CHECK(c0.size() == std::size_t(3)); CHECK(c1.size() == std::size_t(5)); CHECK(c2.size() == std::size_t(0)); for (std::size_t i = 0; i != 3; ++i) { CHECK(c0[i] == 5); } for (std::size_t i = 0; i != 5; ++i) { CHECK(c1[i] == 1); } c0.swap(c1); CHECK(c0.size() == std::size_t(5)); CHECK(c1.size() == std::size_t(3)); for (std::size_t i = 0; i != 5; ++i) { CHECK(c0[i] == 1); } for (std::size_t i = 0; i != 3; ++i) { CHECK(c1[i] == 5); } c2.swap(c1); CHECK(c1.size() == std::size_t(0)); CHECK(c2.size() == std::size_t(3)); for (std::size_t i = 0; i != 3; ++i) { CHECK(c2[i] == 5); } } { // std::swap: same type using C = vector<int, 5>; C c0(3, 5); C c1(5, 1); C c2(0); CHECK(c0.size() == std::size_t(3)); CHECK(c1.size() == std::size_t(5)); CHECK(c2.size() == std::size_t(0)); for (std::size_t i = 0; i != 3; ++i) { CHECK(c0[i] == 5); } for (std::size_t i = 0; i != 5; ++i) { CHECK(c1[i] == 1); } std::swap(c0, c1); CHECK(c0.size() == std::size_t(5)); CHECK(c1.size() == std::size_t(3)); for (std::size_t i = 0; i != 5; ++i) { CHECK(c0[i] == 1); } for (std::size_t i = 0; i != 3; ++i) { CHECK(c1[i] == 5); } std::swap(c2, c1); CHECK(c1.size() == std::size_t(0)); CHECK(c2.size() == std::size_t(3)); for (std::size_t i = 0; i != 3; ++i) { CHECK(c2[i] == 5); } } { constexpr vector<int, 5> v; static_assert(v.data() != nullptr); constexpr vector<int, 0> v0; static_assert(v0.data() == nullptr); } {// emplace: {vector<non_copyable, 3> c; vector<non_copyable, 3>::iterator i = c.emplace(c.cbegin(), 2, 3.5); CHECK(i == c.begin()); CHECK(c.size() == 1); CHECK(c.front().geti() == 2); CHECK(c.front().getd() == 3.5); i = c.emplace(c.cend(), 3, 4.5); CHECK(i == c.end() - 1); CHECK(c.size() == 2); CHECK(c.front().geti() == 2); CHECK(c.front().getd() == 3.5); CHECK(c.back().geti() == 3); CHECK(c.back().getd() == 4.5); i = c.emplace(c.cbegin() + 1, 4, 6.5); CHECK(i == c.begin() + 1); CHECK(c.size() == 3); CHECK(c.front().geti() == 2); CHECK(c.front().getd() == 3.5); CHECK(c[1].geti() == 4); CHECK(c[1].getd() == 6.5); CHECK(c.back().geti() == 3); CHECK(c.back().getd() == 4.5); CHECK_THROWS(c.emplace(c.cbegin(), 2, 3.5), std::bad_alloc); } { vector<non_copyable, 3> c; vector<non_copyable, 3>::iterator i = c.emplace(c.cbegin(), 2, 3.5); CHECK(i == c.begin()); CHECK(c.size() == 1); CHECK(c.front().geti() == 2); CHECK(c.front().getd() == 3.5); i = c.emplace(c.cend(), 3, 4.5); CHECK(i == c.end() - 1); CHECK(c.size() == 2); CHECK(c.front().geti() == 2); CHECK(c.front().getd() == 3.5); CHECK(c.back().geti() == 3); CHECK(c.back().getd() == 4.5); i = c.emplace(c.cbegin() + 1, 4, 6.5); CHECK(i == c.begin() + 1); CHECK(c.size() == 3); CHECK(c.front().geti() == 2); CHECK(c.front().getd() == 3.5); CHECK(c[1].geti() == 4); CHECK(c[1].getd() == 6.5); CHECK(c.back().geti() == 3); CHECK(c.back().getd() == 4.5); } } {// emplace_back vector<non_copyable, 2> c; c.emplace_back(2, 3.5); CHECK(c.size() == 1); CHECK(c.front().geti() == 2); CHECK(c.front().getd() == 3.5); c.emplace_back(3, 4.5); CHECK(c.size() == 2); CHECK(c.front().geti() == 2); CHECK(c.front().getd() == 3.5); CHECK(c.back().geti() == 3); CHECK(c.back().getd() == 4.5); CHECK_THROWS(c.emplace_back(2, 3.5), std::bad_alloc); } {// try_emplace_back vector<non_copyable, 2> c; CHECK((uintptr_t)c.begin() == (uintptr_t)c.try_emplace_back(2, 3.5)); CHECK(c.size() == 1); CHECK(c.front().geti() == 2); CHECK(c.front().getd() == 3.5); CHECK((uintptr_t)(c.begin() + 1) == (uintptr_t)c.try_emplace_back(3, 4.5)); CHECK(c.size() == 2); CHECK(c.front().geti() == 2); CHECK(c.front().getd() == 3.5); CHECK(c.back().geti() == 3); CHECK(c.back().getd() == 4.5); CHECK((uintptr_t)nullptr == (uintptr_t)c.try_emplace_back(2, 3.5)); } {// unchecked_emplace_back vector<non_copyable, 2> c; CHECK((uintptr_t)c.begin() == (uintptr_t)&c.unchecked_emplace_back(2, 3.5)); CHECK(c.size() == 1); CHECK(c.front().geti() == 2); CHECK(c.front().getd() == 3.5); CHECK((uintptr_t)(c.begin() + 1) == (uintptr_t)&c.unchecked_emplace_back(3, 4.5)); CHECK(c.size() == 2); CHECK(c.front().geti() == 2); CHECK(c.front().getd() == 3.5); CHECK(c.back().geti() == 3); CHECK(c.back().getd() == 4.5); } { // emplace extra: {// vector<int, 4> v; v = {1, 2, 3}; v.emplace(v.begin(), v.back()); CHECK(v[0] == 3); } { vector<int, 4> v; v = {1, 2, 3}; v.emplace(v.begin(), v.back()); CHECK(v[0] == 3); } } {// erase {int a1[] = {1, 2, 3}; vector<int, 4> l1(a1, a1 + 3); CHECK(l1.size() == 3); vector<int, 4>::const_iterator i = l1.begin(); ++i; vector<int, 4>::iterator j = l1.erase(i); CHECK(l1.size() == 2); CHECK(std::distance(l1.begin(), l1.end()) == 2); CHECK(*j == 3); CHECK(*l1.begin() == 1); CHECK(*std::next(l1.begin()) == 3); j = l1.erase(j); CHECK(j == l1.end()); CHECK(l1.size() == 1); CHECK(std::distance(l1.begin(), l1.end()) == 1); CHECK(*l1.begin() == 1); j = l1.erase(l1.begin()); CHECK(j == l1.end()); CHECK(l1.empty()); CHECK(std::distance(l1.begin(), l1.end()) == 0); } } { // erase iter iter int a1[] = {1, 2, 3}; using vec_t = vector<int, 5>; { vec_t l1(a1, a1 + 3); vec_t::iterator i = l1.erase(l1.cbegin(), l1.cbegin()); CHECK(l1.size() == 3); CHECK(std::distance(l1.cbegin(), l1.cend()) == 3); CHECK(i == l1.begin()); } { vec_t l1(a1, a1 + 3); vec_t::iterator i = l1.erase(l1.cbegin(), std::next(l1.cbegin())); CHECK(l1.size() == 2); CHECK(std::distance(l1.cbegin(), l1.cend()) == 2); CHECK(i == l1.begin()); CHECK(l1 == vec_t(a1 + 1, a1 + 3)); } { vec_t l1(a1, a1 + 3); vec_t::iterator i = l1.erase(l1.cbegin(), std::next(l1.cbegin(), 2)); CHECK(l1.size() == 1); CHECK(std::distance(l1.cbegin(), l1.cend()) == 1); CHECK(i == l1.begin()); CHECK(l1 == vec_t(a1 + 2, a1 + 3)); } { vec_t l1(a1, a1 + 3); vec_t::iterator i = l1.erase(l1.cbegin(), std::next(l1.cbegin(), 3)); CHECK(l1.empty()); CHECK(std::distance(l1.cbegin(), l1.cend()) == 0); CHECK(i == l1.begin()); } { vector<vec_t, 3> outer(2, vec_t(1)); outer.erase(outer.begin(), outer.begin()); CHECK(outer.size() == 2); CHECK(outer[0].size() == 1); CHECK(outer[1].size() == 1); } } {// insert init list {vector<int, 15> d(10, 1); vector<int, 15>::iterator i = d.insert(d.cbegin() + 2, {3, 4, 5, 6}); CHECK(d.size() == 14); CHECK(i == d.begin() + 2); CHECK(d[0] == 1); CHECK(d[1] == 1); CHECK(d[2] == 3); CHECK(d[3] == 4); CHECK(d[4] == 5); CHECK(d[5] == 6); CHECK(d[6] == 1); CHECK(d[7] == 1); CHECK(d[8] == 1); CHECK(d[9] == 1); CHECK(d[10] == 1); CHECK(d[11] == 1); CHECK(d[12] == 1); CHECK(d[13] == 1); CHECK_THROWS(d.insert(d.cbegin(), {2, 3, 4, 5}), std::bad_alloc); } } {// insert iter iter {vector<int, 120> v(100); int a[] = {1, 2, 3, 4, 5}; const std::size_t n = sizeof(a) / sizeof(a[0]); vector<int, 120>::iterator i = v.insert(v.cbegin() + 10, (a + 0), (a + n)); CHECK(v.size() == 100 + n); CHECK(i == v.begin() + 10); std::size_t j; for (j = 0; j < 10; ++j) { CHECK(v[j] == 0); } for (std::size_t k = 0; k < n; ++j, ++k) { CHECK(v[j] == a[k]); } for (; j < 105; ++j) { CHECK(v[j] == 0); } } { vector<int, 120> v(100); size_t sz = v.size(); int a[] = {1, 2, 3, 4, 5}; const unsigned n = sizeof(a) / sizeof(a[0]); vector<int, 120>::iterator i = v.insert(v.cbegin() + 10, (a + 0), (a + n)); CHECK(v.size() == sz + n); CHECK(i == v.begin() + 10); std::size_t j; for (j = 0; j < 10; ++j) { CHECK(v[j] == 0); } for (std::size_t k = 0; k < n; ++j, ++k) { CHECK(v[j] == a[k]); } for (; j < v.size(); ++j) { CHECK(v[j] == 0); } } } {// insert iter rvalue {vector<moint, 103> v(100); vector<moint, 103>::iterator i = v.insert(v.cbegin() + 10, moint(3)); CHECK(v.size() == 101); CHECK(i == v.begin() + 10); std::size_t j; for (j = 0; j < 10; ++j) { CHECK(v[j] == moint()); } CHECK(v[j] == moint(3)); for (++j; j < 101; ++j) { CHECK(v[j] == moint()); } } } {// insert iter size {vector<int, 130> v(100); vector<int, 130>::iterator i = v.insert(v.cbegin() + 10, 5, 1); CHECK(v.size() == 105); CHECK(i == v.begin() + 10); std::size_t j; for (j = 0; j < 10; ++j) { CHECK(v[j] == 0); } for (; j < 15; ++j) { CHECK(v[j] == 1); } for (++j; j < 105; ++j) { CHECK(v[j] == 0); } } { vector<int, 130> v(100); size_t sz = v.size(); vector<int, 130>::iterator i = v.insert(v.cbegin() + 10, 5, 1); CHECK(v.size() == sz + 5); CHECK(i == v.begin() + 10); std::size_t j; for (j = 0; j < 10; ++j) { CHECK(v[j] == 0); } for (; j < 15; ++j) { CHECK(v[j] == 1); } for (++j; j < v.size(); ++j) { CHECK(v[j] == 0); } } { vector<int, 130> v(100); size_t sz = v.size(); vector<int, 130>::iterator i = v.insert(v.cbegin() + 10, 5, 1); CHECK(v.size() == sz + 5); CHECK(i == v.begin() + 10); std::size_t j; for (j = 0; j < 10; ++j) { CHECK(v[j] == 0); } for (; j < 15; ++j) { CHECK(v[j] == 1); } for (++j; j < v.size(); ++j) { CHECK(v[j] == 0); } } } {// iter value: {vector<int, 130> v(100); vector<int, 130>::iterator i = v.insert(v.cbegin() + 10, 1); CHECK(v.size() == 101); CHECK(i == v.begin() + 10); std::size_t j; for (j = 0; j < 10; ++j) { CHECK(v[j] == 0); } CHECK(v[j] == 1); for (++j; j < 101; ++j) { CHECK(v[j] == 0); } } { vector<int, 130> v(100); size_t sz = v.size(); vector<int, 130>::iterator i = v.insert(v.cbegin() + 10, 1); CHECK(v.size() == sz + 1); CHECK(i == v.begin() + 10); std::size_t j; for (j = 0; j < 10; ++j) { CHECK(v[j] == 0); } CHECK(v[j] == 1); for (++j; j < v.size(); ++j) { CHECK(v[j] == 0); } } { vector<int, 130> v(100); v.pop_back(); v.pop_back(); // force no reallocation size_t sz = v.size(); vector<int, 130>::iterator i = v.insert(v.cbegin() + 10, 1); CHECK(v.size() == sz + 1); CHECK(i == v.begin() + 10); std::size_t j; for (j = 0; j < 10; ++j) { CHECK(v[j] == 0); } CHECK(v[j] == 1); for (++j; j < v.size(); ++j) { CHECK(v[j] == 0); } } } { // push back move only { vector<moint, 6> c; c.push_back(moint(0)); CHECK(c.size() == 1); for (std::size_t j = 0; j < c.size(); ++j) { CHECK(c[j] == moint(j)); } c.push_back(moint(1)); CHECK(c.size() == 2); for (std::size_t j = 0; j < c.size(); ++j) { CHECK(c[j] == moint(j)); } c.push_back(moint(2)); CHECK(c.size() == 3); for (std::size_t j = 0; j < c.size(); ++j) { CHECK(c[j] == moint(j)); } c.push_back(moint(3)); CHECK(c.size() == 4); for (std::size_t j = 0; j < c.size(); ++j) { CHECK(c[j] == moint(j)); } c.push_back(moint(4)); CHECK(c.size() == 5); for (std::size_t j = 0; j < c.size(); ++j) { CHECK(c[j] == moint(j)); } } { vector<moint, 6> c; auto i = c.try_push_back(moint(0)); CHECK(c.size() == 1); CHECK((uintptr_t)(c.begin() + 0) == (uintptr_t)i); for (std::size_t j = 0; j < c.size(); ++j) { CHECK(c[j] == moint(j)); } i = c.try_push_back(moint(1)); CHECK(c.size() == 2); CHECK((uintptr_t)(c.begin() + 1) == (uintptr_t)i); for (std::size_t j = 0; j < c.size(); ++j) { CHECK(c[j] == moint(j)); } i = c.try_push_back(moint(2)); CHECK((uintptr_t)(c.begin() + 2) == (uintptr_t)i); CHECK(c.size() == 3); for (std::size_t j = 0; j < c.size(); ++j) { CHECK(c[j] == moint(j)); } i = c.try_push_back(moint(3)); CHECK((uintptr_t)(c.begin() + 3) == (uintptr_t)i); CHECK(c.size() == 4); for (std::size_t j = 0; j < c.size(); ++j) { CHECK(c[j] == moint(j)); } i = c.try_push_back(moint(4)); CHECK((uintptr_t)(c.begin() + 4) == (uintptr_t)i); CHECK(c.size() == 5); for (std::size_t j = 0; j < c.size(); ++j) { CHECK(c[j] == moint(j)); } } { vector<moint, 6> c; auto i = &c.unchecked_push_back(moint(0)); CHECK(c.size() == 1); CHECK((uintptr_t)(c.begin() + 0) == (uintptr_t)i); for (std::size_t j = 0; j < c.size(); ++j) { CHECK(c[j] == moint(j)); } i = &c.unchecked_push_back(moint(1)); CHECK(c.size() == 2); CHECK((uintptr_t)(c.begin() + 1) == (uintptr_t)i); for (std::size_t j = 0; j < c.size(); ++j) { CHECK(c[j] == moint(j)); } i = &c.unchecked_push_back(moint(2)); CHECK((uintptr_t)(c.begin() + 2) == (uintptr_t)i); CHECK(c.size() == 3); for (std::size_t j = 0; j < c.size(); ++j) { CHECK(c[j] == moint(j)); } i = &c.unchecked_push_back(moint(3)); CHECK((uintptr_t)(c.begin() + 3) == (uintptr_t)i); CHECK(c.size() == 4); for (std::size_t j = 0; j < c.size(); ++j) { CHECK(c[j] == moint(j)); } i = &c.unchecked_push_back(moint(4)); CHECK((uintptr_t)(c.begin() + 4) == (uintptr_t)i); CHECK(c.size() == 5); for (std::size_t j = 0; j < c.size(); ++j) { CHECK(c[j] == moint(j)); } } } std::cerr << "TESTS PASSED" << std::endl; return 0; }
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
#pragma once /* * SPDX-FileCopyrightText: Copyright (c) 2023 Gonzalo Brito Gadeschi. All rights reserved. * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF Precondition, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include <array> #include <algorithm> // for rotate, equals, move_backwards, ... #include <concepts> // for lots... #include <cstddef> // for size_t #include <cstdint> // for fixed-width integer types #include <functional> // for less and equal_to #include <iterator> // for reverse_iterator and iterator traits #include <limits> // for numeric_limits #include <new> // for operator new #include <ranges> #include <stdexcept> // for length_error #include <type_traits> // for aligned_storage and all meta-functions #include <stdio.h> // for assertion diagnostics // Optimizer allowed to assume that EXPR evaluates to true #define __IV_ASSUME(__EXPR) \ static_cast<void>((__EXPR) ? void(0) : __builtin_unreachable) // Assert pretty printer #define __IV_ASSERT(...) \ static_cast<void>((__VA_ARGS__) \ ? void(0) \ : ::std::__iv_detail::__assert_failure( \ static_cast<const char*>(__FILE__), __LINE__, \ "assertion failed: " #__VA_ARGS__)) // Assert in debug, assume in release. #ifdef NDEBUG #define __IV_EXPECT(__EXPR) __IV_ASSUME(__EXPR) #else #define __IV_EXPECT(__EXPR) __IV_ASSERT(__EXPR) #endif // BUGBUG workaround for libstdc++ not providing from_range_t / from_range yet namespace std { #if defined(__GLIBCXX__) || defined(__GLIBCPP__) struct from_range_t {}; inline constexpr from_range_t from_range; #endif } // namespace std // Private utilites namespace std::__iv_detail { template <class = void> [[noreturn]] static constexpr void __assert_failure(char const* __file, int __line, char const* __msg) { if consteval { throw __msg; // TODO: std lib implementor, do better here } else { fprintf(stderr, "%s(%d): %s\n", __file, __line, __msg); abort(); } } // clang-format off // Smallest unsigned integer that can represent values in [0, N]. template <size_t __N> using __smallest_size_t = conditional_t<(__N < numeric_limits<uint8_t>::max()), uint8_t, conditional_t<(__N < numeric_limits<uint16_t>::max()), uint16_t, conditional_t<(__N < numeric_limits<uint32_t>::max()), uint32_t, conditional_t<(__N < numeric_limits<uint64_t>::max()), uint64_t, size_t>>>>; // clang-format on // Index a random-access and sized range doing bound checks in debug builds template <ranges::random_access_range __Rng, integral __Index> static constexpr decltype(auto) __index(__Rng&& __rng, __Index __i) noexcept requires(ranges::sized_range<__Rng>) { __IV_EXPECT(static_cast<ptrdiff_t>(__i) < ranges::size(__rng)); return begin(::std::forward<__Rng>(__rng))[::std::forward<__Index>(__i)]; } // http://eel.is/c++draft/container.requirements.general#container.intro.reqmts-2 template <class __Rng, class __T> concept __container_compatible_range = ranges::input_range<__Rng> && convertible_to<ranges::range_reference_t<__Rng>, __T>; template <class __Ptr, class __T> concept __move_or_copy_insertable_from = requires(__Ptr __ptr, __T&& __value) { { construct_at(__ptr, ::std::forward<__T&&>(__value)) } -> same_as<__Ptr>; }; } // namespace std::__iv_detail // Types implementing the `inplace_vector`'s storage namespace std::__iv_detail::__storage { // TODO: flesh out template <class __T, size_t __N> struct __aligned_storage2 { alignas(__T) byte __d[sizeof(__T) * __N]; constexpr __T* __data(size_t __i) noexcept { __IV_EXPECT(__i < __N); return reinterpret_cast<__T*>(__d) + __i; } constexpr const __T* __data(size_t __i) const noexcept { __IV_EXPECT(__i < __N); return reinterpret_cast<const __T*>(__d) + __i; } }; // Storage for zero elements. template <class __T> struct __zero_sized { protected: using __size_type = uint8_t; static constexpr __T* __data() noexcept { return nullptr; } static constexpr __size_type __size() noexcept { return 0; } static constexpr void __unsafe_set_size(size_t __new_size) noexcept { __IV_EXPECT(__new_size == 0 && "tried to change size of empty storage to non-zero value"); } public: constexpr __zero_sized() = default; constexpr __zero_sized(__zero_sized const&) = default; constexpr __zero_sized& operator=(__zero_sized const&) = default; constexpr __zero_sized(__zero_sized&&) = default; constexpr __zero_sized& operator=(__zero_sized&&) = default; constexpr ~__zero_sized() = default; }; // Storage for trivial types. template <class __T, size_t __N> struct __trivial { static_assert(is_trivial_v<__T>, "storage::trivial<T, C> requires Trivial<T>"); static_assert(__N != size_t{0}, "__N == 0, use __zero_sized"); protected: using __size_type = __smallest_size_t<__N>; private: // If value_type is const, then const array of non-const elements: using __data_t = conditional_t< !is_const_v<__T>, array<__T, __N>, const array<remove_const_t<__T>, __N> >; alignas(alignof(__T)) __data_t __data_{}; __size_type __size_ = 0; protected: constexpr const __T* __data() const noexcept { return __data_.data(); } constexpr __T* __data() noexcept { return __data_.data(); } constexpr __size_type __size() const noexcept { return __size_; } constexpr void __unsafe_set_size(size_t __new_size) noexcept { __IV_EXPECT(__size_type(__new_size) <= __N && "new_size out-of-bounds [0, N]"); __size_ = __size_type(__new_size); } public: constexpr __trivial() noexcept = default; constexpr __trivial(__trivial const&) noexcept = default; constexpr __trivial& operator=(__trivial const&) noexcept = default; constexpr __trivial(__trivial&&) noexcept = default; constexpr __trivial& operator=(__trivial&&) noexcept = default; constexpr ~__trivial() = default; }; /// Storage for non-trivial elements. template <class __T, size_t __N> struct __non_trivial { static_assert(!is_trivial_v<__T>, "use storage::trivial for Trivial<T> elements"); static_assert(__N != size_t{0}, "use storage::zero for __N==0"); protected: using __size_type = __smallest_size_t<__N>; private: using __data_t = conditional_t< !is_const_v<__T>, __aligned_storage2<__T, __N>, const __aligned_storage2<remove_const_t<__T>, __N>>; __data_t __data_{}; // BUGBUG: test SIMD types __size_type __size_ = 0; protected: constexpr const __T* __data() const noexcept { return __data_.__data(0); } constexpr __T* __data() noexcept { return __data_.__data(0); } constexpr __size_type __size() const noexcept { return __size_; } constexpr void __unsafe_set_size(size_t __new_size) noexcept { __IV_EXPECT(__size_type(__new_size) <= __N && "new_size out-of-bounds [0, __N)"); __size_ = __size_type(__new_size); } public: constexpr __non_trivial() noexcept = default; constexpr __non_trivial(__non_trivial const&) noexcept = default; constexpr __non_trivial& operator=(__non_trivial const&) noexcept = default; constexpr __non_trivial(__non_trivial&&) noexcept = default; constexpr __non_trivial& operator=(__non_trivial&&) noexcept = default; constexpr ~__non_trivial() = default; }; // Selects the vector storage. template <class __T, size_t __N> using _t = conditional_t< __N == 0, __zero_sized<__T>, conditional_t<is_trivial_v<__T>, __trivial<__T, __N>, __non_trivial<__T, __N>>>; } // namespace std::iv_detail::storage namespace std { /// Dynamically-resizable fixed-__N vector with inplace storage. template <class __T, size_t __N> struct inplace_vector : private __iv_detail::__storage::_t<__T, __N> { private: static_assert(is_nothrow_destructible_v<__T>, "T must be nothrow destructible"); using __base_t = __iv_detail::__storage::_t<__T, __N>; using __self = inplace_vector<__T, __N>; using __base_t::__unsafe_set_size; using __base_t::__data; using __base_t::__size; public: using value_type = __T; using pointer = __T*; using const_pointer = const __T*; using reference = value_type&; using const_reference = const value_type&; using size_type = size_t; using difference_type = ptrdiff_t; using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = ::std::reverse_iterator<iterator>; using const_reverse_iterator = ::std::reverse_iterator<const_iterator>; // [containers.sequences.inplace_vector.cons], construct/copy/destroy constexpr inplace_vector() noexcept { __unsafe_set_size(0); } // constexpr explicit inplace_vector(size_type __n); // constexpr inplace_vector(size_type __n, const __T& __value); // template <class __InputIterator> // BUGBUG: why not model input_iterator? // constexpr inplace_vector(__InputIterator __first, __InputIterator __last); // template <__iv_detail::__container_compatible_range<__T> __R> // constexpr inplace_vector(from_range_t, __R&& __rg); // from base-class, trivial if is_trivially_copy_constructible_v<T>: // constexpr inplace_vector(const inplace_vector&); // from base-class, trivial if is_trivially_move_constructible_v<T> // constexpr inplace_vector(inplace_vector&&) noexcept(__N == 0 || is_nothrow_move_constructible_v<__T>); // constexpr inplace_vector(initializer_list<__T> __il); // from base-class, trivial if is_trivially_destructible_v<__T> // constexpr ~inplace_vector(); // from base-class, trivial if is_trivially_destructible_v<__T> && is_trivially_copy_assignable_v<__T> // constexpr inplace_vector& operator=(const inplace_vector& __other); // from base-class, trivial if is_trivially_destructible_v<__T> && is_trivially_copy_assignable_v<__T> // constexpr inplace_vector& operator=(inplace_vector&& __other) noexcept(__N == 0 || is_nothrow_move_assignable_v<__T>); // template <class __InputIterator> // BUGBUG: why not model input_iterator // constexpr void assign(__InputIterator __first, __InputIterator l__ast); // template<__iv_detail::__container_compatible_range<__T> __R> // constexpr void assign_range(__R&& __rg); // constexpr void assign(size_type __n, const __T& __u); // constexpr void assign(initializer_list<__T> __il); // iterators constexpr iterator begin() noexcept { return __data(); } constexpr const_iterator begin() const noexcept { return __data(); } constexpr iterator end() noexcept { return begin() + size(); } constexpr const_iterator end() const noexcept { return begin() + size(); } constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } constexpr const_iterator cbegin() const noexcept { return __data(); } constexpr const_iterator cend() const noexcept { return cbegin() + size(); } constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(cend()); } constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator(cbegin()); } [[nodiscard]] constexpr bool empty() const noexcept { return __size() == 0; }; constexpr size_type size() const noexcept { return __size(); } static constexpr size_type max_size() noexcept { return __N; } static constexpr size_type capacity() noexcept { return __N; } // constexpr void resize(size_type __sz); // constexpr void resize(size_type __sz, const __T& __c); constexpr void reserve(size_type __n) { if (__n > __N) [[unlikely]] throw bad_alloc(); } constexpr void shrink_to_fit() {} // element access constexpr reference operator[](size_type __n) { return __iv_detail::__index(*this, __n); } constexpr const_reference operator[](size_type __n) const { return __iv_detail::__index(*this, __n); } // constexpr const_reference at(size_type __n) const; // constexpr reference at(size_type __n); constexpr reference front() { return __iv_detail::__index(*this, size_type(0)); } constexpr const_reference front() const { return __iv_detail::__index(*this, size_type(0)); } constexpr reference back() { return __iv_detail::__index(*this, size() - size_type(1)); } constexpr const_reference back() const { return __iv_detail::__index(*this, size() - size_type(1)); } // [containers.sequences.inplace_vector.data], data access constexpr __T* data() noexcept { return __data(); } constexpr const __T* data() const noexcept { return __data(); } // [containers.sequences.inplace_vector.modifiers], modifiers // template <class... __Args> // constexpr __T& emplace_back(__Args&&... __args); // constexpr __T& push_back(const __T& __x); // constexpr __T& push_back(__T&& __x); // template<__iv_detail::__container_compatible_range<__T> __R> // constexpr void append_range(__R&& __rg); // constexpr void pop_back(); // template<class... __Args> // constexpr __T* try_emplace_back(__Args&&... __args); // constexpr __T* try_push_back(const __T& __value); // constexpr __T* try_push_back(__T&& __value); // template<class... __Args> // constexpr __T& unchecked_emplace_back(__Args&&... __args); // constexpr __T& unchecked_push_back(const __T& __value); // constexpr __T& unchecked_push_back(__T&& __value); // template <class... __Args> // constexpr iterator emplace(const_iterator __position, __Args&&... __args); // constexpr iterator insert(const_iterator __position, const __T& __x); // constexpr iterator insert(const_iterator __position, __T&& __x); // constexpr iterator insert(const_iterator __position, size_type __n, const __T& __x); //template <class __InputIterator> // constexpr iterator insert(const_iterator __position, __InputIterator __first, __InputIterator __last); // template<__iv_detail::__container_compatible_range<__T> __R> // constexpr iterator insert_range(const_iterator __position, __R&& __rg); // constexpr iterator insert(const_iterator __position, initializer_list<__T> __il); // constexpr iterator erase(const_iterator __position); // constexpr iterator erase(const_iterator __first, const_iterator __last); // constexpr void swap(inplace_vector& __x) // noexcept(__N == 0 || (is_nothrow_swappable_v<__T> && is_nothrow_move_constructible_v<__T>)); //constexpr void clear() noexcept; constexpr friend bool operator==(const inplace_vector& __x, const inplace_vector& __y) { return __x.size() == __y.size() && ::std::ranges::equal(__x, __y); } // constexpr friend auto /*synth-three-way-result<T>*/ // operator<=>(const inplace_vector& __x, const inplace_vector& __y); constexpr friend void swap(inplace_vector& __x, inplace_vector& __y) noexcept(__N == 0 || (is_nothrow_swappable_v<__T> && is_nothrow_move_constructible_v<__T>)) { __x.swap(__y); } private: // Utilities constexpr void __assert_iterator_in_range(const_iterator __it) noexcept { __IV_EXPECT(begin() <= __it && "iterator not in range"); __IV_EXPECT(__it <= end() && "iterator not in range"); } constexpr void __assert_valid_iterator_pair(const_iterator __first, const_iterator __last) noexcept { __IV_EXPECT(__first <= __last && "invalid iterator pair"); } constexpr void __assert_iterator_pair_in_range(const_iterator __first, const_iterator __last) noexcept { __assert_iterator_in_range(__first); __assert_iterator_in_range(__last); __assert_valid_iterator_pair(__first, __last); } constexpr void __unsafe_destroy(__T* __first, __T* __last) noexcept(is_nothrow_destructible_v<__T>) { __assert_iterator_pair_in_range(__first, __last); if constexpr(__N > 0 && !is_trivial_v<__T>) { for (; __first != __last; ++__first) __first->~__T(); } } public: // Implementation // [containers.sequences.inplace_vector.modifiers], modifiers template<class... __Args> constexpr __T& unchecked_emplace_back(__Args&&... __args) requires(constructible_from<__T, __Args...>) { __IV_EXPECT(size() < capacity() && "inplace_vector out-of-memory"); construct_at(end(), ::std::forward<__Args>(__args)...); __unsafe_set_size(size() + size_type(1)); return back(); } template<class... __Args> constexpr __T* try_emplace_back(__Args&&... __args) { if (size() == capacity()) [[unlikely]] return nullptr; return &unchecked_emplace_back(::std::forward<__Args>(__args)...); } template <class... __Args> constexpr void emplace_back(__Args&&... __args) requires(constructible_from<__T, __Args...>) { if (!try_emplace_back(::std::forward<__Args>(__args)...)) [[unlikely]] throw bad_alloc(); } constexpr __T& push_back(const __T& __x) requires(constructible_from<__T, const __T&>) { emplace_back(__x); return back(); } constexpr __T& push_back(__T&& __x) requires(constructible_from<__T, __T&&>) { emplace_back(::std::forward<__T&&>(__x)); return back(); } constexpr __T* try_push_back(const __T& __x) requires(constructible_from<__T, const __T&>) { return try_emplace_back(__x); } constexpr __T* try_push_back(__T&& __x) requires(constructible_from<__T, __T&&>) { return try_emplace_back(::std::forward<__T&&>(__x)); } constexpr __T& unchecked_push_back(const __T& __x) requires(constructible_from<__T, const __T&>) { return unchecked_emplace_back(__x); } constexpr __T& unchecked_push_back(__T&& __x) requires(constructible_from<__T, __T&&>) { return unchecked_emplace_back(::std::forward<__T&&>(__x)); } template<__iv_detail::__container_compatible_range<__T> __R> constexpr void append_range(__R&& __rg) requires(constructible_from<__T, ranges::range_reference_t<__R>>) { if constexpr(ranges::sized_range<__R>) { if (size() + ranges::size(__rg) > capacity()) [[unlikely]] throw bad_alloc(); } for (auto&& __e : __rg) { if (size() == capacity()) [[unlikely]] throw bad_alloc(); emplace_back(::std::forward<decltype(__e)>(__e)); } } template <class... __Args> constexpr iterator emplace(const_iterator __position, __Args&&... __args) requires(constructible_from<__T, __Args...> && movable<__T>) { __assert_iterator_in_range(__position); auto __b = end(); emplace_back(std::forward<__Args>(__args)...); auto __pos = begin() + (__position - begin()); rotate(__pos, __b, end()); return __pos; } template <class __InputIterator> constexpr iterator insert(const_iterator __position, __InputIterator __first, __InputIterator __last) requires(constructible_from<__T, iter_reference_t<__InputIterator>> && movable<__T>) { __assert_iterator_in_range(__position); __assert_valid_iterator_pair(__first, __last); if constexpr(random_access_iterator<__InputIterator>) { if (size() + static_cast<size_type>(distance(__first, __last)) > capacity()) [[unlikely]] throw bad_alloc{}; } auto __b = end(); for (; __first != __last; ++__first) emplace_back(::std::move(*__first)); auto __pos = begin() + (__position - begin()); rotate(__pos, __b, end()); return __pos; } template<__iv_detail::__container_compatible_range<__T> __R> constexpr iterator insert_range(const_iterator __position, __R&& __rg) requires(constructible_from<__T, ranges::range_reference_t<__R>> && movable<__T>) { return insert(__position, ::std::begin(__rg), ::std::end(__rg)); } constexpr iterator insert(const_iterator __position, initializer_list<__T> __il) requires(constructible_from<__T, ranges::range_reference_t<initializer_list<__T>>> && movable<__T>) { return insert_range(__position, __il); } constexpr iterator insert(const_iterator __position, size_type __n, const __T& __x) requires(constructible_from<__T, const __T&> && copyable<__T>) { __assert_iterator_in_range(__position); auto __b = end(); for (size_type __i = 0; __i < __n; ++__i) emplace_back(__x); auto __pos = begin() + (__position - begin()); rotate(__pos, __b, end()); return __pos; } constexpr iterator insert(const_iterator __position, const __T& __x) requires(constructible_from<__T, const __T&> && copyable<__T>) { return insert(__position, 1, __x); } constexpr iterator insert(const_iterator __position, __T&& __x) requires(constructible_from<__T, __T&&> && movable<__T>) { return emplace(__position, ::std::move(__x)); } constexpr inplace_vector(initializer_list<__T> __il) requires(constructible_from<__T, ranges::range_reference_t<initializer_list<__T>>> && movable<__T>) { insert(begin(), __il); } constexpr inplace_vector(size_type __n, const __T& __value) requires(constructible_from<__T, const __T&> && copyable<__T>) { insert(begin(), __n, __value); } constexpr explicit inplace_vector(size_type __n) requires(constructible_from<__T, __T&&> && default_initializable<__T>) { for (size_type __i = 0; __i < __n; ++__i) emplace_back(__T{}); } template <class __InputIterator> // BUGBUG: why not ranges::input_iterator? constexpr inplace_vector(__InputIterator __first, __InputIterator __last) requires(constructible_from<__T, iter_reference_t<__InputIterator>> && movable<__T>) { insert(begin(), __first, __last); } template <__iv_detail::__container_compatible_range<__T> __R> constexpr inplace_vector(from_range_t, __R&& __rg) requires(constructible_from<__T, ranges::range_reference_t<__R>> && movable<__T>) { insert_range(begin(), std::forward<__R&&>(__rg)); } constexpr iterator erase(const_iterator __first, const_iterator __last) requires(movable<__T>) { __assert_iterator_pair_in_range(__first, __last); iterator __f = begin() + (__first - begin()); if (__first != __last) { __unsafe_destroy(::std::move(__f + (__last - __first), end(), __f), end()); __unsafe_set_size(size() - static_cast<size_type>(__last - __first)); } return __f; } constexpr iterator erase(const_iterator __position) requires(movable<__T>) { return erase(__position, __position + 1); } constexpr void clear() noexcept { __unsafe_destroy(begin(), end()); __unsafe_set_size(0); } constexpr void resize(size_type __sz, const __T& __c) requires(constructible_from<__T, const __T&> && copyable<__T>) { if (__sz == size()) return; else if (__sz > __N) [[unlikely]] throw bad_alloc{}; else if (__sz > size()) insert(end(), __sz - size(), __c); else { __unsafe_destroy(begin() + __sz, end()); __unsafe_set_size(__sz); } } constexpr void resize(size_type __sz) requires(constructible_from<__T, __T&&> && default_initializable<__T>) { if (__sz == size()) return; else if (__sz > __N) [[unlikely]] throw bad_alloc{}; else if (__sz > size()) while(size() != __sz) emplace_back(__T{}); else { __unsafe_destroy(begin() + __sz, end()); __unsafe_set_size(__sz); } } constexpr reference at(size_type __pos) { if (__pos >= size()) [[unlikely]] throw out_of_range("inplace_vector::at"); return __iv_detail::__index(*this, __pos); } constexpr const_reference at(size_type __pos) const { if (__pos >= size()) [[unlikely]] throw out_of_range("inplace_vector::at"); return __iv_detail::__index(*this, __pos); } constexpr void pop_back() { __IV_EXPECT(size() > 0 && "pop_back from empty inplace_vector!"); __unsafe_destroy(end() - 1, end()); __unsafe_set_size(size() - 1); } constexpr inplace_vector(const inplace_vector& __x) requires(copyable<__T>) { for (auto&& __e : __x) emplace_back(__e); } constexpr inplace_vector(inplace_vector&& __x) requires(movable<__T>) { for (auto&& __e : __x) emplace_back(::std::move(__e)); } constexpr inplace_vector& operator=(const inplace_vector& __x) requires(copyable<__T>) { clear(); for (auto&& __e : __x) emplace_back(__e); return *this; } constexpr inplace_vector& operator=(inplace_vector&& __x) requires(movable<__T>) { clear(); for (auto&& __e : __x) emplace_back(::std::move(__e)); return *this; } constexpr void swap(inplace_vector& __x) noexcept(__N == 0 || (is_nothrow_swappable_v<__T> && is_nothrow_move_constructible_v<__T>)) requires(movable<__T>) { auto tmp = ::std::move(__x); __x = ::std::move(*this); (*this) = ::std::move(tmp); } template <class __InputIterator> constexpr void assign(__InputIterator __first, __InputIterator __last) requires(constructible_from<__T, iter_reference_t<__InputIterator>> && movable<__T>) { clear(); insert(begin(), __first, __last); } template<__iv_detail::__container_compatible_range<__T> __R> constexpr void assign_range(__R&& __rg) requires(constructible_from<__T, ranges::range_reference_t<__R>> && movable<__T>) { assign(begin(__rg), end(__rg)); } constexpr void assign(size_type __n, const __T& __u) requires(constructible_from<__T, const __T&> && movable<__T>) { clear(); insert(begin(), __n, __u); } constexpr void assign(initializer_list<__T> __il) requires(constructible_from<__T, ranges::range_reference_t<initializer_list<__T>>> && movable<__T>) { clear(); insert_range(begin(), __il); } constexpr friend int /*synth-three-way-result<T>*/ operator<=>(const inplace_vector& __x, const inplace_vector& __y) { if (__x.size() < __y.size()) return -1; if (__x.size() > __y.size()) return +1; bool __all_equal = true; bool __all_less = true; for (size_type __i = 0; __i < __x.size(); ++__i) { if (__x[__i] < __y[__i]) __all_equal = false; if (__x[__i] == __y[__i]) __all_less = false; } if (__all_equal) return 0; if (__all_less) return -1; return 1; } }; } // namespace std // undefine all the internal macros #undef __IV_ASSUME #undef __IV_ASSERT #undef __IV_EXPECT
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