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
/* Proposed SG14 status_code (C) 2018 Niall Douglas <http://www.nedproductions.biz/> (5 commits) File Created: Feb 2018 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef SYSTEM_ERROR2_HPP #define SYSTEM_ERROR2_HPP /* Proposed SG14 status_code (C) 2018 Niall Douglas <http://www.nedproductions.biz/> (5 commits) File Created: Feb 2018 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef SYSTEM_ERROR2_ERROR_HPP #define SYSTEM_ERROR2_ERROR_HPP /* Proposed SG14 status_code (C) 2018 Niall Douglas <http://www.nedproductions.biz/> (5 commits) File Created: Jun 2018 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef SYSTEM_ERROR2_ERRORED_STATUS_CODE_HPP #define SYSTEM_ERROR2_ERRORED_STATUS_CODE_HPP /* Proposed SG14 status_code (C) 2018 - 2020 Niall Douglas <http://www.nedproductions.biz/> (5 commits) File Created: May 2020 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef SYSTEM_ERROR2_QUICK_STATUS_CODE_FROM_ENUM_HPP #define SYSTEM_ERROR2_QUICK_STATUS_CODE_FROM_ENUM_HPP /* Proposed SG14 status_code (C) 2018 - 2020 Niall Douglas <http://www.nedproductions.biz/> (5 commits) File Created: Feb 2018 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef SYSTEM_ERROR2_GENERIC_CODE_HPP #define SYSTEM_ERROR2_GENERIC_CODE_HPP /* Proposed SG14 status_code (C) 2018 Niall Douglas <http://www.nedproductions.biz/> (5 commits) File Created: Feb 2018 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef SYSTEM_ERROR2_STATUS_ERROR_HPP #define SYSTEM_ERROR2_STATUS_ERROR_HPP /* Proposed SG14 status_code (C) 2018 - 2020 Niall Douglas <http://www.nedproductions.biz/> (5 commits) File Created: Feb 2018 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef SYSTEM_ERROR2_STATUS_CODE_HPP #define SYSTEM_ERROR2_STATUS_CODE_HPP /* Proposed SG14 status_code (C) 2018 Niall Douglas <http://www.nedproductions.biz/> (5 commits) File Created: Feb 2018 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef SYSTEM_ERROR2_STATUS_CODE_DOMAIN_HPP #define SYSTEM_ERROR2_STATUS_CODE_DOMAIN_HPP /* Proposed SG14 status_code (C) 2018 - 2021 Niall Douglas <http://www.nedproductions.biz/> (5 commits) File Created: Feb 2018 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef SYSTEM_ERROR2_CONFIG_HPP #define SYSTEM_ERROR2_CONFIG_HPP // < 0.1 each #include <cassert> #include <cstddef> // for size_t #include <cstdlib> // for free // 0.22 #include <type_traits> // 0.29 #include <atomic> // 0.28 (0.15 of which is exception_ptr) #include <exception> // for std::exception // <new> includes <exception>, <exception> includes <new> #include <new> // 0.01 #include <initializer_list> #ifndef SYSTEM_ERROR2_HAVE_BIT_CAST #ifdef __has_include #if __has_include(<bit>) && (__cplusplus >= 202002L || _HAS_CXX20) #define SYSTEM_ERROR2_HAVE_BIT_CAST 1 #endif #elif __cplusplus >= 202002L #define SYSTEM_ERROR2_HAVE_BIT_CAST 1 #endif #ifndef SYSTEM_ERROR2_HAVE_BIT_CAST #define SYSTEM_ERROR2_HAVE_BIT_CAST 0 #endif #endif #if SYSTEM_ERROR2_HAVE_BIT_CAST #include <bit> #if __cpp_lib_bit_cast < 201806L #undef SYSTEM_ERROR2_HAVE_BIT_CAST #define SYSTEM_ERROR2_HAVE_BIT_CAST 0 #endif #endif #ifndef SYSTEM_ERROR2_CONSTEXPR14 #if 0L || __cplusplus >= 201400 || _MSC_VER >= 1910 /* VS2017 */ //! Defined to be `constexpr` when on C++ 14 or better compilers. Usually automatic, can be overriden. #define SYSTEM_ERROR2_CONSTEXPR14 constexpr #else #define SYSTEM_ERROR2_CONSTEXPR14 #endif #endif #ifndef SYSTEM_ERROR2_NORETURN #if 0L || (_HAS_CXX17 && _MSC_VER >= 1911 /* VS2017.3 */) #define SYSTEM_ERROR2_NORETURN [[noreturn]] #endif #endif #if !defined(SYSTEM_ERROR2_NORETURN) #ifdef __has_cpp_attribute #if __has_cpp_attribute(noreturn) #define SYSTEM_ERROR2_NORETURN [[noreturn]] #endif #endif #endif #if !defined(SYSTEM_ERROR2_NORETURN) #if defined(_MSC_VER) #define SYSTEM_ERROR2_NORETURN __declspec(noreturn) #elif defined(__GNUC__) #define SYSTEM_ERROR2_NORETURN __attribute__((__noreturn__)) #else #define SYSTEM_ERROR2_NORETURN #endif #endif // GCCs before 7 don't grok [[noreturn]] virtual functions, and warn annoyingly #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 7 #undef SYSTEM_ERROR2_NORETURN #define SYSTEM_ERROR2_NORETURN #endif #ifndef SYSTEM_ERROR2_NODISCARD #if 0L || (_HAS_CXX17 && _MSC_VER >= 1911 /* VS2017.3 */) #define SYSTEM_ERROR2_NODISCARD [[nodiscard]] #endif #endif #ifndef SYSTEM_ERROR2_NODISCARD #ifdef __has_cpp_attribute #if __has_cpp_attribute(nodiscard) #define SYSTEM_ERROR2_NODISCARD [[nodiscard]] #endif #elif defined(__clang__) #define SYSTEM_ERROR2_NODISCARD __attribute__((warn_unused_result)) #elif defined(_MSC_VER) // _Must_inspect_result_ expands into this #define SYSTEM_ERROR2_NODISCARD __declspec("SAL_name" "(" "\"_Must_inspect_result_\"" "," "\"\"" "," "\"2\"" ")") __declspec("SAL_begin") __declspec("SAL_post") __declspec("SAL_mustInspect") __declspec("SAL_post") __declspec("SAL_checkReturn") __declspec("SAL_end") #endif #endif #ifndef SYSTEM_ERROR2_NODISCARD #define SYSTEM_ERROR2_NODISCARD #endif #ifndef SYSTEM_ERROR2_TRIVIAL_ABI #if 0L || (__clang_major__ >= 7 && !defined(__APPLE__)) //! Defined to be `[[clang::trivial_abi]]` when on a new enough clang compiler. Usually automatic, can be overriden. #define SYSTEM_ERROR2_TRIVIAL_ABI [[clang::trivial_abi]] #else #define SYSTEM_ERROR2_TRIVIAL_ABI #endif #endif #ifndef SYSTEM_ERROR2_NAMESPACE //! The system_error2 namespace name. #define SYSTEM_ERROR2_NAMESPACE system_error2 //! Begins the system_error2 namespace. #define SYSTEM_ERROR2_NAMESPACE_BEGIN namespace system_error2 { //! Ends the system_error2 namespace. #define SYSTEM_ERROR2_NAMESPACE_END } #endif //! Namespace for the library SYSTEM_ERROR2_NAMESPACE_BEGIN //! Namespace for user specialised traits namespace traits { /*! Specialise to true if you guarantee that a type is move bitcopying (i.e. its move constructor equals copying bits from old to new, old is left in a default constructed state, and calling the destructor on a default constructed instance is trivial). All trivially copyable types are move bitcopying by definition, and that is the unspecialised implementation. */ template <class T> struct is_move_bitcopying { static constexpr bool value = std::is_trivially_copyable<T>::value; }; } // namespace traits namespace detail { #if __cplusplus >= 201400 || _MSC_VER >= 1910 /* VS2017 */ inline constexpr size_t cstrlen(const char *str) { const char *end = nullptr; for(end = str; *end != 0; ++end) // NOLINT ; return end - str; } #else inline constexpr size_t cstrlen_(const char *str, size_t acc) { return (str[0] == 0) ? acc : cstrlen_(str + 1, acc + 1); } inline constexpr size_t cstrlen(const char *str) { return cstrlen_(str, 0); } #endif /* A partially compliant implementation of C++20's std::bit_cast function contributed by Jesse Towner. Our bit_cast is only guaranteed to be constexpr when both the input and output arguments are either integrals or enums. However, this covers most use cases since the vast majority of status_codes have an underlying type that is either an integral or enum. We still attempt a constexpr union-based type pun for non-array input types, which some compilers accept. For array inputs, we fall back to non-constexpr memmove. */ template <class T> using is_integral_or_enum = std::integral_constant<bool, std::is_integral<T>::value || std::is_enum<T>::value>; template <class To, class From> using is_static_castable = std::integral_constant<bool, is_integral_or_enum<To>::value && is_integral_or_enum<From>::value>; template <class To, class From> using is_union_castable = std::integral_constant<bool, !is_static_castable<To, From>::value && !std::is_array<To>::value && !std::is_array<From>::value>; template <class To, class From> using is_bit_castable = std::integral_constant<bool, sizeof(To) == sizeof(From) && traits::is_move_bitcopying<To>::value && traits::is_move_bitcopying<From>::value>; template <class To, class From> union bit_cast_union { From source; To target; }; #if SYSTEM_ERROR2_HAVE_BIT_CAST using std::bit_cast; // available for all trivially copyable types // For move bit copying types template <class To, class From> requires(is_bit_castable<To, From>::value // &&is_union_castable<To, From>::value // && (!std::is_trivially_copyable_v<From> // || !std::is_trivially_copyable_v<To>) ) // constexpr To bit_cast(const From &from) noexcept { return bit_cast_union<To, From>{from}.target; } template <class To, class From> requires(is_bit_castable<To, From>::value // && !is_union_castable<To, From>::value // && (!std::is_trivially_copyable_v<From> // || !std::is_trivially_copyable_v<To>) ) // To bit_cast(const From &from) noexcept { bit_cast_union<To, From> ret; memmove(&ret.source, &from, sizeof(ret.source)); return ret.target; } #else template <class To, class From, typename std::enable_if< // is_bit_castable<To, From>::value // && is_static_castable<To, From>::value // && !is_union_castable<To, From>::value, // bool>::type = true> // constexpr To bit_cast(const From &from) noexcept { return static_cast<To>(from); } #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif template <class To, class From, typename std::enable_if< // is_bit_castable<To, From>::value // && !is_static_castable<To, From>::value // && is_union_castable<To, From>::value, // bool>::type = true> // constexpr To bit_cast(const From &from) noexcept { return bit_cast_union<To, From>{from}.target; } #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif template <class To, class From, typename std::enable_if< // is_bit_castable<To, From>::value // && !is_static_castable<To, From>::value // && !is_union_castable<To, From>::value, // bool>::type = true> // To bit_cast(const From &from) noexcept { bit_cast_union<To, From> ret; memmove(&ret.source, &from, sizeof(ret.source)); return ret.target; } #endif /* erasure_cast performs a bit_cast with additional rules to handle types of differing sizes. For integral & enum types, it may perform a narrowing or widing conversion with static_cast if necessary, before doing the final conversion with bit_cast. When casting to or from non-integral, non-enum types it may insert the value into another object with extra padding bytes to satisfy bit_cast's preconditions that both types have the same size. */ template <class To, class From> using is_erasure_castable = std::integral_constant<bool, traits::is_move_bitcopying<To>::value && traits::is_move_bitcopying<From>::value>; template <class T, bool = std::is_enum<T>::value> struct identity_or_underlying_type { using type = T; }; template <class T> struct identity_or_underlying_type<T, true> { using type = typename std::underlying_type<T>::type; }; template <class OfSize, class OfSign> using erasure_integer_type = typename std::conditional<std::is_signed<typename identity_or_underlying_type<OfSign>::type>::value, typename std::make_signed<typename identity_or_underlying_type<OfSize>::type>::type, typename std::make_unsigned<typename identity_or_underlying_type<OfSize>::type>::type>::type; template <class ErasedType, std::size_t N> struct padded_erasure_object { static_assert(traits::is_move_bitcopying<ErasedType>::value, "ErasedType must be TriviallyCopyable or MoveBitcopying"); static_assert(alignof(ErasedType) <= sizeof(ErasedType), "ErasedType must not be over-aligned"); ErasedType value; char padding[N]; constexpr explicit padded_erasure_object(const ErasedType &v) noexcept : value(v) , padding{} { } }; template <class To, class From, typename std::enable_if<is_erasure_castable<To, From>::value && (sizeof(To) == sizeof(From)), bool>::type = true> constexpr To erasure_cast(const From &from) noexcept { return bit_cast<To>(from); } template <class To, class From, typename std::enable_if<is_erasure_castable<To, From>::value && is_static_castable<To, From>::value && (sizeof(To) < sizeof(From)), bool>::type = true> constexpr To erasure_cast(const From &from) noexcept { return static_cast<To>(bit_cast<erasure_integer_type<From, To>>(from)); } template <class To, class From, typename std::enable_if<is_erasure_castable<To, From>::value && is_static_castable<To, From>::value && (sizeof(To) > sizeof(From)), bool>::type = true> constexpr To erasure_cast(const From &from) noexcept { return bit_cast<To>(static_cast<erasure_integer_type<To, From>>(from)); } template <class To, class From, typename std::enable_if<is_erasure_castable<To, From>::value && !is_static_castable<To, From>::value && (sizeof(To) < sizeof(From)), bool>::type = true> constexpr To erasure_cast(const From &from) noexcept { return bit_cast<padded_erasure_object<To, sizeof(From) - sizeof(To)>>(from).value; } template <class To, class From, typename std::enable_if<is_erasure_castable<To, From>::value && !is_static_castable<To, From>::value && (sizeof(To) > sizeof(From)), bool>::type = true> constexpr To erasure_cast(const From &from) noexcept { return bit_cast<To>(padded_erasure_object<From, sizeof(To) - sizeof(From)>{from}); } } // namespace detail SYSTEM_ERROR2_NAMESPACE_END #ifndef SYSTEM_ERROR2_FATAL #ifdef SYSTEM_ERROR2_NOT_POSIX #error If SYSTEM_ERROR2_NOT_POSIX is defined, you must define your own SYSTEM_ERROR2_FATAL implementation! #endif #include <cstdlib> // for abort #ifdef __APPLE__ #include <unistd.h> // for write #endif SYSTEM_ERROR2_NAMESPACE_BEGIN namespace detail { namespace avoid_stdio_include { #if !defined(__APPLE__) && !defined(_MSC_VER) extern "C" ptrdiff_t write(int, const void *, size_t); #elif defined(_MSC_VER) extern ptrdiff_t write(int, const void *, size_t); #if (defined(__x86_64__) || defined(_M_X64)) || (defined(__aarch64__) || defined(_M_ARM64)) || (defined(__arm__) || defined(_M_ARM)) #pragma comment(linker, "/alternatename:?write@avoid_stdio_include@detail@system_error2@@YA_JHPEBX_K@Z=write") #elif defined(__x86__) || defined(_M_IX86) || defined(__i386__) #pragma comment(linker, "/alternatename:?write@avoid_stdio_include@detail@system_error2@@YAHHPBXI@Z=_write") #else #error Unknown architecture #endif #endif } // namespace avoid_stdio_include inline void do_fatal_exit(const char *msg) { using namespace avoid_stdio_include; write(2 /*stderr*/, msg, cstrlen(msg)); write(2 /*stderr*/, "\n", 1); abort(); } } // namespace detail SYSTEM_ERROR2_NAMESPACE_END //! Prints msg to stderr, and calls `std::terminate()`. Can be overriden via predefinition. #define SYSTEM_ERROR2_FATAL(msg) ::SYSTEM_ERROR2_NAMESPACE::detail::do_fatal_exit(msg) #endif #endif #include <cstring> // for strchr SYSTEM_ERROR2_NAMESPACE_BEGIN /*! The main workhorse of the system_error2 library, can be typed (`status_code<DomainType>`), erased-immutable (`status_code<void>`) or erased-mutable (`status_code<erased<T>>`). Be careful of placing these into containers! Equality and inequality operators are *semantic* not exact. Therefore two distinct items will test true! To help prevent surprise on this, `operator<` and `std::hash<>` are NOT implemented in order to trap potential incorrectness. Define your own custom comparison functions for your container which perform exact comparisons. */ template <class DomainType> class status_code; class _generic_code_domain; //! The generic code is a status code with the generic code domain, which is that of `errc` (POSIX). using generic_code = status_code<_generic_code_domain>; namespace detail { template <class StatusCode> class indirecting_domain; template <class T> struct status_code_sizer { void *a; T b; }; template <class To, class From> struct type_erasure_is_safe { static constexpr bool value = traits::is_move_bitcopying<From>::value // && (sizeof(status_code_sizer<From>) <= sizeof(status_code_sizer<To>)); }; /* We are severely limited by needing to retain C++ 11 compatibility when doing constexpr string parsing. MSVC lets you throw exceptions within a constexpr evaluation context when exceptions are globally disabled, but won't let you divide by zero, even if never evaluated, ever in constexpr. GCC and clang won't let you throw exceptions, ever, if exceptions are globally disabled. So let's use the trick of divide by zero in constexpr on GCC and clang if and only if exceptions are globally disabled. */ #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdiv-by-zero" #endif #if defined(__cpp_exceptions) || (defined(_MSC_VER) && !defined(__clang__)) #define SYSTEM_ERROR2_FAIL_CONSTEXPR(msg) throw msg #else #define SYSTEM_ERROR2_FAIL_CONSTEXPR(msg) ((void) msg, 1 / 0) #endif constexpr inline unsigned long long parse_hex_byte(char c) { return ('0' <= c && c <= '9') ? (c - '0') : ('a' <= c && c <= 'f') ? (10 + c - 'a') : ('A' <= c && c <= 'F') ? (10 + c - 'A') : SYSTEM_ERROR2_FAIL_CONSTEXPR("Invalid character in UUID"); } constexpr inline unsigned long long parse_uuid2(const char *s) { return ((parse_hex_byte(s[0]) << 0) | (parse_hex_byte(s[1]) << 4) | (parse_hex_byte(s[2]) << 8) | (parse_hex_byte(s[3]) << 12) | (parse_hex_byte(s[4]) << 16) | (parse_hex_byte(s[5]) << 20) | (parse_hex_byte(s[6]) << 24) | (parse_hex_byte(s[7]) << 28) | (parse_hex_byte(s[9]) << 32) | (parse_hex_byte(s[10]) << 36) | (parse_hex_byte(s[11]) << 40) | (parse_hex_byte(s[12]) << 44) | (parse_hex_byte(s[14]) << 48) | (parse_hex_byte(s[15]) << 52) | (parse_hex_byte(s[16]) << 56) | (parse_hex_byte(s[17]) << 60)) // ^ // ((parse_hex_byte(s[19]) << 0) | (parse_hex_byte(s[20]) << 4) | (parse_hex_byte(s[21]) << 8) | (parse_hex_byte(s[22]) << 12) | (parse_hex_byte(s[24]) << 16) | (parse_hex_byte(s[25]) << 20) | (parse_hex_byte(s[26]) << 24) | (parse_hex_byte(s[27]) << 28) | (parse_hex_byte(s[28]) << 32) | (parse_hex_byte(s[29]) << 36) | (parse_hex_byte(s[30]) << 40) | (parse_hex_byte(s[31]) << 44) | (parse_hex_byte(s[32]) << 48) | (parse_hex_byte(s[33]) << 52) | (parse_hex_byte(s[34]) << 56) | (parse_hex_byte(s[35]) << 60)); } template <size_t N> constexpr inline unsigned long long parse_uuid_from_array(const char (&uuid)[N]) { return (N == 37) ? parse_uuid2(uuid) : ((N == 39) ? parse_uuid2(uuid + 1) : SYSTEM_ERROR2_FAIL_CONSTEXPR("UUID does not have correct length")); } template <size_t N> constexpr inline unsigned long long parse_uuid_from_pointer(const char *uuid) { return (N == 36) ? parse_uuid2(uuid) : ((N == 38) ? parse_uuid2(uuid + 1) : SYSTEM_ERROR2_FAIL_CONSTEXPR("UUID does not have correct length")); } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif static constexpr unsigned long long test_uuid_parse = parse_uuid_from_array("430f1201-94fc-06c7-430f-120194fc06c7"); //static constexpr unsigned long long test_uuid_parse2 = parse_uuid_from_array("x30f1201-94fc-06c7-430f-120194fc06c7"); } // namespace detail /*! Abstract base class for a coding domain of a status code. */ class status_code_domain { template <class DomainType> friend class status_code; template <class StatusCode> friend class indirecting_domain; public: //! Type of the unique id for this domain. using unique_id_type = unsigned long long; /*! (Potentially thread safe) Reference to a message string. Be aware that you cannot add payload to implementations of this class. You get exactly the `void *[3]` array to keep state, this is usually sufficient for a `std::shared_ptr<>` or a `std::string`. You can install a handler to be called when this object is copied, moved and destructed. This takes the form of a C function pointer. */ class string_ref { public: //! The value type using value_type = const char; //! The size type using size_type = size_t; //! The pointer type using pointer = const char *; //! The const pointer type using const_pointer = const char *; //! The iterator type using iterator = const char *; //! The const iterator type using const_iterator = const char *; protected: //! The operation occurring enum class _thunk_op { copy, move, destruct }; //! The prototype of the handler function. Copies can throw, moves and destructs cannot. using _thunk_spec = void (*)(string_ref *dest, const string_ref *src, _thunk_op op); #ifndef NDEBUG private: static void _checking_string_thunk(string_ref *dest, const string_ref *src, _thunk_op /*unused*/) noexcept { (void) dest; (void) src; assert(dest->_thunk == _checking_string_thunk); // NOLINT assert(src == nullptr || src->_thunk == _checking_string_thunk); // NOLINT // do nothing } protected: #endif //! Pointers to beginning and end of character range pointer _begin{}, _end{}; //! Three `void*` of state void *_state[3]{}; // at least the size of a shared_ptr //! Handler for when operations occur const _thunk_spec _thunk{nullptr}; constexpr explicit string_ref(_thunk_spec thunk) noexcept : _thunk(thunk) { } public: //! Construct from a C string literal SYSTEM_ERROR2_CONSTEXPR14 explicit string_ref(const char *str, size_type len = static_cast<size_type>(-1), void *state0 = nullptr, void *state1 = nullptr, void *state2 = nullptr, #ifndef NDEBUG _thunk_spec thunk = _checking_string_thunk #else _thunk_spec thunk = nullptr #endif ) noexcept : _begin(str) , _end((len == static_cast<size_type>(-1)) ? (str + detail::cstrlen(str)) : (str + len)) , // NOLINT _state{state0, state1, state2} , _thunk(thunk) { } //! Copy construct the derived implementation. string_ref(const string_ref &o) : _begin(o._begin) , _end(o._end) , _state{o._state[0], o._state[1], o._state[2]} , _thunk(o._thunk) { if(_thunk != nullptr) { _thunk(this, &o, _thunk_op::copy); } } //! Move construct the derived implementation. string_ref(string_ref &&o) noexcept : _begin(o._begin) , _end(o._end) , _state{o._state[0], o._state[1], o._state[2]} , _thunk(o._thunk) { if(_thunk != nullptr) { _thunk(this, &o, _thunk_op::move); } } //! Copy assignment string_ref &operator=(const string_ref &o) { if(this != &o) { #if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) string_ref temp(static_cast<string_ref &&>(*this)); this->~string_ref(); try { new(this) string_ref(o); // may throw } catch(...) { new(this) string_ref(static_cast<string_ref &&>(temp)); throw; } #else this->~string_ref(); new(this) string_ref(o); #endif } return *this; } //! Move assignment string_ref &operator=(string_ref &&o) noexcept { if(this != &o) { this->~string_ref(); new(this) string_ref(static_cast<string_ref &&>(o)); } return *this; } //! Destruction ~string_ref() { if(_thunk != nullptr) { _thunk(this, nullptr, _thunk_op::destruct); } _begin = _end = nullptr; } //! Returns whether the reference is empty or not SYSTEM_ERROR2_NODISCARD bool empty() const noexcept { return _begin == _end; } //! Returns the size of the string size_type size() const noexcept { return _end - _begin; } //! Returns a null terminated C string const_pointer c_str() const noexcept { return _begin; } //! Returns a null terminated C string const_pointer data() const noexcept { return _begin; } //! Returns the beginning of the string iterator begin() noexcept { return _begin; } //! Returns the beginning of the string const_iterator begin() const noexcept { return _begin; } //! Returns the beginning of the string const_iterator cbegin() const noexcept { return _begin; } //! Returns the end of the string iterator end() noexcept { return _end; } //! Returns the end of the string const_iterator end() const noexcept { return _end; } //! Returns the end of the string const_iterator cend() const noexcept { return _end; } }; /*! A reference counted, threadsafe reference to a message string. */ class atomic_refcounted_string_ref : public string_ref { struct _allocated_msg { mutable std::atomic<unsigned> count{1}; }; _allocated_msg *&_msg() noexcept { return reinterpret_cast<_allocated_msg *&>(this->_state[0]); } // NOLINT const _allocated_msg *_msg() const noexcept { return reinterpret_cast<const _allocated_msg *>(this->_state[0]); } // NOLINT static void _refcounted_string_thunk(string_ref *_dest, const string_ref *_src, _thunk_op op) noexcept { auto dest = static_cast<atomic_refcounted_string_ref *>(_dest); // NOLINT auto src = static_cast<const atomic_refcounted_string_ref *>(_src); // NOLINT (void) src; assert(dest->_thunk == _refcounted_string_thunk); // NOLINT assert(src == nullptr || src->_thunk == _refcounted_string_thunk); // NOLINT switch(op) { case _thunk_op::copy: { if(dest->_msg() != nullptr) { auto count = dest->_msg()->count.fetch_add(1, std::memory_order_relaxed); (void) count; assert(count != 0); // NOLINT } return; } case _thunk_op::move: { assert(src); // NOLINT auto msrc = const_cast<atomic_refcounted_string_ref *>(src); // NOLINT msrc->_begin = msrc->_end = nullptr; msrc->_state[0] = msrc->_state[1] = msrc->_state[2] = nullptr; return; } case _thunk_op::destruct: { if(dest->_msg() != nullptr) { auto count = dest->_msg()->count.fetch_sub(1, std::memory_order_release); if(count == 1) { std::atomic_thread_fence(std::memory_order_acquire); free((void *) dest->_begin); // NOLINT delete dest->_msg(); // NOLINT } } } } } public: //! Construct from a C string literal allocated using `malloc()`. explicit atomic_refcounted_string_ref(const char *str, size_type len = static_cast<size_type>(-1), void *state1 = nullptr, void *state2 = nullptr) noexcept : string_ref(str, len, new(std::nothrow) _allocated_msg, state1, state2, _refcounted_string_thunk) { if(_msg() == nullptr) { free((void *) this->_begin); // NOLINT _msg() = nullptr; // disabled this->_begin = "failed to get message from system"; this->_end = strchr(this->_begin, 0); return; } } }; private: unique_id_type _id; protected: /*! Use [https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h](https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h) to get a random 64 bit id. Do NOT make up your own value. Do NOT use zero. */ constexpr explicit status_code_domain(unique_id_type id) noexcept : _id(id) { } /*! UUID constructor, where input is constexpr parsed into a `unique_id_type`. */ template <size_t N> constexpr explicit status_code_domain(const char (&uuid)[N]) noexcept : _id(detail::parse_uuid_from_array<N>(uuid)) { } template <size_t N> struct _uuid_size { }; //! Alternative UUID constructor template <size_t N> constexpr explicit status_code_domain(const char *uuid, _uuid_size<N> /*unused*/) noexcept : _id(detail::parse_uuid_from_pointer<N>(uuid)) { } //! No public copying at type erased level status_code_domain(const status_code_domain &) = default; //! No public moving at type erased level status_code_domain(status_code_domain &&) = default; //! No public assignment at type erased level status_code_domain &operator=(const status_code_domain &) = default; //! No public assignment at type erased level status_code_domain &operator=(status_code_domain &&) = default; //! No public destruction at type erased level ~status_code_domain() = default; public: //! True if the unique ids match. constexpr bool operator==(const status_code_domain &o) const noexcept { return _id == o._id; } //! True if the unique ids do not match. constexpr bool operator!=(const status_code_domain &o) const noexcept { return _id != o._id; } //! True if this unique is lower than the other's unique id. constexpr bool operator<(const status_code_domain &o) const noexcept { return _id < o._id; } //! Returns the unique id used to identify identical category instances. constexpr unique_id_type id() const noexcept { return _id; } //! Name of this category. virtual string_ref name() const noexcept = 0; protected: //! True if code means failure. virtual bool _do_failure(const status_code<void> &code) const noexcept = 0; //! True if code is (potentially non-transitively) equivalent to another code in another domain. virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept = 0; //! Returns the generic code closest to this code, if any. virtual generic_code _generic_code(const status_code<void> &code) const noexcept = 0; //! Return a reference to a string textually representing a code. virtual string_ref _do_message(const status_code<void> &code) const noexcept = 0; #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || 0L //! Throw a code as a C++ exception. SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const = 0; #else // Keep a vtable slot for binary compatibility SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> & /*code*/) const { abort(); } #endif // For a `status_code<erased<T>>` only, copy from `src` to `dst`. Default implementation uses `memcpy()`. virtual void _do_erased_copy(status_code<void> &dst, const status_code<void> &src, size_t bytes) const { memcpy(&dst, &src, bytes); } // NOLINT // For a `status_code<erased<T>>` only, destroy the erased value type. Default implementation does nothing. virtual void _do_erased_destroy(status_code<void> &code, size_t bytes) const noexcept // NOLINT { (void) code; (void) bytes; } }; SYSTEM_ERROR2_NAMESPACE_END #endif #if (__cplusplus >= 201700 || _HAS_CXX17) && !defined(SYSTEM_ERROR2_DISABLE_STD_IN_PLACE) // 0.26 #include <utility> // for in_place SYSTEM_ERROR2_NAMESPACE_BEGIN using in_place_t = std::in_place_t; using std::in_place; SYSTEM_ERROR2_NAMESPACE_END #else SYSTEM_ERROR2_NAMESPACE_BEGIN //! Aliases `std::in_place_t` if on C++ 17 or later, else defined locally. struct in_place_t { explicit in_place_t() = default; }; //! Aliases `std::in_place` if on C++ 17 or later, else defined locally. constexpr in_place_t in_place{}; SYSTEM_ERROR2_NAMESPACE_END #endif SYSTEM_ERROR2_NAMESPACE_BEGIN //! Namespace for user injected mixins namespace mixins { template <class Base, class T> struct mixin : public Base { using Base::Base; }; } // namespace mixins /*! A tag for an erased value type for `status_code<D>`. Available only if `ErasedType` satisfies `traits::is_move_bitcopying<ErasedType>::value`. */ template <class ErasedType, // typename std::enable_if<traits::is_move_bitcopying<ErasedType>::value, bool>::type = true> struct erased { using value_type = ErasedType; }; /*! Specialise this template to quickly wrap a third party enumeration into a custom status code domain. Use like this: ```c++ SYSTEM_ERROR2_NAMESPACE_BEGIN template <> struct quick_status_code_from_enum<AnotherCode> : quick_status_code_from_enum_defaults<AnotherCode> { // Text name of the enum static constexpr const auto domain_name = "Another Code"; // Unique UUID for the enum. PLEASE use https://www.random.org/cgi-bin/randbyte?nbytes=16&format=h static constexpr const auto domain_uuid = "{be201f65-3962-dd0e-1266-a72e63776a42}"; // Map of each enum value to its text string, and list of semantically equivalent errc's static const std::initializer_list<mapping> &value_mappings() { static const std::initializer_list<mapping<AnotherCode>> v = { // Format is: { enum value, "string representation", { list of errc mappings ... } } {AnotherCode::success1, "Success 1", {errc::success}}, // {AnotherCode::goaway, "Go away", {errc::permission_denied}}, // {AnotherCode::success2, "Success 2", {errc::success}}, // {AnotherCode::error2, "Error 2", {}}, // }; return v; } // Completely optional definition of mixin for the status code synthesised from `Enum`. It can be omitted. template <class Base> struct mixin : Base { using Base::Base; constexpr int custom_method() const { return 42; } }; }; SYSTEM_ERROR2_NAMESPACE_END ``` Note that if the `errc` mapping contains `errc::success`, then the enumeration value is considered to be a successful value. Otherwise it is considered to be a failure value. The first value in the `errc` mapping is the one chosen as the `generic_code` conversion. Other values are used during equivalence comparisons. */ template <class Enum> struct quick_status_code_from_enum; namespace detail { template <class T> struct is_status_code { static constexpr bool value = false; }; template <class T> struct is_status_code<status_code<T>> { static constexpr bool value = true; }; template <class T> struct is_erased_status_code { static constexpr bool value = false; }; template <class T> struct is_erased_status_code<status_code<erased<T>>> { static constexpr bool value = true; }; // From http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4436.pdf namespace impl { template <typename... Ts> struct make_void { using type = void; }; template <typename... Ts> using void_t = typename make_void<Ts...>::type; template <class...> struct types { using type = types; }; template <template <class...> class T, class types, class = void> struct test_apply { using type = void; }; template <template <class...> class T, class... Ts> struct test_apply<T, types<Ts...>, void_t<T<Ts...>>> { using type = T<Ts...>; }; } // namespace impl template <template <class...> class T, class... Ts> using test_apply = impl::test_apply<T, impl::types<Ts...>>; template <class T, class... Args> using get_make_status_code_result = decltype(make_status_code(std::declval<T>(), std::declval<Args>()...)); template <class... Args> using safe_get_make_status_code_result = test_apply<get_make_status_code_result, Args...>; } // namespace detail //! Trait returning true if the type is a status code. template <class T> struct is_status_code { static constexpr bool value = detail::is_status_code<typename std::decay<T>::type>::value || detail::is_erased_status_code<typename std::decay<T>::type>::value; }; /*! A type erased lightweight status code reflecting empty, success, or failure. Differs from `status_code<erased<>>` by being always available irrespective of the domain's value type, but cannot be copied, moved, nor destructed. Thus one always passes this around by const lvalue reference. */ template <> class SYSTEM_ERROR2_TRIVIAL_ABI status_code<void> { template <class T> friend class status_code; public: //! The type of the domain. using domain_type = void; //! The type of the status code. using value_type = void; //! The type of a reference to a message string. using string_ref = typename status_code_domain::string_ref; protected: const status_code_domain *_domain{nullptr}; protected: //! No default construction at type erased level status_code() = default; //! No public copying at type erased level status_code(const status_code &) = default; //! No public moving at type erased level status_code(status_code &&) = default; //! No public assignment at type erased level status_code &operator=(const status_code &) = default; //! No public assignment at type erased level status_code &operator=(status_code &&) = default; //! No public destruction at type erased level ~status_code() = default; //! Used to construct a non-empty type erased status code constexpr explicit status_code(const status_code_domain *v) noexcept : _domain(v) { } // Used to work around triggering a ubsan failure. Do NOT remove! constexpr const status_code_domain *_domain_ptr() const noexcept { return _domain; } public: //! Return the status code domain. constexpr const status_code_domain &domain() const noexcept { return *_domain; } //! True if the status code is empty. SYSTEM_ERROR2_NODISCARD constexpr bool empty() const noexcept { return _domain == nullptr; } //! Return a reference to a string textually representing a code. string_ref message() const noexcept { // Avoid MSVC's buggy ternary operator for expensive to destruct things if(_domain != nullptr) { return _domain->_do_message(*this); } return string_ref("(empty)"); } //! True if code means success. bool success() const noexcept { return (_domain != nullptr) ? !_domain->_do_failure(*this) : false; } //! True if code means failure. bool failure() const noexcept { return (_domain != nullptr) ? _domain->_do_failure(*this) : false; } /*! True if code is strictly (and potentially non-transitively) semantically equivalent to another code in another domain. Note that usually non-semantic i.e. pure value comparison is used when the other status code has the same domain. As `equivalent()` will try mapping to generic code, this usually captures when two codes have the same semantic meaning in `equivalent()`. */ template <class T> bool strictly_equivalent(const status_code<T> &o) const noexcept { if(_domain && o._domain) { return _domain->_do_equivalent(*this, o); } // If we are both empty, we are equivalent if(!_domain && !o._domain) { return true; // NOLINT } // Otherwise not equivalent return false; } /*! True if code is equivalent, by any means, to another code in another domain (guaranteed transitive). Firstly `strictly_equivalent()` is run in both directions. If neither succeeds, each domain is asked for the equivalent generic code and those are compared. */ template <class T> inline bool equivalent(const status_code<T> &o) const noexcept; #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || 0L //! Throw a code as a C++ exception. SYSTEM_ERROR2_NORETURN void throw_exception() const { _domain->_do_throw_exception(*this); abort(); // suppress buggy GCC warning } #endif }; namespace detail { template <class DomainType> struct get_domain_value_type { using domain_type = DomainType; using value_type = typename domain_type::value_type; }; template <class ErasedType> struct get_domain_value_type<erased<ErasedType>> { using domain_type = status_code_domain; using value_type = ErasedType; }; template <class DomainType> class SYSTEM_ERROR2_TRIVIAL_ABI status_code_storage : public status_code<void> { using _base = status_code<void>; public: //! The type of the domain. using domain_type = typename get_domain_value_type<DomainType>::domain_type; //! The type of the status code. using value_type = typename get_domain_value_type<DomainType>::value_type; //! The type of a reference to a message string. using string_ref = typename domain_type::string_ref; #ifndef NDEBUG static_assert(std::is_move_constructible<value_type>::value || std::is_copy_constructible<value_type>::value, "DomainType::value_type is neither move nor copy constructible!"); static_assert(!std::is_default_constructible<value_type>::value || std::is_nothrow_default_constructible<value_type>::value, "DomainType::value_type is not nothrow default constructible!"); static_assert(!std::is_move_constructible<value_type>::value || std::is_nothrow_move_constructible<value_type>::value, "DomainType::value_type is not nothrow move constructible!"); static_assert(std::is_nothrow_destructible<value_type>::value, "DomainType::value_type is not nothrow destructible!"); #endif // Replace the type erased implementations with type aware implementations for better codegen //! Return the status code domain. constexpr const domain_type &domain() const noexcept { return *static_cast<const domain_type *>(this->_domain); } //! Reset the code to empty. SYSTEM_ERROR2_CONSTEXPR14 void clear() noexcept { this->_value.~value_type(); this->_domain = nullptr; new(&this->_value) value_type(); } #if __cplusplus >= 201400 || _MSC_VER >= 1910 /* VS2017 */ //! Return a reference to the `value_type`. constexpr value_type &value() &noexcept { return this->_value; } //! Return a reference to the `value_type`. constexpr value_type &&value() &&noexcept { return static_cast<value_type &&>(this->_value); } #endif //! Return a reference to the `value_type`. constexpr const value_type &value() const &noexcept { return this->_value; } //! Return a reference to the `value_type`. constexpr const value_type &&value() const &&noexcept { return static_cast<const value_type &&>(this->_value); } protected: status_code_storage() = default; status_code_storage(const status_code_storage &) = default; SYSTEM_ERROR2_CONSTEXPR14 status_code_storage(status_code_storage &&o) noexcept : _base(static_cast<status_code_storage &&>(o)) , _value(static_cast<status_code_storage &&>(o)._value) { o._domain = nullptr; } status_code_storage &operator=(const status_code_storage &) = default; SYSTEM_ERROR2_CONSTEXPR14 status_code_storage &operator=(status_code_storage &&o) noexcept { this->~status_code_storage(); new(this) status_code_storage(static_cast<status_code_storage &&>(o)); return *this; } ~status_code_storage() = default; value_type _value{}; struct _value_type_constructor { }; template <class... Args> constexpr status_code_storage(_value_type_constructor /*unused*/, const status_code_domain *v, Args &&... args) : _base(v) , _value(static_cast<Args &&>(args)...) { } }; } // namespace detail /*! A lightweight, typed, status code reflecting empty, success, or failure. This is the main workhorse of the system_error2 library. Its characteristics reflect the value type set by its domain type, so if that value type is move-only or trivial, so is this. An ADL discovered helper function `make_status_code(T, Args...)` is looked up by one of the constructors. If it is found, and it generates a status code compatible with this status code, implicit construction is made available. You may mix in custom member functions and member function overrides by injecting a specialisation of `mixins::mixin<Base, YourDomainType>`. Your mixin must inherit from `Base`. */ template <class DomainType> class SYSTEM_ERROR2_TRIVIAL_ABI status_code : public mixins::mixin<detail::status_code_storage<DomainType>, DomainType> { template <class T> friend class status_code; using _base = mixins::mixin<detail::status_code_storage<DomainType>, DomainType>; public: //! The type of the domain. using domain_type = DomainType; //! The type of the status code. using value_type = typename domain_type::value_type; //! The type of a reference to a message string. using string_ref = typename domain_type::string_ref; protected: using _base::_base; public: //! Default construction to empty status_code() = default; //! Copy constructor status_code(const status_code &) = default; //! Move constructor status_code(status_code &&) = default; // NOLINT //! Copy assignment status_code &operator=(const status_code &) = default; //! Move assignment status_code &operator=(status_code &&) = default; // NOLINT ~status_code() = default; //! Return a copy of the code. SYSTEM_ERROR2_CONSTEXPR14 status_code clone() const { return *this; } /***** KEEP THESE IN SYNC WITH ERRORED_STATUS_CODE *****/ //! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`. template <class T, class... Args, // class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<T, Args...>::type, // Safe ADL lookup of make_status_code(), returns void if not found typename std::enable_if<!std::is_same<typename std::decay<T>::type, status_code>::value // not copy/move of self && !std::is_same<typename std::decay<T>::type, in_place_t>::value // not in_place_t && is_status_code<MakeStatusCodeResult>::value // ADL makes a status code && std::is_constructible<status_code, MakeStatusCodeResult>::value, // ADLed status code is compatible bool>::type = true> constexpr status_code(T &&v, Args &&... args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT : status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...)) { } //! Implicit construction from any `quick_status_code_from_enum<Enum>` enumerated type. template <class Enum, // class QuickStatusCodeType = typename quick_status_code_from_enum<Enum>::code_type, // Enumeration has been activated typename std::enable_if<std::is_constructible<status_code, QuickStatusCodeType>::value, // Its status code is compatible bool>::type = true> constexpr status_code(Enum &&v) noexcept(std::is_nothrow_constructible<status_code, QuickStatusCodeType>::value) // NOLINT : status_code(QuickStatusCodeType(static_cast<Enum &&>(v))) { } //! Explicit in-place construction. Disables if `domain_type::get()` is not a valid expression. template <class... Args> constexpr explicit status_code(in_place_t /*unused */, Args &&... args) noexcept(std::is_nothrow_constructible<value_type, Args &&...>::value) : _base(typename _base::_value_type_constructor{}, &domain_type::get(), static_cast<Args &&>(args)...) { } //! Explicit in-place construction from initialiser list. Disables if `domain_type::get()` is not a valid expression. template <class T, class... Args> constexpr explicit status_code(in_place_t /*unused */, std::initializer_list<T> il, Args &&... args) noexcept(std::is_nothrow_constructible<value_type, std::initializer_list<T>, Args &&...>::value) : _base(typename _base::_value_type_constructor{}, &domain_type::get(), il, static_cast<Args &&>(args)...) { } //! Explicit copy construction from a `value_type`. Disables if `domain_type::get()` is not a valid expression. constexpr explicit status_code(const value_type &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value) : _base(typename _base::_value_type_constructor{}, &domain_type::get(), v) { } //! Explicit move construction from a `value_type`. Disables if `domain_type::get()` is not a valid expression. constexpr explicit status_code(value_type &&v) noexcept(std::is_nothrow_move_constructible<value_type>::value) : _base(typename _base::_value_type_constructor{}, &domain_type::get(), static_cast<value_type &&>(v)) { } /*! Explicit construction from an erased status code. Available only if `value_type` is trivially copyable or move bitcopying, and `sizeof(status_code) <= sizeof(status_code<erased<>>)`. Does not check if domains are equal. */ template <class ErasedType, // typename std::enable_if<detail::type_erasure_is_safe<ErasedType, value_type>::value, bool>::type = true> constexpr explicit status_code(const status_code<erased<ErasedType>> &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value) : status_code(detail::erasure_cast<value_type>(v.value())) { #if __cplusplus >= 201400 assert(v.domain() == this->domain()); #endif } //! Return a reference to a string textually representing a code. string_ref message() const noexcept { // Avoid MSVC's buggy ternary operator for expensive to destruct things if(this->_domain != nullptr) { return string_ref(this->domain()._do_message(*this)); } return string_ref("(empty)"); } }; namespace traits { template <class DomainType> struct is_move_bitcopying<status_code<DomainType>> { static constexpr bool value = is_move_bitcopying<typename DomainType::value_type>::value; }; } // namespace traits /*! Type erased, move-only status_code, unlike `status_code<void>` which cannot be moved nor destroyed. Available only if `erased<>` is available, which is when the domain's type is trivially copyable or is move relocatable, and if the size of the domain's typed error code is less than or equal to this erased error code. Copy construction is disabled, but if you want a copy call `.clone()`. An ADL discovered helper function `make_status_code(T, Args...)` is looked up by one of the constructors. If it is found, and it generates a status code compatible with this status code, implicit construction is made available. */ template <class ErasedType> class SYSTEM_ERROR2_TRIVIAL_ABI status_code<erased<ErasedType>> : public mixins::mixin<detail::status_code_storage<erased<ErasedType>>, erased<ErasedType>> { template <class T> friend class status_code; using _base = mixins::mixin<detail::status_code_storage<erased<ErasedType>>, erased<ErasedType>>; public: //! The type of the domain (void, as it is erased). using domain_type = void; //! The type of the erased status code. using value_type = ErasedType; //! The type of a reference to a message string. using string_ref = typename _base::string_ref; public: //! Default construction to empty status_code() = default; //! Copy constructor status_code(const status_code &) = delete; //! Move constructor status_code(status_code &&) = default; // NOLINT //! Copy assignment status_code &operator=(const status_code &) = delete; //! Move assignment status_code &operator=(status_code &&) = default; // NOLINT ~status_code() { if(nullptr != this->_domain) { this->_domain->_do_erased_destroy(*this, sizeof(*this)); } } //! Return a copy of the erased code by asking the domain to perform the erased copy. status_code clone() const { if(nullptr == this->_domain) { return {}; } status_code x; this->_domain->_do_erased_copy(x, *this, sizeof(*this)); return x; } /***** KEEP THESE IN SYNC WITH ERRORED_STATUS_CODE *****/ //! Implicit copy construction from any other status code if its value type is trivially copyable and it would fit into our storage template <class DomainType, // typename std::enable_if<std::is_trivially_copyable<typename DomainType::value_type>::value // && detail::type_erasure_is_safe<value_type, typename DomainType::value_type>::value, bool>::type = true> constexpr status_code(const status_code<DomainType> &v) noexcept // NOLINT : _base(typename _base::_value_type_constructor{}, v._domain_ptr(), detail::erasure_cast<value_type>(v.value())) { } //! Implicit move construction from any other status code if its value type is trivially copyable or move bitcopying and it would fit into our storage template <class DomainType, // typename std::enable_if<detail::type_erasure_is_safe<value_type, typename DomainType::value_type>::value, bool>::type = true> SYSTEM_ERROR2_CONSTEXPR14 status_code(status_code<DomainType> &&v) noexcept // NOLINT : _base(typename _base::_value_type_constructor{}, v._domain_ptr(), detail::erasure_cast<value_type>(v.value())) { v._domain = nullptr; } //! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`. template <class T, class... Args, // class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<T, Args...>::type, // Safe ADL lookup of make_status_code(), returns void if not found typename std::enable_if<!std::is_same<typename std::decay<T>::type, status_code>::value // not copy/move of self && !std::is_same<typename std::decay<T>::type, value_type>::value // not copy/move of value type && is_status_code<MakeStatusCodeResult>::value // ADL makes a status code && std::is_constructible<status_code, MakeStatusCodeResult>::value, // ADLed status code is compatible bool>::type = true> constexpr status_code(T &&v, Args &&... args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT : status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...)) { } //! Implicit construction from any `quick_status_code_from_enum<Enum>` enumerated type. template <class Enum, // class QuickStatusCodeType = typename quick_status_code_from_enum<Enum>::code_type, // Enumeration has been activated typename std::enable_if<std::is_constructible<status_code, QuickStatusCodeType>::value, // Its status code is compatible bool>::type = true> constexpr status_code(Enum &&v) noexcept(std::is_nothrow_constructible<status_code, QuickStatusCodeType>::value) // NOLINT : status_code(QuickStatusCodeType(static_cast<Enum &&>(v))) { } /**** By rights ought to be removed in any formal standard ****/ //! Reset the code to empty. SYSTEM_ERROR2_CONSTEXPR14 void clear() noexcept { *this = status_code(); } //! Return the erased `value_type` by value. constexpr value_type value() const noexcept { return this->_value; } }; namespace traits { template <class ErasedType> struct is_move_bitcopying<status_code<erased<ErasedType>>> { static constexpr bool value = true; }; } // namespace traits SYSTEM_ERROR2_NAMESPACE_END #endif #include <exception> // for std::exception SYSTEM_ERROR2_NAMESPACE_BEGIN /*! Exception type representing a thrown status_code */ template <class DomainType> class status_error; /*! The erased type edition of status_error. */ template <> class status_error<void> : public std::exception { protected: //! Constructs an instance. Not publicly available. status_error() = default; //! Copy constructor. Not publicly available status_error(const status_error &) = default; //! Move constructor. Not publicly available status_error(status_error &&) = default; //! Copy assignment. Not publicly available status_error &operator=(const status_error &) = default; //! Move assignment. Not publicly available status_error &operator=(status_error &&) = default; //! Destructor. Not publicly available. ~status_error() override = default; public: //! The type of the status domain using domain_type = void; //! The type of the status code using status_code_type = status_code<void>; }; /*! Exception type representing a thrown status_code */ template <class DomainType> class status_error : public status_error<void> { status_code<DomainType> _code; typename DomainType::string_ref _msgref; public: //! The type of the status domain using domain_type = DomainType; //! The type of the status code using status_code_type = status_code<DomainType>; //! Constructs an instance explicit status_error(status_code<DomainType> code) : _code(static_cast<status_code<DomainType> &&>(code)) , _msgref(_code.message()) { } //! Return an explanatory string virtual const char *what() const noexcept override { return _msgref.c_str(); } // NOLINT //! Returns a reference to the code const status_code_type &code() const & { return _code; } //! Returns a reference to the code status_code_type &code() & { return _code; } //! Returns a reference to the code const status_code_type &&code() const && { return _code; } //! Returns a reference to the code status_code_type &&code() && { return _code; } }; SYSTEM_ERROR2_NAMESPACE_END #endif #include <cerrno> // for error constants SYSTEM_ERROR2_NAMESPACE_BEGIN //! The generic error coding (POSIX) enum class errc : int { success = 0, unknown = -1, address_family_not_supported = EAFNOSUPPORT, address_in_use = EADDRINUSE, address_not_available = EADDRNOTAVAIL, already_connected = EISCONN, argument_list_too_long = E2BIG, argument_out_of_domain = EDOM, bad_address = EFAULT, bad_file_descriptor = EBADF, bad_message = EBADMSG, broken_pipe = EPIPE, connection_aborted = ECONNABORTED, connection_already_in_progress = EALREADY, connection_refused = ECONNREFUSED, connection_reset = ECONNRESET, cross_device_link = EXDEV, destination_address_required = EDESTADDRREQ, device_or_resource_busy = EBUSY, directory_not_empty = ENOTEMPTY, executable_format_error = ENOEXEC, file_exists = EEXIST, file_too_large = EFBIG, filename_too_long = ENAMETOOLONG, function_not_supported = ENOSYS, host_unreachable = EHOSTUNREACH, identifier_removed = EIDRM, illegal_byte_sequence = EILSEQ, inappropriate_io_control_operation = ENOTTY, interrupted = EINTR, invalid_argument = EINVAL, invalid_seek = ESPIPE, io_error = EIO, is_a_directory = EISDIR, message_size = EMSGSIZE, network_down = ENETDOWN, network_reset = ENETRESET, network_unreachable = ENETUNREACH, no_buffer_space = ENOBUFS, no_child_process = ECHILD, no_link = ENOLINK, no_lock_available = ENOLCK, no_message = ENOMSG, no_protocol_option = ENOPROTOOPT, no_space_on_device = ENOSPC, no_stream_resources = ENOSR, no_such_device_or_address = ENXIO, no_such_device = ENODEV, no_such_file_or_directory = ENOENT, no_such_process = ESRCH, not_a_directory = ENOTDIR, not_a_socket = ENOTSOCK, not_a_stream = ENOSTR, not_connected = ENOTCONN, not_enough_memory = ENOMEM, not_supported = ENOTSUP, operation_canceled = ECANCELED, operation_in_progress = EINPROGRESS, operation_not_permitted = EPERM, operation_not_supported = EOPNOTSUPP, operation_would_block = EWOULDBLOCK, owner_dead = EOWNERDEAD, permission_denied = EACCES, protocol_error = EPROTO, protocol_not_supported = EPROTONOSUPPORT, read_only_file_system = EROFS, resource_deadlock_would_occur = EDEADLK, resource_unavailable_try_again = EAGAIN, result_out_of_range = ERANGE, state_not_recoverable = ENOTRECOVERABLE, stream_timeout = ETIME, text_file_busy = ETXTBSY, timed_out = ETIMEDOUT, too_many_files_open_in_system = ENFILE, too_many_files_open = EMFILE, too_many_links = EMLINK, too_many_symbolic_link_levels = ELOOP, value_too_large = EOVERFLOW, wrong_protocol_type = EPROTOTYPE }; namespace detail { SYSTEM_ERROR2_CONSTEXPR14 inline const char *generic_code_message(errc code) noexcept { switch(code) { case errc::success: return "Success"; case errc::address_family_not_supported: return "Address family not supported by protocol"; case errc::address_in_use: return "Address already in use"; case errc::address_not_available: return "Cannot assign requested address"; case errc::already_connected: return "Transport endpoint is already connected"; case errc::argument_list_too_long: return "Argument list too long"; case errc::argument_out_of_domain: return "Numerical argument out of domain"; case errc::bad_address: return "Bad address"; case errc::bad_file_descriptor: return "Bad file descriptor"; case errc::bad_message: return "Bad message"; case errc::broken_pipe: return "Broken pipe"; case errc::connection_aborted: return "Software caused connection abort"; case errc::connection_already_in_progress: return "Operation already in progress"; case errc::connection_refused: return "Connection refused"; case errc::connection_reset: return "Connection reset by peer"; case errc::cross_device_link: return "Invalid cross-device link"; case errc::destination_address_required: return "Destination address required"; case errc::device_or_resource_busy: return "Device or resource busy"; case errc::directory_not_empty: return "Directory not empty"; case errc::executable_format_error: return "Exec format error"; case errc::file_exists: return "File exists"; case errc::file_too_large: return "File too large"; case errc::filename_too_long: return "File name too long"; case errc::function_not_supported: return "Function not implemented"; case errc::host_unreachable: return "No route to host"; case errc::identifier_removed: return "Identifier removed"; case errc::illegal_byte_sequence: return "Invalid or incomplete multibyte or wide character"; case errc::inappropriate_io_control_operation: return "Inappropriate ioctl for device"; case errc::interrupted: return "Interrupted system call"; case errc::invalid_argument: return "Invalid argument"; case errc::invalid_seek: return "Illegal seek"; case errc::io_error: return "Input/output error"; case errc::is_a_directory: return "Is a directory"; case errc::message_size: return "Message too long"; case errc::network_down: return "Network is down"; case errc::network_reset: return "Network dropped connection on reset"; case errc::network_unreachable: return "Network is unreachable"; case errc::no_buffer_space: return "No buffer space available"; case errc::no_child_process: return "No child processes"; case errc::no_link: return "Link has been severed"; case errc::no_lock_available: return "No locks available"; case errc::no_message: return "No message of desired type"; case errc::no_protocol_option: return "Protocol not available"; case errc::no_space_on_device: return "No space left on device"; case errc::no_stream_resources: return "Out of streams resources"; case errc::no_such_device_or_address: return "No such device or address"; case errc::no_such_device: return "No such device"; case errc::no_such_file_or_directory: return "No such file or directory"; case errc::no_such_process: return "No such process"; case errc::not_a_directory: return "Not a directory"; case errc::not_a_socket: return "Socket operation on non-socket"; case errc::not_a_stream: return "Device not a stream"; case errc::not_connected: return "Transport endpoint is not connected"; case errc::not_enough_memory: return "Cannot allocate memory"; #if ENOTSUP != EOPNOTSUPP case errc::not_supported: return "Operation not supported"; #endif case errc::operation_canceled: return "Operation canceled"; case errc::operation_in_progress: return "Operation now in progress"; case errc::operation_not_permitted: return "Operation not permitted"; case errc::operation_not_supported: return "Operation not supported"; #if EAGAIN != EWOULDBLOCK case errc::operation_would_block: return "Resource temporarily unavailable"; #endif case errc::owner_dead: return "Owner died"; case errc::permission_denied: return "Permission denied"; case errc::protocol_error: return "Protocol error"; case errc::protocol_not_supported: return "Protocol not supported"; case errc::read_only_file_system: return "Read-only file system"; case errc::resource_deadlock_would_occur: return "Resource deadlock avoided"; case errc::resource_unavailable_try_again: return "Resource temporarily unavailable"; case errc::result_out_of_range: return "Numerical result out of range"; case errc::state_not_recoverable: return "State not recoverable"; case errc::stream_timeout: return "Timer expired"; case errc::text_file_busy: return "Text file busy"; case errc::timed_out: return "Connection timed out"; case errc::too_many_files_open_in_system: return "Too many open files in system"; case errc::too_many_files_open: return "Too many open files"; case errc::too_many_links: return "Too many links"; case errc::too_many_symbolic_link_levels: return "Too many levels of symbolic links"; case errc::value_too_large: return "Value too large for defined data type"; case errc::wrong_protocol_type: return "Protocol wrong type for socket"; default: return "unknown"; } } } // namespace detail /*! The implementation of the domain for generic status codes, those mapped by `errc` (POSIX). */ class _generic_code_domain : public status_code_domain { template <class> friend class status_code; template <class StatusCode> friend class detail::indirecting_domain; using _base = status_code_domain; public: //! The value type of the generic code, which is an `errc` as per POSIX. using value_type = errc; using string_ref = _base::string_ref; public: //! Default constructor constexpr explicit _generic_code_domain(typename _base::unique_id_type id = 0x746d6354f4f733e9) noexcept : _base(id) { } _generic_code_domain(const _generic_code_domain &) = default; _generic_code_domain(_generic_code_domain &&) = default; _generic_code_domain &operator=(const _generic_code_domain &) = default; _generic_code_domain &operator=(_generic_code_domain &&) = default; ~_generic_code_domain() = default; //! Constexpr singleton getter. Returns the constexpr generic_code_domain variable. static inline constexpr const _generic_code_domain &get(); virtual _base::string_ref name() const noexcept override { return string_ref("generic domain"); } // NOLINT protected: virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT { assert(code.domain() == *this); // NOLINT return static_cast<const generic_code &>(code).value() != errc::success; // NOLINT } virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override // NOLINT { assert(code1.domain() == *this); // NOLINT const auto &c1 = static_cast<const generic_code &>(code1); // NOLINT if(code2.domain() == *this) { const auto &c2 = static_cast<const generic_code &>(code2); // NOLINT return c1.value() == c2.value(); } return false; } virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT { assert(code.domain() == *this); // NOLINT return static_cast<const generic_code &>(code); // NOLINT } virtual _base::string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT { assert(code.domain() == *this); // NOLINT const auto &c = static_cast<const generic_code &>(code); // NOLINT return string_ref(detail::generic_code_message(c.value())); } #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || 0L SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override // NOLINT { assert(code.domain() == *this); // NOLINT const auto &c = static_cast<const generic_code &>(code); // NOLINT throw status_error<_generic_code_domain>(c); } #endif }; //! A specialisation of `status_error` for the generic code domain. using generic_error = status_error<_generic_code_domain>; //! A constexpr source variable for the generic code domain, which is that of `errc` (POSIX). Returned by `_generic_code_domain::get()`. constexpr _generic_code_domain generic_code_domain; inline constexpr const _generic_code_domain &_generic_code_domain::get() { return generic_code_domain; } // Enable implicit construction of generic_code from errc SYSTEM_ERROR2_CONSTEXPR14 inline generic_code make_status_code(errc c) noexcept { return generic_code(in_place, c); } /*************************************************************************************************************/ template <class T> inline bool status_code<void>::equivalent(const status_code<T> &o) const noexcept { if(_domain && o._domain) { if(_domain->_do_equivalent(*this, o)) { return true; } if(o._domain->_do_equivalent(o, *this)) { return true; } generic_code c1 = o._domain->_generic_code(o); if(c1.value() != errc::unknown && _domain->_do_equivalent(*this, c1)) { return true; } generic_code c2 = _domain->_generic_code(*this); if(c2.value() != errc::unknown && o._domain->_do_equivalent(o, c2)) { return true; } } // If we are both empty, we are equivalent, otherwise not equivalent return (!_domain && !o._domain); } //! True if the status code's are semantically equal via `equivalent()`. template <class DomainType1, class DomainType2> inline bool operator==(const status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept { return a.equivalent(b); } //! True if the status code's are not semantically equal via `equivalent()`. template <class DomainType1, class DomainType2> inline bool operator!=(const status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept { return !a.equivalent(b); } //! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`. template <class DomainType1, class T, // class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code inline bool operator==(const status_code<DomainType1> &a, const T &b) { return a.equivalent(make_status_code(b)); } //! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`. template <class T, class DomainType1, // class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code inline bool operator==(const T &a, const status_code<DomainType1> &b) { return b.equivalent(make_status_code(a)); } //! True if the status code's are not semantically equal via `equivalent()` to `make_status_code(T)`. template <class DomainType1, class T, // class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code inline bool operator!=(const status_code<DomainType1> &a, const T &b) { return !a.equivalent(make_status_code(b)); } //! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`. template <class T, class DomainType1, // class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code inline bool operator!=(const T &a, const status_code<DomainType1> &b) { return !b.equivalent(make_status_code(a)); } //! True if the status code's are semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(b)`. template <class DomainType1, class T, // class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated > inline bool operator==(const status_code<DomainType1> &a, const T &b) { return a.equivalent(QuickStatusCodeType(b)); } //! True if the status code's are semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(a)`. template <class T, class DomainType1, // class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated > inline bool operator==(const T &a, const status_code<DomainType1> &b) { return b.equivalent(QuickStatusCodeType(a)); } //! True if the status code's are not semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(b)`. template <class DomainType1, class T, // class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated > inline bool operator!=(const status_code<DomainType1> &a, const T &b) { return !a.equivalent(QuickStatusCodeType(b)); } //! True if the status code's are not semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(a)`. template <class T, class DomainType1, // class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated > inline bool operator!=(const T &a, const status_code<DomainType1> &b) { return !b.equivalent(QuickStatusCodeType(a)); } SYSTEM_ERROR2_NAMESPACE_END #endif SYSTEM_ERROR2_NAMESPACE_BEGIN template <class Enum> class _quick_status_code_from_enum_domain; //! A status code wrapping `Enum` generated from `quick_status_code_from_enum`. template <class Enum> using quick_status_code_from_enum_code = status_code<_quick_status_code_from_enum_domain<Enum>>; //! Defaults for an implementation of `quick_status_code_from_enum<Enum>` template <class Enum> struct quick_status_code_from_enum_defaults { //! The type of the resulting code using code_type = quick_status_code_from_enum_code<Enum>; //! Used within `quick_status_code_from_enum` to define a mapping of enumeration value with its status code struct mapping { //! The enumeration type using enumeration_type = Enum; //! The value being mapped const Enum value; //! A string representation for this enumeration value const char *message; //! A list of `errc` equivalents for this enumeration value const std::initializer_list<errc> code_mappings; }; //! Used within `quick_status_code_from_enum` to define mixins for the status code wrapping `Enum` template <class Base> struct mixin : Base { using Base::Base; }; }; /*! The implementation of the domain for status codes wrapping `Enum` generated from `quick_status_code_from_enum`. */ template <class Enum> class _quick_status_code_from_enum_domain : public status_code_domain { template <class DomainType> friend class status_code; template <class StatusCode> friend class detail::indirecting_domain; using _base = status_code_domain; using _src = quick_status_code_from_enum<Enum>; public: //! The value type of the quick status code from enum using value_type = Enum; using _base::string_ref; constexpr _quick_status_code_from_enum_domain() : status_code_domain(_src::domain_uuid, _uuid_size<detail::cstrlen(_src::domain_uuid)>()) { } _quick_status_code_from_enum_domain(const _quick_status_code_from_enum_domain &) = default; _quick_status_code_from_enum_domain(_quick_status_code_from_enum_domain &&) = default; _quick_status_code_from_enum_domain &operator=(const _quick_status_code_from_enum_domain &) = default; _quick_status_code_from_enum_domain &operator=(_quick_status_code_from_enum_domain &&) = default; ~_quick_status_code_from_enum_domain() = default; #if __cplusplus < 201402L && !defined(_MSC_VER) static inline const _quick_status_code_from_enum_domain &get() { static _quick_status_code_from_enum_domain v; return v; } #else static inline constexpr const _quick_status_code_from_enum_domain &get(); #endif virtual string_ref name() const noexcept override { return string_ref(_src::domain_name); } protected: // Not sure if a hash table is worth it here, most enumerations won't be long enough to be worth it // Also, until C++ 20's consteval, the hash table would get emitted into the binary, bloating it static SYSTEM_ERROR2_CONSTEXPR14 const typename _src::mapping *_find_mapping(value_type v) noexcept { for(const auto &i : _src::value_mappings()) { if(i.value == v) { return &i; } } return nullptr; } virtual bool _do_failure(const status_code<void> &code) const noexcept override { assert(code.domain() == *this); // NOLINT // If `errc::success` is in the generic code mapping, it is not a failure const auto *mapping = _find_mapping(static_cast<const quick_status_code_from_enum_code<value_type> &>(code).value()); assert(mapping != nullptr); if(mapping != nullptr) { for(errc ec : mapping->code_mappings) { if(ec == errc::success) { return false; } } } return true; } virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override { assert(code1.domain() == *this); // NOLINT const auto &c1 = static_cast<const quick_status_code_from_enum_code<value_type> &>(code1); // NOLINT if(code2.domain() == *this) { const auto &c2 = static_cast<const quick_status_code_from_enum_code<value_type> &>(code2); // NOLINT return c1.value() == c2.value(); } if(code2.domain() == generic_code_domain) { const auto &c2 = static_cast<const generic_code &>(code2); // NOLINT const auto *mapping = _find_mapping(c1.value()); assert(mapping != nullptr); if(mapping != nullptr) { for(errc ec : mapping->code_mappings) { if(ec == c2.value()) { return true; } } } } return false; } virtual generic_code _generic_code(const status_code<void> &code) const noexcept override { assert(code.domain() == *this); // NOLINT const auto *mapping = _find_mapping(static_cast<const quick_status_code_from_enum_code<value_type> &>(code).value()); assert(mapping != nullptr); if(mapping != nullptr) { if(mapping->code_mappings.size() > 0) { return *mapping->code_mappings.begin(); } } return errc::unknown; } virtual string_ref _do_message(const status_code<void> &code) const noexcept override { assert(code.domain() == *this); // NOLINT const auto *mapping = _find_mapping(static_cast<const quick_status_code_from_enum_code<value_type> &>(code).value()); assert(mapping != nullptr); if(mapping != nullptr) { return string_ref(mapping->message); } return string_ref("unknown"); } #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || 0L SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override { assert(code.domain() == *this); // NOLINT const auto &c = static_cast<const quick_status_code_from_enum_code<value_type> &>(code); // NOLINT throw status_error<_quick_status_code_from_enum_domain>(c); } #endif }; #if __cplusplus >= 201402L || defined(_MSC_VER) template <class Enum> constexpr _quick_status_code_from_enum_domain<Enum> quick_status_code_from_enum_domain = {}; template <class Enum> inline constexpr const _quick_status_code_from_enum_domain<Enum> &_quick_status_code_from_enum_domain<Enum>::get() { return quick_status_code_from_enum_domain<Enum>; } #endif namespace mixins { template <class Base, class Enum> struct mixin<Base, _quick_status_code_from_enum_domain<Enum>> : public quick_status_code_from_enum<Enum>::template mixin<Base> { using quick_status_code_from_enum<Enum>::template mixin<Base>::mixin; }; } // namespace mixins SYSTEM_ERROR2_NAMESPACE_END #endif /* Pointer to a SG14 status_code (C) 2018 Niall Douglas <http://www.nedproductions.biz/> (5 commits) File Created: Sep 2018 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef SYSTEM_ERROR2_STATUS_CODE_PTR_HPP #define SYSTEM_ERROR2_STATUS_CODE_PTR_HPP SYSTEM_ERROR2_NAMESPACE_BEGIN namespace detail { template <class StatusCode> class indirecting_domain : public status_code_domain { template <class DomainType> friend class status_code; using _base = status_code_domain; public: using value_type = StatusCode *; using _base::string_ref; constexpr indirecting_domain() noexcept : _base(0xc44f7bdeb2cc50e9 ^ typename StatusCode::domain_type().id() /* unique-ish based on domain's unique id */) { } indirecting_domain(const indirecting_domain &) = default; indirecting_domain(indirecting_domain &&) = default; // NOLINT indirecting_domain &operator=(const indirecting_domain &) = default; indirecting_domain &operator=(indirecting_domain &&) = default; // NOLINT ~indirecting_domain() = default; #if __cplusplus < 201402L && !defined(_MSC_VER) static inline const indirecting_domain &get() { static indirecting_domain v; return v; } #else static inline constexpr const indirecting_domain &get(); #endif virtual string_ref name() const noexcept override { return typename StatusCode::domain_type().name(); } // NOLINT protected: using _mycode = status_code<indirecting_domain>; virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT { assert(code.domain() == *this); const auto &c = static_cast<const _mycode &>(code); // NOLINT return typename StatusCode::domain_type()._do_failure(*c.value()); } virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override // NOLINT { assert(code1.domain() == *this); const auto &c1 = static_cast<const _mycode &>(code1); // NOLINT return typename StatusCode::domain_type()._do_equivalent(*c1.value(), code2); } virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT { assert(code.domain() == *this); const auto &c = static_cast<const _mycode &>(code); // NOLINT return typename StatusCode::domain_type()._generic_code(*c.value()); } virtual string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT { assert(code.domain() == *this); const auto &c = static_cast<const _mycode &>(code); // NOLINT return typename StatusCode::domain_type()._do_message(*c.value()); } #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || 0L SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override // NOLINT { assert(code.domain() == *this); const auto &c = static_cast<const _mycode &>(code); // NOLINT typename StatusCode::domain_type()._do_throw_exception(*c.value()); } #endif virtual void _do_erased_copy(status_code<void> &dst, const status_code<void> &src, size_t /*unused*/) const override // NOLINT { // Note that dst will not have its domain set assert(src.domain() == *this); auto &d = static_cast<_mycode &>(dst); // NOLINT const auto &_s = static_cast<const _mycode &>(src); // NOLINT const StatusCode &s = *_s.value(); new(&d) _mycode(in_place, new StatusCode(s)); } virtual void _do_erased_destroy(status_code<void> &code, size_t /*unused*/) const noexcept override // NOLINT { assert(code.domain() == *this); auto &c = static_cast<_mycode &>(code); // NOLINT delete c.value(); // NOLINT } }; #if __cplusplus >= 201402L || defined(_MSC_VER) template <class StatusCode> constexpr indirecting_domain<StatusCode> _indirecting_domain{}; template <class StatusCode> inline constexpr const indirecting_domain<StatusCode> &indirecting_domain<StatusCode>::get() { return _indirecting_domain<StatusCode>; } #endif } // namespace detail /*! Make an erased status code which indirects to a dynamically allocated status code. This is useful for shoehorning a rich status code with large value type into a small erased status code like `system_code`, with which the status code generated by this function is compatible. Note that this function can throw due to `bad_alloc`. */ template <class T, typename std::enable_if<is_status_code<T>::value, bool>::type = true> // inline status_code<erased<typename std::add_pointer<typename std::decay<T>::type>::type>> make_status_code_ptr(T &&v) { using status_code_type = typename std::decay<T>::type; return status_code<detail::indirecting_domain<status_code_type>>(in_place, new status_code_type(static_cast<T &&>(v))); } /*! If a status code refers to a `status_code_ptr` which indirects to a status code of type `StatusCode`, return a pointer to that `StatusCode`. Otherwise return null. */ template <class StatusCode, class U, typename std::enable_if<is_status_code<StatusCode>::value, bool>::type = true> inline StatusCode *get_if(status_code<erased<U>> *v) noexcept { if((0xc44f7bdeb2cc50e9 ^ typename StatusCode::domain_type().id()) != v->domain().id()) { return nullptr; } union { U value; StatusCode *ret; }; value = v->value(); return ret; } //! \overload Const overload template <class StatusCode, class U, typename std::enable_if<is_status_code<StatusCode>::value, bool>::type = true> inline const StatusCode *get_if(const status_code<erased<U>> *v) noexcept { if((0xc44f7bdeb2cc50e9 ^ typename StatusCode::domain_type().id()) != v->domain().id()) { return nullptr; } union { U value; const StatusCode *ret; }; value = v->value(); return ret; } /*! If a status code refers to a `status_code_ptr`, return the id of the erased status code's domain. Otherwise return a meaningless number. */ template <class U> inline typename status_code_domain::unique_id_type get_id(const status_code<erased<U>> &v) noexcept { return 0xc44f7bdeb2cc50e9 ^ v.domain().id(); } SYSTEM_ERROR2_NAMESPACE_END #endif SYSTEM_ERROR2_NAMESPACE_BEGIN /*! A `status_code` which is always a failure. The closest equivalent to `std::error_code`, except it cannot be modified, and is templated. Differences from `status_code`: - Never successful (this contract is checked on construction, if fails then it terminates the process). - Is immutable. */ template <class DomainType> class errored_status_code : public status_code<DomainType> { using _base = status_code<DomainType>; using _base::clear; using _base::success; void _check() { if(_base::success()) { std::terminate(); } } public: //! The type of the erased error code. using typename _base::value_type; //! The type of a reference to a message string. using typename _base::string_ref; //! Default constructor. errored_status_code() = default; //! Copy constructor. errored_status_code(const errored_status_code &) = default; //! Move constructor. errored_status_code(errored_status_code &&) = default; // NOLINT //! Copy assignment. errored_status_code &operator=(const errored_status_code &) = default; //! Move assignment. errored_status_code &operator=(errored_status_code &&) = default; // NOLINT ~errored_status_code() = default; //! Explicitly construct from any similarly erased status code explicit errored_status_code(const _base &o) noexcept(std::is_nothrow_copy_constructible<_base>::value) : _base(o) { _check(); } //! Explicitly construct from any similarly erased status code explicit errored_status_code(_base &&o) noexcept(std::is_nothrow_move_constructible<_base>::value) : _base(static_cast<_base &&>(o)) { _check(); } /***** KEEP THESE IN SYNC WITH STATUS_CODE *****/ //! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`. template <class T, class... Args, // class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<T, Args...>::type, // Safe ADL lookup of make_status_code(), returns void if not found typename std::enable_if<!std::is_same<typename std::decay<T>::type, errored_status_code>::value // not copy/move of self && !std::is_same<typename std::decay<T>::type, in_place_t>::value // not in_place_t && is_status_code<MakeStatusCodeResult>::value // ADL makes a status code && std::is_constructible<errored_status_code, MakeStatusCodeResult>::value, // ADLed status code is compatible bool>::type = true> errored_status_code(T &&v, Args &&... args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT : errored_status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...)) { _check(); } //! Implicit construction from any `quick_status_code_from_enum<Enum>` enumerated type. template <class Enum, // class QuickStatusCodeType = typename quick_status_code_from_enum<Enum>::code_type, // Enumeration has been activated typename std::enable_if<std::is_constructible<errored_status_code, QuickStatusCodeType>::value, // Its status code is compatible bool>::type = true> errored_status_code(Enum &&v) noexcept(std::is_nothrow_constructible<errored_status_code, QuickStatusCodeType>::value) // NOLINT : errored_status_code(QuickStatusCodeType(static_cast<Enum &&>(v))) { _check(); } //! Explicit in-place construction. template <class... Args> explicit errored_status_code(in_place_t _, Args &&... args) noexcept(std::is_nothrow_constructible<value_type, Args &&...>::value) : _base(_, static_cast<Args &&>(args)...) { _check(); } //! Explicit in-place construction from initialiser list. template <class T, class... Args> explicit errored_status_code(in_place_t _, std::initializer_list<T> il, Args &&... args) noexcept(std::is_nothrow_constructible<value_type, std::initializer_list<T>, Args &&...>::value) : _base(_, il, static_cast<Args &&>(args)...) { _check(); } //! Explicit copy construction from a `value_type`. explicit errored_status_code(const value_type &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value) : _base(v) { _check(); } //! Explicit move construction from a `value_type`. explicit errored_status_code(value_type &&v) noexcept(std::is_nothrow_move_constructible<value_type>::value) : _base(static_cast<value_type &&>(v)) { _check(); } /*! Explicit construction from an erased status code. Available only if `value_type` is trivially destructible and `sizeof(status_code) <= sizeof(status_code<erased<>>)`. Does not check if domains are equal. */ template <class ErasedType, // typename std::enable_if<detail::type_erasure_is_safe<ErasedType, value_type>::value, bool>::type = true> explicit errored_status_code(const status_code<erased<ErasedType>> &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value) : errored_status_code(detail::erasure_cast<value_type>(v.value())) // NOLINT { assert(v.domain() == this->domain()); // NOLINT _check(); } //! Always false (including at compile time), as errored status codes are never successful. constexpr bool success() const noexcept { return false; } //! Return a const reference to the `value_type`. constexpr const value_type &value() const &noexcept { return this->_value; } }; namespace traits { template <class DomainType> struct is_move_bitcopying<errored_status_code<DomainType>> { static constexpr bool value = is_move_bitcopying<typename DomainType::value_type>::value; }; } // namespace traits template <class ErasedType> class errored_status_code<erased<ErasedType>> : public status_code<erased<ErasedType>> { using _base = status_code<erased<ErasedType>>; using _base::success; void _check() { if(_base::success()) { std::terminate(); } } public: using value_type = typename _base::value_type; using string_ref = typename _base::string_ref; //! Default construction to empty errored_status_code() = default; //! Copy constructor errored_status_code(const errored_status_code &) = default; //! Move constructor errored_status_code(errored_status_code &&) = default; // NOLINT //! Copy assignment errored_status_code &operator=(const errored_status_code &) = default; //! Move assignment errored_status_code &operator=(errored_status_code &&) = default; // NOLINT ~errored_status_code() = default; //! Explicitly construct from any similarly erased status code explicit errored_status_code(const _base &o) noexcept(std::is_nothrow_copy_constructible<_base>::value) : _base(o) { _check(); } //! Explicitly construct from any similarly erased status code explicit errored_status_code(_base &&o) noexcept(std::is_nothrow_move_constructible<_base>::value) : _base(static_cast<_base &&>(o)) { _check(); } /***** KEEP THESE IN SYNC WITH STATUS_CODE *****/ //! Implicit copy construction from any other status code if its value type is trivially copyable and it would fit into our storage template <class DomainType, // typename std::enable_if<std::is_trivially_copyable<typename DomainType::value_type>::value // && detail::type_erasure_is_safe<value_type, typename DomainType::value_type>::value, bool>::type = true> errored_status_code(const status_code<DomainType> &v) noexcept : _base(v) // NOLINT { _check(); } //! Implicit copy construction from any other status code if its value type is trivially copyable and it would fit into our storage template <class DomainType, // typename std::enable_if<std::is_trivially_copyable<typename DomainType::value_type>::value // && detail::type_erasure_is_safe<value_type, typename DomainType::value_type>::value, bool>::type = true> errored_status_code(const errored_status_code<DomainType> &v) noexcept : _base(static_cast<const status_code<DomainType> &>(v)) // NOLINT { _check(); } //! Implicit move construction from any other status code if its value type is trivially copyable or move bitcopying and it would fit into our storage template <class DomainType, // typename std::enable_if<detail::type_erasure_is_safe<value_type, typename DomainType::value_type>::value, bool>::type = true> errored_status_code(status_code<DomainType> &&v) noexcept : _base(static_cast<status_code<DomainType> &&>(v)) // NOLINT { _check(); } //! Implicit move construction from any other status code if its value type is trivially copyable or move bitcopying and it would fit into our storage template <class DomainType, // typename std::enable_if<detail::type_erasure_is_safe<value_type, typename DomainType::value_type>::value, bool>::type = true> errored_status_code(errored_status_code<DomainType> &&v) noexcept : _base(static_cast<status_code<DomainType> &&>(v)) // NOLINT { _check(); } //! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`. template <class T, class... Args, // class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<T, Args...>::type, // Safe ADL lookup of make_status_code(), returns void if not found typename std::enable_if<!std::is_same<typename std::decay<T>::type, errored_status_code>::value // not copy/move of self && !std::is_same<typename std::decay<T>::type, value_type>::value // not copy/move of value type && is_status_code<MakeStatusCodeResult>::value // ADL makes a status code && std::is_constructible<errored_status_code, MakeStatusCodeResult>::value, // ADLed status code is compatible bool>::type = true> errored_status_code(T &&v, Args &&... args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT : errored_status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...)) { _check(); } //! Implicit construction from any `quick_status_code_from_enum<Enum>` enumerated type. template <class Enum, // class QuickStatusCodeType = typename quick_status_code_from_enum<Enum>::code_type, // Enumeration has been activated typename std::enable_if<std::is_constructible<errored_status_code, QuickStatusCodeType>::value, // Its status code is compatible bool>::type = true> errored_status_code(Enum &&v) noexcept(std::is_nothrow_constructible<errored_status_code, QuickStatusCodeType>::value) // NOLINT : errored_status_code(QuickStatusCodeType(static_cast<Enum &&>(v))) { _check(); } //! Always false (including at compile time), as errored status codes are never successful. constexpr bool success() const noexcept { return false; } //! Return the erased `value_type` by value. constexpr value_type value() const noexcept { return this->_value; } }; namespace traits { template <class ErasedType> struct is_move_bitcopying<errored_status_code<erased<ErasedType>>> { static constexpr bool value = true; }; } // namespace traits //! True if the status code's are semantically equal via `equivalent()`. template <class DomainType1, class DomainType2> inline bool operator==(const errored_status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept { return a.equivalent(static_cast<const status_code<DomainType2> &>(b)); } //! True if the status code's are semantically equal via `equivalent()`. template <class DomainType1, class DomainType2> inline bool operator==(const status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept { return a.equivalent(static_cast<const status_code<DomainType2> &>(b)); } //! True if the status code's are semantically equal via `equivalent()`. template <class DomainType1, class DomainType2> inline bool operator==(const errored_status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept { return static_cast<const status_code<DomainType1> &>(a).equivalent(b); } //! True if the status code's are not semantically equal via `equivalent()`. template <class DomainType1, class DomainType2> inline bool operator!=(const errored_status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept { return !a.equivalent(static_cast<const status_code<DomainType2> &>(b)); } //! True if the status code's are not semantically equal via `equivalent()`. template <class DomainType1, class DomainType2> inline bool operator!=(const status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept { return !a.equivalent(static_cast<const status_code<DomainType2> &>(b)); } //! True if the status code's are not semantically equal via `equivalent()`. template <class DomainType1, class DomainType2> inline bool operator!=(const errored_status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept { return !static_cast<const status_code<DomainType1> &>(a).equivalent(b); } //! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`. template <class DomainType1, class T, // class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code inline bool operator==(const errored_status_code<DomainType1> &a, const T &b) { return a.equivalent(make_status_code(b)); } //! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`. template <class T, class DomainType1, // class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code inline bool operator==(const T &a, const errored_status_code<DomainType1> &b) { return b.equivalent(make_status_code(a)); } //! True if the status code's are not semantically equal via `equivalent()` to `make_status_code(T)`. template <class DomainType1, class T, // class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code inline bool operator!=(const errored_status_code<DomainType1> &a, const T &b) { return !a.equivalent(make_status_code(b)); } //! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`. template <class T, class DomainType1, // class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code inline bool operator!=(const T &a, const errored_status_code<DomainType1> &b) { return !b.equivalent(make_status_code(a)); } //! True if the status code's are semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(b)`. template <class DomainType1, class T, // class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated > inline bool operator==(const errored_status_code<DomainType1> &a, const T &b) { return a.equivalent(QuickStatusCodeType(b)); } //! True if the status code's are semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(a)`. template <class T, class DomainType1, // class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated > inline bool operator==(const T &a, const errored_status_code<DomainType1> &b) { return b.equivalent(QuickStatusCodeType(a)); } //! True if the status code's are not semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(b)`. template <class DomainType1, class T, // class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated > inline bool operator!=(const errored_status_code<DomainType1> &a, const T &b) { return !a.equivalent(QuickStatusCodeType(b)); } //! True if the status code's are not semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(a)`. template <class T, class DomainType1, // class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated > inline bool operator!=(const T &a, const errored_status_code<DomainType1> &b) { return !b.equivalent(QuickStatusCodeType(a)); } namespace detail { template <class T> struct is_errored_status_code { static constexpr bool value = false; }; template <class T> struct is_errored_status_code<errored_status_code<T>> { static constexpr bool value = true; }; template <class T> struct is_erased_errored_status_code { static constexpr bool value = false; }; template <class T> struct is_erased_errored_status_code<errored_status_code<erased<T>>> { static constexpr bool value = true; }; } // namespace detail //! Trait returning true if the type is an errored status code. template <class T> struct is_errored_status_code { static constexpr bool value = detail::is_errored_status_code<typename std::decay<T>::type>::value || detail::is_erased_errored_status_code<typename std::decay<T>::type>::value; }; SYSTEM_ERROR2_NAMESPACE_END #endif /* Proposed SG14 status_code (C) 2018 Niall Douglas <http://www.nedproductions.biz/> (5 commits) File Created: Feb 2018 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef SYSTEM_ERROR2_SYSTEM_CODE_HPP #define SYSTEM_ERROR2_SYSTEM_CODE_HPP #ifndef SYSTEM_ERROR2_NOT_POSIX /* Proposed SG14 status_code (C) 2018-2020 Niall Douglas <http://www.nedproductions.biz/> (5 commits) File Created: Feb 2018 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef SYSTEM_ERROR2_POSIX_CODE_HPP #define SYSTEM_ERROR2_POSIX_CODE_HPP #ifdef SYSTEM_ERROR2_NOT_POSIX #error <posix_code.hpp> is not includable when SYSTEM_ERROR2_NOT_POSIX is defined! #endif #include <cstring> // for strchr and strerror_r SYSTEM_ERROR2_NAMESPACE_BEGIN class _posix_code_domain; //! A POSIX error code, those returned by `errno`. using posix_code = status_code<_posix_code_domain>; //! A specialisation of `status_error` for the POSIX error code domain. using posix_error = status_error<_posix_code_domain>; namespace mixins { template <class Base> struct mixin<Base, _posix_code_domain> : public Base { using Base::Base; //! Returns a `posix_code` for the current value of `errno`. static posix_code current() noexcept; }; } // namespace mixins /*! The implementation of the domain for POSIX error codes, those returned by `errno`. */ class _posix_code_domain : public status_code_domain { template <class DomainType> friend class status_code; template <class StatusCode> friend class detail::indirecting_domain; using _base = status_code_domain; static _base::string_ref _make_string_ref(int c) noexcept { char buffer[1024] = ""; #ifdef _WIN32 strerror_s(buffer, sizeof(buffer), c); #elif defined(__gnu_linux__) && !defined(__ANDROID__) // handle glibc's weird strerror_r() char *s = strerror_r(c, buffer, sizeof(buffer)); // NOLINT if(s != nullptr) { strncpy(buffer, s, sizeof(buffer)); // NOLINT buffer[1023] = 0; } #else strerror_r(c, buffer, sizeof(buffer)); #endif size_t length = strlen(buffer); // NOLINT auto *p = static_cast<char *>(malloc(length + 1)); // NOLINT if(p == nullptr) { return _base::string_ref("failed to get message from system"); } memcpy(p, buffer, length + 1); // NOLINT return _base::atomic_refcounted_string_ref(p, length); } public: //! The value type of the POSIX code, which is an `int` using value_type = int; using _base::string_ref; //! Default constructor constexpr explicit _posix_code_domain(typename _base::unique_id_type id = 0xa59a56fe5f310933) noexcept : _base(id) { } _posix_code_domain(const _posix_code_domain &) = default; _posix_code_domain(_posix_code_domain &&) = default; _posix_code_domain &operator=(const _posix_code_domain &) = default; _posix_code_domain &operator=(_posix_code_domain &&) = default; ~_posix_code_domain() = default; //! Constexpr singleton getter. Returns constexpr posix_code_domain variable. static inline constexpr const _posix_code_domain &get(); virtual string_ref name() const noexcept override { return string_ref("posix domain"); } // NOLINT protected: virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT { assert(code.domain() == *this); // NOLINT return static_cast<const posix_code &>(code).value() != 0; // NOLINT } virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override // NOLINT { assert(code1.domain() == *this); // NOLINT const auto &c1 = static_cast<const posix_code &>(code1); // NOLINT if(code2.domain() == *this) { const auto &c2 = static_cast<const posix_code &>(code2); // NOLINT return c1.value() == c2.value(); } if(code2.domain() == generic_code_domain) { const auto &c2 = static_cast<const generic_code &>(code2); // NOLINT if(static_cast<int>(c2.value()) == c1.value()) { return true; } } return false; } virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT { assert(code.domain() == *this); // NOLINT const auto &c = static_cast<const posix_code &>(code); // NOLINT return generic_code(static_cast<errc>(c.value())); } virtual string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT { assert(code.domain() == *this); // NOLINT const auto &c = static_cast<const posix_code &>(code); // NOLINT return _make_string_ref(c.value()); } #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || 0L SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override // NOLINT { assert(code.domain() == *this); // NOLINT const auto &c = static_cast<const posix_code &>(code); // NOLINT throw status_error<_posix_code_domain>(c); } #endif }; //! A constexpr source variable for the POSIX code domain, which is that of `errno`. Returned by `_posix_code_domain::get()`. constexpr _posix_code_domain posix_code_domain; inline constexpr const _posix_code_domain &_posix_code_domain::get() { return posix_code_domain; } namespace mixins { template <class Base> inline posix_code mixin<Base, _posix_code_domain>::current() noexcept { return posix_code(errno); } } // namespace mixins SYSTEM_ERROR2_NAMESPACE_END #endif #else #endif #if defined(_WIN32) || 0L /* Proposed SG14 status_code (C) 2018 Niall Douglas <http://www.nedproductions.biz/> (5 commits) File Created: Feb 2018 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef SYSTEM_ERROR2_NT_CODE_HPP #define SYSTEM_ERROR2_NT_CODE_HPP #if !defined(_WIN32) && !0L #error This file should only be included on Windows #endif /* Proposed SG14 status_code (C) 2018 Niall Douglas <http://www.nedproductions.biz/> (5 commits) File Created: Feb 2018 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef SYSTEM_ERROR2_WIN32_CODE_HPP #define SYSTEM_ERROR2_WIN32_CODE_HPP #if !defined(_WIN32) && !0L #error This file should only be included on Windows #endif SYSTEM_ERROR2_NAMESPACE_BEGIN //! \exclude namespace win32 { // A Win32 DWORD using DWORD = unsigned long; // Used to retrieve the current Win32 error code extern DWORD __stdcall GetLastError(); // Used to retrieve a locale-specific message string for some error code extern DWORD __stdcall FormatMessageW(DWORD dwFlags, const void *lpSource, DWORD dwMessageId, DWORD dwLanguageId, wchar_t *lpBuffer, DWORD nSize, void /*va_list*/ *Arguments); // Converts UTF-16 message string to UTF-8 extern int __stdcall WideCharToMultiByte(unsigned int CodePage, DWORD dwFlags, const wchar_t *lpWideCharStr, int cchWideChar, char *lpMultiByteStr, int cbMultiByte, const char *lpDefaultChar, int *lpUsedDefaultChar); #pragma comment(lib, "kernel32.lib") #if (defined(__x86_64__) || defined(_M_X64)) || (defined(__aarch64__) || defined(_M_ARM64)) #pragma comment(linker, "/alternatename:?GetLastError@win32@system_error2@@YAKXZ=GetLastError") #pragma comment(linker, "/alternatename:?FormatMessageW@win32@system_error2@@YAKKPEBXKKPEA_WKPEAX@Z=FormatMessageW") #pragma comment(linker, "/alternatename:?WideCharToMultiByte@win32@system_error2@@YAHIKPEB_WHPEADHPEBDPEAH@Z=WideCharToMultiByte") #elif defined(__x86__) || defined(_M_IX86) || defined(__i386__) #pragma comment(linker, "/alternatename:?GetLastError@win32@system_error2@@YGKXZ=__imp__GetLastError@0") #pragma comment(linker, "/alternatename:?FormatMessageW@win32@system_error2@@YGKKPBXKKPA_WKPAX@Z=__imp__FormatMessageW@28") #pragma comment(linker, "/alternatename:?WideCharToMultiByte@win32@system_error2@@YGHIKPB_WHPADHPBDPAH@Z=__imp__WideCharToMultiByte@32") #elif defined(__arm__) || defined(_M_ARM) #pragma comment(linker, "/alternatename:?GetLastError@win32@system_error2@@YAKXZ=GetLastError") #pragma comment(linker, "/alternatename:?FormatMessageW@win32@system_error2@@YAKKPBXKKPA_WKPAX@Z=FormatMessageW") #pragma comment(linker, "/alternatename:?WideCharToMultiByte@win32@system_error2@@YAHIKPB_WHPADHPBDPAH@Z=WideCharToMultiByte") #else #error Unknown architecture #endif } // namespace win32 class _win32_code_domain; class _com_code_domain; //! (Windows only) A Win32 error code, those returned by `GetLastError()`. using win32_code = status_code<_win32_code_domain>; //! (Windows only) A specialisation of `status_error` for the Win32 error code domain. using win32_error = status_error<_win32_code_domain>; namespace mixins { template <class Base> struct mixin<Base, _win32_code_domain> : public Base { using Base::Base; //! Returns a `win32_code` for the current value of `GetLastError()`. static inline win32_code current() noexcept; }; } // namespace mixins /*! (Windows only) The implementation of the domain for Win32 error codes, those returned by `GetLastError()`. */ class _win32_code_domain : public status_code_domain { template <class DomainType> friend class status_code; template <class StatusCode> friend class detail::indirecting_domain; friend class _com_code_domain; using _base = status_code_domain; static int _win32_code_to_errno(win32::DWORD c) { switch(c) { case 0: return 0; case 0x1: return ENOSYS; case 0x2: return ENOENT; case 0x3: return ENOENT; case 0x4: return EMFILE; case 0x5: return EACCES; case 0x6: return EINVAL; case 0x8: return ENOMEM; case 0xc: return EACCES; case 0xe: return ENOMEM; case 0xf: return ENODEV; case 0x10: return EACCES; case 0x11: return EXDEV; case 0x13: return EACCES; case 0x14: return ENODEV; case 0x15: return EAGAIN; case 0x19: return EIO; case 0x1d: return EIO; case 0x1e: return EIO; case 0x20: return EACCES; case 0x21: return ENOLCK; case 0x27: return ENOSPC; case 0x37: return ENODEV; case 0x50: return EEXIST; case 0x52: return EACCES; case 0x57: return EINVAL; case 0x6e: return EIO; case 0x6f: return ENAMETOOLONG; case 0x70: return ENOSPC; case 0x7b: return EINVAL; case 0x83: return EINVAL; case 0x8e: return EBUSY; case 0x91: return ENOTEMPTY; case 0xaa: return EBUSY; case 0xb7: return EEXIST; case 0xd4: return ENOLCK; case 0x10b: return EINVAL; case 0x3e3: return ECANCELED; case 0x3e6: return EACCES; case 0x3f3: return EIO; case 0x3f4: return EIO; case 0x3f5: return EIO; case 0x4d5: return EAGAIN; case 0x961: return EBUSY; case 0x964: return EBUSY; case 0x2714: return EINTR; case 0x2719: return EBADF; case 0x271d: return EACCES; case 0x271e: return EFAULT; case 0x2726: return EINVAL; case 0x2728: return EMFILE; case 0x2733: return EWOULDBLOCK; case 0x2734: return EINPROGRESS; case 0x2735: return EALREADY; case 0x2736: return ENOTSOCK; case 0x2737: return EDESTADDRREQ; case 0x2738: return EMSGSIZE; case 0x2739: return EPROTOTYPE; case 0x273a: return ENOPROTOOPT; case 0x273b: return EPROTONOSUPPORT; case 0x273d: return EOPNOTSUPP; case 0x273f: return EAFNOSUPPORT; case 0x2740: return EADDRINUSE; case 0x2741: return EADDRNOTAVAIL; case 0x2742: return ENETDOWN; case 0x2743: return ENETUNREACH; case 0x2744: return ENETRESET; case 0x2745: return ECONNABORTED; case 0x2746: return ECONNRESET; case 0x2747: return ENOBUFS; case 0x2748: return EISCONN; case 0x2749: return ENOTCONN; case 0x274c: return ETIMEDOUT; case 0x274d: return ECONNREFUSED; case 0x274f: return ENAMETOOLONG; case 0x2751: return EHOSTUNREACH; } return -1; } //! Construct from a Win32 error code static _base::string_ref _make_string_ref(win32::DWORD c) noexcept { wchar_t buffer[32768]; win32::DWORD wlen = win32::FormatMessageW(0x00001000 /*FORMAT_MESSAGE_FROM_SYSTEM*/ | 0x00000200 /*FORMAT_MESSAGE_IGNORE_INSERTS*/, nullptr, c, 0, buffer, 32768, nullptr); size_t allocation = wlen + (wlen >> 1); win32::DWORD bytes; if(wlen == 0) { return _base::string_ref("failed to get message from system"); } for(;;) { auto *p = static_cast<char *>(malloc(allocation)); // NOLINT if(p == nullptr) { return _base::string_ref("failed to get message from system"); } bytes = win32::WideCharToMultiByte(65001 /*CP_UTF8*/, 0, buffer, (int) (wlen + 1), p, (int) allocation, nullptr, nullptr); if(bytes != 0) { char *end = strchr(p, 0); while(end[-1] == 10 || end[-1] == 13) { --end; } *end = 0; // NOLINT return _base::atomic_refcounted_string_ref(p, end - p); } free(p); // NOLINT if(win32::GetLastError() == 0x7a /*ERROR_INSUFFICIENT_BUFFER*/) { allocation += allocation >> 2; continue; } return _base::string_ref("failed to get message from system"); } } public: //! The value type of the win32 code, which is a `win32::DWORD` using value_type = win32::DWORD; using _base::string_ref; public: //! Default constructor constexpr explicit _win32_code_domain(typename _base::unique_id_type id = 0x8cd18ee72d680f1b) noexcept : _base(id) { } _win32_code_domain(const _win32_code_domain &) = default; _win32_code_domain(_win32_code_domain &&) = default; _win32_code_domain &operator=(const _win32_code_domain &) = default; _win32_code_domain &operator=(_win32_code_domain &&) = default; ~_win32_code_domain() = default; //! Constexpr singleton getter. Returns the constexpr win32_code_domain variable. static inline constexpr const _win32_code_domain &get(); virtual string_ref name() const noexcept override { return string_ref("win32 domain"); } // NOLINT protected: virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT { assert(code.domain() == *this); return static_cast<const win32_code &>(code).value() != 0; // NOLINT } virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override // NOLINT { assert(code1.domain() == *this); const auto &c1 = static_cast<const win32_code &>(code1); // NOLINT if(code2.domain() == *this) { const auto &c2 = static_cast<const win32_code &>(code2); // NOLINT return c1.value() == c2.value(); } if(code2.domain() == generic_code_domain) { const auto &c2 = static_cast<const generic_code &>(code2); // NOLINT if(static_cast<int>(c2.value()) == _win32_code_to_errno(c1.value())) { return true; } } return false; } virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT { assert(code.domain() == *this); const auto &c = static_cast<const win32_code &>(code); // NOLINT return generic_code(static_cast<errc>(_win32_code_to_errno(c.value()))); } virtual string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT { assert(code.domain() == *this); const auto &c = static_cast<const win32_code &>(code); // NOLINT return _make_string_ref(c.value()); } #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || 0L SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override // NOLINT { assert(code.domain() == *this); const auto &c = static_cast<const win32_code &>(code); // NOLINT throw status_error<_win32_code_domain>(c); } #endif }; //! (Windows only) A constexpr source variable for the win32 code domain, which is that of `GetLastError()` (Windows). Returned by `_win32_code_domain::get()`. constexpr _win32_code_domain win32_code_domain; inline constexpr const _win32_code_domain &_win32_code_domain::get() { return win32_code_domain; } namespace mixins { template <class Base> inline win32_code mixin<Base, _win32_code_domain>::current() noexcept { return win32_code(win32::GetLastError()); } } // namespace mixins SYSTEM_ERROR2_NAMESPACE_END #endif SYSTEM_ERROR2_NAMESPACE_BEGIN //! \exclude namespace win32 { // A Win32 NTSTATUS using NTSTATUS = long; // A Win32 HMODULE using HMODULE = void *; // Used to retrieve where the NTDLL DLL is mapped into memory extern HMODULE __stdcall GetModuleHandleW(const wchar_t *lpModuleName); #pragma comment(lib, "kernel32.lib") #if (defined(__x86_64__) || defined(_M_X64)) || (defined(__aarch64__) || defined(_M_ARM64)) #pragma comment(linker, "/alternatename:?GetModuleHandleW@win32@system_error2@@YAPEAXPEB_W@Z=GetModuleHandleW") #elif defined(__x86__) || defined(_M_IX86) || defined(__i386__) #pragma comment(linker, "/alternatename:?GetModuleHandleW@win32@system_error2@@YGPAXPB_W@Z=__imp__GetModuleHandleW@4") #elif defined(__arm__) || defined(_M_ARM) #pragma comment(linker, "/alternatename:?GetModuleHandleW@win32@system_error2@@YAPAXPB_W@Z=GetModuleHandleW") #else #error Unknown architecture #endif } // namespace win32 class _nt_code_domain; //! (Windows only) A NT error code, those returned by NT kernel functions. using nt_code = status_code<_nt_code_domain>; //! (Windows only) A specialisation of `status_error` for the NT error code domain. using nt_error = status_error<_nt_code_domain>; /*! (Windows only) The implementation of the domain for NT error codes, those returned by NT kernel functions. */ class _nt_code_domain : public status_code_domain { template <class DomainType> friend class status_code; template <class StatusCode> friend class detail::indirecting_domain; friend class _com_code_domain; using _base = status_code_domain; static int _nt_code_to_errno(win32::NTSTATUS c) { if(c >= 0) { return 0; // success } switch(static_cast<unsigned>(c)) { case 0x80000002: return EACCES; case 0x8000000f: return EAGAIN; case 0x80000010: return EAGAIN; case 0x80000011: return EBUSY; case 0xc0000002: return ENOSYS; case 0xc0000005: return EACCES; case 0xc0000008: return EINVAL; case 0xc000000e: return ENOENT; case 0xc000000f: return ENOENT; case 0xc0000010: return ENOSYS; case 0xc0000013: return EAGAIN; case 0xc0000017: return ENOMEM; case 0xc000001c: return ENOSYS; case 0xc000001e: return EACCES; case 0xc000001f: return EACCES; case 0xc0000021: return EACCES; case 0xc0000022: return EACCES; case 0xc0000024: return EINVAL; case 0xc0000033: return EINVAL; case 0xc0000034: return ENOENT; case 0xc0000035: return EEXIST; case 0xc0000037: return EINVAL; case 0xc000003a: return ENOENT; case 0xc0000040: return ENOMEM; case 0xc0000041: return EACCES; case 0xc0000042: return EINVAL; case 0xc0000043: return EACCES; case 0xc000004b: return EACCES; case 0xc0000054: return ENOLCK; case 0xc0000055: return ENOLCK; case 0xc0000056: return EACCES; case 0xc000007f: return ENOSPC; case 0xc0000087: return ENOMEM; case 0xc0000097: return ENOMEM; case 0xc000009b: return ENOENT; case 0xc000009e: return EAGAIN; case 0xc00000a2: return EACCES; case 0xc00000a3: return EAGAIN; case 0xc00000af: return ENOSYS; case 0xc00000ba: return EACCES; case 0xc00000c0: return ENODEV; case 0xc00000d4: return EXDEV; case 0xc00000d5: return EACCES; case 0xc00000fb: return ENOENT; case 0xc0000101: return ENOTEMPTY; case 0xc0000103: return EINVAL; case 0xc0000107: return EBUSY; case 0xc0000108: return EBUSY; case 0xc000010a: return EACCES; case 0xc000011f: return EMFILE; case 0xc0000120: return ECANCELED; case 0xc0000121: return EACCES; case 0xc0000123: return EACCES; case 0xc0000128: return EINVAL; case 0xc0000189: return EACCES; case 0xc00001ad: return ENOMEM; case 0xc000022d: return EAGAIN; case 0xc0000235: return EINVAL; case 0xc000026e: return EAGAIN; case 0xc000028a: return EACCES; case 0xc000028b: return EACCES; case 0xc000028d: return EACCES; case 0xc000028e: return EACCES; case 0xc000028f: return EACCES; case 0xc0000290: return EACCES; case 0xc000029c: return ENOSYS; case 0xc00002c5: return EACCES; case 0xc00002d3: return EAGAIN; case 0xc00002ea: return EACCES; case 0xc00002f0: return ENOENT; case 0xc0000373: return ENOMEM; case 0xc0000416: return ENOMEM; case 0xc0000433: return EBUSY; case 0xc0000434: return EBUSY; case 0xc0000455: return EINVAL; case 0xc0000467: return EACCES; case 0xc0000491: return ENOENT; case 0xc0000495: return EAGAIN; case 0xc0000503: return EAGAIN; case 0xc0000507: return EBUSY; case 0xc0000512: return EACCES; case 0xc000070a: return EINVAL; case 0xc000070b: return EINVAL; case 0xc000070c: return EINVAL; case 0xc000070d: return EINVAL; case 0xc000070e: return EINVAL; case 0xc000070f: return EINVAL; case 0xc0000710: return ENOSYS; case 0xc0000711: return ENOSYS; case 0xc0000716: return EINVAL; case 0xc000071b: return ENOSYS; case 0xc000071d: return ENOSYS; case 0xc000071e: return ENOSYS; case 0xc000071f: return ENOSYS; case 0xc0000720: return ENOSYS; case 0xc0000721: return ENOSYS; case 0xc000080f: return EAGAIN; case 0xc000a203: return EACCES; } return -1; } static win32::DWORD _nt_code_to_win32_code(win32::NTSTATUS c) // NOLINT { if(c >= 0) { return 0; // success } switch(static_cast<unsigned>(c)) { case 0x80000002: return 0x3e6; case 0x80000005: return 0xea; case 0x80000006: return 0x12; case 0x80000007: return 0x2a3; case 0x8000000a: return 0x2a4; case 0x8000000b: return 0x56f; case 0x8000000c: return 0x2a8; case 0x8000000d: return 0x12b; case 0x8000000e: return 0x1c; case 0x8000000f: return 0x15; case 0x80000010: return 0x15; case 0x80000011: return 0xaa; case 0x80000012: return 0x103; case 0x80000013: return 0xfe; case 0x80000014: return 0xff; case 0x80000015: return 0xff; case 0x80000016: return 0x456; case 0x80000017: return 0x2a5; case 0x80000018: return 0x2a6; case 0x8000001a: return 0x103; case 0x8000001b: return 0x44d; case 0x8000001c: return 0x456; case 0x8000001d: return 0x457; case 0x8000001e: return 0x44c; case 0x8000001f: return 0x44e; case 0x80000020: return 0x2a7; case 0x80000021: return 0x44f; case 0x80000022: return 0x450; case 0x80000023: return 0x702; case 0x80000024: return 0x713; case 0x80000025: return 0x962; case 0x80000026: return 0x2aa; case 0x80000027: return 0x10f4; case 0x80000028: return 0x2ab; case 0x80000029: return 0x2ac; case 0x8000002a: return 0x2ad; case 0x8000002b: return 0x2ae; case 0x8000002c: return 0x2af; case 0x8000002d: return 0x2a9; case 0x8000002e: return 0x321; case 0x8000002f: return 0x324; case 0x80000030: return 0xab; case 0x80000032: return 0xeb; case 0x80000288: return 0x48d; case 0x80000289: return 0x48e; case 0x80000803: return 0x1abb; case 0x8000a127: return 0x3bdf; case 0x8000cf00: return 0x16e; case 0x8000cf04: return 0x16d; case 0x8000cf05: return 0x176; case 0x80130001: return 0x13c5; case 0x80130002: return 0x13c6; case 0x80130003: return 0x13c7; case 0x80130004: return 0x13c8; case 0x80130005: return 0x13c9; case 0x80190009: return 0x19e5; case 0x80190029: return 0x1aa0; case 0x80190031: return 0x1aa2; case 0x80190041: return 0x1ab3; case 0x80190042: return 0x1ab4; case 0x801c0001: return 0x7a; case 0xc0000001: return 0x1f; case 0xc0000002: return 0x1; case 0xc0000003: return 0x57; case 0xc0000004: return 0x18; case 0xc0000005: return 0x3e6; case 0xc0000006: return 0x3e7; case 0xc0000007: return 0x5ae; case 0xc0000008: return 0x6; case 0xc0000009: return 0x3e9; case 0xc000000a: return 0xc1; case 0xc000000b: return 0x57; case 0xc000000c: return 0x21d; case 0xc000000d: return 0x57; case 0xc000000e: return 0x2; case 0xc000000f: return 0x2; case 0xc0000010: return 0x1; case 0xc0000011: return 0x26; case 0xc0000012: return 0x22; case 0xc0000013: return 0x15; case 0xc0000014: return 0x6f9; case 0xc0000015: return 0x1b; case 0xc0000016: return 0xea; case 0xc0000017: return 0x8; case 0xc0000018: return 0x1e7; case 0xc0000019: return 0x1e7; case 0xc000001a: return 0x57; case 0xc000001b: return 0x57; case 0xc000001c: return 0x1; case 0xc000001e: return 0x5; case 0xc000001f: return 0x5; case 0xc0000020: return 0xc1; case 0xc0000021: return 0x5; case 0xc0000022: return 0x5; case 0xc0000023: return 0x7a; case 0xc0000024: return 0x6; case 0xc0000027: return 0x21e; case 0xc0000028: return 0x21f; case 0xc0000029: return 0x220; case 0xc000002a: return 0x9e; case 0xc000002c: return 0x1e7; case 0xc000002d: return 0x1e7; case 0xc000002e: return 0x221; case 0xc000002f: return 0x222; case 0xc0000030: return 0x57; case 0xc0000031: return 0x223; case 0xc0000032: return 0x571; case 0xc0000033: return 0x7b; case 0xc0000034: return 0x2; case 0xc0000035: return 0xb7; case 0xc0000036: return 0x72a; case 0xc0000037: return 0x6; case 0xc0000038: return 0x224; case 0xc0000039: return 0xa1; case 0xc000003a: return 0x3; case 0xc000003b: return 0xa1; case 0xc000003c: return 0x45d; case 0xc000003d: return 0x45d; case 0xc000003e: return 0x17; case 0xc000003f: return 0x17; case 0xc0000040: return 0x8; case 0xc0000041: return 0x5; case 0xc0000042: return 0x6; case 0xc0000043: return 0x20; case 0xc0000044: return 0x718; case 0xc0000045: return 0x57; case 0xc0000046: return 0x120; case 0xc0000047: return 0x12a; case 0xc0000048: return 0x57; case 0xc0000049: return 0x57; case 0xc000004a: return 0x9c; case 0xc000004b: return 0x5; case 0xc000004c: return 0x57; case 0xc000004d: return 0x57; case 0xc000004e: return 0x57; case 0xc000004f: return 0x11a; case 0xc0000050: return 0xff; case 0xc0000051: return 0x570; case 0xc0000052: return 0x570; case 0xc0000053: return 0x570; case 0xc0000054: return 0x21; case 0xc0000055: return 0x21; case 0xc0000056: return 0x5; case 0xc0000057: return 0x32; case 0xc0000058: return 0x519; case 0xc0000059: return 0x51a; case 0xc000005a: return 0x51b; case 0xc000005b: return 0x51c; case 0xc000005c: return 0x51d; case 0xc000005d: return 0x51e; case 0xc000005e: return 0x51f; case 0xc000005f: return 0x520; case 0xc0000060: return 0x521; case 0xc0000061: return 0x522; case 0xc0000062: return 0x523; case 0xc0000063: return 0x524; case 0xc0000064: return 0x525; case 0xc0000065: return 0x526; case 0xc0000066: return 0x527; case 0xc0000067: return 0x528; case 0xc0000068: return 0x529; case 0xc0000069: return 0x52a; case 0xc000006a: return 0x56; case 0xc000006b: return 0x52c; case 0xc000006c: return 0x52d; case 0xc000006d: return 0x52e; case 0xc000006e: return 0x52f; case 0xc000006f: return 0x530; case 0xc0000070: return 0x531; case 0xc0000071: return 0x532; case 0xc0000072: return 0x533; case 0xc0000073: return 0x534; case 0xc0000074: return 0x535; case 0xc0000075: return 0x536; case 0xc0000076: return 0x537; case 0xc0000077: return 0x538; case 0xc0000078: return 0x539; case 0xc0000079: return 0x53a; case 0xc000007a: return 0x7f; case 0xc000007b: return 0xc1; case 0xc000007c: return 0x3f0; case 0xc000007d: return 0x53c; case 0xc000007e: return 0x9e; case 0xc000007f: return 0x70; case 0xc0000080: return 0x53d; case 0xc0000081: return 0x53e; case 0xc0000082: return 0x44; case 0xc0000083: return 0x103; case 0xc0000084: return 0x53f; case 0xc0000085: return 0x103; case 0xc0000086: return 0x9a; case 0xc0000087: return 0xe; case 0xc0000088: return 0x1e7; case 0xc0000089: return 0x714; case 0xc000008a: return 0x715; case 0xc000008b: return 0x716; case 0xc0000095: return 0x216; case 0xc0000097: return 0x8; case 0xc0000098: return 0x3ee; case 0xc0000099: return 0x540; case 0xc000009a: return 0x5aa; case 0xc000009b: return 0x3; case 0xc000009c: return 0x17; case 0xc000009d: return 0x48f; case 0xc000009e: return 0x15; case 0xc000009f: return 0x1e7; case 0xc00000a0: return 0x1e7; case 0xc00000a1: return 0x5ad; case 0xc00000a2: return 0x13; case 0xc00000a3: return 0x15; case 0xc00000a4: return 0x541; case 0xc00000a5: return 0x542; case 0xc00000a6: return 0x543; case 0xc00000a7: return 0x544; case 0xc00000a8: return 0x545; case 0xc00000a9: return 0x57; case 0xc00000aa: return 0x225; case 0xc00000ab: return 0xe7; case 0xc00000ac: return 0xe7; case 0xc00000ad: return 0xe6; case 0xc00000ae: return 0xe7; case 0xc00000af: return 0x1; case 0xc00000b0: return 0xe9; case 0xc00000b1: return 0xe8; case 0xc00000b2: return 0x217; case 0xc00000b3: return 0x218; case 0xc00000b4: return 0xe6; case 0xc00000b5: return 0x79; case 0xc00000b6: return 0x26; case 0xc00000b7: return 0x226; case 0xc00000b8: return 0x227; case 0xc00000b9: return 0x228; case 0xc00000ba: return 0x5; case 0xc00000bb: return 0x32; case 0xc00000bc: return 0x33; case 0xc00000bd: return 0x34; case 0xc00000be: return 0x35; case 0xc00000bf: return 0x36; case 0xc00000c0: return 0x37; case 0xc00000c1: return 0x38; case 0xc00000c2: return 0x39; case 0xc00000c3: return 0x3a; case 0xc00000c4: return 0x3b; case 0xc00000c5: return 0x3c; case 0xc00000c6: return 0x3d; case 0xc00000c7: return 0x3e; case 0xc00000c8: return 0x3f; case 0xc00000c9: return 0x40; case 0xc00000ca: return 0x41; case 0xc00000cb: return 0x42; case 0xc00000cc: return 0x43; case 0xc00000cd: return 0x44; case 0xc00000ce: return 0x45; case 0xc00000cf: return 0x46; case 0xc00000d0: return 0x47; case 0xc00000d1: return 0x48; case 0xc00000d2: return 0x58; case 0xc00000d3: return 0x229; case 0xc00000d4: return 0x11; case 0xc00000d5: return 0x5; case 0xc00000d6: return 0xf0; case 0xc00000d7: return 0x546; case 0xc00000d8: return 0x22a; case 0xc00000d9: return 0xe8; case 0xc00000da: return 0x547; case 0xc00000db: return 0x22b; case 0xc00000dc: return 0x548; case 0xc00000dd: return 0x549; case 0xc00000de: return 0x54a; case 0xc00000df: return 0x54b; case 0xc00000e0: return 0x54c; case 0xc00000e1: return 0x54d; case 0xc00000e2: return 0x12c; case 0xc00000e3: return 0x12d; case 0xc00000e4: return 0x54e; case 0xc00000e5: return 0x54f; case 0xc00000e6: return 0x550; case 0xc00000e7: return 0x551; case 0xc00000e8: return 0x6f8; case 0xc00000e9: return 0x45d; case 0xc00000ea: return 0x22c; case 0xc00000eb: return 0x22d; case 0xc00000ec: return 0x22e; case 0xc00000ed: return 0x552; case 0xc00000ee: return 0x553; case 0xc00000ef: return 0x57; case 0xc00000f0: return 0x57; case 0xc00000f1: return 0x57; case 0xc00000f2: return 0x57; case 0xc00000f3: return 0x57; case 0xc00000f4: return 0x57; case 0xc00000f5: return 0x57; case 0xc00000f6: return 0x57; case 0xc00000f7: return 0x57; case 0xc00000f8: return 0x57; case 0xc00000f9: return 0x57; case 0xc00000fa: return 0x57; case 0xc00000fb: return 0x3; case 0xc00000fc: return 0x420; case 0xc00000fd: return 0x3e9; case 0xc00000fe: return 0x554; case 0xc00000ff: return 0x22f; case 0xc0000100: return 0xcb; case 0xc0000101: return 0x91; case 0xc0000102: return 0x570; case 0xc0000103: return 0x10b; case 0xc0000104: return 0x555; case 0xc0000105: return 0x556; case 0xc0000106: return 0xce; case 0xc0000107: return 0x961; case 0xc0000108: return 0x964; case 0xc000010a: return 0x5; case 0xc000010b: return 0x557; case 0xc000010c: return 0x230; case 0xc000010d: return 0x558; case 0xc000010e: return 0x420; case 0xc000010f: return 0x21a; case 0xc0000110: return 0x21a; case 0xc0000111: return 0x21a; case 0xc0000112: return 0x21a; case 0xc0000113: return 0x21a; case 0xc0000114: return 0x21a; case 0xc0000115: return 0x21a; case 0xc0000116: return 0x21a; case 0xc0000117: return 0x5a4; case 0xc0000118: return 0x231; case 0xc0000119: return 0x233; case 0xc000011a: return 0x234; case 0xc000011b: return 0xc1; case 0xc000011c: return 0x559; case 0xc000011d: return 0x55a; case 0xc000011e: return 0x3ee; case 0xc000011f: return 0x4; case 0xc0000120: return 0x3e3; case 0xc0000121: return 0x5; case 0xc0000122: return 0x4ba; case 0xc0000123: return 0x5; case 0xc0000124: return 0x55b; case 0xc0000125: return 0x55c; case 0xc0000126: return 0x55d; case 0xc0000127: return 0x55e; case 0xc0000128: return 0x6; case 0xc0000129: return 0x235; case 0xc000012a: return 0x236; case 0xc000012b: return 0x55f; case 0xc000012c: return 0x237; case 0xc000012d: return 0x5af; case 0xc000012e: return 0xc1; case 0xc000012f: return 0xc1; case 0xc0000130: return 0xc1; case 0xc0000131: return 0xc1; case 0xc0000132: return 0x238; case 0xc0000133: return 0x576; case 0xc0000134: return 0x239; case 0xc0000135: return 0x7e; case 0xc0000136: return 0x23a; case 0xc0000137: return 0x23b; case 0xc0000138: return 0xb6; case 0xc0000139: return 0x7f; case 0xc000013a: return 0x23c; case 0xc000013b: return 0x40; case 0xc000013c: return 0x40; case 0xc000013d: return 0x33; case 0xc000013e: return 0x3b; case 0xc000013f: return 0x3b; case 0xc0000140: return 0x3b; case 0xc0000141: return 0x3b; case 0xc0000142: return 0x45a; case 0xc0000143: return 0x23d; case 0xc0000144: return 0x23e; case 0xc0000145: return 0x23f; case 0xc0000146: return 0x240; case 0xc0000147: return 0x242; case 0xc0000148: return 0x7c; case 0xc0000149: return 0x56; case 0xc000014a: return 0x243; case 0xc000014b: return 0x6d; case 0xc000014c: return 0x3f1; case 0xc000014d: return 0x3f8; case 0xc000014e: return 0x244; case 0xc000014f: return 0x3ed; case 0xc0000150: return 0x45e; case 0xc0000151: return 0x560; case 0xc0000152: return 0x561; case 0xc0000153: return 0x562; case 0xc0000154: return 0x563; case 0xc0000155: return 0x564; case 0xc0000156: return 0x565; case 0xc0000157: return 0x566; case 0xc0000158: return 0x567; case 0xc0000159: return 0x3ef; case 0xc000015a: return 0x568; case 0xc000015b: return 0x569; case 0xc000015c: return 0x3f9; case 0xc000015d: return 0x56a; case 0xc000015e: return 0x245; case 0xc000015f: return 0x45d; case 0xc0000160: return 0x4db; case 0xc0000161: return 0x246; case 0xc0000162: return 0x459; case 0xc0000163: return 0x247; case 0xc0000164: return 0x248; case 0xc0000165: return 0x462; case 0xc0000166: return 0x463; case 0xc0000167: return 0x464; case 0xc0000168: return 0x465; case 0xc0000169: return 0x466; case 0xc000016a: return 0x467; case 0xc000016b: return 0x468; case 0xc000016c: return 0x45f; case 0xc000016d: return 0x45d; case 0xc000016e: return 0x249; case 0xc0000172: return 0x451; case 0xc0000173: return 0x452; case 0xc0000174: return 0x453; case 0xc0000175: return 0x454; case 0xc0000176: return 0x455; case 0xc0000177: return 0x469; case 0xc0000178: return 0x458; case 0xc000017a: return 0x56b; case 0xc000017b: return 0x56c; case 0xc000017c: return 0x3fa; case 0xc000017d: return 0x3fb; case 0xc000017e: return 0x56d; case 0xc000017f: return 0x56e; case 0xc0000180: return 0x3fc; case 0xc0000181: return 0x3fd; case 0xc0000182: return 0x57; case 0xc0000183: return 0x45d; case 0xc0000184: return 0x16; case 0xc0000185: return 0x45d; case 0xc0000186: return 0x45d; case 0xc0000187: return 0x24a; case 0xc0000188: return 0x5de; case 0xc0000189: return 0x13; case 0xc000018a: return 0x6fa; case 0xc000018b: return 0x6fb; case 0xc000018c: return 0x6fc; case 0xc000018d: return 0x6fd; case 0xc000018e: return 0x5dc; case 0xc000018f: return 0x5dd; case 0xc0000190: return 0x6fe; case 0xc0000191: return 0x24b; case 0xc0000192: return 0x700; case 0xc0000193: return 0x701; case 0xc0000194: return 0x46b; case 0xc0000195: return 0x4c3; case 0xc0000196: return 0x4c4; case 0xc0000197: return 0x5df; case 0xc0000198: return 0x70f; case 0xc0000199: return 0x710; case 0xc000019a: return 0x711; case 0xc000019b: return 0x712; case 0xc000019c: return 0x24c; case 0xc000019d: return 0x420; case 0xc000019e: return 0x130; case 0xc000019f: return 0x131; case 0xc00001a0: return 0x132; case 0xc00001a1: return 0x133; case 0xc00001a2: return 0x325; case 0xc00001a3: return 0x134; case 0xc00001a4: return 0x135; case 0xc00001a5: return 0x136; case 0xc00001a6: return 0x137; case 0xc00001a7: return 0x139; case 0xc00001a8: return 0x1abb; case 0xc00001a9: return 0x32; case 0xc00001aa: return 0x3d54; case 0xc00001ab: return 0x329; case 0xc00001ac: return 0x678; case 0xc00001ad: return 0x8; case 0xc00001ae: return 0x2f7; case 0xc00001af: return 0x32d; case 0xc0000201: return 0x41; case 0xc0000202: return 0x572; case 0xc0000203: return 0x3b; case 0xc0000204: return 0x717; case 0xc0000205: return 0x46a; case 0xc0000206: return 0x6f8; case 0xc0000207: return 0x4be; case 0xc0000208: return 0x4be; case 0xc0000209: return 0x44; case 0xc000020a: return 0x34; case 0xc000020b: return 0x40; case 0xc000020c: return 0x40; case 0xc000020d: return 0x40; case 0xc000020e: return 0x44; case 0xc000020f: return 0x3b; case 0xc0000210: return 0x3b; case 0xc0000211: return 0x3b; case 0xc0000212: return 0x3b; case 0xc0000213: return 0x3b; case 0xc0000214: return 0x3b; case 0xc0000215: return 0x3b; case 0xc0000216: return 0x32; case 0xc0000217: return 0x32; case 0xc0000218: return 0x24d; case 0xc0000219: return 0x24e; case 0xc000021a: return 0x24f; case 0xc000021b: return 0x250; case 0xc000021c: return 0x17e6; case 0xc000021d: return 0x251; case 0xc000021e: return 0x252; case 0xc000021f: return 0x253; case 0xc0000220: return 0x46c; case 0xc0000221: return 0xc1; case 0xc0000222: return 0x254; case 0xc0000223: return 0x255; case 0xc0000224: return 0x773; case 0xc0000225: return 0x490; case 0xc0000226: return 0x256; case 0xc0000227: return 0x4ff; case 0xc0000228: return 0x257; case 0xc0000229: return 0x57; case 0xc000022a: return 0x1392; case 0xc000022b: return 0x1392; case 0xc000022c: return 0x258; case 0xc000022d: return 0x4d5; case 0xc000022e: return 0x259; case 0xc000022f: return 0x25a; case 0xc0000230: return 0x492; case 0xc0000231: return 0x25b; case 0xc0000232: return 0x25c; case 0xc0000233: return 0x774; case 0xc0000234: return 0x775; case 0xc0000235: return 0x6; case 0xc0000236: return 0x4c9; case 0xc0000237: return 0x4ca; case 0xc0000238: return 0x4cb; case 0xc0000239: return 0x4cc; case 0xc000023a: return 0x4cd; case 0xc000023b: return 0x4ce; case 0xc000023c: return 0x4cf; case 0xc000023d: return 0x4d0; case 0xc000023e: return 0x4d1; case 0xc000023f: return 0x4d2; case 0xc0000240: return 0x4d3; case 0xc0000241: return 0x4d4; case 0xc0000242: return 0x25d; case 0xc0000243: return 0x4c8; case 0xc0000244: return 0x25e; case 0xc0000245: return 0x25f; case 0xc0000246: return 0x4d6; case 0xc0000247: return 0x4d7; case 0xc0000248: return 0x4d8; case 0xc0000249: return 0xc1; case 0xc0000250: return 0x260; case 0xc0000251: return 0x261; case 0xc0000252: return 0x262; case 0xc0000253: return 0x4d4; case 0xc0000254: return 0x263; case 0xc0000255: return 0x264; case 0xc0000256: return 0x265; case 0xc0000257: return 0x4d0; case 0xc0000258: return 0x266; case 0xc0000259: return 0x573; case 0xc000025a: return 0x267; case 0xc000025b: return 0x268; case 0xc000025c: return 0x269; case 0xc000025e: return 0x422; case 0xc000025f: return 0x26a; case 0xc0000260: return 0x26b; case 0xc0000261: return 0x26c; case 0xc0000262: return 0xb6; case 0xc0000263: return 0x7f; case 0xc0000264: return 0x120; case 0xc0000265: return 0x476; case 0xc0000266: return 0x26d; case 0xc0000267: return 0x10fe; case 0xc0000268: return 0x26e; case 0xc0000269: return 0x26f; case 0xc000026a: return 0x1b8e; case 0xc000026b: return 0x270; case 0xc000026c: return 0x7d1; case 0xc000026d: return 0x4b1; case 0xc000026e: return 0x15; case 0xc000026f: return 0x21c; case 0xc0000270: return 0x21c; case 0xc0000271: return 0x271; case 0xc0000272: return 0x491; case 0xc0000273: return 0x272; case 0xc0000275: return 0x1126; case 0xc0000276: return 0x1129; case 0xc0000277: return 0x112a; case 0xc0000278: return 0x1128; case 0xc0000279: return 0x780; case 0xc000027a: return 0x291; case 0xc000027b: return 0x54f; case 0xc000027c: return 0x54f; case 0xc0000280: return 0x781; case 0xc0000281: return 0xa1; case 0xc0000282: return 0x273; case 0xc0000283: return 0x488; case 0xc0000284: return 0x489; case 0xc0000285: return 0x48a; case 0xc0000286: return 0x48b; case 0xc0000287: return 0x48c; case 0xc000028a: return 0x5; case 0xc000028b: return 0x5; case 0xc000028c: return 0x284; case 0xc000028d: return 0x5; case 0xc000028e: return 0x5; case 0xc000028f: return 0x5; case 0xc0000290: return 0x5; case 0xc0000291: return 0x1777; case 0xc0000292: return 0x1778; case 0xc0000293: return 0x1772; case 0xc0000295: return 0x1068; case 0xc0000296: return 0x1069; case 0xc0000297: return 0x106a; case 0xc0000298: return 0x106b; case 0xc0000299: return 0x201a; case 0xc000029a: return 0x201b; case 0xc000029b: return 0x201c; case 0xc000029c: return 0x1; case 0xc000029d: return 0x10ff; case 0xc000029e: return 0x1100; case 0xc000029f: return 0x494; case 0xc00002a0: return 0x274; case 0xc00002a1: return 0x200a; case 0xc00002a2: return 0x200b; case 0xc00002a3: return 0x200c; case 0xc00002a4: return 0x200d; case 0xc00002a5: return 0x200e; case 0xc00002a6: return 0x200f; case 0xc00002a7: return 0x2010; case 0xc00002a8: return 0x2011; case 0xc00002a9: return 0x2012; case 0xc00002aa: return 0x2013; case 0xc00002ab: return 0x2014; case 0xc00002ac: return 0x2015; case 0xc00002ad: return 0x2016; case 0xc00002ae: return 0x2017; case 0xc00002af: return 0x2018; case 0xc00002b0: return 0x2019; case 0xc00002b1: return 0x211e; case 0xc00002b2: return 0x1127; case 0xc00002b3: return 0x275; case 0xc00002b4: return 0x276; case 0xc00002b5: return 0x277; case 0xc00002b6: return 0x651; case 0xc00002b7: return 0x49a; case 0xc00002b8: return 0x49b; case 0xc00002b9: return 0x278; case 0xc00002ba: return 0x2047; case 0xc00002c1: return 0x2024; case 0xc00002c2: return 0x279; case 0xc00002c3: return 0x575; case 0xc00002c4: return 0x27a; case 0xc00002c5: return 0x3e6; case 0xc00002c6: return 0x1075; case 0xc00002c7: return 0x1076; case 0xc00002c8: return 0x27b; case 0xc00002c9: return 0x4ed; case 0xc00002ca: return 0x10e8; case 0xc00002cb: return 0x2138; case 0xc00002cc: return 0x4e3; case 0xc00002cd: return 0x2139; case 0xc00002ce: return 0x27c; case 0xc00002cf: return 0x49d; case 0xc00002d0: return 0x213a; case 0xc00002d1: return 0x27d; case 0xc00002d2: return 0x27e; case 0xc00002d3: return 0x15; case 0xc00002d4: return 0x2141; case 0xc00002d5: return 0x2142; case 0xc00002d6: return 0x2143; case 0xc00002d7: return 0x2144; case 0xc00002d8: return 0x2145; case 0xc00002d9: return 0x2146; case 0xc00002da: return 0x2147; case 0xc00002db: return 0x2148; case 0xc00002dc: return 0x2149; case 0xc00002dd: return 0x32; case 0xc00002de: return 0x27f; case 0xc00002df: return 0x2151; case 0xc00002e0: return 0x2152; case 0xc00002e1: return 0x2153; case 0xc00002e2: return 0x2154; case 0xc00002e3: return 0x215d; case 0xc00002e4: return 0x2163; case 0xc00002e5: return 0x2164; case 0xc00002e6: return 0x2165; case 0xc00002e7: return 0x216d; case 0xc00002e8: return 0x280; case 0xc00002e9: return 0x577; case 0xc00002ea: return 0x52; case 0xc00002eb: return 0x281; case 0xc00002ec: return 0x2171; case 0xc00002ed: return 0x2172; case 0xc00002f0: return 0x2; case 0xc00002fe: return 0x45b; case 0xc00002ff: return 0x4e7; case 0xc0000300: return 0x4e6; case 0xc0000301: return 0x106f; case 0xc0000302: return 0x1074; case 0xc0000303: return 0x106e; case 0xc0000304: return 0x12e; case 0xc000030c: return 0x792; case 0xc000030d: return 0x793; case 0xc0000320: return 0x4ef; case 0xc0000321: return 0x4f0; case 0xc0000350: return 0x4e8; case 0xc0000352: return 0x177d; case 0xc0000353: return 0x282; case 0xc0000354: return 0x504; case 0xc0000355: return 0x283; case 0xc0000357: return 0x217c; case 0xc0000358: return 0x2182; case 0xc0000359: return 0xc1; case 0xc000035a: return 0xc1; case 0xc000035c: return 0x572; case 0xc000035d: return 0x4eb; case 0xc000035f: return 0x286; case 0xc0000361: return 0x4ec; case 0xc0000362: return 0x4ec; case 0xc0000363: return 0x4ec; case 0xc0000364: return 0x4ec; case 0xc0000365: return 0x287; case 0xc0000366: return 0x288; case 0xc0000368: return 0x289; case 0xc0000369: return 0x28a; case 0xc000036a: return 0x28b; case 0xc000036b: return 0x4fb; case 0xc000036c: return 0x4fb; case 0xc000036d: return 0x28c; case 0xc000036e: return 0x28d; case 0xc000036f: return 0x4fc; case 0xc0000371: return 0x21ac; case 0xc0000372: return 0x312; case 0xc0000373: return 0x8; case 0xc0000374: return 0x54f; case 0xc0000388: return 0x4f1; case 0xc000038e: return 0x28e; case 0xc0000401: return 0x78c; case 0xc0000402: return 0x78d; case 0xc0000403: return 0x78e; case 0xc0000404: return 0x217b; case 0xc0000405: return 0x219d; case 0xc0000406: return 0x219f; case 0xc0000407: return 0x28f; case 0xc0000408: return 0x52e; case 0xc0000409: return 0x502; case 0xc0000410: return 0x503; case 0xc0000411: return 0x290; case 0xc0000412: return 0x505; case 0xc0000413: return 0x78f; case 0xc0000414: return 0x506; case 0xc0000416: return 0x8; case 0xc0000417: return 0x508; case 0xc0000418: return 0x791; case 0xc0000419: return 0x215b; case 0xc000041a: return 0x21ba; case 0xc000041b: return 0x21bb; case 0xc000041c: return 0x21bc; case 0xc000041d: return 0x2c9; case 0xc0000420: return 0x29c; case 0xc0000421: return 0x219; case 0xc0000423: return 0x300; case 0xc0000424: return 0x4fb; case 0xc0000425: return 0x3fa; case 0xc0000426: return 0x301; case 0xc0000427: return 0x299; case 0xc0000428: return 0x241; case 0xc0000429: return 0x307; case 0xc000042a: return 0x308; case 0xc000042b: return 0x50c; case 0xc000042c: return 0x2e4; case 0xc0000432: return 0x509; case 0xc0000433: return 0xaa; case 0xc0000434: return 0xaa; case 0xc0000435: return 0x4c8; case 0xc0000441: return 0x1781; case 0xc0000442: return 0x1782; case 0xc0000443: return 0x1783; case 0xc0000444: return 0x1784; case 0xc0000445: return 0x1785; case 0xc0000446: return 0x513; case 0xc0000450: return 0x50b; case 0xc0000451: return 0x3b92; case 0xc0000452: return 0x3bc3; case 0xc0000453: return 0x5bb; case 0xc0000454: return 0x5be; case 0xc0000455: return 0x6; case 0xc0000456: return 0x57; case 0xc0000457: return 0x57; case 0xc0000458: return 0x57; case 0xc0000459: return 0xbea; case 0xc0000460: return 0x138; case 0xc0000461: return 0x13a; case 0xc0000462: return 0x3cfc; case 0xc0000463: return 0x13c; case 0xc0000464: return 0x141; case 0xc0000465: return 0x13b; case 0xc0000466: return 0x40; case 0xc0000467: return 0x20; case 0xc0000468: return 0x142; case 0xc0000469: return 0x3d00; case 0xc000046a: return 0x151; case 0xc000046b: return 0x152; case 0xc000046c: return 0x153; case 0xc000046d: return 0x156; case 0xc000046e: return 0x157; case 0xc000046f: return 0x158; case 0xc0000470: return 0x143; case 0xc0000471: return 0x144; case 0xc0000472: return 0x146; case 0xc0000473: return 0x14b; case 0xc0000474: return 0x147; case 0xc0000475: return 0x148; case 0xc0000476: return 0x149; case 0xc0000477: return 0x14a; case 0xc0000478: return 0x14c; case 0xc0000479: return 0x14d; case 0xc000047a: return 0x14e; case 0xc000047b: return 0x14f; case 0xc000047c: return 0x150; case 0xc000047d: return 0x5b4; case 0xc000047e: return 0x3d07; case 0xc000047f: return 0x3d08; case 0xc0000480: return 0x40; case 0xc0000481: return 0x7e; case 0xc0000482: return 0x7e; case 0xc0000483: return 0x1e3; case 0xc0000486: return 0x159; case 0xc0000487: return 0x1f; case 0xc0000488: return 0x15a; case 0xc0000489: return 0x3d0f; case 0xc000048a: return 0x32a; case 0xc000048b: return 0x32c; case 0xc000048c: return 0x15b; case 0xc000048d: return 0x15c; case 0xc000048e: return 0x162; case 0xc000048f: return 0x15d; case 0xc0000490: return 0x491; case 0xc0000491: return 0x2; case 0xc0000492: return 0x490; case 0xc0000493: return 0x492; case 0xc0000494: return 0x307; case 0xc0000495: return 0x15; case 0xc0000496: return 0x163; case 0xc0000497: return 0x3d5a; case 0xc0000499: return 0x167; case 0xc000049a: return 0x168; case 0xc000049b: return 0x12e; case 0xc000049c: return 0x169; case 0xc000049d: return 0x16f; case 0xc000049e: return 0x170; case 0xc000049f: return 0x49f; case 0xc00004a0: return 0x4a0; case 0xc00004a1: return 0x18f; case 0xc0000500: return 0x60e; case 0xc0000501: return 0x60f; case 0xc0000502: return 0x610; case 0xc0000503: return 0x15; case 0xc0000504: return 0x13f; case 0xc0000505: return 0x140; case 0xc0000506: return 0x5bf; case 0xc0000507: return 0xaa; case 0xc0000508: return 0x5e0; case 0xc0000509: return 0x5e1; case 0xc000050b: return 0x112b; case 0xc000050e: return 0x115c; case 0xc000050f: return 0x10d3; case 0xc0000510: return 0x4df; case 0xc0000511: return 0x32e; case 0xc0000512: return 0x5; case 0xc0000513: return 0x180; case 0xc0000514: return 0x115d; case 0xc0000602: return 0x675; case 0xc0000604: return 0x677; case 0xc0000606: return 0x679; case 0xc000060a: return 0x67c; case 0xc000060b: return 0x67d; case 0xc0000700: return 0x54f; case 0xc0000701: return 0x54f; case 0xc0000702: return 0x57; case 0xc0000703: return 0x54f; case 0xc0000704: return 0x32; case 0xc0000705: return 0x57; case 0xc0000706: return 0x57; case 0xc0000707: return 0x32; case 0xc0000708: return 0x54f; case 0xc0000709: return 0x30b; case 0xc000070a: return 0x6; case 0xc000070b: return 0x6; case 0xc000070c: return 0x6; case 0xc000070d: return 0x6; case 0xc000070e: return 0x6; case 0xc000070f: return 0x6; case 0xc0000710: return 0x1; case 0xc0000711: return 0x1; case 0xc0000712: return 0x50d; case 0xc0000713: return 0x310; case 0xc0000714: return 0x52e; case 0xc0000715: return 0x5b7; case 0xc0000716: return 0x7b; case 0xc0000717: return 0x459; case 0xc0000718: return 0x54f; case 0xc0000719: return 0x54f; case 0xc000071a: return 0x54f; case 0xc000071b: return 0x1; case 0xc000071c: return 0x57; case 0xc000071d: return 0x1; case 0xc000071e: return 0x1; case 0xc000071f: return 0x1; case 0xc0000720: return 0x1; case 0xc0000721: return 0x1; case 0xc0000722: return 0x72b; case 0xc0000723: return 0x1f; case 0xc0000724: return 0x1f; case 0xc0000725: return 0x1f; case 0xc0000726: return 0x1f; case 0xc0000800: return 0x30c; case 0xc0000801: return 0x21a4; case 0xc0000802: return 0x50f; case 0xc0000804: return 0x510; case 0xc0000805: return 0x1ac1; case 0xc0000806: return 0x1ac3; case 0xc0000808: return 0x319; case 0xc0000809: return 0x31a; case 0xc000080a: return 0x31b; case 0xc000080b: return 0x31c; case 0xc000080c: return 0x31d; case 0xc000080d: return 0x31e; case 0xc000080e: return 0x31f; case 0xc000080f: return 0x4d5; case 0xc0000810: return 0x328; case 0xc0000811: return 0x54f; case 0xc0000901: return 0xdc; case 0xc0000902: return 0xdd; case 0xc0000903: return 0xde; case 0xc0000904: return 0xdf; case 0xc0000905: return 0xe0; case 0xc0000906: return 0xe1; case 0xc0000907: return 0xe2; case 0xc0000908: return 0x317; case 0xc0000909: return 0x322; case 0xc0000910: return 0x326; case 0xc0009898: return 0x29e; case 0xc000a002: return 0x17; case 0xc000a003: return 0x139f; case 0xc000a004: return 0x154; case 0xc000a005: return 0x155; case 0xc000a006: return 0x32b; case 0xc000a007: return 0x32; case 0xc000a010: return 0xea; case 0xc000a011: return 0xea; case 0xc000a012: return 0x4d0; case 0xc000a013: return 0x32; case 0xc000a014: return 0x4d1; case 0xc000a080: return 0x314; case 0xc000a081: return 0x315; case 0xc000a082: return 0x316; case 0xc000a083: return 0x5b9; case 0xc000a084: return 0x5ba; case 0xc000a085: return 0x5bc; case 0xc000a086: return 0x5bd; case 0xc000a087: return 0x21bd; case 0xc000a088: return 0x21be; case 0xc000a089: return 0x21c6; case 0xc000a100: return 0x3bc4; case 0xc000a101: return 0x3bc5; case 0xc000a121: return 0x3bd9; case 0xc000a122: return 0x3bda; case 0xc000a123: return 0x3bdb; case 0xc000a124: return 0x3bdc; case 0xc000a125: return 0x3bdd; case 0xc000a126: return 0x3bde; case 0xc000a141: return 0x3c28; case 0xc000a142: return 0x3c29; case 0xc000a143: return 0x3c2a; case 0xc000a145: return 0x3c2b; case 0xc000a146: return 0x3c2c; case 0xc000a200: return 0x109a; case 0xc000a201: return 0x109c; case 0xc000a202: return 0x109d; case 0xc000a203: return 0x5; case 0xc000a281: return 0x1130; case 0xc000a282: return 0x1131; case 0xc000a283: return 0x1132; case 0xc000a284: return 0x1133; case 0xc000a285: return 0x1134; case 0xc000a2a1: return 0x1158; case 0xc000a2a2: return 0x1159; case 0xc000a2a3: return 0x115a; case 0xc000a2a4: return 0x115b; case 0xc000ce01: return 0x171; case 0xc000ce02: return 0x172; case 0xc000ce03: return 0x173; case 0xc000ce04: return 0x174; case 0xc000ce05: return 0x181; case 0xc000cf00: return 0x166; case 0xc000cf01: return 0x16a; case 0xc000cf02: return 0x16b; case 0xc000cf03: return 0x16c; case 0xc000cf06: return 0x177; case 0xc000cf07: return 0x178; case 0xc000cf08: return 0x179; case 0xc000cf09: return 0x17a; case 0xc000cf0a: return 0x17b; case 0xc000cf0b: return 0x17c; case 0xc000cf0c: return 0x17d; case 0xc000cf0d: return 0x17e; case 0xc000cf0e: return 0x17f; case 0xc000cf0f: return 0x182; case 0xc000cf10: return 0x183; case 0xc000cf11: return 0x184; case 0xc000cf12: return 0x185; case 0xc000cf13: return 0x186; case 0xc000cf14: return 0x187; case 0xc000cf15: return 0x188; case 0xc000cf16: return 0x189; case 0xc000cf17: return 0x18a; case 0xc000cf18: return 0x18b; case 0xc000cf19: return 0x18c; case 0xc000cf1a: return 0x18d; case 0xc000cf1b: return 0x18e; } return static_cast<win32::DWORD>(-1); } //! Construct from a NT error code static _base::string_ref _make_string_ref(win32::NTSTATUS c) noexcept { wchar_t buffer[32768]; static win32::HMODULE ntdll = win32::GetModuleHandleW(L"NTDLL.DLL"); win32::DWORD wlen = win32::FormatMessageW(0x00000800 /*FORMAT_MESSAGE_FROM_HMODULE*/ | 0x00001000 /*FORMAT_MESSAGE_FROM_SYSTEM*/ | 0x00000200 /*FORMAT_MESSAGE_IGNORE_INSERTS*/, ntdll, c, (1 << 10) /*MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)*/, buffer, 32768, nullptr); size_t allocation = wlen + (wlen >> 1); win32::DWORD bytes; if(wlen == 0) { return _base::string_ref("failed to get message from system"); } for(;;) { auto *p = static_cast<char *>(malloc(allocation)); // NOLINT if(p == nullptr) { return _base::string_ref("failed to get message from system"); } bytes = win32::WideCharToMultiByte(65001 /*CP_UTF8*/, 0, buffer, (int) (wlen + 1), p, (int) allocation, nullptr, nullptr); if(bytes != 0) { char *end = strchr(p, 0); while(end[-1] == 10 || end[-1] == 13) { --end; } *end = 0; // NOLINT return _base::atomic_refcounted_string_ref(p, end - p); } free(p); // NOLINT if(win32::GetLastError() == 0x7a /*ERROR_INSUFFICIENT_BUFFER*/) { allocation += allocation >> 2; continue; } return _base::string_ref("failed to get message from system"); } } public: //! The value type of the NT code, which is a `win32::NTSTATUS` using value_type = win32::NTSTATUS; using _base::string_ref; public: //! Default constructor constexpr explicit _nt_code_domain(typename _base::unique_id_type id = 0x93f3b4487e4af25b) noexcept : _base(id) { } _nt_code_domain(const _nt_code_domain &) = default; _nt_code_domain(_nt_code_domain &&) = default; _nt_code_domain &operator=(const _nt_code_domain &) = default; _nt_code_domain &operator=(_nt_code_domain &&) = default; ~_nt_code_domain() = default; //! Constexpr singleton getter. Returns the constexpr nt_code_domain variable. static inline constexpr const _nt_code_domain &get(); virtual string_ref name() const noexcept override { return string_ref("NT domain"); } // NOLINT protected: virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT { assert(code.domain() == *this); return static_cast<const nt_code &>(code).value() < 0; // NOLINT } virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override // NOLINT { assert(code1.domain() == *this); const auto &c1 = static_cast<const nt_code &>(code1); // NOLINT if(code2.domain() == *this) { const auto &c2 = static_cast<const nt_code &>(code2); // NOLINT return c1.value() == c2.value(); } if(code2.domain() == generic_code_domain) { const auto &c2 = static_cast<const generic_code &>(code2); // NOLINT if(static_cast<int>(c2.value()) == _nt_code_to_errno(c1.value())) { return true; } } if(code2.domain() == win32_code_domain) { const auto &c2 = static_cast<const win32_code &>(code2); // NOLINT if(c2.value() == _nt_code_to_win32_code(c1.value())) { return true; } } return false; } virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT { assert(code.domain() == *this); const auto &c = static_cast<const nt_code &>(code); // NOLINT return generic_code(static_cast<errc>(_nt_code_to_errno(c.value()))); } virtual string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT { assert(code.domain() == *this); const auto &c = static_cast<const nt_code &>(code); // NOLINT return _make_string_ref(c.value()); } #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || 0L SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override // NOLINT { assert(code.domain() == *this); const auto &c = static_cast<const nt_code &>(code); // NOLINT throw status_error<_nt_code_domain>(c); } #endif }; //! (Windows only) A constexpr source variable for the NT code domain, which is that of NT kernel functions. Returned by `_nt_code_domain::get()`. constexpr _nt_code_domain nt_code_domain; inline constexpr const _nt_code_domain &_nt_code_domain::get() { return nt_code_domain; } SYSTEM_ERROR2_NAMESPACE_END #endif // NOT "com_code.hpp" #endif SYSTEM_ERROR2_NAMESPACE_BEGIN /*! An erased-mutable status code suitably large for all the system codes which can be returned on this system. For Windows, these might be: - `com_code` (`HRESULT`) [you need to include "com_code.hpp" explicitly for this] - `nt_code` (`LONG`) - `win32_code` (`DWORD`) For POSIX, `posix_code` is possible. You are guaranteed that `system_code` can be transported by the compiler in exactly two CPU registers. */ using system_code = status_code<erased<intptr_t>>; #ifndef NDEBUG static_assert(sizeof(system_code) == 2 * sizeof(void *), "system_code is not exactly two pointers in size!"); static_assert(traits::is_move_bitcopying<system_code>::value, "system_code is not move bitcopying!"); #endif SYSTEM_ERROR2_NAMESPACE_END #endif SYSTEM_ERROR2_NAMESPACE_BEGIN /*! An erased `system_code` which is always a failure. The closest equivalent to `std::error_code`, except it cannot be null and cannot be modified. This refines `system_code` into an `error` object meeting the requirements of [P0709 Zero-overhead deterministic exceptions](https://wg21.link/P0709). Differences from `system_code`: - Always a failure (this is checked at construction, and if not the case, the program is terminated as this is a logic error) - No default construction. - No empty state possible. - Is immutable. As with `system_code`, it remains guaranteed to be two CPU registers in size, and move bitcopying. */ using error = errored_status_code<erased<system_code::value_type>>; #ifndef NDEBUG static_assert(sizeof(error) == 2 * sizeof(void *), "error is not exactly two pointers in size!"); static_assert(traits::is_move_bitcopying<error>::value, "error is not move bitcopying!"); #endif SYSTEM_ERROR2_NAMESPACE_END #endif #endif /* Example use of status_code with outcome (C) 2020 Niall Douglas <http://www.nedproductions.biz/> (5 commits) File Created: Sept 2020 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #include <iostream> // This is some third party enumeration type in another namespace namespace another_namespace { // "Initialiser list" custom status code domain enum class AnotherCode : size_t { success1, goaway, success2, error2 }; } // namespace another_namespace // To synthesise a custom status code domain for `AnotherCode`, inject the following // template specialisation: SYSTEM_ERROR2_NAMESPACE_BEGIN template <> struct quick_status_code_from_enum<another_namespace::AnotherCode> : quick_status_code_from_enum_defaults<another_namespace::AnotherCode> { // Text name of the enum static constexpr const auto domain_name = "Another Code"; // Unique UUID for the enum. PLEASE use https://www.random.org/cgi-bin/randbyte?nbytes=16&format=h static constexpr const auto domain_uuid = "{be201f65-3962-dd0e-1266-a72e63776a42}"; // Map of each enum value to its text string, and list of semantically equivalent errc's static const std::initializer_list<mapping> &value_mappings() { static const std::initializer_list<mapping> v = { // Format is: { enum value, "string representation", { list of errc mappings ... } } {another_namespace::AnotherCode::success1, "Success 1", {errc::success}}, // {another_namespace::AnotherCode::goaway, "Go away", {errc::permission_denied}}, // {another_namespace::AnotherCode::success2, "Success 2", {errc::success}}, // {another_namespace::AnotherCode::error2, "Error 2", {errc::function_not_supported}}, // }; return v; } // Completely optional definition of mixin for the status code synthesised from `Enum`. // It can be omitted. template <class Base> struct mixin : Base { using Base::Base; // A custom method on the synthesised status code constexpr int custom_method() const { return 42; } }; }; SYSTEM_ERROR2_NAMESPACE_END // If you wish easy manufacture of status codes from AnotherCode: namespace another_namespace { // ADL discovered, must be in same namespace as AnotherCode constexpr inline SYSTEM_ERROR2_NAMESPACE::quick_status_code_from_enum_code<another_namespace::AnotherCode> status_code(AnotherCode c) { return SYSTEM_ERROR2_NAMESPACE::quick_status_code_from_enum_code<another_namespace::AnotherCode>{c}; } } // namespace another_namespace int main(int argc, char *argv[]) { // Make a status code of the synthesised code domain for `AnotherCode`. Note the // unqualified lookup, ADL discovers the status_code() free function. SYSTEM_ERROR2_CONSTEXPR14 auto v = status_code(another_namespace::AnotherCode::error2); assert(v.value() == another_namespace::AnotherCode::error2); assert(v.custom_method() == 42); // If you don't need custom methods, just use system_code, all erased // status codes recognise quick_status_code_from_enum SYSTEM_ERROR2_NAMESPACE::system_code v2(another_namespace::AnotherCode::error2); assert(v2 == v); // If v.success() is true, this is a precondition failure which terminates // the program SYSTEM_ERROR2_NAMESPACE::error err = v; assert(v2 == err); return 0; }
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