Compare commits

...

915 Commits
dev ... master

Author SHA1 Message Date
SachinVin
7a926d689b backend/A64: Rename PackedAbsDiffSumS8 to PackedAbsDiffSumU8 2022-11-20 22:42:00 +05:30
SachinVin
cd304cca6c clang-format 2022-11-20 22:22:17 +05:30
Steven Smith
d968f7ad81 backend/A64: Fix SpinLockImpl not setting required memory permissions. (#9) 2022-11-20 22:22:17 +05:30
PabloMK7
571c73a8f3 Add edge case for FCMP with 0 immediate. (#8)
* Add edge case for FCMP with 0 immediate.

* Update emit_a64_floating_point.cpp
2022-11-20 22:22:17 +05:30
SachinVin
8691f52aaa backend/A64/reg_alloc: fix moving zero to FPR 2022-11-20 22:22:17 +05:30
SachinVin
bf8ca8d05d decoder_detail.h: clang workarounds 2022-11-20 22:22:17 +05:30
SachinVin
717866a1e5 spin_lock_arm64.cpp: fixes and cleanup 2022-11-20 22:22:17 +05:30
Macdu
c85ad17cd2 backend/A64: Fix halt_reason test in GenRunCode (#7) 2022-11-20 22:22:17 +05:30
SachinVin
2b761074d0 backend/A64/reg_alloc.cpp: cleanup 2022-11-20 22:22:17 +05:30
Merry
7f48f061d8 tests: Add test generator
fix test_generator
2022-11-20 22:22:17 +05:30
SachinVin
14d1018f92 backend/A64/block_of_code.h: add CallLambda 2022-11-20 22:20:54 +05:30
SachinVin
0dde1d1ff3 # This is a combination of 4 commits.
^ This is the 1st commit message:

backend/A64: impl EmitA32SetCpsrNZ(C) + GetCFlagFromNZCV

Fix NZC Stuff

impl GetCFlagFromNZCV

fix EmitA32SetCpsrNZC

simplify EmitGetCFlagFromNZCV

EmitGetNZCVFromOp clang-format

clang format

^ This is the commit message #2:

fix EmitA32SetCpsrNZC

# This is the commit message #3:

simplify EmitGetCFlagFromNZCV

# This is the commit message #4:

EmitGetNZCVFromOp clang-format
2022-11-20 22:20:54 +05:30
SachinVin
40db85e783 backend/A64: Implement AndNot32
fix AndNot32
2022-11-20 22:20:54 +05:30
SachinVin
ef03b3f16c backend/A64: remove Set{N,Z,C,V}Flag impl 2022-11-20 22:20:54 +05:30
SachinVin
a4fc791ae8 Backend/A64: add Polyfill optimization 2022-11-20 22:20:54 +05:30
SachinVin
6aea986fb2 backend/A64: update API for Memory{Read,Write}Exclusive{8,16,32,64}
fix ReadMemory

fix write

fix exclusive read/write

simplify readMemory
2022-11-20 22:20:54 +05:30
SachinVin
a692cf61a2 Backend/A64: Partial global exclusive monitor
fix spinlocks on arm64

backend A64: no xbyak

spin_lock_arm64 fixes

simplify spin_lock_arm64

a64_emitter.cpp: fix some exclusive load/store codegen

spin lcok clang format
2022-11-20 22:20:53 +05:30
SachinVin
c500e61966 remove unused disassemble 2022-11-20 22:20:53 +05:30
SachinVin
1f302f397f clang-format 2022-11-20 22:20:53 +05:30
SachinVin
d459cb6f59 backend/A64: clear upper 32bits for PackedAbsDiffSumS8 test case 2022-11-20 22:20:53 +05:30
SachinVin
60e798d886 backend\A64\a32_emit_a64: Implement UpdateUpperLocationDescriptor 2022-11-20 22:20:53 +05:30
SachinVin
5aa60e72a3 backend\A64\a32_interface.cpp: update Disassemble inteface 2022-11-20 22:20:53 +05:30
SachinVin
d57e1f9010 backend/A64: update Optimization flags 2022-11-20 22:20:53 +05:30
SachinVin
b525a3c20f backend/A64: implement HaltReason
fix Jz

backend/A64: Jz again
2022-11-20 22:20:53 +05:30
SachinVin
8bd79dc382 CI: add initial CI build
CI cross compile

CI: add initial arm
# This is the 1st commit message:
2022-11-20 22:20:53 +05:30
SachinVin
b93759f914 backend\A64: remove unused insructions 2022-11-20 22:20:53 +05:30
SachinVin
c654544aeb backend\A64\reg_alloc.cpp: Handle AccType 2022-11-20 22:20:53 +05:30
SachinVin
41bdd03bbe backend/A64/opcodes.inc: Add new ir instructions 2022-11-20 22:20:52 +05:30
SachinVin
5198956e72 a64_emitter.cpp: Fix fmt formatting in asserts 2022-11-20 22:20:52 +05:30
SachinVin
0d66d30d42 backend\A64\emitter: Fix Windows build
constify

constify2

constify3: the uncostification
2022-11-20 22:20:52 +05:30
SachinVin
8e0ec356c0 backend/A64: Update header path
fix header

using
2022-11-20 22:20:52 +05:30
SachinVin
a870e9e74b backend/A64: migrate to mcl
backend\A64\devirtualize.h: fixup mcl
2022-11-20 22:20:52 +05:30
SachinVin
df9d373a84 Debt: backport A64 backend
enable W^X on Apple silicon
2022-11-20 22:20:52 +05:30
Macdu
97edb626c7 emit_arm64_a32: Improve A32SetCpsr 2022-11-20 16:21:47 +00:00
Macdu
ad6a04c584 backend/arm64: FPVectorToHalf32 implementation 2022-11-20 16:21:47 +00:00
Merry
5e2206d0e9 dynarmic: 6.3.0 2022-11-19 21:42:42 +00:00
Merry
93b18ee8e2 A32: Allow for user-adjustable per-instruction tick counts 2022-11-19 21:42:13 +00:00
Merry
07c614f91b dynarmic: 6.2.4 2022-11-19 20:07:34 +00:00
Merry
f2781c58b7 a64_emit_x64_memory: Correct bug in GenMemory128Accessors, misaligned stack 2022-11-19 20:07:10 +00:00
Wunk
e23d61d124
backend/arm64: Add MSVC C++ ABI devirtualization (#718)
MSVC C++ uses a non-standard ABI definition that must be specially
handled:
https://rants.vastheman.com/2021/09/21/msvc
2022-11-15 20:22:47 +00:00
Merry
dd36a52048 externals: Update oaknut to 1.1.3
Merge commit 'cb8abc3ae5a1fcd3d7b6ab73472cdf9093302631'
2022-11-15 15:37:16 +00:00
Merry
cb8abc3ae5 Squashed 'externals/oaknut/' changes from c0c715505..72f7ccd94
72f7ccd94 oaknut: 1.1.3
0b5745e4e oaknut: Add Windows on Arm support (#1)
5de40335d oaknut: 1.1.2
2952b759f oaknut: Correct MOV (UMOV alias)
c90eb31ca oaknut: 1.1.1
7c777a28f oaknut: Fix ADR and ADRP
7470c7611 oaknut: Add ARMv8.2 instructions
9eb7cca88 oaknut: Update README
3fe32849a oaknut: 1.1.0
542128b51 oaknut: Add ARMv8.1 instructions
9acafdcdd oaknut: fpsimd MOV and UMOV corrections
636f91bac oaknut: MOV: Fix MOVN case
9cb332621 oaknut: Implement arranged accessors from DReg and QReg
ba2dc2afe oaknut: dx
94bf56b08 oaknut: align
aa7a3519f oaknut: Add dw
898f666ec oaknut: Add common system registers

git-subtree-dir: externals/oaknut
git-subtree-split: 72f7ccd9409dadf6a4ab98bad1fb11fbf0ca4d74
2022-11-15 15:36:04 +00:00
Merry
068519b2cd a32_interface: Clear cache invalidation flag prior to performing cache invalidation 2022-11-13 15:38:42 +00:00
Merry
9d6758b4ae emit_arm64: Fix 1MB block link limit 2022-11-11 23:57:07 +00:00
Liam
424fdb5c50 a64_interface: stub for A64 backend 2022-11-09 21:55:11 +00:00
Merry
5f753e483f test_generator: Allow rerunning jit 2022-11-08 21:40:45 +00:00
Merry
d6f2a15834 backend/arm64: Simple block linking 2022-11-08 21:40:45 +00:00
Merry
fa6b58d3a8 emit_arm64: EmitAddCycles: Do not emit code if cycles_to_add == 0 2022-11-08 21:40:45 +00:00
Merry
7dbd87ba2d backend/arm64/a32_address_space: Terminate early if halted prior to execution beginning 2022-11-08 21:40:45 +00:00
Liam
282bd3ad5c a32_interface: fix copy paste error 2022-11-06 21:24:05 +00:00
Merry
e476fad5a2 backend/arm64: Implement cycle counting 2022-11-06 01:10:29 +00:00
SachinVin
b5ad066372
backend/arm64: Properly return halt reason (#713) 2022-11-05 19:32:48 +00:00
Merry
848e0913df decoder_detail: Fix Android NDK compilation issue 2022-11-05 19:25:12 +00:00
Banny
4b80be4bd9
backend/arm64/a32_address_space: Protect code memory at end of prologue emission (#712)
Bug fix
2022-10-23 23:04:10 +01:00
Macdu
f374d6acb0 FPVectorFromHalf32 implementation 2022-10-18 15:04:30 +01:00
Macdu
58a1e4cc63 Implement CallHostFunction 2022-10-18 15:04:30 +01:00
Macdu
79ff9401f3 Small fixes 2022-10-18 15:04:30 +01:00
FreddyFunk
64a5ca7c2e tests: remove unused default iterations in TestThumb 2022-10-18 15:04:30 +01:00
Merry
85fa32ce98 github: Run unit tests for aarch64 2022-10-18 15:04:30 +01:00
Merry
1d60047078 a32_interface: Temporary implementation of ranged cache invalidation 2022-10-18 15:04:30 +01:00
Merry
d90e0db502 backend/arm64: Implement Step 2022-10-18 15:04:30 +01:00
Merry
cf47ab3b42 emit_arm64_a32_memory: Implement all callbacks 2022-10-18 15:04:30 +01:00
Merry
d2deb496da tests/A32: Add coprocessor tests 2022-10-18 15:04:30 +01:00
Merry
94f5ae4f37 emit_arm64_a32_coprocessor: Implement coprocessor IR instructions 2022-10-18 15:04:30 +01:00
Merry
0f0744cb78 emit_arm64_a32: Implement A32CallSupervisor and A32ExceptionRaised 2022-10-18 15:04:30 +01:00
Merry
882490b372 frontend: Fix MSVC narrowing conversion warning for VectorSignedSaturatedShiftLeftUnsigned argument 2022-10-18 15:04:30 +01:00
Merry
f4747aea10 test_generator: Increase iterations 2022-10-18 15:04:30 +01:00
Merry
806a50703b test_generator: Test ASIMD 2022-10-18 15:04:30 +01:00
Merry
2532cfba4d emit_arm64_vector_floating_point: Implement 2022-10-18 15:04:30 +01:00
Merry
1badc92456 emit_arm64_cryptography: Fix sha256h2 2022-10-18 15:04:30 +01:00
Merry
d4b98c7be4 emit_arm64_vector: Implement VectorPaired{Max,Min}Lower 2022-10-18 15:04:30 +01:00
Merry
f92cb5e66f IR: Remove VectorShuffleWords
Introduce VectorRotateWholeVectorRight
2022-10-18 15:04:30 +01:00
Merry
8fb37e0e4f IR: Introduce VectorPaired{Min,Max}Lower 2022-10-18 15:04:30 +01:00
Merry
3df0eb30be emit_arm64_vector: Implement Saturated Accumulate 2022-10-18 15:04:30 +01:00
Merry
c5b45dc5d5 emit_arm64_vector: Implement VectorSignedSaturatedShiftLeftUnsigned 2022-10-18 15:04:30 +01:00
Merry
08b123feb5 IR: Modify VectorSignedSaturatedShiftLeftUnsigned to only accept immediate shift amounts 2022-10-18 15:04:30 +01:00
Merry
3216ed3451 emit_arm64_vector: Fix VectorTranspose 2022-10-18 15:04:30 +01:00
Merry
0a5ebd5b57 emit_arm64_vector: Fix VectorTableLookup64 2022-10-18 15:04:30 +01:00
Merry
99d5caa06d A32/asimd_two_regs_misc: Remove use of VectorShuffleWords in VUZP 2022-10-18 15:04:30 +01:00
Merry
4417314619 emit_arm64_vector: Implement VectorReverseElement 2022-10-18 15:04:30 +01:00
Merry
9313f5ea88 IR: Remove VectorShuffleHighHalfwords and VectorShuffleLowHalfwords 2022-10-18 15:04:30 +01:00
Merry
c6667997bc emit_arm64_vector: Implement VectorSignedSaturatedDoublingMultiply{High,HighRounding,Long} 2022-10-18 15:04:30 +01:00
Merry
600f8e29c1 emit_arm64_cryptography: Implement most 2022-10-18 15:04:30 +01:00
Merry
a97105c296 IR: Split VectorSignedSaturatedDoublingMultiply into VectorSignedSaturatedDoublingMultiply{High,HighRounding} 2022-10-18 15:04:30 +01:00
Merry
aaf7c41ab3 emit_arm64_vector_saturation: Implement all 2022-10-18 15:04:30 +01:00
Merry
6306e3462e emit_arm64_vector: Implement most IR insturctions 2022-10-18 15:04:30 +01:00
Merry
61d509dda2 IR: Add VectorMultiply{Signed,Unsigned}Widen instructions
Polyfill for x86-64 backend
2022-10-18 15:04:30 +01:00
Merry
bbf0179d30 test_generator: Enable vfp testing 2022-10-18 15:04:30 +01:00
Merry
11c02e5a62 backend/arm64/fpsr_manager: Bugfixes 2022-10-18 15:04:30 +01:00
Merry
2ab0e64be4 backend/arm64/reg_alloc: Update uses on all locations
Trying to optimize just for args is incorrect when inst has zero uses
2022-10-18 15:04:30 +01:00
Merry
2c75ca746b backend/arm64/stack_layout: Remove unused variable 2022-10-18 15:04:30 +01:00
Merry
72357aba04 emit_arm64_vector: Implement VectorBroadcast 2022-10-18 15:04:30 +01:00
Merry
3c3f30c0ac emit_arm64_vector: Implement Vector{Get,Set}Element 2022-10-18 15:04:30 +01:00
Merry
ee6433889e emit_arm64_floating_point: Implement a majority of floating point instructions 2022-10-18 15:04:30 +01:00
Merry
2cc5b09bdf emit_arm64_data_processing: Implement ConditionalSelect 2022-10-18 15:04:30 +01:00
Merry
a4a665148c emit_arm64_a32: Get/Set ext_reg state 2022-10-18 15:04:30 +01:00
Merry
0288540155 backend/arm64/reg_alloc: Implement ReadWrite mode 2022-10-18 15:04:30 +01:00
Merry
208b19b89a backend/arm64: FPCR/FPSR handling 2022-10-18 15:04:30 +01:00
Merry
60a119da6a backend: Implement FpsrManager 2022-10-18 15:04:30 +01:00
Merry
72026c91b5 oaknut: fpsimd MOV and UMOV corrections 2022-10-18 15:04:30 +01:00
Merry
3b98af5810 test_generator: Generate Arm instructions 2022-10-18 15:04:30 +01:00
Merry
2ac12562ab emit_arm64: Handle cond prologue 2022-10-18 15:04:30 +01:00
Merry
aa6b31f2b8 emit_arm64: Handle 64-bit values in GetNZFromOp 2022-10-18 15:04:30 +01:00
Merry
5086432f19 a32_emit_x64: EmitA32SetCpsr: Correct cpsr_jaifm mask 2022-10-18 15:04:30 +01:00
Merry
23c23fbca3 arm64/reg_alloc: Bugfix in ValueInfo 2022-10-18 15:04:30 +01:00
Merry
6dfd94f3fb arm64/reg_alloc: Ban materialization of U1 constants 2022-10-18 15:04:30 +01:00
Merry
73b48448cb emit_arm64_data_processing: Handle immediate carry in for shift instructions 2022-10-18 15:04:30 +01:00
Merry
db5db43fd4 emit_arm64_a32: A32SetCpsrNZC: Handle immediate 2022-10-18 15:04:30 +01:00
Merry
65a7d9be8d emit_arm64_a32: A32SetCheckBit: Handle immediate 2022-10-18 15:04:30 +01:00
Merry
49589168c9 oaknut: MOV: Fix MOVN case 2022-10-18 15:04:30 +01:00
Merry
8649345886 emit_arm64_cryptography: Implement CRC 2022-10-18 15:04:30 +01:00
Merry
f84e489969 test_generator: Expand testing to thumb32 2022-10-18 15:04:30 +01:00
Merry
6d6cbe2e66 emit_arm64_saturation: Fix UnsignedSaturation for < 0 2022-10-18 15:04:30 +01:00
Merry
b059384bc0 emit_arm64_saturation: Implement SignedSaturatedSubWithFlag32 2022-10-18 15:04:30 +01:00
Merry
090e79add2 emit_arm64_data_processing: Implement CountLeadingZeros 2022-10-18 15:04:30 +01:00
Merry
e921c397ac emit_arm64_data_processing: Fix BitImms for exceptional immediates 2022-10-18 15:04:30 +01:00
Merry
f642f49b93 emit_arm64_data_processing: Implement RotateRightExtended 2022-10-18 15:04:30 +01:00
Merry
22d87bcbe5 emit_arm64_a32: Implement A32SetGEFlagsCompressed 2022-10-18 15:04:30 +01:00
Merry
735f5b787a emit_arm64_a32: Fix A32SetCpsrNZC for immediate carry 2022-10-18 15:04:30 +01:00
Merry
33b3376fb1 emit_arm64_a32: Implement A32SetCpsrNZCVRaw, A32SetCpsrNZCVQ 2022-10-18 15:04:30 +01:00
Merry
11b665c027 emit_arm64_a32: Implement A32SetCpsr (temporary implementation) 2022-10-18 15:04:30 +01:00
Merry
950400fb6b arm64/a32_jitstate: Adjust structure 2022-10-18 15:04:30 +01:00
Merry
726e116e28 emit_arm64_saturation: Implement SignedSaturatedAddWithFlag32 2022-10-18 15:04:30 +01:00
Merry
babfb7d7b8 IR/saturation: Revamp saturated add/sub IR instructions 2022-10-18 15:04:30 +01:00
Merry
2d0bf7ca9b emit_arm64_data_processing: Implement overflow output for Add 2022-10-18 15:04:30 +01:00
Merry
adb18fd0a7 emit_arm64_data_processing: Implement LogicalShift{Left,Right}64 2022-10-18 15:04:30 +01:00
Merry
0692f1d40e emit_arm64_data_processing: EmitAddSub: Handle zero immediate w/ flag output 2022-10-18 15:04:30 +01:00
Merry
cd537dc711 IR: Rename PackedAbsDiffSumS8 to PackedAbsDiffSumU8 2022-10-18 15:04:30 +01:00
Merry
ee2bc92993 emit_arm64_saturation: Implement SignedSaturation 2022-10-18 15:04:30 +01:00
Merry
e73c390927 emit_arm64_packed: Fix signed packed add sub 2022-10-18 15:04:30 +01:00
Merry
c8b3be5512 emit_arm64_data_processing: Implement Div 2022-10-18 15:04:30 +01:00
Merry
a320a333e1 emit_arm64_packed: Implement PackedAbsDiffSumS8 2022-10-18 15:04:30 +01:00
Merry
0ebbc4a9c5 emit_arm64_packed: Implement PackedSelect 2022-10-18 15:04:30 +01:00
Merry
ac7908164a emit_arm64_packed: Implement packed halving operations 2022-10-18 15:04:30 +01:00
Merry
d1909c5efb emit_arm64_packed: Implement halving add sub exchange 2022-10-18 15:04:30 +01:00
Merry
ff34f4c6ae emit_arm64_data_processing: Fix flag reading in AddSub
Also improve codegen for ZR case.
2022-10-18 15:04:30 +01:00
Merry
aaa0773695 emit_arm64_data_processing: Add carry output to MostSignificantWord 2022-10-18 15:04:30 +01:00
Merry
5c54c7d968 emit_arm64_packed: Implement packed add sub exchange 2022-10-18 15:04:30 +01:00
Merry
0bd7601844 emit_arm64_packed: Implement PackedSubU16 2022-10-18 15:04:30 +01:00
Merry
1810bd6547 emit_arm64_packed: Implement PackedSubU16 2022-10-18 15:04:30 +01:00
Merry
fb6ac45259 emit_arm64_packed: Implement PackedSubS8 2022-10-18 15:04:30 +01:00
Merry
2076495d9e emit_arm64_packed: Implement PackedSubU8 2022-10-18 15:04:30 +01:00
Merry
0b53290dd7 emit_arm64_a32: Implement A32GetCpsr 2022-10-18 15:04:30 +01:00
Merry
8a0359ec52 emit_arm64_a32: Implement barriers 2022-10-18 15:04:30 +01:00
Merry
a7f675864b emit_arm64_packed: Implement all saturated packed operations 2022-10-18 15:04:30 +01:00
Merry
7aeaa46a0b emit_arm64_packed: Implement PackedAddS16 2022-10-18 15:04:30 +01:00
Merry
66858c99b8 emit_arm64_packed: Implement PackedAddU16 2022-10-18 15:04:30 +01:00
Merry
179137be5a emit_arm64_saturation: Implement UnsignedSaturation 2022-10-18 15:04:30 +01:00
Merry
02d3a5a242 emit_arm64_a32: Implement A32OrQFlag 2022-10-18 15:04:30 +01:00
Merry
a50eb6cf34 emit_arm64_packed: Implement PackedAddS8 2022-10-18 15:04:30 +01:00
Merry
619adce84f emit_arm64_packed: Implement PackedAddU8 2022-10-18 15:04:30 +01:00
Merry
8f1f1c8f0b emit_arm64_packed: Implement {Get,Set}GEFlags 2022-10-18 15:04:30 +01:00
Merry
2dce8ea5a8 emit_arm64_data_processing: Fix MostSignificantWord 2022-10-18 15:04:30 +01:00
Merry
9b09acee47 oaknut: Implement arranged accessors from DReg and QReg 2022-10-18 15:04:30 +01:00
Merry
3d420e34ae emit_arm64_data_processing: Fix LogicalShiftRight32 for immediate shift = 32 2022-10-18 15:04:30 +01:00
Merry
78e266a869 test_generator: Increase iterations 2022-10-18 15:04:30 +01:00
Merry
a5f3164c38 backend/arm64/reg_alloc: Handle immediates in DefineAsExisting 2022-10-18 15:04:30 +01:00
Merry
277f7a76e9 arm64: Stub PushRSB 2022-10-18 15:04:30 +01:00
Merry
ef137dd8b9 emit_arm64_data_processing: Correct ArithmeticShiftRight32 2022-10-18 15:04:30 +01:00
Merry
70d9137859 backend/arm64/reg_alloc: Handle immediates in PrepareForCall 2022-10-18 15:04:30 +01:00
Merry
187f89951d emit_arm64_data_processing: Implement Mul 2022-10-18 15:04:30 +01:00
Merry
bf55920ce9 backend/arm64/reg_alloc: Support multiple locks on a location 2022-10-18 15:04:30 +01:00
Merry
6bcfaee1f4 emit_arm64_data_processing: Implement LogicalShiftRight32 2022-10-18 15:04:30 +01:00
Merry
7840caef6e emit_arm64_data_processing: Fix bug in EmitBitOp 2022-10-18 15:04:30 +01:00
Merry
02cfbb8b0b backend/arm64/reg_alloc: Generate immediates when required 2022-10-18 15:04:30 +01:00
Merry
bdb41be0c5 emit_arm64_data_processing: Implement ZeroExtend 2022-10-18 15:04:30 +01:00
Merry
7ed217ff77 emit_arm64_data_processing: Implement SignExtend 2022-10-18 15:04:30 +01:00
Merry
777d9a1045 emit_arm64_data_processing: Implement ByteReverse 2022-10-18 15:04:30 +01:00
Merry
156bcecb02 emit_arm64_data_processing: Implement ArithmeticShiftRight32 2022-10-18 15:04:30 +01:00
Merry
a6e761daa9 emit_arm64_a32: Fix CheckBit 2022-10-18 15:04:30 +01:00
Merry
95ae21bd41 backend/arm64: Fix Sub 2022-10-18 15:04:30 +01:00
Merry
46f4063952 backend/arm64: Implement Not 2022-10-18 15:04:30 +01:00
Merry
6ad7758165 backend/arm64: Implement AndNot 2022-10-18 15:04:30 +01:00
Merry
fcd2bd600e backend/arm64: Implement Or 2022-10-18 15:04:30 +01:00
Merry
4cff0d9977 backend/arm64: Implement Eor 2022-10-18 15:04:30 +01:00
Merry
4e3fd70f6e backend/arm64: Implement And64 2022-10-18 15:04:30 +01:00
Merry
32e54481e7 github: Test arm64 backend 2022-10-18 15:04:30 +01:00
Merry
129af4f6b4 backend/arm64: Implement A32SetCpsrNZ 2022-10-18 15:04:30 +01:00
Merry
7056913b6b backend/arm64: Implement And32 2022-10-18 15:04:30 +01:00
Merry
f97b520221 backend/arm64: Implement RotateRight32 2022-10-18 15:04:30 +01:00
Merry
6885f9a6d8 backend/arm64: Invalidation fixes 2022-10-18 15:04:30 +01:00
Merry
eaf87ec1e4 backend/arm64: Simple implementation of memory read/write 2022-10-18 15:04:30 +01:00
Merry
77634509b5 arm64/abi: Deduplicate register code 2022-10-18 15:04:30 +01:00
Merry
f3bf27c816 backend/arm64: Implement Devirtualize 2022-10-18 15:04:30 +01:00
Merry
6239eb5eb6 oaknut: dx 2022-10-18 15:04:30 +01:00
Merry
9a35946aec oaknut: align 2022-10-18 15:04:30 +01:00
Merry
2e72d69268 backend/arm64: ABI 2022-10-18 15:04:30 +01:00
Merry
e1ad7ef482 oaknut: Add dw 2022-10-18 15:04:30 +01:00
Merry
f74a5f262f backend/arm64/reg_alloc: RAReg is non-copyable and non-moveable 2022-10-18 15:04:30 +01:00
Merry
3a3b43b963 backend/arm64: Implement A32ClearExclusive 2022-10-18 15:04:30 +01:00
Merry
9bdff6a9aa constant_propagation_pass: Shift with non-zero value does not require c flag as input 2022-10-18 15:04:30 +01:00
Merry
5a864f41c6 backend/arm64/reg_alloc: Implement DefineAsRegister 2022-10-18 15:04:30 +01:00
Merry
16701ae6d5 backend/arm64/reg_alloc: Use NZCV instead of magic numbers 2022-10-18 15:04:30 +01:00
Merry
ba00b3586c oaknut: Add common system registers 2022-10-18 15:04:30 +01:00
Merry
c2ff75e29c backend/arm64: Implement Sub 2022-10-18 15:04:30 +01:00
Merry
8ac57bd6ed backend/arm64/reg_alloc: Assert on bad RAReg 2022-10-18 15:04:30 +01:00
Merry
78bc0812b9 backend/arm64/reg_alloc: More flag handling 2022-10-18 15:04:30 +01:00
Merry
21601764de backend/arm64: Implement Add 2022-10-18 15:04:30 +01:00
Merry
679efb9c44 backend/arm64: Implement A32SetCpsrNZCV 2022-10-18 15:04:30 +01:00
Merry
67df13f886 backend/arm64: Update for new C flag representation 2022-10-18 15:04:30 +01:00
Merry
d69582f548 backend/arm64/reg_alloc: Tidy up HostLocInfo 2022-10-18 15:04:30 +01:00
Merry
01f28facbd abi: Add Rscratch{0,1} 2022-10-18 15:04:30 +01:00
Merry
8b41755db0 ir_emitter: Remove unused ResultAndCarryAndOverflow structure 2022-10-18 15:04:30 +01:00
Merry
b6bb94872a backend/arm64: Implement IsZero64 2022-10-18 15:04:30 +01:00
Merry
3821c4a16b backend/arm64: Implement MostSignificantWord 2022-10-18 15:04:30 +01:00
Merry
ec3c597591 backend/arm64: Implement LeastSignificantByte 2022-10-18 15:04:30 +01:00
Merry
a33d186fea backend/arm64: Implement LeastSignificantHalf 2022-10-18 15:04:30 +01:00
Merry
163ed9b185 backend/arm64: Implement LeastSignificantWord 2022-10-18 15:04:30 +01:00
Merry
7c86b06233 backend/arm64: Implement Pack2x64To1x128 2022-10-18 15:04:30 +01:00
Merry
98806139a5 backend/arm64/reg_alloc: Argument HostLoc location 2022-10-18 15:04:30 +01:00
Merry
fe4e864e4c backend/arm64: Implement Pack2x32To1x64 2022-10-18 15:04:30 +01:00
Merry
ff9b92c791 backend/arm64: Implement NZCVFromPackedFlags 2022-10-18 15:04:30 +01:00
Merry
7ea97f7629 backend/arm64: Implement GetLowerFromOp 2022-10-18 15:04:30 +01:00
Merry
92026a456a backend/arm64: Implement GetUpperFromOp 2022-10-18 15:04:30 +01:00
Merry
8c4ea10a38 backend/arm64: Implement GetNZCVFromOp 2022-10-18 15:04:30 +01:00
Merry
e34749336a backend/arm64: Implement GetGEFromOp 2022-10-18 15:04:30 +01:00
Merry
fbcbc1d90d backend/arm64: Implement GetOverflowFromOp 2022-10-18 15:04:30 +01:00
Merry
fb3b828158 backend/arm64: Implement Identity 2022-10-18 15:04:30 +01:00
Merry
97ba8a0f14 backend/arm64: Implement Void 2022-10-18 15:04:30 +01:00
Merry
2a24bb2c1e backend/arm64: Implement Breakpoint 2022-10-18 15:04:30 +01:00
Merry
3a11467220 backend/arm64: Stub all IR instruction implementations 2022-10-18 15:04:30 +01:00
Merry
402abf5ea3 backend/arm64: Implement A32GetExtendedRegister 2022-10-18 15:04:30 +01:00
Merry
84cad9f831 backend/arm64: Implement A32SetCheckBit 2022-10-18 15:04:30 +01:00
Merry
3e5309bd96 tests: Add test generator 2022-10-18 15:04:30 +01:00
Merry
52a46d841b backend/arm64: Implement A32BXWritePC 2022-10-18 15:04:30 +01:00
Merry
67dc7f2e4e backend/arm64: Implement A32UpdateUpperLocationDescriptor 2022-10-18 15:04:30 +01:00
Merry
00ad84b7ab backend/arm64: Initial implementation of terminals 2022-10-18 15:04:30 +01:00
Merry
80c89401b9 a32_address_space: Add StackLayout to stack 2022-10-18 15:04:30 +01:00
Merry
9b2391ec7b backend/arm64/reg_alloc: Implement AssertNoMoreUses 2022-10-18 15:04:30 +01:00
Merry
ecacb6cdc6 tests/rand_int: Expose PRNG 2022-10-18 15:04:30 +01:00
Merry
8e6467bf45 backend/arm64/reg_alloc: Add flag handling 2022-10-18 15:04:30 +01:00
Merry
77436bbbbb backend/arm64: Toy implementation of enough to execute LSLS 2022-10-18 15:04:30 +01:00
Merry
7e046357ff backend/arm64: Initial implementation of register allocator 2022-10-18 15:04:30 +01:00
Merry
3bf2b0aba9 backend/arm64: Adjust how relocations are stored 2022-10-18 15:04:30 +01:00
Merry
e0f091b6a6 backend/arm64: void* -> CodePtr 2022-10-18 15:04:30 +01:00
Merry
f6e80f1e0e backend/arm64: First dummy code execution 2022-10-18 15:04:30 +01:00
Merry
d877777c50 backend/arm64: Initial framework 2022-10-18 15:04:30 +01:00
Merry
e7b2eb2c7c Add aarch64 CI 2022-10-18 15:04:30 +01:00
Wunkolo
e886bfb7c1 backend/x64: Fix FixupLUT argument order
The last two arguments(fixup response response for finite values) are
neg-pos, not pos-neg. Found this out while re-using this function for
some math stuff. Thankfully nothing currently uses this fixup response
at the moment.
2022-09-30 23:10:21 +01:00
Merry
af51845a53 decoder_detail: Workaround #708 2022-09-02 21:16:43 +01:00
Bart Ribbers
e49fee0ca1 block_of_code: rename PAGE_SIZE to DYNARMIC_PAGE_SIZE to prevent use of reserved name
PAGE_SIZE is a kernel symbol and depending on the libc in use, it will
"leak". In this case dynarmic was using it's own PAGE_SIZE and in
combination with the Musl libc the compiler would complain it was overwriting
the kernel symbol
2022-08-25 23:32:18 +01:00
Merry
bf422a190a decoder_detail: Simplify DYNARMIC_DECODER_GET_MATCHER 2022-08-21 18:22:14 +01:00
GPUCode
a62dc19605 cmake: Bump minimum required cmake version
Version 3.12 is the minimum that supports the value of 20 for CMAKE_CXX_STANDARD. Also remove /std:c++latest to get rid of compiler logspam
2022-08-15 21:00:01 +01:00
merry
3cb939e70b fuzz_arm: Avoid backwards jumps that may jump into code 2022-08-08 21:05:00 +01:00
Merry
c60fd3f0ac block_of_code: Fix running under Rosetta
Rosetta doesn't have accurate emulation of the sahf instruction
2022-08-05 23:43:01 +01:00
Merry
a38966a874 block_of_code: Extract flag loading into a function
LoadRequiredFlagsForCondFromRax
2022-08-05 23:42:19 +01:00
Merry
d7bd5bb7a7 emit_x64: Use movzx(eax, ah) instead of emitting byte equivalent
Emission fixed in xbyak v6.61
2022-07-31 17:52:35 +01:00
Merry
8f890d327a externals: Update xbyak to 6.61
Merge commit '5b6e3d8b54e428fceedd907cf5c0f52ca98eb003'
2022-07-31 17:50:57 +01:00
Merry
5b6e3d8b54 Squashed 'externals/xbyak/' changes from 913099fc8..88f2f771f
88f2f771f Merge branch 'dev'
8623616e0 v6.61
1b911598d mingw uses __thread instead of __declspec(thread)
d224701f4 fix movzx eax, ah on 64bit and test it
1c35e34ab Merge branch 'dev'
4fb0e58aa test of cpuid
913c798ff update doc
8f6dee319 v6.60.2
21419721e Merge branch 'Wunkolo-standalone-cpuid' into dev
1b2e7c7da Fix detection of `GFNI`,`VAES`, and `VPCLMULQDQ`

git-subtree-dir: externals/xbyak
git-subtree-split: 88f2f771f179a3d856ecd0b07a20598bd06ba21d
2022-07-31 17:50:57 +01:00
Merry
f33c6f062b Revert "block_of_code: Refactor MConst to Xmm{B}Const"
This reverts commit 5d9b720189a64eec7f35f844320d0b30ca3997f3.

Obscure bugs resulting from this commit due to assumptions regarding zero-extension of higher bits.
2022-07-27 20:31:08 +01:00
Merry
fbdcfeab99 emit_x64_packed: Do not use XmmBConst here
Broadcasting is inappropriate
2022-07-27 20:14:49 +01:00
Merry
2d4602a651 6.2.3 2022-07-26 13:06:05 +01:00
Merry
b002419993 tests/{a32,a64}_unicorn: Avoid use of deprecated fmt API 2022-07-26 12:04:52 +01:00
Merry
64e6546827 github: Rename build-and-test to x86-64
Prepare for non x64 backends
2022-07-26 11:50:45 +01:00
Merry
35b1da4b1f 6.2.2 2022-07-26 11:21:37 +01:00
Merry
1f51dceb60 Update for fmt 9.0.0 2022-07-26 11:20:47 +01:00
Merry
764b5fdb76 externals: Update fmt to 9.0.0
Merge commit 'a7f9129f18b171ecec9533921ba32449b3c394ac'
2022-07-26 10:51:24 +01:00
Merry
a7f9129f18 Squashed 'externals/fmt/' changes from b6f4ceaed..c4ee72653
c4ee72653 Update version
fa2eb2d2e Bump version
35f72bf21 Bump version
d22f00d7e Update changelog
4e8d21560 Update changelog
84eecb656 Prune CI configs
55727e3b2 More compile-time checks
1010b7f14 Update docs
2ac51fc44 Update changelog
831132293 Workaround for Microsoft Visual Studio 2022 Internal compiler error.
115e00e0b Replace __cplusplus with FMT_CPLUSPLUS.
94114b05c New CI: Microsoft Visual Studio 2022.
d2a232082 Fix partial specialization problem for filesystem for Visual Studio (#2957)
0c06c81da Deprecated implicit conversion of enums to ints for consistency with scoped enums
c12b4c0cf New CI: GCC-8 C++17, Clang-8 C++17.
99bb5b1d1 Fix std::variant, std::filesystem::path tests on GCC-8, Clang-7,8.
e29c2bc60 Update docs
c65e4286b Update changelog
69c24e47e Update changelog
6a775e956 Add support for 'std::variant' in C++17 (#2941)
51535866d Update docs
3ef5caa9f Update docs
dccd3e674 Fix docs
9cb02aaaa Fix UDLs
e6d478f8e Update changelog and docs
2d931b149 Add fmt::streamed
0506a5733 Update changelog
e8bd2a804 Fix enable_ifs for map formatter (#2944)
7c56e11ec Update changelog
69a20db08 Update changelog and fix an apidoc comment
7a2a97c88 Update changelog
568233889 Fix is_formattable for tuple-like types. (#2940)
f0de12844 Remove /source-charset:utf-8 compile option.
eaa8efb95 Fix ofstream handling in msvc
fb991e9d3 Update changelog
8e47cfd1c fix -Wsign-conversion warning
247187586 Make the tests pass on a CHERI system.
b135f1c01 Refactor handling of argument types
f61a1e813 Add format_arg_types
48b7e3daf Added a FMT_STRING wrapper for system_error() call.
4bb3af7a6 Improve compile-time checks
d02c582b9 Fix 'duplicate symbol' error.
b59d8c3a2 Make std::filesystem::path formatter utf-8 compatible.
232e21d51 Add utf-8 test for std::filesystem::path formatter.
864465419 Docs: add comment about empty format context range
ba50c19e8 use qualified call to avoid ADL conflict with std::format_to
9d6039595 Fix compilation on ppc64
a2681aabc Debug ppc failure
bfc576736 Add support for std.h in Bazel build
798d09bb7 Debug ppc failure
8c7cf5139 Cleanup
cdfacb434 Cleanup parse_format_string
926ddd063 Move compile string to detail
cb682f36f Move to_string_view to detail
156744ad4 Simplify fmt::runtime
d9c7166cf bi_iterator -> base
11316b29a chore: Set permissions for GitHub actions
fe6eb792d Cleanup check_format_string
054b1d980 Remove unused include
e927149f8 Cleanup macros
1761e2666 Remove FMT_CONSTEXPR_DECL
d6b568a6c Cleanup string_view checks
c83a5d42b FMT_MSC_VER -> FMT_MSC_VERSION
27cd68c30 Cleanup macros
08be4abb3 Remove FMT_NVCOMPILER_VERSION
661b19254 Remove FMT_HEADER_ONLY_CONSTEXPR20
d1026fa5d Remove extern format_float
7e63b600b Make to_string work with __float128
b2ea212cd Update README.rst
c2fcdc54e Move format_float to format.h for __float128
2b9037a19 Move basic_fp to format.h for compile-time formatting
542785ccb Get rid of detail::bits
65dd2ea52 Use write_escaped_string to std::filesystem::path.
9860f67cd Improve xchar support for std formatters.
03b1b2838 Improve std::filesystem::path formatter.
4f9311e68 Fix definition of error_handler::on_error
652fea45a Visual Studio 2022: fmt/format.h(1526,27): warning C4127: conditional expression is constant #2908
1f9eae7e3 Add xchar support for write_escaped_string.
90b68783f Skip cmake targets inclusion if fmt::fmt already exists (#2907)
ce246aaf7 Remove deprecated APIs
edeb3d809 Remove deprecated APIs
496aff7c3 Remove deprecated APIs
f5cdf7cb0 Simplify snprintf_float
440512f08 Remove deprecated APIs
621eb80bb Remove deprecated APIs
5c7d315de Remove locale.h
c6324009b Add initial double-double support
147e8ca58 Fix Windows max mix-up (#2903)
6bf039d75 Add std:🧵:id formatter
9730fb015 Fix path formatter
f0903ad9d Add a path formatter
8833f386e Merge branch 'master' of github.com:fmtlib/fmt
5ab9d3925 Namespace-qualify format_to to avoid conflict with std::format_to
af5644c27 Update README.rst
3e28dc021 VS2022 17.2: C4189: 'zero': local variable is initialized but not referenced #2891 (#2892)
f6f920a1a Tweak a comment and apply clang-format
ae963e444 Implement constexpr isfinite to avoid producing NaN
358f5a7e5 Make precision computation consistent with width
f63afd161 Fixed all clang -Wsigned-enum-bitfield warnings (#2882)
7e4ad4017 Add initial support for double-double
ffb5e6a73 Suppress a -Wliteral-range warning on Apple M1 (#2861)
5d804ee7f Fix handling of subnormals in exotic FP
86e27ccb4 Suppress a warning
192f79aaa Fix handling of locale separators in FP formatting
395cf0f03 Fix detection of unformattable pointers
fc429d18b Avoid overhead on sensible platforms
ce7ecdb7a Replace conditional compilation with SFINAE
8751a03a0 Fix Unicode handling when writing to an ostream
c55175a58 Add an issue template
a935ac3e6 MSVC CMake generation optimization (#2852)
22d31b31f Add a __float128 test
f607e3e97 Add __float128 support
686de5888 Implement 128-bit constant mul in bigint
02eb215f2 Replace uint128_wrapper with uint128_fallback
b4dc7a1d3 Add 128-bit operations to bigint
ef54f9aa3 Suppress -Wfloat-equal
288c3b928 Remove dead code in ostream.h format_value
96930161f Implement 128-bit operator+= for uint128_fallback
b41890c1e Make arg_mapper SFINAE-friendly again
e2408f37c Check if formatter is not defined if there is format_as
db5b8993a Fix formatting of std::byte via format_as
1c83eaf75 Fix incompatible between Jinja2 >= 3.1 and sphinx 3.3.0
5379063b5 Fixed clang -Wreserved-identifier warings
b591fc87d Fixed all clang -Wreserved-id-macro warnings (on macOS at least)
17dda5839 constexpr -> const for portability
7ffe87c0b Fix docs
3c4273dd0 Simplify UDL
36d95c9fc Fix docs
44abd1f48 Update signatures in docs and ostream.h
db745986f Workaround broken std::numeric_limits
8271e43e5 Improve __float128 support and use constexpr
3f9b7433a Improve __float128 support
71778e8b9 Specialize float_info for __float128
f024565c3 Improve exponent handling in Dragon
e7f31f5cd Cleanup format_dragon
3c61799fb Cleanup fuzzing mode
4e39e1308 Remove xchar.h include from ostream.h
ac0d9d5fe Issue #2816: also strip named-arg for the fallback formatter
4ad90578f Fix #2818: diagnose unformattable arguments in unpacked case
17ba99c1d Fix #2817: add compile-time checking to ostream overloads of fmt::print
3d19be282 Fix #2816: strip named argument wrappers for compile-time checking
c076a54a4 Move snprintf_float to format.h
0419d2388 Add FMT_USE_FLOAT128
69396347a Update color.h (#2815)
c51604a0e Reduce the number of configs
587dc9946 Remove windows-2016 env no longer suppported by GA
1f3d44b85 Update std::tm/chrono docs
bc654faf8 Add is_floating_point that works with __float128
26bffce66 Simplify basic_memory_buffer
ed18ca3ea Implement isnan
a204b8dde Add initial __float128 support
b6b003b07 Cleanup test
f2543b0a9 Add initial support for 128-bit floats
72f487562 Simplify float_info
f91f61cd1 Reuse num_significand_bits
9a1beab57 Workaround Windows API garbage
a8fe8becf Fix compilation error for ranges with ADL `begin`/`end` (#2807)
f6bcb25e1 Remove extra dot
b4a4189d0 Fix handling of implicit bit
32d477e5f Add `styled` in documentation (#2805)
0b7c045a2 Simplify _cf
c10fffecd Make _cf visible in the doc build
dcfbe4a77 Document output_file default behavior correctly (#2803)
8c9bc070f Implement styled arguments (#2793)
5bc39d363 Eliminate intel compiler warnings (#2802)
e3d688e79 Fix warning C4251: class fmt::v8::file needs to have dll-interface (#2797)
8d4f3e91b Update docs
0cef1f819 Fixing formatting of certain kinds of ranges of ranges. (#2787)
5c0d65640 Fix apt install
d416a995e Update README.rst
3f67a1247 Update README.rst
cc57e3597 Update godbolt link in the readme (#2789)
86477f7ec Fix size computation
0742606f1 Fix Conversion Warning (#2782)
1ba69fb5a Remove snprintf FP fallback
ea6f0bf0e Minor cleanup
1a18a2f3d Fixing "C4127: conditional expression is constant" Visual Studio 2022 warning in pedantic mode (#2783)
4fcacea35 Parameterized fp on significand type
cf940ae82 Simplify to_decimal
70dc3de05 Update format.h
cbc59ca89 Clear moved from memory buffer
ea3d326c6 Fix clang -Wliteral-range warning (#2779)
aad44f283 Add fmt::enums::format_as
1319719a5 Add underlying_t
af5d8004f Limit Dragonbox to supported FP formats
7b9642096 Remove unused include
a0b43bfae Add support for 96-bit long double
2c8cd2db3 Fix handling of zero precision
b6d56170f Remove unnecessary inline
05432e570 Use consistent indentation
47da218cc Remove uintptr_fallback
4ddab8901 Merge accumulator into int128_fallback
d38f72aff Refactor fallback ints
15c2a3bac int128_t -> int128_opt
532a69a63 Fix handling of 96-bit long double with -m32
d8e1dd4ab improve installing headers
ae25f7968 add ability to build Apple framework using CMAKE_FRAMEWORK
ce93a66df Implement a fallback uint128_t
6a1346405 Include 128-bit with other signed integers in specifier check
70de324aa Apply 2746 fix for NVidia compiler also (#2770)
a1ea3e015 Move built-in formatter specialization to core
161059dd9 Add support for extended precision FP
c4c6b42de Bump version
21785040c Fix markup
2b6f7fc7a Add partial support for extended precision FP
0a24a0714 Clz builtin may be not constexpr (Issue #2761) (#2762)
ba6f89c76 Update .bazelversion (#2766)
5594edaf6 Address https://github.com/fmtlib/fmt/issues/2763 (#2765)
10e3b83a7 Replace ``make_args_checked`` with ``make_format_args`` (#2760)
c48353cb7 Update docs
083510f0f Add FMT_CONSTEXPR to rotr instead
dba99bc86 Revert adding constexpr to rotr to satisfy C++11 compilers
c04af4bfc Simplify remove_trailing_zeros
b348caa9e Remove some C-style casts for consistency
c8bd1e646 Simplify remove_trailing_zeros
9b23e9dcb Fix wrong comment/refer to a correct reference
69f2c550a Remove std:: infront of uint32_t/64_t & add constexpr to rotr
9b62310f0 Fix some conversion issues
08d12f31d Fix typo
dbddb1d06 Remove literal separator to satisfy some compilers
7dbe3dcde Recover log10_2_significand
10642e608 Optimize remove_trailing_zeros
7b4323e1e Add rotr
f1bd6f773 Check r < deltai first, because that is the major branch chosen for short inputs
5d8eb6a1a Reflect the new paper   - Change constants appearing in log & division computations   - Rename beta_minus_1 to beta
8e2e4d403 Suppress a gcc warning
a44716f58 Workaround to Intel compiler (#2758)
c71b07016 Add missing const qualifier (#2755)
ecd6022c2 Update docs
afbcf1e8e Remove legacy C locale wrapper
90325d097 Fix stored type detection
e2ba01fcb Fix overload ambiguity in print
17b362f78 Simplify ostream opt-in API
a5a7e3a26 Update docs
f055ebbd2 Make ostream operators opt in to reduce the risk of ODR violations
8a21e328b Remove problematic constructibility check
31e743d06 Don't use ostream for types convertible to string_view
35c0286cd Simplify byte handling
c7173a36a Drop :: and fix formatting
3e8372b96 qualify unqualified calls to format in compile.h (#2742)
a34a97cc1 Supporting ? as a string presentation type (#2674)
ae1aaaee5 Fix access mode of files created (#2530) (#2733)
1557ab764 Add format_as for enums
b00a1eac7 Fixes NVIDIA HPC compiler and Intel ICC compatibility (#2732)
a7aecbfca Remove an old mingw workaround
dfcc730cb Making target_compile_options PRIVATE, fix #2726, fix #2507
f7a809be6 Clarify the choice of magic numbers and compute the most magic one
09fde7f4b Add fmt::underlying for enum classes
0014024a2 Don't rely on transitive includes
c28500556 FMT_NOEXCEPT -> noexcept
6240d0201 Improve comments
925b744ae Improve comments
22b14ff25 Simplify cache recovery
3dc26b44d Make a fallback path more compiler-friendly
2e4038bf5 Simplify lines with __builtin_addcll and friends
76336b4f6 Replace noexcept with FMT_NOEXCEPT
918198348 Fix syntax errors
74097a149 Remove now-unused stuffs
21a1c5338 Fix typo
04eea0f0a Remove now-unused stuffs
35a468ed3 Simplify integer checks
1882a7a2c Replace Dragonbox cache which allows simpler cache recovery & integer checks
f4dd1b1b8 Simplify Dragonbox Step 3.
70561ed13 Minimize the usage of built-in 128-bit ints It usually generates slower code than manual handling.
cdf1a3b53 Fix codecvt warning (#2408) (#2725)
b8b037e93 Fix -Wconversion warning  (#2724)
5985f0a7d Fix overflow for chrono durations (#2722)
8f8a1a02d Fix handling of formattable types implicitly convertible to pointers
b02e5af52 fmt::join support FMT_COMPILE (#2720)
58fb78239 Improve docs
4fe6129d6 Fix FMT_NOEXCEPT definition
c056a009d Docs: Fix link to "Compile-time Format String Checks" section (#2712)
7c12118c1 Deprecate buffered_file::fileno
2a09d468d Use noexcept unconditionally
a126b4d88 Check if right shift is arithmetic
9ff91b18c Simplify write_fractional_seconds
d9f045fba Fix a UB in chrono
c06bef727 Adding comments for range formatting. (#2706)
3c98f1a4c Comment style
6e0f1399d Supporting nested format specs for ranges. (#2673)
0102101ac Make colored print handle UTF-8 (#2701)
4ac5269b4 Update ChangeLog.rst

git-subtree-dir: externals/fmt
git-subtree-split: c4ee726532178e556d923372f29163bd206d7732
2022-07-26 10:51:24 +01:00
Merry
82d71b850e a32_emit_x64: Bugfix for A32GetCpsr for non-FastBMI2
Incorrect loading of E and T flags
2022-07-26 10:44:30 +01:00
Merry
a2b3199adf Convert NZCV to C flag where able 2022-07-23 11:46:07 +01:00
Merry
6bcc424e1a emit_x64_vector: Ensure FPSR.QC is set even if output is invalidated 2022-07-20 19:44:39 +01:00
Merry
34cb465fc7 translate_thumb: IsThumb16: Mask not required 2022-07-20 17:34:31 +01:00
Merry
72c87d11e4 a32_get_set_elimination_pass: Correct insertion point 2022-07-20 16:53:48 +01:00
Merry
da2b1c5724 a32_get_set_elimination_pass: Convert NZ to NZC 2022-07-20 16:45:14 +01:00
Merry
6f106602ba a32_get_set_elimination_pass: Add option to disable NZC -> NZ conversion 2022-07-20 16:42:39 +01:00
Merry
52aa68c31c backend/x64: Fixup NZ flag emission 2022-07-20 14:58:28 +01:00
Merry
b97147e187 a32_get_set_elimination_pass: Reduce NZC to 00C 2022-07-20 14:44:33 +01:00
Merry
03dcc3fa50 a32_get_set_elimination_pass: Reduce NZC to NZ where possible 2022-07-20 14:08:41 +01:00
Merry
cf08130f2c A32: Condense flag handling
Remove individual flag handlers, and handle them in chuks where able, to produce more optimal code.
2022-07-19 22:05:13 +01:00
Merry
2e1ab36240 microinstruction: Also track MostSignificantBit and IsZero{32,64} as pseudoops 2022-07-19 22:02:56 +01:00
Merry
ac19912fe7 microinstruction: Optimize storage of associated pseudooperation 2022-07-19 22:02:18 +01:00
Merry
91d1f944e3 6.2.1 2022-07-17 22:42:56 +01:00
Merry
0050a6abe1 github: Add -Wp,-D_GLIBCXX_ASSERTIONS to CXXFLAGS 2022-07-17 22:42:56 +01:00
Merry
51a89dbb7a A64CallbackConfigPass: Ensure IR instructions emitted by this pass have correct location descriptors attached 2022-07-17 22:42:56 +01:00
Merry
4e89756169 Squashed 'externals/oaknut/' changes from c2cb5ec49..c0c715505
c0c715505 oaknut: pragma once

git-subtree-dir: externals/oaknut
git-subtree-split: c0c715505020e69e3acbd959cbfe112083f292b5
2022-07-16 20:28:26 +01:00
Merry
786161b416 externals: Update oaknut
Merge commit '4e8975616946b89c53533549c0d3bab4d0dc9653'
2022-07-16 20:28:26 +01:00
Merry
da5d06c32a backend/x64: Remove unused member halt_requested from StackLayout 2022-07-15 15:19:01 +01:00
Merry
1f0a43753e 6.2.0 2022-07-15 09:30:49 +01:00
Merry
a10070578d README: Update licenses 2022-07-14 22:14:44 +01:00
Merry
e9b550de3a fuzz_arm: Correct unicorn overrun recovery code 2022-07-14 12:30:53 +01:00
Merry
840982be95 block_of_code: Remove far code machinery 2022-07-14 08:58:00 +01:00
Merry
dd60f4b7d8 emit_x64_memory: Use deferred emits 2022-07-14 08:58:00 +01:00
Merry
0d1e4fc4a8 a32_emit_x64: Remove use of far code from EmitTerminalImpl LinkBlock 2022-07-14 08:58:00 +01:00
Merry
36f6114559 emit_x64_vector_floating_point: Use deferred emits 2022-07-14 08:58:00 +01:00
Merry
7d5e078baa emit_x64_floating_point: MSVC fixup 2022-07-14 08:58:00 +01:00
Merry
11ba75b7f0 emit_x64_floating_point: Use deferred emits 2022-07-14 08:58:00 +01:00
Merry
6c38ed8a89 emit_x86: Introduce the concept of deferred emits
Remove the concept of the far code region
2022-07-14 08:58:00 +01:00
Merry
b6ddeeea0f Implement memory aborts 2022-07-13 12:38:03 +01:00
Merry
285e617e35 Revert "frontend: Add option to halt after memory accesses (#682)"
This reverts commit 5ad1d02351bf4fee681a3d701d210b419f41a505.
2022-07-13 12:34:37 +01:00
Merry
04cfab01ba Squashed 'externals/oaknut/' changes from 86f2ca872..c2cb5ec49
c2cb5ec49 github: Faster CI
1ed4284bc code_block: Correct headers

git-subtree-dir: externals/oaknut
git-subtree-split: c2cb5ec49aa4a0748172a6a93df6a0fb17368183
2022-07-12 20:41:36 +01:00
Merry
83f484f190 externals: Update oaknut
Merge commit '04cfab01ba40307ce5421e6dde3598be7eac02bd'
2022-07-12 20:41:36 +01:00
Merry
7016ace72b llvm_disassemble: Add hex output 2022-07-12 19:20:25 +01:00
Merry
e4aeb8c738 Update .gitignore 2022-07-12 16:08:20 +01:00
Merry
9ebf6a8384 6.1.1 2022-07-11 20:59:25 +01:00
Merry
cd85b7fdaa emit_x64: Fix bugs in fast dispatcher
* We failed to invalidate entries if there are no patches required for a location descriptor.
* Bug in A64 hashing code (rbx instead of rbp).
* Bug in A32 and A64 lookup code (inconsistent choice of key: PC vs IR::LocationDescriptor).
* Test case added.
2022-07-11 16:06:54 +01:00
Merry
6243e5a90e externals: Update to mcl 0.1.11
Merge commit '78bb1d1571ec6adb716ddd080bfbfebc6e889d70'
2022-07-10 10:10:22 +01:00
Merry
78bb1d1571 Squashed 'externals/mcl/' changes from 761b7c05e..0172df743
0172df743 CMakeLists: Only add tests if MASTER_PROJECT
52e8dff62 0.1.11
fc8d745cc container: hmap fixups
5b5c0130d memory: Add overaligned_unique_ptr
c7c9bbd17 mcl: Increment version to 0.1.10
678aa32a8 assert: Handle expr strings separately
b38a9d2ef tests: Update to Catch 3.0.1
8aeacfe32 mcl: Increment version to 0.1.9
b468a2ab5 mcl: meta_byte: Split off meta_byte_group
d3ae1ae47 mcl: ihmap: Implement inline variant of hmap
5cbfe6eed mcl: hmap: Split detail into headers
ee7467677 mcl: hmap: Better default hash
f1d902ce9 mcl: hash: Add xmrx
322a221f0 mcl: hmap: Bugfix skip_empty_or_tombstone
689f393f7 mcl: hmap: x64 implementation
fa6ff746a mcl: hmap: Add generic meta_byte_group implementation
91e3073ad mcl: hmap: Add more member functions
4998335a5 mcl: Install only if master project
7ff4d2549 mcl: hmap prototype
416a2c6b5 mcl: clang-format: Adopt WebKit style bracing
d5a46fa70 mcl/assert: Flush stderr
e3b6cc79e externals: Update mcl to 0.1.7
190c68475 mcl: Build as PIC

git-subtree-dir: externals/mcl
git-subtree-split: 0172df74316351868c215f735e5a2538b10d71fb
2022-07-10 10:10:04 +01:00
Merry
501d7ce602 externals: Add oaknut
Merge commit '621367dce8abf82e3924679d72f4da0913cc1520' as 'externals/oaknut'
2022-07-10 09:38:20 +01:00
Merry
621367dce8 Squashed 'externals/oaknut/' content from commit 86f2ca872
git-subtree-dir: externals/oaknut
git-subtree-split: 86f2ca87222e59fb0b89b2f2a6b422a58a2e0892
2022-07-10 09:35:44 +01:00
Merry
6c913e8913 6.1.0 2022-07-07 23:46:59 +01:00
Wunkolo
a5318c775c constant_pool: Use std::span to manage pool
Simplifies some raw pointer arithmetic and type-usage into the new
`ConstantT` type.
2022-07-07 23:46:21 +01:00
Wunkolo
5d9b720189 block_of_code: Refactor MConst to Xmm{B}Const
`MConst` is refactored into `XmmConst` to clearly communicate the
addressable space of the newly allocated 16-byte memory constant.
`GetVectorOf` is elevated into a globally available `XmmBConst` function
that "broadcasts" bits of the input-value into n-bit elements that span
the width of the Xmm-constant.

`emit_x64_floating_point` will utilize the same 16-byte
broadcasted-constants to encourage more cache-hits within the
constant-pool between vector and non-vector code.
2022-07-07 23:46:05 +01:00
Liam
02c8b434c7 interface: allow clear of previously-signaled halt 2022-07-07 23:45:09 +01:00
Merry
ff47d0de72 externals: Remove vixl 2022-06-28 14:43:04 +01:00
Merry
7f84870712 6.0.1 2022-06-22 00:09:43 +01:00
Wunkolo
4d78d167d6 emit_x64_{vector_}floating_point: Add AVX512 implementation for ForceToDefaultNaN
`vfpclassp* k, xmm, i8` has better latency(4->3) and allocates better
execution ports(01->5) that are out of the way of ALU-ports than
`vcmpunordp* xmm, xmm, xmm`(`vcmpp* xmm, xmm, xmm, i8`) and removes the
pipeline dependency on `xmm0` in favor AVX512 `k`-mask registers.

`vblendmp* xmm, k, xmm, mem` is about the same throughput and latency as
`blendvp* xmm. mem` but has the benefit of embedded broadcasts to reduce
memory bandwidth(32/64-bit read rather than 128-bit) and lends itself to
a future size optimization feature of `constant_pool`.
2022-06-22 00:08:49 +01:00
Wunkolo
6367a26e62 emit_x64_{vector_}floating_point: Add AVX512 implementation for DenormalsAreZero
Both single and double precision floating point numbers as well as the
packed and unpacked version of this instruction will be able to use the
same memory constant. This takes advantage of the fact that `VFIXUPIMM*`
doesn't just copy from the source, but it will convert to `0.0` if it
turns out that it is a denormal and the `MXCSR.DAZ` flag is set.

```
tsrc[31:0]←((src1[30:23] = 0) AND (MXCSR.DAZ =1)) ? 0.0 : src1[31:0]
...
CASE(token_response[3:0]) {
    ...
    0001: dest[31:0]←tsrc[31:0]; ; pass through src1 normal input value, denormal as zero
    ...
```
2022-06-22 00:08:14 +01:00
Wunkolo
3ed2aebb20 backend/x64: Update FpFixup constants with denormal behavior
There is an important subtlety that should be documented here. All the
operands of `FpFixup` that read from the `Src` register actually do a
`DAZ` operation if `MXCSR.DAZ` is set.
2022-06-22 00:08:14 +01:00
Merry
94f84cf1ef Version bump to 6.0.0
Version bump to start semantic versioning
2022-06-21 21:44:19 +01:00
Merry
d40557b751 A32/A64: Allow std::nullopt from MemoryReadCode
Raise a fault at runtime if this block is executed
2022-06-21 21:41:27 +01:00
liamwhite
5ad1d02351
frontend: Add option to halt after memory accesses (#682)
Intended to be used for library users wishing implement accurate memory watchpoints.

* A32: optionally make memory instructions the end of basic blocks
* A64: optionally make memory instructions the end of basic blocks
* Make memory halt checking a user configurable
* oops
2022-06-16 18:09:04 +01:00
Merry
9af5f5908c Squashed 'externals/xbyak/' changes from 9357732aa..913099fc8
913099fc8 v6.60.1
d3910abbe update doc
7ac6b37fd Merge branch 'dev'
72c4b8ad5 refactoring
e649372b6 modify definition of Type for Visual Studio with /O0
e9cec7582 Merge branch 'dev'
153b40ed1 update changelog
f0c522af8 v6.60
553246c16 the version format has changed from A.BC(D) to A.BC(.D)

git-subtree-dir: externals/xbyak
git-subtree-split: 913099fc80e80f01fc0877c6016b9dd8cf1f0322
2022-06-16 06:53:34 +01:00
Merry
e99ba06cf3 externals: Update xbyak to 6.60.1
Merge commit '9af5f5908cee0e3d502a79cba26b4cf817d4ad3f'
2022-06-16 06:53:34 +01:00
Merry
11d12d0b84 x64_cpu_info: Update test for latest xbyak 2022-06-05 14:03:57 +01:00
Merry
c926d9f409 Squashed 'externals/xbyak/' changes from 590c10e37..9357732aa
9357732aa v6.06
b161a3eb7 update changelog
e5453b064 Merge branch 'dev'
2a265d9d9 memfd: keep file descriptor open during allocation lifetime
31ff018ed replace unsigned int with uint32_t in xbyak_util.h
e427b2231 move Type into Cpu
8cf41063b refactoring Cpu
66d62968d add -cpuid to test_util
cf7cb744c add comments
028112949 add detection of clzero
c88007b03 update doc
4cb2e77a9 v6.052
015c27cf6 Merge branch 'dev'
d808f9ecb add test of Cpu::has
b48a7bb1b add operator== to Type
1a90f456c v6.051
96cb1d660 update changelog
1f5a77f56 Merge branch 'dev'
87e14f02a add test with noexception
30144f809 fix error when XBYAK_NO_EXCEPTION is defined
ec15751df Merge branch 'dev'
4831b3fb3 v6.05
9ddf251f3 remove debug code
905b31bab fix typo
72d1ac118 add movdir64b
a6665996b add detection of movdir64b
92ddc6dfd remove Type::operator<<() because it's ambiguous
9cdd40f5e add detection of movdiri
379f8bf37 add movdiri
0ad6db138 fix cldemote test for 32-bit
84ab46bb3 add cldemote to Cpu
a84ddc12d support cldemote
3a6cc626e add clwb
38c40c02e detection of clflushopt
c061ac839 avoid unnecessary replacement in readme.md
095ebbff1 extend Cpu::Type to 128 bit
3ea8e45d3 Merge branch 'dev'
f7bfc2634 v6.041
ab4e52d67 update doc
2bef54399 include intrin.h on mingw
621ed0775 Merge branch 'dev'
4f5893e1e memfd_create: disable for ANDROID_API < 30
684d69db0 Merge branch 'dev'
ea88b6d85 disable warning on mingw
7e8923fa5 add colon
9914216bd Merge branch 'dev'
b335602ff [skip ci] tweak doc
25fbb3996 tweak doc
122054dc4 Formatted Supported OS Section
d4fa7e46b Reworked Authors Section
9e4b64a74 Adjusted Spacing
ff9fdb45f Use Github Sponsor Widget
893b31d46 Added Quicklinks
2d2adf78b Added License Badge
335b5941b Formatted Header
70603addf Moved Install / Usage Into Dedicated Files
1659d28fe Moved History Into Dedicated File
fb953284b Merge branch 'dev'
dbd96b277 add news
898c354e6 v6.04
f8e2ad1e9 add waitpkg detection to Cpu
a220fd69a add umwait
64ec053e6 add umonitor
764d54f6f add tpause
c68646e8d remove warning of vc
4e8214ca2 Merge branch 'dev'
360f4b673 test badSSE only for 32-bit mode
a9fddc454 fix typo of readme
250b5dc39 fix typo of readme
c46e92756 Merge branch 'dev'
31b7cd350 v6.03
a2f9ed085 rename isValidXMm to isValidSSE
2bc8fcbd3 add tests to badSSE
6de93fb88 add baseSSE test
e2eda384c update doc
71a7b1773 fix condition to throw error for SSE instructions when using XMM16-XMM31
615b665cc sample/memfd shows /proc/self/maps
2861517f2 add memfd sample
507b0285e apt update at first
452c07f77 typedef for no-MmapAllocator
8af6e2026 minimize diff
0af3b5d07 Allocator: take optional name parameter and use it with memfd
a67e24505 Merge branch 'dev'
b3892c15e Merge pull request #138 from Tachi107/make-cxx-cpp-ld-flags
b4eddaced build(make): honour CXXFLAGS, CPPFLAGS and LDFLAGS
fbe60e590 test generates only a.asm
0a4a7571d Merge branch 'patch-1' of https://github.com/Tachi107/xbyak into Tachi107-patch-1
55b9f131b build(make): fix clean target in test/Makefile
7aef3ff54 Merge branch 'dev'
82e0deb8a v6.02
4d9906a94 fix condition to throw error for invalid displacements
c79311a51 fix test_util.cpp
9b2c175b3 Merge branch 'dev'
06d797e33 Allow parallel feature checks
2a85bba3f Merge branch 'dev'
8d5af80a6 v6.01
df39606fe update doc
08f11817c supprt retf
1abfc3465 support call(mem, T_FAR)
fb158f901 support jmp(mem, T_FAR)
9be47ceb2 Merge branch 'lioncash-hlt' into dev
3162eb16f add test of hlt
bb55725a9 xbyak: Add hlt opcode function
47cf85fdb fix conflict
b29e471ea build(meson): fix CMake Config file include dir
2cc21925f delete the sentences translated into Japanese from COPYRIGHT
dca3930de remove tabs
cecd204a5 Merge pull request #129 from Tachi107/meson-cmake-config
345de8a54 build(meson): generate CMake package config files
e831805cc revert change of the type of Pack::util::operator[]
fc9d953e5 util::Pack has not pointer but instance of Reg64
0868c54a9 use _WIN32 instead of _MSC_VER for mingw64
894a1b14a use original uint8_t
dfc079ca1 add cstrs of Xbyak::util::Pack for 11 or 12 args
06e8f531f Merge branch 'Tachi107-meson' into dev
ef90b6bd2 Makefile updates the version of meson.build
0000938f5 build: add Meson support This allows Meson users to use xbyak more easly, while it also provides a pkg-config file generator, useful to Linux distributions
757e4063f v6.00
b3489f548 add vcvtusi2sh
16d9898ab add vcvtsi2sh
cfc03cb8f unify T_66, T_F3, T_F2 flags
02fa7057d add vcvttph2qq
4e72a9dc4 add vcvttsh2usi
05d08e05b add vcvttsh2si
621e6548c add vcvtsh2usi
34abda5c5 extend vcvtps2ph
facd622b2 add vcvtw2ph
270af1cb2 add vcvtuw2ph
17dc697cd add vcvttph2w
62f022aea vcvttph2uw
836346bfd add vcvtph2w
300edb37b add vcvtph2uw
737904b5a add vcvtuqq2ph
52b2ebf18 add vcvtqq2ph
6761f1e05 add vcvtpd2ph
03f95b7e3 add vcvtudq2ph
64430b2bb add vcvtps2phx
88e426aa4 add vcvtdq2ph
bf28a94a5 add vcvttph2uqq
4c4e665d3 add vcvtph2uqq
2b0099b63 add vcvtph2qq
3ff69a474 add vcvtph2pd
678b52956 add vcvttph2udq
72a5717e4 add vcvttph2dq
524d52bf6 add vcvtph2udq
d1cf4db97 add vcvtph2psx
fccd2c49b add vcvtph2dq
6530f4099 refactor gen-cvt
c51e16156 tweak
ed9f6c72a add vcvtsh2si
ac1407bd1 add vcvtss2sh
2958a19bb add vcvtsh2ss
10d683303 add vcvtsh2sd
3920c950c add vcvtsd2sh
9a1b73932 add vmovw
d86e4882f vmovsh xmm, addr
61f85a204 add vmovsh
847166cef add tests of vgetmant{ph,sh}
c11a21cf4 add vgetmantph
55ab361f0 add tests of vgetexp{ph,sh}
8653f4152 add vgetexpsh
697eeb627 add vgetexpph
ee920a991 add vfpclasssh
7aed436e6 add vfpclassph
56dca14e4 v5.997
b3b1e4e3c fix vrndscale* to support {sae}
681077eb1 add vrndscalesh
2f14eae85 add vrndscaleph
f96870a44 add vreducesh
043c94ae9 add vreduceph
37bf3bb49 add vscalefsh
c16f91c59 add vscalefph
61ad45935 add vsqrtsh
e00b508d5 add vsqrtph
52765d54f add vrsqrtsh
2ec6a7ab4 add vrsqrtph
b1ff7891d add vrcpph, vrcpsh
4f543ca0e add vucomish
412b95f02 add vf{,c}mulcph
9fc53baed add vf{,c}maddcph
0098ce98d add vf{,n}m{sub,add}sh
849dffb10 add vfmadd, vfnmadd, vfnmsub for avx512-fp16
eadb93d0b add vfmsubaddcph
9b8802cba add vfmaddsub{132,213,231}ph
ab9481b4c add vcomish
cd036ea17 fix vcmpsh
b494b321a vcmpsh supports ptr_b
eb2d63c83 vcmpph uses T_B16
a480b3dd9 v5.996
16d18b1d4 fix v{add,sub,mul,...}{sd,ss} to support T_rd_sae etc.
66c6ca1ab support vaddsh with T_rd_sae
6333ec099 add m16bcst
84053c8e7 add vcmpph
5df23d263 move FP16 to AVX-512
d5c7336f8 fix disp scaling of v{add,sub,mul,div,max,min}sh
ebf29542d add vaddsh test
f29689d02 add test of vaddph
2c4b6ac16 add v{add,sub,mul,div,min,max}{ph,sh}
edf3c2f6f remove mask for mmm
2c561aad6 add T_MAP5 and T_MAP6
acd360c38 add Cpu::tAVX512_FP16
1554f479c remove unused flags(tSSE4a and tSSE5) of Cpu
c313a8758 update CMakeLists.txt version
740b39e24 Merge pull request #122 from abouvier/cmake
10a1e5759 v5.995
0a557a099 rename XBYAK_MEMFD_CREATE to XBYAK_USE_MEMFD
0ad9b9bbe Merge branch 'captain5050-master' into dev
c7bb66383 fix for mac and enable it if XBYAK_MEMFD_CREATE is defined
c1e6569f1 fix cmake config files
ccd4130ec Name mmap pages on Linux with memfd_create
2fb843c32 v5.994
413a66b44 add alias of vcmpXX{ps,pd,ss,sd} for mask register
6f4f76890 v5.993
19043cb9a add test for gather/scatter
b5acb1d1c gather test does not generate bad combination of regs
67ec1674a check restriction of gather/scatter regs
ea9814f4f check bad reg combination of gather
a34850b2d add endbr32 and endbr64

git-subtree-dir: externals/xbyak
git-subtree-split: 9357732aa2aa3cf97809027596dfa5c61d1515b2
2022-06-05 13:31:49 +01:00
Merry
39e21920db externals: Update xbyak to v6.06
Merge commit 'c926d9f40978bee57fbf245cf1c6eb347943e4d9'
2022-06-05 13:31:49 +01:00
SachinVin
46989efc2b asimd_one_reg_modified_immediate.cpp: Rename mvn to mvn_ 2022-05-28 13:27:14 +01:00
Merry
57de35a821 tests: Enable tests dependent on active frontend 2022-05-28 13:27:14 +01:00
Merry
e44ac5b84c CMakeLists: Allow building on arm64 2022-05-28 13:27:14 +01:00
Merry
2779f24862 emit_x64_packed: Optimize GE flag generation for signed packed add/sub
sum >= 0 is equivalent to sum > -1
2022-05-17 23:50:51 +01:00
Merry
b224fad171 emit_x64_vector_floating_point: Implement workaround for issue 678 2022-05-17 21:06:16 +01:00
Merry
b1dc11a32d exception_handler_macos: Avoid use of deprecated function mach_port_destroy 2022-05-17 20:47:13 +01:00
Merry
e007d94133 backend/x64: Use templated lambda in each use of GenerateLookupTableFromList 2022-05-17 20:25:27 +01:00
Alexandre Bouvier
5e95a23174 cmake: build static externals as PIC 2022-04-23 19:45:33 +01:00
Merry
65ed1e7054 mcl/assert: Flush stderr 2022-04-23 19:37:29 +01:00
Merry
da45f689b9 externals: Update mcl to 0.1.7
Merge commit '5da4668a0d928ffa527ca03642902c92c4b78a64'
2022-04-23 18:39:02 +01:00
Merry
5da4668a0d Squashed 'externals/mcl/' changes from a86a53843..761b7c05e
761b7c05e mcl: Build as PIC
4aad0b5e6 mcl/bit: Simplify sign_extend
0733afd2a mcl: Fix bug in non-template mcl::bit::ones
e26df0587 mcl: bit_field: Fix incorrect argument order in replicate_element

git-subtree-dir: externals/mcl
git-subtree-split: 761b7c05e80d789acf572b52175b852c6509e753
2022-04-23 18:37:57 +01:00
merry
e3199f8f65 mcl: Build as PIC 2022-04-23 18:26:31 +01:00
Merry
57af72a567 CMakeLists: Make mcl a public link dependency 2022-04-19 20:33:26 +01:00
Liam
898f14b772 backend/x64: use mmap for all code allocations on Linux 2022-04-19 18:45:46 +01:00
Merry
78b4ba10c9 Migrate to mcl 2022-04-19 18:05:04 +01:00
Merry
ed9955891f mcl: Fix bug in non-template mcl::bit::ones 2022-04-19 18:05:04 +01:00
Merry
95422b2091 mcl: bit_field: Fix incorrect argument order in replicate_element 2022-04-19 16:53:45 +01:00
Merry
de4154aa18 externals: Remove mp and replace uses with mcl 2022-04-19 16:28:28 +01:00
Merry
f642637971 externals: Add mcl v0.1.3
Merge commit '7eb1d05f63c7ba8df6a203138932ea428ab4aa49' as 'externals/mcl'
2022-04-19 16:27:57 +01:00
Merry
7eb1d05f63 Squashed 'externals/mcl/' content from commit a86a53843
git-subtree-dir: externals/mcl
git-subtree-split: a86a53843f82e4d6ca2f2e1437824495acad2712
2022-04-19 16:27:52 +01:00
Wunkolo
27bbf4501b backend/x64: Use upper EVEX registers as scratch space
AVX512 adds an additional **16** simd registers, for a total of 32 simd
registers, accessible by utilizing EVEX encoded instructions. Rather
than using the `ScratchXmm` function, adding additional
register-pressure and spilling, AVX512-enabled contexts can just
directly use `xmm{16-31}` registers as intermediate scratch registers.
2022-04-06 17:41:55 +01:00
Wunkolo
f0b9cb9ccf tests/A64: Add {S,U}SHL instruction unit tests 2022-04-06 17:41:55 +01:00
merry
644172477e Implement enable_cycle_counting 2022-04-03 16:10:32 +01:00
merry
aac1f6ab1b Implement halt_reason
* Provide reason for halting and atomically update this.
* Allow user to specify a halt reason and return this information on halt.
* Check if halt was requested prior to starting execution.
2022-04-03 15:37:20 +01:00
merry
116297ccd5 common: Add atomic
Implement atomic or operation on u32
2022-04-03 15:30:39 +01:00
merry
f6be6bc14b emit_x64_memory: Appease MSVC
Associated with changes in 8bcd46b7e9dc487da217b216c908f2ef15e7a8cf
2022-04-02 20:41:34 +01:00
merry
8bcd46b7e9 emit_x64_memory: Ensure 128-bit loads/stores are atomic 2022-04-02 19:33:48 +01:00
merry
e27733464b emit_x64_memory: Always order exclusive accesses 2022-04-02 19:33:15 +01:00
merry
cd91a36613 emit_x64_memory: Fix bug in 16-bit ordered EmitReadMemoryMov 2022-04-02 19:32:46 +01:00
merry
9cadab8fa9 backend/emit_x64_memory: Enforce memory ordering 2022-03-29 20:57:34 +01:00
merry
675efecf47 emit_x64_memory: Combine A32 and A64 memory code 2022-03-29 20:51:50 +01:00
merry
af2d50288f A64/sys_ic: Return to dispatch on possible invalidation 2022-03-27 15:27:34 +01:00
merry
cf0709c7f1 emit_x64_memory: Share Emit{Read,Write}MemoryMove 2022-03-26 16:51:55 +00:00
merry
64adc91ca2 emit_x64_memory: Move EmitFastmemVAddr to common file 2022-03-26 16:49:14 +00:00
merry
18f02e2088 emit_x64_memory: Move EmitVAddrLookup to common file 2022-03-26 16:46:06 +00:00
merry
3d657c450a emit_x64_memory: Share EmitDetectMisalignedVAddr 2022-03-26 16:09:56 +00:00
merry
fb586604b4 emit_x64_memory: Share constants 2022-03-26 16:05:03 +00:00
merry
5cf2d59913 A32: Add AccType information and propagate to IR-level 2022-03-26 15:38:10 +00:00
merry
614ecb7020 A64: Propagate AccType information to IR-level 2022-03-26 15:38:10 +00:00
merry
879f211686 ir/value: Add AccType to Value 2022-03-26 15:38:10 +00:00
Alexandre Bouvier
9d369436d8 cmake: Fix unicorn and llvm 2022-03-22 20:27:01 +00:00
merry
7b69c87ffc fuzz_arm: Add offset thumb instruction test
Test thumb instructions when (PC % 4) == 2
2022-03-20 21:05:55 +00:00
merry
c78b82dd2c vfp: VLDM is UNPREDICABLE when n is R15 in thumb mode 2022-03-20 20:52:11 +00:00
Sergi Granell
0ec4a23710 thumb32: Implement LDA and STL
Note that those are ARMv8 additions to the Thumb instruction set.
2022-03-20 20:16:27 +00:00
merry
e1a266b929 A32: Implement SHA256SU1 2022-03-20 13:59:18 +00:00
merry
ab4c6cfefb A32: Implement SHA256SU0 2022-03-20 13:59:18 +00:00
merry
c022a778d6 A32: Implement SHA256H, SHA256H2 2022-03-20 13:59:18 +00:00
merry
bb713194a0 backend/x64: Implement SHA256 polyfills 2022-03-20 13:59:18 +00:00
merry
98cff8dd0d IR: Implement SHA256MessageSchedule{0,1} 2022-03-20 13:59:18 +00:00
merry
f0a4bf1f6a IR: Implement SHA256Hash 2022-03-20 13:59:18 +00:00
merry
81536e4630 github: Use GCC 10 on Ubuntu 2022-03-20 13:59:18 +00:00
merry
a4daad6336 block_of_code: Add HostFeature SHA 2022-03-20 00:13:03 +00:00
merry
36f1541347 externals: Update catch to 2.13.8 2022-03-19 17:51:45 +00:00
Andrea Pappacoda
e4b669fd5b build: remove extra include path for system vixl
As far as I know the only pkg-config file provided by Vixl is the one generated by Meson when applying my yet to be merged patch.

That extra include path was needed because I mistakenly thought that adding `vixl` as an include subdirectory was not necessary, but I fixed it in my latest revision - more details here: https://github.com/Linaro/vixl/pull/7#discussion_r778167004

The fix already landed in Debian and Ubuntu, that as far as I know are the only Linux distros that ship my patch, so manually adding that include directory shouldn't be necessary anymore
2022-03-13 20:24:26 +00:00
Merry
bcfe377aaa x64/reg_alloc: More zero extension paranoia 2022-03-06 12:24:50 +00:00
Merry
316b95bb3f {a32,a64}_emit_x64_memory: Zero extension paranoia 2022-03-06 12:10:40 +00:00
Merry
0fd32c5fa4 a64_emit_x64_memory: Fix bug in 128 bit exclusive write fallback 2022-02-28 19:53:43 +00:00
merry
5ea2b49ef0
backend/x64: Inline exclusive memory access operations (#664)
* a64_emit_x64_memory: Add Unsafe_IgnoreGlobalMonitor optimization

* a32_emit_x64_memory: Add Unsafe_IgnoreGlobalMonitor optimization

* a32_emit_x64_memory: Remove dead code

* {a32,a64}_emit_x64_memory: Also verify vaddr in Exclusive{Read,Write}MemoryInlineUnsafe

* a64_emit_x64_memory: Full fallback for ExclusiveWriteMemoryInlineUnsafe

* a64_emit_x64_memory: Inline full locking

* a64_emit_x64_memory: Allow inlined locking to be optionally removed

* spin_lock: Use xbyak instead of inline asm

* a64_emit_x64_memory: Recompile on exclusive fastmem failure

* Avoid variable shadowing

* a32_emit_x64_memory: Implement recompilation

* Fix recompilation

* spin_lock: Clang format fix

* fix fallback function calls
2022-02-28 08:13:10 +00:00
merry
0a11e79b55 backend/x64: Ensure all HostCalls are appropriately zero-extended 2022-02-27 20:04:44 +00:00
merry
6c4fa780e0 {a32,a64}_emit_x64_memory: Ensure return value of fastmem callback are zero-extended 2022-02-27 19:58:23 +00:00
merry
dc3e70c552 fuzz_arm: Sometimes we have to step more to sync up with unicorn
This happens if unicorn happens to jump back on an IT instruction.
2022-02-27 19:51:09 +00:00
merry
593de127d2 a64_emit_x64: Clear fastmem patch information on ClearCache 2022-02-27 19:50:05 +00:00
Merry
c90173151e backend/x64: Split off memory emitters 2022-02-26 21:25:09 +00:00
Merry
19a423034e block_of_code: Fix inaccurate size reporting in SpaceRemaining
Typo: getCode should be getCurr: Instead of comparing against the current pointer,
we were incorrectly comparing against the start of memory
2022-02-26 16:09:11 +00:00
Merry
123efbbfbe github: Update for windows-2022 builder 2022-02-26 13:38:36 +00:00
Merry
5092972843 CMakeLists: Use system vixl when able 2022-02-26 13:35:36 +00:00
Merry
ea08a389b4 emit_x64_floating_point: EmitFPToFixed: No need to round if rounding_mode == TowardsZero
cvttsd2si truncates during operation
2022-02-23 20:44:02 +00:00
merry
b34214f953 emit_x64_floating_point: Improve EmitFPToFixed codegen 2022-02-23 19:42:15 +00:00
merry
5fe274f510 emit_x64_floating_point: Deinterlace 64-bit FPToFixed signed/unsigned codepaths 2022-02-23 19:14:41 +00:00
merry
442c01373a gitignore: Add .DS_Store 2022-02-23 19:14:41 +00:00
Merry
8b1859d5ca github: Add windows build, remove appveyor 2022-02-15 15:48:13 +00:00
Merry
4fa646bae5 a32_unicorn: Throw on error to trigger SCOPE_EXIT code 2022-02-15 15:20:01 +00:00
Merry
c4087d68bc fuzz_arm: Don't generate thumb32_MSR_reg: Unicorn steps by 2 instead of 4 2022-02-15 15:13:41 +00:00
Merry
88906b642c fuzz_arm: Handle unicorn overrun on internal jump 2022-02-15 14:11:02 +00:00
Merry
6633089a44 Squashed 'externals/fmt/' changes from 9e8b86fd2..b6f4ceaed
b6f4ceaed Update version
15f812dae Update changelog
6884aab49 Update changelog
88ec4e706 Bump version
dd3d2490e Update changelog
739055ae7 Fix apidocs
dbbd711f4 Suppress a warning
98cbb6a43 Fix ABI compatiblity issue
214cf13f1 Fix endianness bug in write_digit2_separated (#2699)
17a5c808d Restore FMT_API on error_handler::on_error() (#2696)
fc1783fcc Avoid undefined symbols with mingw-w64 (#2692)
1b193e7b3 Deprecate more
8e59744b8 Switch to new github auth mechanism
7081a6aa3 Update version
64dc8fbad Bump version
fc8e3de7d Fix manage.py script
57bee9fcd Fix formating
dce52e491 Update changelog
9405a4724 Update changelog
495b8bf12 Update changelog
e221166fa Update changelog
035cab8da Update changelog
89c6ed12b Clarify in comments (for now) deprecated map functions
e462da828 Add some noexcept (#2684)
79c66d66b Update changelog
5d37f705f Update changelog
6bb370cec Update changelog
bb6920157 Fix tuple join
4fac7daae Cleanup bit_cast
3617c2795 Update changelog
9c0c1bcdb Simplify tuple formatting
187e8db1b Update changelog
c7f88180f add tests for format string compile-time checks
8a2c3fb88 add reverse tests to compile-error-test
1164eda5a disable compile-error-test on Windows
4482f6f1f rewrite compile-error-test to use non-header-only library
796662a61 Escape range items convertible to std::string_view
33ee4cc51 Improve noexception test
3bbf2c673 Fix throw with exceptions disabled
074c9c52e Update changelog
3110ec5a2 Update changelog
3014b3d77 Clarify that C strings must be null-terminated
eab2ea9fc Replace an assert with an exception
21ed92a6e Update changelog
04111dd1e Fix issue #2670 (#2671)
817788fbf remove incorrect C++20 check from test/CMakeLists.txt (#2663)
4511030af Minor code style tweaks for consistency
7812813a3 Don't explicitly delete copy ctor of dynamic_format_arg_store (#2664)
664cd6067 Remove std-format-test
784e2a7b4 Fix an overflow when formatting very large durations
fc2a376d8 Remove two expressions which had no effect (reported by LGTM)
c5aafd8f9 expose headers as SYSTEM depending on special configuration option
eaddd1e3c Fix handling of byte
2d4457758 Try fixing byte regression
e46392ea2 deprecate _format UDL in code using FMT_DEPRECATED
c882790a2 Add a set formatter
121002d70 Add a map formatter
be51ee1ce Disable broken copy ctor of dynamic_format_arg_store
659de779e Fix a UB in parse_format_specs when begin is null
51b14b6c0 remove commented out lines
223a0fa55 move gtest-specific check into gtest/CMakeLists.txt
ef72b471f enable named arguments check in compile-time checks (#2649)
82246b876 fix throw with exceptions disabled (#2647)
35f60377a Update ChangeLog.rst
3a951a66c Avoid qualifying by inline namespace. Fixes #2642. (#2643)
e0136fc8b Qualify calls to make_wformat_args. Fixes #2639. (#2641)
ac1b5f3da Refactor problematic trailing returns in arg_mapper
fd62fba98 Don't convert scoped enums to integers
c652f8243 Make header guard consistent with header name
a9c7b9b8f Clarify that _format is deprecated
e4f0564aa Disable is_streamable for string[_view]
91533d3c3 Minor tweaks to chrono subsecond formatting
0bbc9708f Implement c++20 std::chrono::duration subsecond formatting (#2623)
9d5b9defd Enable tzset only on Windows desktop app (#2633)
215f21a03 Detect overflow on large precision
c240d98ff Optimize tm formatting (Non C-locales and %Z) (#2617)
6ab73113f Mark grow as FMT_CONSTEXPR20 (#2630)
713c7c7c6 Cleanup os.cc
9b1807a8a fix int -> uint warning (#2611)
ec3b097cb [doc] FMT_STRING supports C++14 and no-op in C++11 (#2620)
c472a2781 Fix handling of very large precision in fixed format
201971e29 Make MSVC use [[nodiscard]] (#2615)
acad8cfab Reformat all source code; no functional changes
491ba2dda Annotate fmt::format and fmt::formatted_size as [[nodiscard]]
5abe9e826 Add platform-specific 'z' formatter
be3a3a5ae Use predefined formats for C-locale
a3ab36c80 Formatting of function pointers, member function pointers, member object pointers... (#2610)
19cac63fe Broken link in README.rst
43419a4ad Workaround a bug in gcc
c089f7d49 Simplify std::tm formatter
aa5517f6b Reuse tm_writer in chrono_formatter
50140be7a Reuse tm_writer in weekday formatter
8b8945499 Improve consistency
5380ff4d8 Detect types convertible to unformattable pointers
094b66e81 changed locale retrieval way to a fancy one
b69ae4854 Reorder classes (#2591)
0b843af56 sped up chrono.h formatting for cases without providing locale (#2576)
12b1d8b14 Fix precision 0 with std::chrono::duration and added additional tests. (#2588)
e67f92c55 Cleanup warnings with nvhpc/21.9. (#2582)
812733cc9 const qualify format function for systen_clock
028f22775 Handle implicit conversions in write
5b0aa638c Minor grammar fix
6eaceb5f7 Fix incompatible between docutils 1.18.0 and sphinx 3.3.0 (#2575)
0697c5edb FMT_USE_FCNTL can be predefined (#2573)
1031eedf2 Replacing strftime with std::time_put (#2550)
90034e4c4 Add FMT_ASSERT and validation of values of struct tm members (#2564)
df40e9467 Upgrade `module-test` to msvc 16.11.5 and 17.0-pre5 (#2558)
e6d5059cb Simplify js tag in basic-bootstrap theme (#2562)
3b6e409cd Enable `consteval` for msvc 17.0-pre5 (#2559)
249f03bbb do not detect LLVM based IBMXL compiler (on ppc) as clang (#2555)
7463c8320 Fix overflow for very bigger years (>2*10^9) (#2551)
1266c2b60 Fix handling of exotic character types
684e2fdc9 Minor cleanup
a1d586302 Minor cleanup
7a604cdd9 Cleanup
aeb54b0dd Fix bug on '%Y' and '%C' formats with negative years Requested changes
f88c020fc Generalization of strftime/wcsftime function calls in tests
2eeddba75 Renaming, splitting of functions
275454608 Fix errors in ISO week-base-year formatter
218cecb6d Fix error in test
e9f4453b0 Fix Microsoft Visual Studio 14.0 build
27c3674ce Improve performance
5dc3dd3d4 New tests
f8542cd98 Unified formatters for std::chrono::time_point<std::chrono::system_clock, Duration> and std::tm
4707373d3 Fix year formatter
79c00ad8f Improve ISO week-base-year formatter
fbaaa5906 Improve week of the year formatter
cde44ddb7 Improve year formatter
b04601b91 Switch from std::strftime/std::wcsftime to internal implementation for locale independent formats
d3d30a46f New tests
7911d8d3f Add format spec checker
fbbfc3b03 Reorder formatters
509eac957 Workarounds for implementation-defined std::strftime behavior
85b38190d New tests for all C++11 std::strftime format specifiers
7aca36bca Extending fmt::join to support C++20-only ranges. (#2549)
f5371a75f locale.h -> format.h
febdef43f fix: add workaround for intel parameter pack bug
f56756986 fix: check to make sure both 'if constexpr' and return type deduction are available
dcd282bb2 Namespace qualify calls to get
9c14474d3 Include `<bit>` when using `std::bit_cast`
1e96e0176 Fix compiler flag check (#2540)
7e4bc9451 Speeding up write_significand() (#2499)
26c1ca4c3 Replaced default spec with equivalent one, which is potentially more optimizable (#2537)
1e865b353 Fix docs
4a85db1ce Change default open mode to -rw-r--r-- (#2530)
0a985fd4c Move size_ initialization to initializer list (#2529)
012cc709d Workaround gcc _Pragma bug 59884
d6590e3bd Fix compiler check
134aec40f Fix search in docs
48a476ae0 Update example (#2522)
023c2018f Don't use strlen in constexpr
800d4c8ac Refactor Windows workarounds
32865aeaa changed detection of Intel Compiler Classic to distinguish MS-Windows (#2510)
7b339795a Describe a better approach of how to use {fmt} as a depency in a Bazel project (#2516)
ae9bbe116 Suppress warning C4127 in chrono.h (conditional expression is constant) (#2518)
927dbd134 Misplaced comma in README.rst (#2515)
2a9a77dd8 Remove misplaced comment
1aee4bc90 Refactor FP formatting
e1bd6cc91 Refactor FP formatting
027fcaf05 Replace use_grisu with fallback since Grisu is only one of multiple implemented algorithms
716d69f27 Refactor FP formatting
ff7e73af6 Always run grisu_gen_digits before fallback_format
2976e31ac Refactor format_float
807ee5ec3 Disable consteval in Apple clang
d9a731d48 Add basic support for Bazel (#2505)
9c57357e0 Add `static` to a table (#2509)
2742611ca Fix formatting
5092b198b Document group_digits
b4d9d82e1 make FP formatting available to be used at compile-time (#2426)
d9fd695ac Fix wchar_t tm formatting
92614ecbf Optimize %T in tm formatting
aaeca12d8 Move FMT_MAYBE_UNUSED to format.h where it is used
3d0c7ae38 Move data to format.cc
04e3a79f7 Use memcpy in more cases in copy2
e47e99bb0 Simplify format_decimal (#2498)
9b6b0e403 Remove data
4d1c6034e Deprecate basic_data
a3348eccd Deprecate most of basic_data
3a0448148 Remove data::hex_digits
ad77331c0 Move log10_2_significand to format-inl.h
d9ebc4e82 Add a function to get sign char
c00eb4f4c Add missing inline
25af02f21 positive -> nonnegative (#2493)
67cb2dad3 Optimize %F in tm formatting
1aa98f8b9 Eliminate double copying in vformat_to_n (#2489)
a58c13382 Improve code_point_length codegen on older gcc
aeee70a81 Remove unnecessary cast
c771ba361 Fix build for the clang-10 / libstdc++-9 couple (#2491)
ab6e2272c Clarify shifts encoding
e4728409e Use throw_format_error in more places to reduce bloat
e3ebf366a Inline padding shifts
894faf3fe Refactor presentation types
4eb97fa4e Reduce code bloat
6b55c8325 is_const_formattable -> has_const_formatter
2fe94ad7e Make specifiers support in tuple_join an opt-in
3940de595 thousands -> group_digits
c4d0f96a6 Implement format specs in fmt::thousands
3b9c44268 Implement thousands separators without locales
08f98c7fa Simplify get_arg_index_by_name
a151f955a Remove FMT_OVERRIDE
42a225cbd Remove redundand final
bf20d1990 Simplify the core API
fc0884037 Move FMT_GCC_VISIBILITY_HIDDEN to format.h
1aeed2dbc Require inline namespaces
799bea473 Remove FMT_HAS_GXX_CXX11
60cd5ea3f Add support for more formattable types in ranges
4fd9a00f3 Simplify ostream interface
568156389 Cleanup ostream interface
20931baf1 Disable fallback_formatter for arrays
d58d19ba3 Fix an odr violation in ranges.h (#2483)
ee0659f8b Fix formatting of abstract classes via ostream
8029bf955 Fix copy_str performance (#2477)
2520f410c Workaround for #2478 (#2482)
ee63f5f04 Workaround to MSVC bug (#2474) (#2476)
1aaf72fb6 Add an example to fmt::runtime
c1313c205 Clarify that format_to[_n] do not append a terminating null
cb0f177c3 Improve docs
71677e520 Improve docs
4db572352 add fuzzers for chrono timepoint and localtime,gmtime (#2469)
dc7f3ef2b Fix header name
419ba86a9 Improve docs
6a5b4d5fa Document format_string
2599163b8 Document format_string
8ef22f774 Update docs
c0c4d1ada Update docs
729a44e67 Depreate strtod and remove problematic tests
74c111896 Apply force inline
596508a92 Cleanup
043e3b342 Remove static_assert from arg_mapper
8b0cb944d Fix error reporting when mixing character types
117fc6707 CI: replace g++ C++20 build to test FP formatting at compile-time
c79a3841e make detail::fp and detail::bigit constexpr
5888de9f3 make detail::make_checked() constexpr
04b4b69b1 make detail::bit_cast() constexpr with C++20
fd34a3d24 make detail::basic_memory_buffer constexpr with C++20
6d597e39c Fix overload ambiguity in arg_mapper
b9ce56d93 Improve comments
f889e52a1 Improve error reporting
34caecd6b Use consistent initialization style
a44c8f651 reimplement `formatter<tuple_join_view>` (#2457)
4b8bda25c Fix 2462
6b5e6119e set clang in one place
7af1dc1d2 fix UB in fuzzer common (memcpy on nullptr)
e77686f7a clang format
2207ea0b3 More escaping
a212ff757 Escape invalid code points
a76031e11 check -> is_printable
a7f280765 Improve naming
07d033ecb Fix is_printable
cdb4299ac Add Unicode support to is_printable
7df2c82a8 Rewrite printable.py codegen to emit C++
6cf90d7ce Add script license and fix python version
2f1ad8ed3 Add printable codegen from Rust
371d8e2ee Escape Unicode
6397095ca More escaping
f69a57253 Don't overescape wide strings
11b07a56b We should escape
b559cfd4c Implement basic escaping
11d49491c Handle global locale
6ea6cf946 Add decimal separator support to float
9730a2af0 Update ChangeLog.rst
c2ed5f686 Update ChangeLog.rst
7b66e72e2 Use builtin intrinsics on intel (#2450)
d57b2a652 Suppress a warning
bdfbd794e Cleanup begin/end usage
111de881f Don't copy non-const-iterable ranges
d6e882ed8 Undo the move because the doc is not a GH template
f488eed10 Resolve default constructor error in Xcode 7.2.1 and 8.2.1
652c3653b Move CONTRIBUTING.md to .github
fb19faa31 Improves README with svg badge (#2446)
07211701f Disable the -Wstringop-overflow warning from GCC 7 (#2442)
bba0a9d96 Make flush public
f1794a885 Switch to threadsafe death test style
0544a2279 Exclude fallback functions when FMT_BUILTIN_CLZ(LL) is not defined (#2434)
5c222f056 Add support for nonconst formattable types
3def950b8 Set FMT_CAN_MODULE=OFF for MSVC 19.29.30035+
63fe2d5bd Add copy constructor for dynamic_format_arg_store, and test
561834650 Improve digit count
f20f50368 Replace `throw` with `FMT_THROW` (#2427)
00235d8a9 fix module test odr violations (#2414)
2038bf618 Update format_to usage
e41ac1f87 Don't use deprecated API in docs
8465869d7 Move ignore_unused to detail
3d53d1539 Warning removals in test code (#2399)
20e4ef8b4 Pass significand_size by value
c4a3c2342 Refactor locale handling
7a0d30175 Update README.rst
f2b03facd Include test sources to pick up functions and classes from the module rather than from the non-modular library which is baked into the `test-main` library. (#2356)
02ad5e11d Add faint, blink, reverse and conceal to the emphases (#2394)
d141cdbeb Update version
cfc05e05f Bump version
8ea312633 Update changelog
e461f3dbb Minor consitency and comment tweaks
54014e42e silence warning C4100 on MSVC 2019 when exceptions are disabled (#2397)
3e7a29cc9 Workaround clang/gcc incompatibility
00a57a9f8 Update changelog
1d7384530 Add missing presentation type checks for std::string (#2402)
889bbf27a Fix missing std::get overload in MSVC (#2407)
5f8473914 Remove outdated apidoc
785908ee3 Fix warnings
fbb70eec5 suppress unused variable warnings (#2381)
002bb759f Remove unneeded `num_result_bigits` decrement
a3f762c5a [doc] Minor: fix ``code``.
c3c27e5ab Fix MSVC warning C4819
c6b1f181a Fix docs
94564b058 Fix docs
0fc73a2a8 Merge branch 'master' of github.com:fmtlib/fmt
3156fcf5f Switch to older breathe version
f85fb9fdf Adjust definition for FMT_HAS_INCLUDE
0bc3d664e Fix docs
e5c46e13e Fix docs: breathe 18 and earlier corrupts trailing return type
49a3b58c8 Specify size for static data arrays
d0c8d45a2 apt update before install
c9a10631c format: do not use udl_{arg,formatter} return types when UDL is not in use
3bd806f12 Eliminate intel compiler warning
fd16bcb20 Fix bug in cmake join function
5221242f6 Instruct msvc to report the _true_ value in `__cplusplus` and force _full_ C++ conformance
31a5f0d39 Bump version in inline namespace
102a4d492 Bump version in inline namespace
f68508b6c Update ChangeLog.rst

git-subtree-dir: externals/fmt
git-subtree-split: b6f4ceaed0a0a24ccf575fab6c56dd50ccf6f1a9
2022-02-15 11:15:34 +00:00
Merry
8b3bef13dc externals: Update fmt to 8.1.1
Merge commit '6633089a44b13022ddb37a44229c9d9a88a9096f'
2022-02-15 11:15:34 +00:00
merry
76ec1afdad fuzz_arm: Ensure that FPSCR.QC is tested 2022-02-12 22:07:26 +00:00
merry
b8dd1c7510 emit_x64_floating_point: Correct dead-code warning in MSVC 2019 2022-02-12 22:07:26 +00:00
merry
95a1ebfb97 backend/x64: Bugfix: A32 frontent also uses FPSCR.QC 2022-02-12 21:46:45 +00:00
merry
473bbd422e test_arm_instructions: Add vmsr/vcmp/vmrs test 2022-02-12 21:43:05 +00:00
Fernando Sahmkow
a8cbfd9af4 X86_Backend: set fences correctly for memory barriers and synchronization. 2022-02-01 14:27:54 +00:00
Alexandre Bouvier
0cafcc1af9 cmake: Always build static externals 2022-01-08 14:23:34 +00:00
Mai M
1635958d06
Merge pull request #658 from liushuyu/master
disassembler_thumb: fix formatting issues with fmt 8.1.x
2022-01-06 00:17:16 -05:00
liushuyu
40afbe1927
disassembler_thumb: fix formatting issues with fmt 8.1.x ...
... fmt 8.1.0 added more formatting checks and Cond can't be formatted
directly now
2022-01-05 21:49:51 -07:00
Wunkolo
ad5465d6ce constant_pool: Use tsl::robin_map rather than unordered_map
Finding a much more drastic improvement with `robin_map`.

`map`:
```
[master] % hyperfine -r 100 "./dynarmic_tests --durations yes"
Benchmark 1: ./dynarmic_tests --durations yes
  Time (mean ± σ):     567.0 ms ±   6.9 ms    [User: 513.1 ms, System: 53.2 ms]
  Range (min … max):   554.4 ms … 588.1 ms    100 runs
```

`unordered_map`:
```
[opt_const_pool] % hyperfine -r 100 "./dynarmic_tests --durations yes"
Benchmark 1: ./dynarmic_tests --durations yes
  Time (mean ± σ):     561.1 ms ±   4.5 ms    [User: 508.1 ms, System: 52.3 ms]
  Range (min … max):   552.6 ms … 574.2 ms    100 runs
```

`tsl::robin_map`:
```
[opt_const_pool] % hyperfine -r 100 "./dynarmic_tests --durations yes"
Benchmark 1: ./dynarmic_tests --durations yes
  Time (mean ± σ):     553.5 ms ±   5.6 ms    [User: 500.7 ms, System: 52.1 ms]
  Range (min … max):   545.7 ms … 569.3 ms    100 runs
```
2022-01-01 12:13:13 +00:00
Wunkolo
e57bb0569a constant_pool: Convert hashtype from tuple to pair 2022-01-01 12:13:13 +00:00
Wunkolo
befc22a61e constant_pool: Use unordered_map rather than map
`map` is an ordinal structure with log(n) time searches.
`unordered_map` uses O(1) average-time searches and O(n) in the worst
case where a bucket has a to a colliding hash and has to start chaining.
The unordered version should speed up our general-case when looking up
constants.

I've added a trivial order-dependent(_(0,1) and (1,0) will return a
different hash_) hash to combine a 128-bit constant into a
64-bit hash that generally will not collide, using a bit-rotate to
preserve entropy.
2022-01-01 12:13:13 +00:00
Morph
28714ee75a general: Rename files with duplicate names
In MSVC, having files with identical filenames will result into massive slowdowns when compiling.
The approach I have taken to resolve this is renaming the identically named files in frontend/(A32, A64) to (a32, a64)_filename.cpp/h
2021-12-23 11:38:58 +00:00
Andrea Pappacoda
4dcebc1822 build(cmake): add install target
This makes dynarmic installable, and also adds a CMake package config
file, that allows projects to use `find_package(dynarmic)` to import the
library.

I know #636 adds the same thing, but while experimenting with the
different install options in
https://github.com/merryhime/dynarmic/pull/636#discussion_r725656034
I ended up with a working patch, so I'm proposing this as well. This
implements solution 2.
2021-10-30 19:03:23 +01:00
Mai M
cce7e4ee5d
Merge pull request #651 from ameerj/fmt-cmake
externals/cmake: Fix fmt target check
2021-10-12 14:33:36 -04:00
ameerj
4cfbbe3df2 externals/cmake: Fix fmt target check 2021-10-11 13:44:19 -04:00
Andrea Pappacoda
b87a889d98 build(cmake): add version and soversion to the library
This adds versioning information to the built library.

When building the shared library on Linux systems, a new object will
be created: libdynarmic.so.5

This is really useful when talking about ABI compatibility.

The variables dynarmic_VERSION and dynarmic_VERSION_MAJOR
are implicitly created when calling project(dynarmic VERSION x.y.z)
2021-10-11 06:53:05 +01:00
ameerj
55bede81f8 CMake: Fix fmt target check 2021-10-11 06:52:52 +01:00
Fernando S
e4146ec3a1
x64 Interface: Allow for asynchronous invalidation (#647)
* x64 Interface: Make Invalidation asynchronous.

* Apply suggestions from code review
2021-10-05 15:06:41 +01:00
Wunkolo
5e7d2afe0f IR: Introduce VectorReduceAdd{8,16,32,64} opcode
Adds all elements of vector and puts the result into the lowest element.
Accelerates the `addv` instruction into a vectorized implementation
rather than a serial one.
2021-09-27 19:54:11 +01:00
Wunkolo
69b831d7d2 tests: Add {S,V}ADD{V,P} tests
These are the instructions emitted for each variant of the `vaddv{q}_{s}{8,16,32,64}` intrinsic.
2021-09-27 19:54:11 +01:00
Marshall Mohror
0b8fd755d8 Fix signal_stack_size for glibc 2.34
`SIGSTKSZ` is now defined as `sysconf(_SC_SIGSTKSZ)` which is not constexpr, and returns a long which throws off the `std::max` template deduction.
2021-09-22 20:38:11 +01:00
Ben
6ce8bfaf32
Add API function to retrieve dissassembly as vector of strings (#644)
Co-authored-by: ben <Avuxo@users.noreply.github.com>
2021-09-16 16:45:20 -04:00
Macchiarch
f88aa570a3
cpu_info: remove tSSE4a and tSSE5 (#643)
tSSE4a and tSSE5 have been removed from xbyak
2021-09-06 20:49:10 +01:00
merry
1697902948
Merge pull request #641 from abouvier/unbundle
CMakeLists: Add options to unbundle most external libraries
2021-08-25 07:56:12 +01:00
Alexandre Bouvier
352898e88b cmake: Add options to unbundle Zydis 2021-08-24 12:28:44 +02:00
Merry
517e35f845 decoder_detail: Avoid MSVC ICE
MSVC has an internal compiler error when assume is present in this constexpr function
2021-08-15 19:32:05 +01:00
Merry
2e4f99ae3d CMakeLists: Expose DYNARMIC_IGNORE_ASSERTS option 2021-08-15 16:09:37 +01:00
Merry
3b4459d112 CMakeLists: Enable C++20 support 2021-08-15 15:17:01 +01:00
Merry
4988d9fab3 disassembler_arm: Fix format strings for vfp_VMOV_from_i{8,16} 2021-08-15 15:16:53 +01:00
Merry
615ce8c7c5 IR: Remove A32 IR instructions Get{N,Z,V}Flag 2021-08-12 13:06:15 +01:00
Alexandre Bouvier
04b1c78166 cmake: Add checks for projects using dynarmic as subproject 2021-08-10 16:16:02 +02:00
Alexandre Bouvier
33b89cca08 cmake: Add options to unbundle some externals 2021-08-10 16:05:38 +02:00
Merry
72f8abe11d externals: Update mp to latest
Merge commit '163b59390c32745f95838b121be3ef5e2cf08e8c'
2021-08-10 12:30:46 +01:00
Merry
163b59390c Squashed 'externals/mp/' changes from 649fde1e..b50053ce
b50053ce function_info: Implement equivalent_function_type_with_class

git-subtree-dir: externals/mp
git-subtree-split: b50053cef50385419c59fb3aebb78974547318bc
2021-08-10 12:30:46 +01:00
Merry
2bc86209bd catch: Correct include directory 2021-08-08 12:52:55 +01:00
Wunkolo
1e94acff66 ir: Add VectorBroadcastElement{Lower} IR instruction
The lane-splatting variant of `FMUL` and `FMLA` is very
common in instruction streams when implementing things like
matrix multiplication. When used, they are used very densely.

https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/coding-for-neon---part-3-matrix-multiplication

The way this is currently implemented is by grabbing the particular lane
into a general purpose register and then broadcasting it into a simd
register through `VectorGetElement` and `VectorBroadcast`.

```cpp
    const IR::U128 operand2 = v.ir.VectorBroadcast(esize, v.ir.VectorGetElement(esize, v.V(idxdsize, Vm), index));
```

What could be done instead is to keep it within
the vector-register and use a permute/shuffle to "splat" the particular
lane across all other lanes, removing the GPR-round-trip.

This is implemented as the new IR instruction `VectorBroadcastElement`:

```cpp
    const IR::U128 operand2 = v.ir.VectorBroadcastElement(esize, v.V(idxdsize, Vm), index);
```
2021-08-07 23:03:57 +01:00
Wunkolo
46b8cfabc0 bit_util: Protect Replicate from automatic up-casting
Recursive calls to `Replicate` beyond the first call might
cause an unintentional up-casting to an `int` type due
to `|` and `<<` operations on types such as `uint8_t` and `uint16_t`

This makes sure calls such as `Recursive<u8>` stay as the `u8` type
through-out.
2021-08-07 23:03:57 +01:00
Wunkolo
f171ce7859 tests: Add FMLA(lane) test
Math operations such as Matrix multiplication utilize these particular
instructions enough that there should be some unit tests for thesein particular.
The lane-splatting form of FMUL and FMLA instructions are of particular
interest and I've found them to be very common in retail game binaries
such as Pokemon Sword.

https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/coding-for-neon---part-3-matrix-multiplication

I'm primarily adding this unit test so that I can ensure compatibility
while I tune and optimize them.
2021-08-07 23:03:57 +01:00
Merry
d41bc492fe {a32,a64}_jitstate: Remove unnecessary headers 2021-08-07 19:35:33 +01:00
Merry
07b5734fb0 xbyak: Correct xbyak include directory
xbyak is intended to be installed in /usr/local/include/xbyak.
Since we desire not to install xbyak before using it, we copy the headers
to the appropriate directory structure and use that instead
2021-08-07 15:13:49 +01:00
Merry
31cefb22a0 fuzz_with_unicorn: Correct printing of vectors 2021-08-06 15:29:43 +01:00
Merry
59fb568b27 tests: Use Zydis for disassembly 2021-08-06 15:29:43 +01:00
Wunkolo
f33bd69ec2 emit_x64_vector_floating_point: AVX512 implementation of EmitFPVectorToFixed
AVX512 introduces the _unsigned_ variant of float-to-integer conversion
functions via `vcvttp{sd}2u{dq}q`. In the case that a value is not
representable as an unsigned integer, it will result in `0xFFFFF...`
which can be utilized to get "free" saturation when the floating point
value exceeds the unsigned range, after masking away negative values.

https://www.felixcloutier.com/x86/vcvttps2udq
https://www.felixcloutier.com/x86/vcvttpd2uqq

This PR also speeds up the _signed_ conversion function for fp64->int64
https://www.felixcloutier.com/x86/vcvttpd2qq
2021-07-17 22:13:11 +01:00
SachinVin
048da372e9 block_of_code.cpp: remove redundant align() 2021-07-17 22:12:31 +01:00
Kappamalone
6ca6461450
docs/Design: Fix links (#633) 2021-07-11 19:22:46 +01:00
Merry
65309eb6bc gitignore: Update mig path 2021-07-11 11:38:43 +01:00
Wunkolo
5971361160 IR: Add AndNot{32,64} IR instruction
Also includes BMI1-acceleration for x64, when available
2021-07-02 22:27:29 +01:00
Wunkolo
49d00634f9 IR: Add VectorAndNot IR instruction
And(a, Not(b)) is a common enough operation that this can
be fused into a single `AndNot` operation. On x64 this is also
a single `pandn` instruction rather than two.
2021-07-02 22:27:29 +01:00
Wunkolo
253713baf1 opcodes.inc: Disable clang format 2021-07-02 22:27:29 +01:00
Wunkolo
1fc96fd0c2 emit_x64{_vector}_floating_point: Unsafe AVX512 implementation of Emit{RSqrt,Recip}Estimate
This implementation exists within the unsafe optimization paths and
utilize the 14-bit-precision `vrsqrt14*` and `vrcp14p*`
instructions provided by AVX512F+VL. These are _more_ accurate than
the fallback path and the current `rsqrt`-based unsafe code-path
but still falls in line with what is expected of the
`Unsafe_ReducedErrorFP` optimization flag.

Having AVX512 available will mean this function has 14 bits of precision.
Not having AVX512 available will mean these functions have 11 bits of precision.
2021-06-27 11:18:58 +01:00
MerryMage
ea02a7d05d conditional_state: Break from translation when invalid NV instruction is hit 2021-06-25 22:09:39 +01:00
merry
7946868af4
Merge pull request #629 from lioncash/fmt
externals: Update fmt to 8.0.0
2021-06-23 13:52:31 +01:00
Lioncash
9bb464a203 externals: Update fmt to 8.0.0 2021-06-23 05:04:53 -04:00
Lioncash
3e6176d6f6 Squashed 'externals/fmt/' changes from cd4af11e..9e8b86fd
9e8b86fd Update version
92fec0f0 Bump version
4749cc93 Update changelog
78a0ba0a Improve conversion of paragraphs
7a39837d Use a working breathe version
55b6e92d Fix docs
69dc3a85 Fix docs
27f4cdd5 Update changelog
70d61a0a Update changelog
427b5340 Add no_value state to value
e421d527 Simplify error handling in parse_nonnegative_int
a59678f3 Fix chrono_test.locale
c98254c3 Install locales into CI
c123a728 Fix set locale error in chrono formatter
3c8fad12 Optimize parse_nonnegative_int
f28cf330 adding a default format for std::chrono::time_point<std::chrono::syst… (#2345)
55010a9d Support non-`char` overloads (module)
0193e7c4 Support compile-time strings and compile-time format string compilation in module
3423d754 Remove the msvc workaround (#2351)
f6b5cc9f Fix chrono_test.weekday on legacy glibc
59a298f1 Enable `enforce-checks-test` for MSVC, too
36c29482 Update docs
c9fe1fa5 Remove unused flag
dccddc2b Apply clang-format
0e36681b Cleanup digit count
1de80f5b Workaround lack of static constexpr in constexpr functions
2039dce7 Detect consteval
d551b88a Move is_char specializations to xchar.h
16c3514d wchar-test -> xchar-test
206000a0 Workaround pathological conversion (#2343)
76ee4904 Move wchar/custom char overloads to xchar.h
e77b22d6 Deprecate memory buffer overload of format_to
07039f4b Update README.rst
4678192c Remove bsr2log10
7c3d3dfa Update thousands_sep_impl signature
ef826b86 Fix docs
5223f552 Remove FMT_ALWAYS_INLINE
cfde93af Add FMT_STATIC_CONSTEXPR
986a5a6c Fixed join_view formatter for wchar_t
7c8b35ff fix MSVC Win32 count_digits
3eeb084e Optimize count_digits
2ac0bfe5 Improve handling of thousands separator
024741b4 CI: set up multi-thread build for all platforms
f4c95f6d Improve handling of thousands separator
d4fbeacc Fix docs build
0eef389d Code style
e27b1ce5 Fix docs
9f8b6dac Fix wheel installation
6060bcfc Fix docs
ff967346 Fix docs
1085cc21 Fix docs
11addaa1 Update docs
760ca5cc Update docs
290d3f8b Cleanup ranges API
aa09e0f5 Update docs
d142579e Cleanup the format API
f286139d Fix "undefined reference to `fmt::v7::detail::basic_data<void>::digits'"
7b9d69b8 Add xchar.h to docs
cbd861f1 Update docs
faf972f0 Update docs
622d1c04 Update changelog
634c9487 Update changelog
a04e3a2d Comment
87876d54 Cleanup the printf implementation
d338d663 Cleanup the printf implementation
272660e7 Remove deprecated printf functions
5a95c5ae Update changelog
70e67ae0 Re-enable module testing Prepare for compilation with gcc (modules branch).
ad972589 Merge branch 'master' of github.com:fmtlib/fmt
ed2a6377 Workaround msvc constexpr issues
99768695 fix custom types formatting at compile-time, add test
8c1b22ba Workaround a gcc 9.1 bug (#2334)
2dba1cfa Update changelog
d7ba6c3e Use qualified name-lookup in module. (#2324)
bf9904ee Workaround msvc bugs
577bce90 Apply clang-format
ba4c7f19 Swap parameter order to match #2327 (#2329)
e9e89b35 Update ChangeLog.rst
9bb406d7 Update changelog
11a14db2 Update format_to taking a buffer and remove undocumented vformat_to overload
832ec098 Fix argument order in locale overload of vformat_to (#2327)
486a80e8 Move wchar_t overloads to xchar.h
19d45f4b Update changelog
5a2b88f6 Reduce binary size
00a39ad5 Enable `Char` types other than `char` (#2323)
ff37e416 wchar.h -> xchar.h because it handles other code unit types too
0901176f arg_join -> join_view
a9a90181 Move wmemory_buffer to wchar.h
4a7801c3 Update changelog
517578f8 Update changelog
85442ed0 Update changelog
6a12b13a Update changelog
1cfe3c73 Update ChangeLog.rst
c0601479 Update changelog
6fe04871 Update changelog
9d67988a FMT_DEPRECATED_WCHAR -> FMT_DEPRECATED_INCLUDE_WCHAR
765b451e Update changelog
17c993c7 Fixed compilation with CMake < 3.7 (#2321)
dde69373 Update changelog
272b0f36 More module tests (#2309)
126c8cb4 Export os.h API, too (#2318)
98b9ff47 Align hex floats right as default (#2317)
ece4b4b3 Update changelog
a70a4ae0 Ignore zero-padding for non-finite floating points (#2310)
7612f18d Update changelog
b9f2c276 Update changelog
4e21baff Simplify get_units
683ef11a Update changelog
ca466374 qualify make_format_args (#2315)
5a2a1856 Make buffers non-movable
ee52a6dc add `fmt::print()` overload to support compiled format (#2304)
82607efb Fixed int conversion warning (#2313)
35a2c2a7 Refactor chrono formatting
b955e7a6 Refactor chrono formatting
883d9595 Support alternative locale names in tests
1f308a3c Update integer presentation types documentation.
1cd9899c Add initial support for weekday formatting
069131dc Add unicode-test
dd8f38fc Cleanup printf API
a216f256 Remove undocumented and obsolete vprintf overload
0c092639 Add is_exotic_char trait
bc13c6de Update README.rst
8ec0b9e3 Do *not* export namespace `detail`
b99c2bd3 Remove deprecated `locale.h` from module interface unit
c04a2439 Update changelog
b099a56f Update changelog
703005c8 Deprecate locale.h
51f01786 Cleanup the format API
5d59dcf6 Remove deprecated aliases / undeprecate has_formatter
c242dd40 Move cerrno include to where it is used
2216e0b7 Update changelog
1c83a49b Simplify buffer extraction
2617384d Improve buffer extraction
34b8acae More wchar_t-specific API to wchar.h
6326c189 Improve code style consistency
5c4b0c86 Add missing Allocator template argument for basic_memory_buffer in format_to
00149c0b Move detail::null to chrono where it is used
c5c968cb Improve binary size
128cbdeb cmake: hide private symbols by default
18af1dc4 Fix binary size regression caused by b268f88
d1e6f0f8 Fix binary size regression caused by b268f88
5a0d99fa Add a test for the module
6e2e6b79 Restore support for `wchar_t` overloads in module
24b677d0 Improve symbol sizes
63271a51 Fix ADL issues
61b4c923 Reduce code bloat
2a2e4c58 addressing nits.
be48f4d6 Avoid unwanted sign extensions from MSVC in is_utf8.
13e65293 export missed symbols
71fb1138 fix compile error on msvc preview 4 (16.10) involving lookup clash /w STL
08d22503 Remove outdated comments
56f518a9 Update signatures
b7f29337 Update signatures
7483dfc6 Update signatures
95c358f7 Improve separation between code unit types
39c3c4ec Simplify the core API
e9c1c415 Improve compile-time checks
21d93bfd Move generic format functions to format.h
9a92eb41 Move more wchar overloads to wchar.h
0dd91e20 Add wchar.h for wide char overloads
ce14eafc Simplify format string checks
8d70c0ed Refactor the format API
813ac495 More API cleanups
4ab01fb1 Cleanup printf API
d5036b11 Remove deprecated APIs
25819462 Cleanup the core API
b35db4e0 Improve handling of 128-bit ints
d35f1ad5 Cleanup core
8f1902c0 Move format string checks to core.h
6469b903 Silence msvc warning about an unused named parameter
7d4c92fb Update ChangeLog.rst
0763d8ca Fix Visual Studio warning
5466373a Do *not* export namespace `detail`
588bdb54 Simplify get_arg_index_by_name
54f22a3e add support for statically named arguments with FMT_STRING
ea94d6d9 Prevent ambiguity in name lookup
57280762 Move specs checker to core.h
ced30375 Move dynamic specs to core.h
dd2bc998 Move specs to core.h
08da1adc Remove unused headers
3be0cc20 Fix handling of 128-bit ints
9648bdce add missing header
d1aebdbd Inline format_to
8f0fadfa Cleanup docs
02896dab Avoid use after move (#2278)
0036a1d1 Fix issue #2274.
2a9b3146 Replace fmt::error_code to std::error_code
2165bef4 Update README.rst
48629308 Optimize format string compilation
3207a8bb Get rid of unnecessary recursion to enable inlining
6214f15a Optimize standard formatter specialization
cd2c78fb Use write directly in formatter specializations
4211d865 Add a formatter specialization for std::error_code.
39f28424 Cleanup tests
84feeb0f Remove redundant comments and put common case check first
2665afb5 Cleanup add-subdirectory-test
d0abe7c2 Make chrono formatting locale-independent by default
50fb0b5e Fix formatting
16f2ef91 Replace fmt::system_error with std::system_error
4b885c86 Replace windows_error with system_error
5238055f Move esoteric char type support to format.h
9ac088f3 Add fmtlog to projects
849c9f61 Move is_name_start to core
23892caf Move more parsing to core
8e6390c3 Move FMT_STRING to core
51a33713 Move parsing to core
9c3af11a Cleanup tests
9d7b53cb Remove redundant formatter specialization for byte
f0095ccd Add support for ranges of types without formatters to join (#2262)
4f0eadfc Exclude fallback from is_formattable
400b953f Use [] instead of {} in ranges for consistency with Python format
38bcc04a Drop range limit and cleanup tests
c738c343 Cleanup tests
ed7c4320 Cleanup tests
9155e2de Cleanup tests
38127d9e Cleanup tests
c9c0e507 Cleanup tests
ccf4ccde Cleanup tests and format string compilation
e96a92f8 Cleanup tests and format string compilation
fd43e4dc gtest: fix std::is_trivially_copy_constructible for GCC 4.8 & 4.9 properly
3d51ccda gtest: remove obsolete `GTEST_LANG_CXX11` compile definition setting
833377ff gtest: add `.clang-format` file into `test/gtest` directory to prevent formatting there
53ca0cbe gtest: move GTest/GMock files to separate directory, update GTest/GMock usages
342973b3 Make wchar_t overloads usable in module Bring ''detail::find()' into scope.
355be4b1 Make FMT_COMPILE fallback on runtime without if constexpr (#2261)
0cd0fb91 C++17: std::char_traits<>::{compare,length} is constexpr - v2
d1a6e560 Keep defaulted destructors inline applies to exception classes in case of msvc only
84a36b99 Move data to functions
ab7c33ed Suppress checked iterator warnings
77258f60 fix FMT_CONSTEXPR_CHAR_TRAITS check for MSVC
d23e315e CI windows: add MSVC C++20 build
f085c3d7 use proper check for non-type template parameters
69bdc20a Workaround missing std::system on iOS, take 2
847aac43 Follow naming conventions in tests
39818e79 Cleanup core-test
0e6f989b __THROW warning fix for e2k (#2253)
1678ed62 simplify field::format() and spec_field::format(), fix typo
ca821982 use named arg with static name in compile-time API
ce6e7d86 use fixed_string to create named arg class with static name for _a literal
fc56af14 move fixed_string from compile.h to format.h
bb006f97 Replace TYPED_TEST_CASE with TYPED_TEST_SUITE
6956b10b Fix gcc 4.8 build
b4f9a058 Update gtest
8f9ddf45 Remove deprecated posix.h
dacd1356 Add module interface unit
d3c523e0 Export printf-related contexts from printf.h
2c25df08 Export replacement type_traits, too
553022dc Don't use std::system on iOS (#2248)
8a040d18 Cleanup core-test
064cac2b Bump version
5b2c740a Remove deprecated APIs
b9ab5c88 Remove printf.h dependency on ostream.h
c47f2112 Simplify data handling
54d3b171 Move more data out of basic_data
128f007b C++17: std::char_traits<>::{compare,length} is constexpr. (#2246)
841aad95 Move data out of basic_data
1d4199f4 fix udl_compiled_string with non-byte chars (e.g. wchar) (#2242)
c5d4fcb1 Appending a space to guarantee non-empty strftime() result. (#2244)
62714062 Fix a warning (#2233)
52bd62c7 Create separate dllexport marking points for clang and msvc. (#2229)
f4bbc54c Tag official API for module export (#2235)
d8910af8 Use qualified name lookup rather than ADL. (#2239)
92601141 Ranges wide strings support (#2236)
24c97515 Try to suppress MVSC warn of narrowing (#2230)
a1c6bfd7 Add a link to llvm diff
42eccac4 Fix clang warning about ignoring __declspec(dllexport) on basic_data<void> template instantitation definition (#2220)
aec50434 Update README.rst
0b411454 Update README.rst
00f3d16b Update docs
99c2f7a3 Allow including fmt/core.h in the header-only mode
b4415323 CI linux: add clang++-11 C++20 (with LLVM libc++) build
1dbadb65 CI linux: add clang++-11 C++20 build
09dbad47 CI linux: add missing build_type
e2facffe CI linux: remove excessive clang++-9 include
273d8865 Suppress redef warning of _CRT_SECURE_NO_WARNINGS if any. (#2218)
5a8bf1f6 Workaround hexfloat inconsistency on windows (#2205)
78776ee4 Fix a conditional expression is constant warning #2210 (#2211)
266107f5 constexpr uint128_wrapper (#2215)
2e0d64cf specify size for `prefixes` static data
95da4847 Fix a link
06b3a100 Add support for time points with arbitrary durations (#2208)
dac42f52 Inline fallback is_constant_evaluated
7c43f8b8 Don't use strlen at compile time (#2205)
c62e4c30 Make buffer_appender default-constructible when back_insert_iterator is
0d6b70d9 Install gcc 8
15c10b0c Add speech synthesis support
308510eb "Use" `fwrite` result (workaround for `warn_unused_result`)
afe23e7f Don't call fileno on NULL file in tests (#2196)
b49af043 Remove noexcept from file's move assignment
14848875 Fix: fmt::ostream cannot be moved while holding buffered data #2197 (#2198)
7d8c3401 Update pull_request_template.md
b966afcc Remove formattable
ec5315a9 Use strlen when possible in fallback basic_string_view
4f8778ba Inline basic_format_args's ctor
e2d87548 user-defined constructor
f7151d38 Extra flag to prevent Intel compiler with Clang front-end warning of 'unknown attribute no_sanitize'
0fb8ef8f Inline trivial argument handling functions
1b23e25f Simplify formattability check
35c71ff5 Only use -Og with optimizations disabled
243d8beb Enable minimal optimizations in debug mode
9b34681d Work around xl compiler bug when nvcc preprocesses this file (#2190)
4dc7170d Fix C++17 builds: (#2192)
9cb347b4 Simplify argument formatters
0f85a468 add default cases (#2186)
417e1cee Stop using deprecated UDL templates
f7e900e1 Simplify UDL definitions
d9661c8f Mark grouping as deprecated
14a2a64d Fix handling of formattable types with to_string_view (#2181)
6ae402fd Fix handling of types with to_string_view and formatter specialization (#2180)
a6408a3b Add args-test
1147782c Fix an ambiguous call to check caused by ADL (#2184)
2f3f3862 Fix harmless MSVS warning about using undefined _MANAGED symbol (#2183)
d0bded59 Fix MSVC /clr builds (#2179)
8308f52c Fix dynamic_format_arg_store::push_back comment
6151d0dc Fix the comment
5a1127b7 Don't wrap named arg in cref and clarify docs
b8ff3c18 optimize append (#2164)
c8d8b882 fix GCC 7,8,9 warning about unused but set parameter (#2177)
d2810187 Document ostream support limitation
bac14ef9 Simplify integer spec checking
8f9db3fc Make ubsan happy on empty format specs (#2175)
af567538 Bitpack integral prefixes
cdf877d4 Workaround missed optimization opportunity
eef4ba9c Optimize integer formatting without padding
a1ea8a82 Unbloat my heart
a457e163 Simplify integer formatter
05bc87a6 Optimize padding
605b6037 Optimize count_digits for powers of 2
85ba2716 Implement 128-bit count_digits in terms of count_digits_fallback
d9835737 spec -> specs
f9e0e904 Apply clang-format
60f5d244 Simplify arg_formatter
30e1302e Simplify on_format_specs
87c5cd46 Optimize parsing of argument ids
6a9016ea fix `formatted_size` with "compiled format" as argument (#2161)
6e1fc017 Move detail::truncating_iterator to fmt/compile.h
e718ec3e Make truncating_iterator an output_iterator (#2158)
772aeca3 Don't include <cassert>. (#2148) (#2152)
684b5b0e Fix fallback to runtime API from compile-time API (#2143)
d8b92543 use simplified `void_t` for all compilers other than gcc 4.x (#2160)
835b910e Add an is_formattable trait
57887403 Revert "Optimize handling of integer constants" (#2147)
640acba8 Print x.what() of FMT_THROW when exception is disabled (#2145)
d8e1c9f1 fix `fmt::get` for some GCC versions and legacy Clang (#2144)
2797588b Optimize handling of integer constants
e8eff3b8 Fix FMT_STATIC_THOUSANDS_SEPARATOR (#2142)
ab0f7d7f use const& for arguments
29cc8282 update chrono duration formatter (constness), use it in compile-test for specs checks
3f69af3a update wording in the error inside `arg_id_handler`, use `FMT_ASSERT` instead of `throw`
499047e1 fix incorrect indexing mode for named args, update tests
78c67157 prepare tests, fix incorrect handling of named args with simple `{}` replacement fields
b31bc2dc simplify `try_format_argument()`, make `manual_indexing_id()` a variable
95e1aa2d add support for manual indexing and named fields, add tests
7e72673d Improve width estimation (#2033)
13b117b5 Improve code point computation
ee0fed63 Fix handling of the + flag with locales (#2133)
c5979d56 Fix fmt::localtime formatting not working in wide-char string contexts
e6ef927e fmt::ptr: Support function pointers (#2131)
58aa0457 Fix ordering of install commands for CMake (#2122)
1980ca8c fix #2118: FMT_COMPILE did not work with tm formatter (#2119)
2a25e2bf Make ranges-test available with C++11 (#2114)
b0b56b43 fix #2116 (FMT_COMPILE requires exceptions enabled) (#2117)
373262f9 Update docs
ce519e93 Fix exception propagation from iterators (#2097)
acef0bb5 use gcc-10.2 instead of gcc-10.1 on CI, also fix one problem (#2110)
8bf28e6b Add support for s format specifier to bool (#2094) (#2109)
9c418bc4 Update README.rst
456efa46 add missing detail namespace (#2107)
80dc7cce Fixed format.h(1465): warning C4702: unreachable code (#2106)
7fd535c6 Cleanup 'L' handling
b4b8917c Update docs
e4f2cf45 Make 'L' a modifier
6972b5f3 Add build variable: FMT_MASTER_PROJECT (#2100)
ac352081 Install fmt/args.h (#2096)
532e846b Fix width computation in float formatter
f8c2f848 Fix handling of width when formatting int as char
0fe0b15e Fix handling of # in width computation
061e364b Document output_file
018688da Correct a typo on syntax.rst (documentation) (#2081)
9ec5592b Fix writing to stdout when redirected to NUL on Windows (#2080)
cdc5ef67 Remove fallback to inline specifier from FMT_CONSTEXPR(20) macro (#2075)
c9dd1eb9 Don't change charset
d09b5c14 Fix std::byte formatting with compile-time API (#2072)
bbd6ed5b Add support of most format_specs for formatting at compile-time (#2056)
a750bf3a Update api.rst
1256541d Fix formatting
4fa4c924 Add tests for FMT_ENFORCE_COMPILE_STRING, fix several errors (#2038)
aa89e380 add cwchar to format.h for std::fputws (#2073)
5a37e182 Disable warning about format string (#2067)
fa43fd14 Forward arguments to work with views (#2068)
3551f5d1 Workaround a gcc 10 -Warray-bounds bug (#2065)
e7376726 Remove an old mingw workaround (#2059)
25a41b80 Fix a link to Android.mk (#2057)
9293f707 Suppress gcc warning on privates-only class (#2053)
c20874c2 Reenable support for fallback formatter in join (#2040) (#2050)
5de0bc1d Add UDL as replacement for FMT_COMPILE (#2043)
a6fafe2f docs: use https for some links (#2051)
33f9a6d3 Fix handling of enums in to_string (#2036)
aabe0a84 simplify tests by reordering arguments of `EXPECT_EQ` (#2044)
1f4a76d2 Add a missing include (#2047)
4a6eadbd Make std::byte formattabe (#1981)
683a7450 fix formatting with empty compiled format string (#2042)
f43416e1 Add a link to contents from index
5a493560 Move some code from core.h to format.h where it is used
9ed0a981 Fix docs build
dac753b8 Basics of formatting at compile-time based on compile-time API (#2019)
119f7dc3 Truncate file by default
22a68d16 Don't emit trailing zeros by default
d0110b7e Update README.rst
3f4839ce Merge branch 'release' of github.com:fmtlib/fmt
7bdf0628 Update version
fc135511 Update changelog
926233bd Fix test
0683fa7d Bump version
6ce207b9 Fix formatting
07b1c1a1 Update changelog
58992761 Reintroduce ostream support to range formatters (#2014)
b8957f50 Fix an overflow in format_to_n (#2029)
df66516e Workaround an issue with mixing std versions in gcc (#2017)
a57baa69 Fix more linkage errors (#2011)
85534a13 Fix linkage errors when linking with a shared library (#2011)
a2fa5d62 Update changelog
cd300368 Fix more linkage errors (#2011)
d1ef29d6 Fix initialization of iterator_buffer (#1996)
5f41bb0f clang-format
a58a6b27 Add a newline
a036cc97 Reintroduce ostream support to range formatters (#2014)
38c7def4 Update clang version to 3.4 since there are ICEs on earlier ones
55336413 🆕 [CI] Test with C++14 in Windows 2019 (#2020)
55dfdd92 Update README.rst
2c734c9b Fix an overflow in format_to_n (#2029)
6cdd1be9 Update build.gradle for latest AGP (#2026)
bcc20b29 Implement compile-time checks by default
befd7d4a Always use FMT_STRING internally where possible [Issue #2002] (#2006)
f8640d40 Add more standards
f81c14aa Workaround an issue with mixing std versions in gcc (#2017)
5555651c Fix more linkage errors (#2011)
b268f881 detail::write in one more place relevant to printf with long argument… (#2016)
aa9b09a9 🐛 Cannot call non-constexpr function in constexpr context (#2010)
986fa004 Printf get container (#1982)
7abc3c01 Suppress a useless warning (#2004)
6d14f781 Fix linkage errors when linking with a shared library (#2011)
9534b9fe Refactor warning suppression
60dc2735 Simplify on_text
b5dac0f0 Reduce <algorithm> usage (#1998)
a07627b1 🐛 Implicit sign conversion warning in clang in c++17 and 20 modes (#2009)
1b8f499e 🔧 Silence useless cast warnings (#2008)
f428d286 Update README.rst
beb248b6 Optimize handling of large format strings
1936dddc fix gcc warning of missing override (#2001)
14f6bd0f Move one more headers to args.h
e01d26e1 Optimize includes
e528d919 Merge branch 'master' of github.com:fmtlib/fmt
48816772 Update signatures
3302fd10 use memchr for searching for '%' in printf format string (#1984)
4c2d6372 Update signatures
beaff396 Update signatures
ffa0a083 Use newer versions of Sphinx and Breathe
038057eb Document contexts
5bedcb66 Fix initialization of iterator_buffer (#1996)
2435ea41 Workaround MSVC mess
8c6215f5 Fix fmt/color.h
10ebe6cb Document color
1ac50fcb Suppress more bogus warnings
e098be8e Fix warning filtering
8cf0afaf Improve docs
e29f93e8 Suppress more bogus warnings
4e8d000f Suppress more bogus warnings
7787792e Fix re usage
6ee5e507 Fix imports
06ee32d1 Filter useless doxygen warnings
86bb7fe6 Add a missing import
959a9f5c Merge branch 'master' of github.com:fmtlib/fmt
4f7df299 Improve docs
b3ab0bc7 🎨 [CI] Specify the exact version of clang to use (#1991)
701ed6c8 Install deps in github actions instead of script
8f2131cf Document chrono
32c4af8f Document chrono
295a60ec Document chrono
a4fae96c Document chrono
263bb0e6 Document chrono
0506b328 Document chrono
4e426c19 Document chrono
9795d873 Update docs
2eb0be0b Remove debug code and fix bot contact
cd955798 Move less installation to actions
98639d0f Debug doc build
ab5e0632 Debug doc build
b123129f Dump the content of html dir
81d2b986 Print less command
7a0b1d57 Add key
9f0617cb Fix branch ref
75b07598 Chrono docs
dfbb6975 Remove travis config
5b3052f9 Switch doc build to github actions
506ff320 Fix build failure when not using fcntl with -Werror (#1990)
a30b279b Apply clang-format and tweak comments
6a2495c8 -Wattributes visibility warning with some GCC versions (#1975)
cba5970c Remove migrated build configs
689081d8 Merge branch 'release' of github.com:fmtlib/fmt
cc09f1a6 Update version
e4eb242c Update changelog and bump version
ce98e0c6 Fix fallback float formatter at assymetric bounds (#1976)
49544ea9 Fuzz fallback formatter
6b7bfed4 Fix fallback float formatter at assymetric bounds (#1976)
bcab36da Update CI config
1689e73e Move PR template
0103408a Update CI config
38a16ecb Move build config to github actions
205eb3a8 Update CI config
fe61b8c6 Update CI config
867b15d7 Update CI config
98cb9f99 Update CI config
95077d60 Update CI config
bc49f094 Update CI config
cef6dfb4 Update CI config
c8703ba4 Update CI config
ab4405be Update README.rst
78a55e28 Update CI config
d0a2494a Update cmake.yml
89d009ba Update cmake.yml
1f4ff47b Create cmake.yml
eb52ac7a 🆕 Enable -Wshadow in pedantic mode
e904e891 🎨 🐛 Rename all shadowed types and variables
771292c3 Remove sizeof from unused variable silencer (#1974)
86bf6045 Merge branch 'release' of github.com:fmtlib/fmt
5f7f7b95 Update version
5d3f0741 Update changelog and bump version
563cbb6c Add a macro to workaround clang/gcc ABI incompatibility on ARM
425778aa Fix ABI compatibility (#1961)
69a84198 Remove accidental parenthesis (#1968)
5c045049 Removed [-Wsign-conversion] warning in GCC
556a1cfb Instantiate to_decimal to make gcc lto happy (#1955)
28a8eae8 Cleanup
236fea1f Workaround bugs in gcc 8
e50ced88 Add a macro to workaround clang/gcc ABI incompatibility on ARM
112755cf Remove FMT_SAFEBUFFERS (#1966)
4081b2fe Fix ABI compatibility (#1961)
2d9311e8 Remove accidental parenthesis (#1968)
b3a4f28a Fix implicit signedness conversion warning (#1963)
97c88732 Allocator::max_size support in basic_memory_buffer (#1960)
bb68f608 Removed [-Wsign-conversion] warning in GCC
f4ca065c Range support
cb224eca Instantiate to_decimal to make gcc lto happy (#1955)
7977c2b4 Cleanup
e54eb676 Workaround bugs in gcc 8
4fe0b111 Update version
df4bd60f Bump version
764fb35e Always install the required version of breathe
e1bdc0ec Use the correct version of sphinx
39bde329 Tweak markup
204d299a Tweak markup
e0995b1c Update readme
4af178bd Remove outdated build config
aa41dc02 Remove unused script
6a77ea3c Tweak markup
62c72059 Update changelog
c10e3f7f Update changelog
e542e695 Update changelog
530cf316 Point to the release, not dev documentation
740385d6 Update changelog
cd465111 Update changelog
46291be3 Update changelog
90071c1d Update ChangeLog.rst
25293d7a Update ChangeLog.rst
5024742f Update ChangeLog.rst
0452a4e7 Update changelog
8de96817 Woraround bugs in gcc 8
47e16767 Simplify arg formatter
f0a42346 Move parsing optimization one level up
86287b8d Optimize common case in parse_format_specs
8924211f Update README.rst
525e7649 Update CONTRIBUTING.md
0ecb3d18 Optimize alignment parsing
97553078 Optimize format_uint
7446818f Simplify vformat_to
280b5612 Add option to force usage of inline namespaces
e57ec7d5 Merge vformat_to overloads
2a3f4de3 Remove iterator_category
27fdb4ea Unshadow floaty
297e0bad Apply clang-format
e3b4c22e Simplify is_output_iterator
da8278e1 Update changelog and bump version
17fba753 added position independent documentation (#1939)
71e705a2 Update README.rst
74654c8c Fix compilation for systems without fcntl.h (#1942)
f468b203 Avoid conversion from long long to size_t (#1935)
20d4f2e8 Fix handling of weird character types when parsing sign (#1932)
08370c39 Update README.rst
bd3c7925 Fix float fuzzer
8d3fd86d Merge branch 'master' of github.com:fmtlib/fmt
40347157 Update README.rst
37d738fa Update README.rst
271eff14 Make classes derived from buffer<T> final to silence the virtual destructor warning. (#1937)
010efc31 Add float fuzzer and cleanup
811c8b58 Add float fuzzer and cleanup
82c4e223 Cleanup fuzzing
63e40c96 Fix naming of fuzzers
2f448ed5 Fix fuzzer timeouts
af283059 Cleanup
48ea8193 Explain why assert-test is a separate test
1d112bdd Remove old test
5eb292a6 Update README.rst
7e56b6b6 Fix coding style and remove duplicate fuzzer
41d97e1e Fix a UB on ridiculously large precision
01c37e0a Added check for `-mbig-obj` and ref qualifier check (#1929)
a5e7e7db Fix handling of thousand separator (#1927)
bf19051a Optimize floating point formatting
3c13a88b Optimize floating point formatting
f6d75c53 Refactor write_float
e9c0b2d6 Merge write_float overloads
7eddbfed Cleanup exponent handling in write_float
b347b302 Update dynamic_formatter comment (#1923)
3541880e Fix integer overflow when using max int precision
7b50dc0b Don't exclude all detail symbols from docs
28052431 Fix the doc config
34f22e88 Cleanup CMake config
a18b3fbb Fix fixed precision handling when rounding (#1917)
72770357 Fix long lines in usage.md
7612c1ea Add reference to lhelper package manager in usage
b91d39f2 Get rid of float_writer
b4b64b9c Refactor float formatting
712abe40 Workaround a bug in gcc 7.5 (#1912)
af8a180a Make GetCachedPower test more precise
a581e9e5 Fix warning C4018: '<=': signed/unsigned mismatch (#1908)
05a28312 Update docs
4d0aa4d8 Update link
575f4018 Simplify FP formatting and follow coding conventions
6f3536f9 Move zero-check to an earlier branch (#1906)
90ef46df Fix dragonbox integration
3ae88147 Fix declaration
64179525 Improve dragonbox integration
79694d42 Fix WriteConsole signature
51f2e2ca Move nan test to where it belongs
68555fdb Make format-test not depend on color.h
63e0c354 Make dragonbox::to_decimal available in format.h
2213a711 Update README.rst
79ba37f3 Update README.rst
a905d8f7 Merge grisu-test into format-test
762c33a9 Simplify windows handling (#1903)
253d6315 Remove dependency on windows.h (#1900)
c156093f Fix carry in fallback_format
34179b33 Update format.h (#1898)
0651e459 Minor tweaks to get_cached_power
6c025520 Test that max_k is correctly defined
51f8d0cc Reuse log10_2_significand constant
1305cbeb Fix MSVC2019 error C2049 when compiling with /clr (#1897)
2d4fde3a Don't emit trailing zero for consistency with std::format
5fd89d50 Minor simplifications
605ce5e4 Simplify divisible_by_power_of_2
085171e7 Remove grisu_count_digits
aa729bf2 Remove dead code
aa2ddf9b Simplify Dragonbox integration
c1654ce4 Simplify uint32_or_64_or_128_t definition
33712dc0 Combine pragmas
e5942ac9 Tweak comments
aae7a133 Remove unused pragmas
6bcde9aa https://github.com/fmtlib/fmt/pull/1882#issuecomment-696823912 (#1894)
bb0db5e5 clang-format
16410056 Optimize copy_str for counting_iterator
2591ab91 MSVC optimizations for count_digits. (#1890)
d5b8002d Update README.rst
821471e1 qkw: generalizing aliasing | using fmt library and it's features (#1888)
2e620ddb Small improvements that should have zero to negligible impact on the runtime (#1887)
2f7e0885 Disable range formatter if value type is not formattable (#1885)
c46a8de4 Simplify test
2696dc92 add forgotten template argument to make_format_args which made some u… (#1877)
0016da7a Don't generate zeros and fix UB on huge precision
ce3f7699 Merge intrinsic blocks
3b6248f6 Change formatting
2d9b1dd0 Fix sign mismatch
1f0600a2 Fix bug regarding FMT_SAFEBUFFERS
2ecdbb98 Fix a bug in ctzll
6f81ea15 Fix typo (and thus bug)
0c8ffe9b Implement Dragonbox (first version)
42699bf4 Fix msvc version of clz & clzll (#1880)
bc51a8df Disable fallthrough attributes for the Intel compilers on Linux and MacOS (#1879)
45da432d fix compiler warnings in public header files
d55e61f1 Improve FMT_ALWAYS_INLINE (#1878)
7e682752 Remove trailing zeros when using fallback formatter (#1873)
1d696dc2 Handle exotic character types in compilation
f674434a Add format_to_n overload that accepts FMT_COMPILE (from #1767) (#1869)
5b5a5971 Fix handling of wide alignment
f80ed64d Update README.rst
38139664 Simplify fallback format
dce8e49b Handle float in fallback formatter
78b59443 Spelling
f233b56c Don't generate insignificant digits
595902f8 Update test
4f2ee892 Use built-in FP formatter for any precision
58a044be Use built-in FP formatter for any precision
efe3694f Macro tweak and clang-format
9f312fe8 Implement fallback FP formatting with given precision (#1526)
fb289cf5 Fix coding conventions
86f0a704 Fix formatting
bff4d18e Add color format_to overloads * Fix variable size basic_memory_buffer colorization * Fix an unused arguments warning on GCC that blocks the CI otherwise * Ref #1842 * Ref #1593
f19b8885 Fixed a warning in mingw32/mingw64 (#1860)
f8e00a08 NOMINMAX not handled properly (#1855)
6cccdc24 Fix move constructor (#1844)
69902c17 Allow use of <fcntl.h> in Linux when __has_include is not available (#1848)
1edd38b9 Add append mode. (#1847)
e66ba169 Added build2 usage instructions. (#1838)
f39e6fb6 Add formatters for chrono::time_point<system_clock> (#1837)
77b627be Fix bogus MSVC warnings (#1825)
5dff01d3 Add complex tests
d16d585e Update signatures
c7e6d8af Fix usage of override (#1836)
92bff2fe Revert "Add missing includes"
a0dcfbc5 Add ptr to docs
1651b2d4 Fix detail::write with fallback formatter (#1829)
06895a76 Add missing includes
92a448a0 Apply clang-format
6be65446 Fixing buffer_appender's ++ slicing (#1822)
951e0d23 CMakeLists.txt: Added Wundef warning to clang and gcc. (#1823)
f9f02df7 CMakeLists.txt: Clang-warnings: removed -Wno-sign-conversion (#1817)
76e97dc4 Eliminate shadowed variable warnings on intel (#1816)
e204df0e nvcc compiler should be EDG-based, but fails test (#1818)
1c8bb547 small changes to reduce clang-9 warnings (#1808)
4b69c787 fix: warning C4100: unreferenced formal parameter (#1814)
fb0aeb82 fix: disabled UDL templates for PGI (#1811) (#1812)
54daa086 Add dynamic width support to FMT_COMPILE (#1809)
6fb7c6fb Workaround a bug in gcc10 (#1810)
16985fda Update README.rst
1378ddae Update README.rst
4fd95e4b Don't remove trailing zeros with #
e06ae322 Avoid warnings on functions with external linkage that don't have declarations
7fc3d1f5 Add override to grow
065889a5 Use correct capacity in iterator_buffer (#1807)
d0dd6786 Adding convenience append(range)
0e7cef06 Merge commit 'c13f79e0'
e2c8c455 Update README.rst
e4c954ff Update README.rst
c13f79e0 Merge release branch
d7921d64 Update README.rst
4a4fc225 Update changelog
61602a75 Remove -Wno-shadow
2f8fc29e Update README.rst
717b226b include/fmt/format.h: explicit cast to std::size_t for parameter to buffer.resize() in order to get rid of warning 'implicit conversion changes signedness:' in clang-8 (#1802)
2a69f567 Tweak buffer size
ea769338 Simplify ostream
5413713c Remove unused function
57f46242 Increase the default buffer size
0b6e7cc6 Update README.rst
e587adb4 Simplify count_digits
279d698e Fix handling of default alignmment with locale (#1801)
76cfb50b Test complex formatter
20829120 Optimize count_digits
8d9ab967 Cut a few cycles from count_digits
73434493 Simplify ostream_params
2a47a1e4 Update README.rst
7c4c5c79 Make buffer size configurable
f0b84da5 Don't use 128 bit integers with clang-cl (#1800)
a3dfd6f9 Workaround a bug in msvc
51d05521 Workaround broken numeric_limites, part 2 (#1787)
21c8b5c1 Report error on missing named argument (#1796)
d82fdcc9 Fix handling of iterators in locale-specific formatting (#1782)
633213d9 Merge release branch
e8f2580a Bump version
6cefe55a Update changelog
64e2da15 Update README.rst
1c8c810f Update README.rst
c2399ccf Update README.rst
a7c5db06 Update README.rst
a4c22acd Update README.rst
0c1f4b5a Update README.rst
63b422ee Update README.rst
26e81a67 Update README.rst
de5fc6af Update README.rst
9c2edfd1 Partially revert 638db5 because it breaks the doc build
810357c0 Document color
0a7032a4 Update README.rst
95d3abf9 Make format_to_n part of the core API
98626093 Correct the locale format specifier in api.rst (#1792)
47f8d7a3 Make formatted_size part of the core API
46a63b70 Update docs
430f393d Disabled __attribute__((deprecated)) usage for LCC (#1790)
febffa4e Make join() handle non-const-only begin/end ranges (#1786)
d69e2da2 Fix apidoc
ce73ea37 Reorder functions
d39d661b Workaround broken numeric_limits (#1725)
c228bfe8 Improve docs
38ce19f7 Update README.rst
d11849bc Add FMT_REDUCE_INT_INSTANTIATIONS flag (#1781)
c08518a2 Move make_args_checked to the public API
e2837084 Add a color section
9f0c0033 Simplify format string checks
d615137c Improve handling of buffer iterator
26b47b6f Bump tested CMake version to 3.18
7a01c9c5 Update README.rst
b17d5c4f Fix a regression in handling digit separators (#1782)
eb90da2e Type erase output iterators
9d3cd0af Type erase output iterators
18024853 Fix compatibility with CMake 3.4 (#1779)
f5d4215b Trying to clear ambiguous compile time claims (#1775)
c26349f4 Improve error reporting
f4b11ef6 Add a short anchor
0097cf11 Report unformattable type name more prominently
8fa20b47 dev -> latest
a03bd3dd Autodetect MSVC static runtime (#1770)
c108ee1d Clarify a comment
a8074a86 Update README.rst
5f629548 Update README.rst
bd903f96 Clarify precedence
16cac46a Improve handling of streamable and convertible to bool types (#1766)
415cd519 direct_buffered_file -> ostream
e1bfb596 Fix handling of code units in compile
ba8d98cb Cleanup direct_buffered_file
04a1f6e9 Improve handling of single code units in compile
e4f57bfd Add an overload of write for buffer_appender
d8704681 Make append work with fixed-size buffer
e8ec09ae Cleanup core-test
a2c4fed9 Double buffering no more
36406509 Add a fixed buffer
60c43e87 Apply clang-format
b998e0f3 Reduce symbol sizes and simplify iterator use
c5adfc51 Update README.rst
c4ad94ce Update README.rst
c1429651 Fix image source link
638db5ca Use Cmake to find Python and Sphinx-doc.
c0905697 Update readme
1efdb2dd Simplify readme
dc69afad Cleanup example
445f5d39 Break long lines
23063c34 Update readme
f57b6257 Move PR template to the top level

git-subtree-dir: externals/fmt
git-subtree-split: 9e8b86fd2d9806672cc73133d21780dd182bfd24
2021-06-23 03:39:40 -04:00
Wunkolo
c6125082ea emit_x64_floating_point: AVX512 implementation of EmitFPMinMaxNumeric 2021-06-20 10:12:27 +01:00
Wunkolo
a1192a51d8 tests: add F{MIN,MAX}NM tests 2021-06-20 10:12:27 +01:00
MerryMage
e61e771a5f README: Update link to higan 2021-06-19 11:37:32 +01:00
SachinVin
a626a2ec63 ir_emitter: Remove 32-bit-only SubWithCarry 2021-06-11 17:27:34 +01:00
Wunkolo
776208742b emit_x64_{vector_}floating_point: Centralize implementation of FP{Vector}{Abs,Neg}
Removes dependency on the constants at the top of some files
such as `f16_negative_zero` and `f32_non_sign_mask` in favor
of the `FPInfo` trait-type.

Also removes bypass delays by selecting between instructions
such as `pand`, `andps`, or `andpd` depending on the type
and keeps them in their respective uop domain.

See https://www.agner.org/optimize/instruction_tables.pdf for
more info on bypass delays.
2021-06-10 00:04:57 +01:00
Wunkolo
759459e181 tests: Add FABS tests 2021-06-10 00:04:57 +01:00
Wunkolo
58ffde23f9 bit_util: Make Replicate constexpr 2021-06-10 00:04:57 +01:00
SachinVin
ccf27f9c8c ir_emitter: Remove 32-bit-only AddWithCarry 2021-06-09 01:54:03 +01:00
Wunkolo
5385edcc66 emit_x64_vector_floating_point: AVX512 implementation of EmitFPVector{Min,Max}{32,64} 2021-06-08 17:50:28 +01:00
Wunkolo
87aac2a46b tests: Add F{MIN,MAX} tests
Very minimal tests that includes some denormals and {Q,S}NANs
2021-06-08 17:50:28 +01:00
Wunkolo
0c67b913fe backend/x64: Add vcmp constants 2021-06-08 17:50:28 +01:00
Wunkolo
8fde505943 backend/x64: Add vfpclass constants
Bit-wise constants for use with the `vfpclass` instruction.
2021-06-08 17:50:28 +01:00
Wunkolo
c82e29ed82 backend/x64: Add vrange constants
Adds compile-time `FpRangeLUT` for generating the 8-bit
immediate LUT value for the `vrange*` instruction
2021-06-08 17:50:28 +01:00
MerryMage
c1d5a7977e Add Unsafe_IgnoreStandardFPCRValue optimization 2021-06-08 17:26:45 +01:00
Wunkolo
c157dfcc4c emit_x64_vector: Reduce gf2p8affineqb requirement to GFNI
Currently, every usage of `gf2p8affineqb` is guarded by the
`AVX512F + AVX512VL + GFNI` requirement, when really
we only need `GFNI` on its own.

This will allow `GFNI`-only chips to get emit GFNI features without
needing to have AVX512 as well.
There _are_ chips in existance currently that strictly ship with GFNI and
have no implementation of AVX1/AVX2/AVX512(and thus no VEX/EVEX
encoding) such as Tremont(Lakefield) chips.
2021-06-08 14:00:00 +01:00
Wunkolo
e47d0d11c3 emit_x64_vector: AVX512 implementation of EmitVectorNot
Single in-place ternary logic instruction.
2021-06-08 03:11:38 +01:00
Markus Wick
0c12614d1a A64/config.h: Split fastmem and page_table options.
We might want to allocate different sizes for each of them.
e.g. for the unsafe fastmem approach without bounds checking.
Or for using the full 48bit adress range (with mirrors) by allocating our real arena as close to 1<<47 as possible.
2021-06-06 17:25:51 +01:00
MerryMage
828959caed IR: Implement FPVector{To,From}Half32
Implement ASIMD VCVT (half) in terms of this instruction.
Correct handling of ASIMDStandardValue.
2021-06-05 03:39:48 +01:00
Wunkolo
9a23c09c3b emit_x64_floating_point: AVX implementation of ZeroIfNaN 2021-05-31 13:41:05 +01:00
Wunkolo
e9c5c01eda emit_x64{_vector}_floating_point: AVX512 implementation of ZeroIfNaN
Using a single `vfixupimm` to turn `QNaN`/`SNan` to `+0`
2021-05-31 13:39:56 +01:00
Wunkolo
fe5abdb3e1 backend/x64: Add vfixup constants
Adds compile-time `FixupLUT` function for generating the 32-bit
LUT of src->dst mappings
2021-05-31 13:39:56 +01:00
MerryMage
0a77ee1a58 tests: Format to clang-format mandated style 2021-05-31 12:54:27 +01:00
MerryMage
1d9a0415f9 github: Add clang-format action 2021-05-31 12:51:47 +01:00
MerryMage
bda1399a69 travis: Remove travis 2021-05-31 12:51:47 +01:00
merry
1672f907af github: Add build-and-test workflow 2021-05-31 12:51:47 +01:00
Lioncash
07710c89b6 CMakeLists: Add missing EXCLUDE_FROM_ALL specifiers 2021-05-31 11:20:45 +01:00
MerryMage
8235de9829 {a32,a64}_emit_x64: Fix fast_dispatch_table_lookup call in Unpatch on W^X systems
fast_dispatch_table_lookup is in JITted code, and thus execution must be enabled before it can be called.
2021-05-30 22:30:51 +01:00
MerryMage
0a98e5d3d7 exception_handler_*: Simplify message for case when exception is not our fault 2021-05-30 22:22:02 +01:00
MerryMage
9815502fee emit_x64_data_processing: operand in EmitExtractRegister is not modified 2021-05-30 22:18:21 +01:00
Markus Wick
36c3b289a0 fixup! a64/fastmem: Implement fastmem on 128 bit memory access. 2021-05-28 22:14:09 +01:00
Markus Wick
e82685223a a64/fastmem: Implement fastmem on 128 bit memory access. 2021-05-28 18:49:31 +01:00
Markus Wick
ff01b1c6f9 a64/fastmem: Only generate abort handler if needed.
If fastmem fails, we call the callback from the signal handler. So this callback proxy in slowmem won't be used ever.
2021-05-28 18:49:31 +01:00
Jeremy Van de woestyne
b4ee976a6f unit tests & various fixes 2021-05-28 18:49:31 +01:00
MerryMage
709773dcf1 a64_emit_x64: Implement fastmem for A64 frontend for 8-64 bit reads/writes 2021-05-28 18:49:31 +01:00
Merry
bbffae2f96 emit_x64_vector_saturation: AVX implementation of EmitVectorSignedSaturated 2021-05-28 15:34:49 +01:00
Merry
56e3bf57d2 emit_x64_vector_saturated: Consolidate unsigned operations into EmitVectorUnsignedSaturated 2021-05-28 15:34:49 +01:00
Merry
a76e8c8827 emit_x64_vector_saturation: Reduce esize noise in EmitVectorSignedSaturated 2021-05-28 15:34:49 +01:00
Merry
de31caca49 emit_x64_vector_saturation: AVX implementation of EmitVectorUnsignedSaturatedSub32 2021-05-28 15:34:49 +01:00
Merry
b46e6a24dc emit_x64_vector_saturation: AVX implementation of EmitVectorUnsignedSaturatedAdd32 2021-05-28 15:34:49 +01:00
Merry
d087ef42b9 emit_x64_vector_saturation: AVX implementation of EmitVectorUnsignedSaturatedSub32 2021-05-28 15:34:49 +01:00
Merry
0a232a6fbf emit_x64_vector_saturation: AVX2 implementation of EmitVectorUnsignedSaturatedAdd64 2021-05-28 15:34:49 +01:00
Wunkolo
57601f064b emit_x64_vector_saturation: AVX512 implementation of EmitVectorSignedSaturated 2021-05-28 15:34:49 +01:00
Wunkolo
332c26d432 emit_x64_vector_saturation: AVX512 implementation of VectorUnsignedSaturated{Add,Sub}{32,64} 2021-05-28 15:34:49 +01:00
Wunkolo
fa8cc1ac36 backend/x64: Add constants
Used to redefine x86 assembly-constants without
including platform-dependent headers such as `immintrin.h`.

Currently includes vpcmp constants as well as ternary logic
utility-terms.

Removes `immintrin.h` requirement from emit_x64_vector_saturation
and updates our usage of `vpcmp` and `vpternlog` with the new constants
2021-05-28 14:13:11 +01:00
Wunkolo
e8c266d0d3 tests/A64: Add VQADD/VQSUB unit tests 2021-05-28 14:13:11 +01:00
merry
8b4c73c833
README: Update readme
- Add 'projects using' section
- Update guest architectures supported section
2021-05-26 17:18:06 +01:00
MerryMage
6f87951178 externals: Remove unused submodule 2021-05-25 21:59:40 +01:00
MerryMage
f6f8024fb5 a32_emit_x64: Dump x64 disassembly upon fastmem patch failure 2021-05-25 21:57:29 +01:00
MerryMage
4256d21481 common: Add x64_disassemble 2021-05-25 21:56:59 +01:00
MerryMage
731c7fa4d9 externals: Build zydis 2021-05-25 21:32:34 +01:00
MerryMage
eed33f255d externals: Add zycore
Merge commit '80d62f224900ab486a5bc5a6e80ce1e25a0e38e8' as 'externals/zycore'
2021-05-25 21:28:58 +01:00
MerryMage
80d62f2249 Squashed 'externals/zycore/' content from commit 0c372cdef
git-subtree-dir: externals/zycore
git-subtree-split: 0c372cdefe799e99812c008a0b74537bfa5fe077
2021-05-25 21:28:55 +01:00
MerryMage
343b21ff7b externals: Add zydis
Merge commit '6ee9beab3209bc301af98ee881bd15f0aeea2513' as 'externals/zydis'
2021-05-25 21:23:45 +01:00
MerryMage
6ee9beab32 Squashed 'externals/zydis/' content from commit 25193db00
git-subtree-dir: externals/zydis
git-subtree-split: 25193db008e8799ff59fd655c2a26b2ffd79d40d
2021-05-25 21:23:39 +01:00
Mai M
fff4d9a4c7
Merge pull request #612 from Wunkolo/cpuinfo-concise
cpu_info: Add CPU Name, Family, compact output
2021-05-24 15:57:23 -04:00
Wunkolo
dc7fb1f3ed cpu_info: Add CPU Name, Family, compact output
Compacts and formats the output a bit to be much more
concise. Sorts CPU features by alphabetical order. Mostly
to speed up `HostFeature` testing.
2021-05-24 12:25:01 -07:00
MerryMage
17ae7f9ce1 IR: Implement IR instruction CallHostFunction 2021-05-23 15:44:57 +01:00
Wunkolo
3c693f2576 emit_x64_vector: AVX512VBMI implementation of EmitVectorTableLookup128
Also adds AVX512VBMI detection to host_feature
2021-05-22 22:48:31 +01:00
Wunkolo
37b24ee29e emit_x64_vector: AVX512{VL+BW} implementation of EmitVectorTableLookup128
Based off of the SSE41 implementation but utilizing
embedded broadcasting, mask registers, and
the special zero-mask to default-initialize out-of-bound
indices to zero in the `is_defaults_zero` case.
2021-05-22 22:47:21 +01:00
Wunkolo
9ba5e8e52d tests/A64: Add TBL/TBX instruction unit tests
Tests the TBL instruction with implementation with {1-4} register
lookups and the handling of out-of-bound indices.
Intended to target the implementation of VectorTableLookup128
2021-05-22 22:47:21 +01:00
MerryMage
53493b2024 Add .clang-format file
Using clang-format version 12.0.0
2021-05-22 15:07:02 +01:00
MerryMage
51b155df92 A32: Introduce PreCodeTranslationHook 2021-05-22 14:16:10 +01:00
Merry
714216fd0e Consolidate all source files into src/ directory 2021-05-19 17:41:59 +01:00
MerryMage
c6ecc835b6 ASIMD: Implement VCVT (between half-precision and single-precision) 2021-05-16 23:48:29 +01:00
MerryMage
d93145bd04 decoder_tests: Only run ASIMD decoder test explicitly
The test is a 2 minute test whose result only really matters if the ASIMD decoder is modified.
2021-05-16 21:48:25 +01:00
MerryMage
9de58f2875 assert: Check for unreachable code if DYNARMIC_IGNORE_ASSERTS isn't enabled 2021-05-16 21:46:44 +01:00
MerryMage
5bf74b5f04 reg_alloc: Determine size of spill slot with sizeof 2021-05-16 21:46:10 +01:00
MerryMage
b6bff56523 translate_thumb: Update current_instruction_size in TranslateSingleThumbInstruction 2021-05-16 10:31:30 +01:00
Wunkolo
2c0be5e18c emit_x64_vector: AVX512 Implementation of EmitVectorNarrow{32,64}
Includes a new test case with the XTN instruction to verify
the implementation
2021-05-16 10:02:49 +01:00
MerryMage
1643e8f3c6 translate_thumb: VFP/ASIMD conflict with coprocessor instructions 2021-05-15 20:54:35 +01:00
Wunkolo
105b464bc1 backend/x64: Implement HostFeature 2021-05-14 21:20:21 +01:00
MerryMage
b93ae62acf thumb32: Add coprocessor instructions 2021-05-13 18:15:35 +01:00
MerryMage
5ebe11c329 reg_alloc: Inform RegAlloc about rsp changes 2021-05-07 12:47:55 +01:00
MerryMage
05a6b5f623 translate_thumb: Permit ASIMD element or structure load/store instructions to be translated 2021-05-07 12:47:55 +01:00
MerryMage
62ecc2537e print_info: Add thumb mode 2021-05-07 08:24:51 +01:00
sunho
cb79bfa1dc thumb32: Support setflags in shift reg instructions 2021-05-05 11:47:49 +01:00
MerryMage
075fdeaee0 thumb32: Add Rn argument to ADD/SUB (Plain Binary Immediate) 2021-05-05 11:47:49 +01:00
MerryMage
ebe44dab7a stack_layout: Ignore warning C4324 for StackLayout
We expect the structure to be padded
2021-05-04 16:26:28 +01:00
MerryMage
462c884685 frontend/A32: Correct more IT state 2021-05-04 16:25:24 +01:00
MerryMage
c5f5c1d40f frontend: Standardize emitted IR for exception raising 2021-05-04 16:14:26 +01:00
MerryMage
3b2c6afdc2 backend/x64: Move cycles_remaining and cycles_to_run from JitState to stack 2021-05-04 14:40:13 +01:00
MerryMage
d6592c7142 Remove ExceptionalExit hack 2021-05-04 14:40:13 +01:00
MerryMage
030ff82ba8 backend/x64: Move check_bit from JitState to stack 2021-05-04 14:40:13 +01:00
MerryMage
a1950d1d2f backend/x64: Move save_host_MXCSR from JitState to stack 2021-05-04 14:19:05 +01:00
MerryMage
ddbc50cee0 backend/x64: Move spill from JitState onto the stack 2021-05-04 14:18:44 +01:00
MerryMage
f8d8ea0deb thumb32: Implement MRS (register) 2021-05-04 12:43:51 +01:00
MerryMage
61333917a4 thumb32: Implement MRS (register) 2021-05-04 12:43:38 +01:00
MerryMage
a5a210a9a5 T32: Add ASIMD instructions 2021-05-04 00:09:55 +01:00
MerryMage
d1e62b9993 T32: Add VFP instructions 2021-05-04 00:09:55 +01:00
MerryMage
cd837c5b37 A32: Merge ArmTranslateVistor and ThumbTranslateVisitor 2021-05-04 00:09:55 +01:00
MerryMage
6d292e3eac decoder: Ensure more compiler-time computation
Replace with consteval when C++20 hits
2021-05-03 13:09:51 +01:00
MerryMage
795b9bea9a Remove ChangeProcessorID hack
* No library users require this hack any longer.
2021-05-01 20:33:14 +01:00
MerryMage
6404f58d23 rsqrt_test: Fix on GCC 2021-05-01 20:33:14 +01:00
MerryMage
6759942b56 emit_x64_data_processing: Correct bug in ArithmeticShiftRight64
This branch of this implementation is unused, and thus has not been tested.
2021-04-27 18:51:23 +01:00
MerryMage
68088c277c emit_x64_data_processing: Reduce codesize of RotateRight32 for carry case 2021-04-26 21:57:22 +01:00
MerryMage
f77b98de36 emit_x64_data_processing: Reduce codesize of ArithmeticShiftRight32 for carry case 2021-04-26 21:57:08 +01:00
MerryMage
a2a687f208 emit_x64_data_processing: Reduce codesize of LogicalShiftRight32 for carry case 2021-04-26 21:56:42 +01:00
MerryMage
58ff457339 emit_x64_data_processing: Reduce codesize of LogicalShiftLeft32 for carry case 2021-04-26 21:35:06 +01:00
MerryMage
510862e50c backend/x64: Change V flag testing to cmp instead of add
Prefer a non-destructive read to a destructive read.
2021-04-26 00:26:28 +01:00
MerryMage
f35d98c923 fuzz_with_unicorn: Widen scope of floating point fuzzing 2021-04-26 00:26:28 +01:00
MerryMage
3f74a839b9 emit_x64_floating_point: Optimize 64-bit EmitFPRSqrtEstimate 2021-04-26 00:26:28 +01:00
MerryMage
7bc9e36ed7 emit_x64_floating_point: Optimize 32-bit EmitFPRSqrtEstimate 2021-04-26 00:26:28 +01:00
MerryMage
e19f898aa2 ir: Reorganize to new top level folder 2021-04-21 22:22:07 +01:00
MerryMage
5bec200c36 block_of_code: Add santiy check that far_code_offset < total_code_size 2021-04-21 18:26:26 +01:00
MerryMage
08ed8b4a11 abi: Consolodate ABI information into one place 2021-04-21 18:25:04 +01:00
Lioncash
f5263cc196 thumb32: Implement exclusive loads
Implements the remaining loads for ARMv7
2021-04-19 19:46:19 +01:00
MerryMage
9c6332fcbd thumb32_load_store_dual: imm8 in STREX should be shifted left by 2 2021-04-19 18:57:28 +01:00
MerryMage
b2a4da5e65 block_of_code: Correct SpaceRemaining 2021-04-11 15:37:25 +01:00
Lioncash
6241ff6be2 thumb32: Implement STREX variants
Implements the exclusive store instructions. Now all that remains for
ARMv7 load/stores to be done is the exclusive loads.
2021-04-10 17:15:19 +01:00
MerryMage
d8066b091b decoder/arm: Complete instruction version information 2021-04-10 17:11:24 +01:00
merry
71491c0a4a
Merge pull request #596 from degasus/fix_perf_register
backend/x64: Fix PerfMapRegister usages.
2021-04-05 21:43:10 +01:00
MerryMage
9ab83180db {a32,a64}_interface: Clear exclusive state during an exceptional exit
This is normally done by the ERET instruction during a service call.
2021-04-02 19:33:28 +01:00
MerryMage
c788bcdf17 block_of_code: Enable configuration of code cache sizes 2021-04-02 11:17:46 +01:00
Markus Wick
b2acdec8cb backend/x64: Fix PerfMapRegister usages.
Both the far code and fast_dispatch_table_lookup were missing.
2021-04-02 00:17:07 +02:00
merry
d0372aebaf
Merge pull request #592 from lioncash/dual
thumb32: Implement LDRD/STRD/TBB/TBH
2021-04-01 20:54:10 +01:00
bunnei
1819c2183f
backend: x64: block_of_code: Double the total code size. (#595)
- The current limits are being hit in yuzu with some games (e.g. newer updates of BotW and SSBU).
- Increasing this fixes slow-downs in these games due to code being recompiled.
2021-04-01 20:53:49 +01:00
MerryMage
c4cff773b9 emit_x64_vector_floating_point: Avoid checking inputs for NaNs for three-ops where able 2021-03-28 21:54:36 +01:00
Wunk
e06933f123
block_of_code: Allow Fast BMI2 paths on Zen 3 (#593)
BMI2 instructions such as `pdep` and `pext` have been
known to be incredibly slow on AMD. But on Zen3
and newer, the performance of these instructions
are now much greater, but previous versions of AMD
architectures should still avoid BMI2.

On Zen 2, pdep/pext were 300 cycles. Now on Zen 3 it is 3 cycles.
This is a big enough improvement to allow BMI2 code to
be dispatched if available. The Zen 3 architecture is checked for
by detecting the family of the processor.
2021-03-27 21:36:51 +00:00
Merry
c28f13af97 emit_x64_vector: Bugfix for EmitVectorReverseBits on AVX-512: Do not reverse bytes without vector 2021-03-27 21:32:43 +00:00
Merry
4d33feb1fa emit_x64_vector: Bugfix for EmitVectorLogicalShiftRight8: shift_amount can be >= 8 2021-03-27 21:32:07 +00:00
Merry
91337788ee emit_x64_vector: Bugfix for EmitVectorLogicalShiftLeft8: shift_amount can be >= 8 2021-03-27 21:31:51 +00:00
Merry
dc37fe6e28 emit_x64_vector: Bugfix for ArithmeticShiftRightByte: shift_amount can be >= 8 2021-03-27 21:31:22 +00:00
MerryMage
2f9dea5cc3 Squashed 'externals/xbyak/' changes from 0140eeff1..590c10e37
590c10e37 fix typo
396715a89 use github action
69a25fd92 change build status to travis-ci.com
a6a9dac91 meanings of the name
8d1e41b65 test_util.cpp supports OpenBSD
77ffe7173 Merge pull request #115 from Ryan-rsm-McKenzie/master
a1da3403a fix build interface include directory
e0136d4ef fix add_library call with INTERFACE
3071eee0c support slightly more modern cmake
e626d6209 v5.991
a49c4bc11 disable XBYAK_CONSTEXPR for g++-5 -std=c++-14
70777a699 Merge branch 'atafra-old_mac_fix' into dev
6b81678d0 fixed compile error on some older macOS versions
2c3b43f15 refactor util
91784e2b8 test_util checks AMX and AVX_VNNI
70b70c557 update to v5.99
284cc5bed refactor
6b3eb9c1e default encoding is always evex
f85b1100b refactor vnni
276d09bae Merge branch 'akharito-akharito/adl_support' into dev
50df86ce3 v5.98
97ce92d58 Merge branch 'akharito/adl_support' of https://github.com/akharito/xbyak into akharito-akharito/adl_support
1f119a04a support [scale * reg]
9ee1bef9a cpuid - check that GRT CPUID leaf 7 subleaf 0 should return EAX=1
be93adb2c add AVX VNNI instruction support
0c277240a add ADL CPUID
a9a5cc2e2 Add option to choose VEX or EVEX encoding
29bfd25ba fix indent
a0c49fa2e Merge branch 'atafra-mac_avx512_fix' into dev
ea388b3c6 fixed incorrect detection of AVX-512 on macOS
ed1b8186f Merge branch 'FEX-Emu-extended_features' into dev
3dacddfec Merge branch 'extended_features' of https://github.com/FEX-Emu/xbyak into FEX-Emu-extended_features
898f78ca3 Merge branch 'kariya-mitsuru-use-sh'
0b7f1411c Merge branch 'use-sh' of https://github.com/kariya-mitsuru/xbyak into kariya-mitsuru-use-sh
99e2b13b2 Fixes extended feature support checking
b0a43c7e5 Use sh instead of tcsh for test scripts
87e8f41ae remove warning of _MSC_VER

git-subtree-dir: externals/xbyak
git-subtree-split: 590c10e3746978dbfcf102d6da933ac2659e4544
2021-03-27 21:08:22 +00:00
MerryMage
ad9b33164e externals: Update xbyak
- Fix on-demand AVX512 on macOS

Merge commit '2f9dea5cc355c266ad46d2f6397b141b99f78480'
2021-03-27 21:08:22 +00:00
Lioncash
5873e6b955 thumb32: Implement LDRD (immediate) 2021-03-13 15:29:56 -05:00
Lioncash
9757e2353f thumb32: Implement LDRD (literal) 2021-03-13 15:29:56 -05:00
Lioncash
a74843ca17 thumb32: Implement STRD 2021-03-13 15:29:56 -05:00
Lioncash
258ca93c53 thumb32: Implement TBB/TBH 2021-03-13 15:29:49 -05:00
merry
03575dea84
Merge pull request #591 from lioncash/multiple
thumb32: Implement LDM/STM variants
2021-03-13 07:58:40 +00:00
Lioncash
1d0b705996 thumb32: Implement PUSH
This can be handled as an alias for STMDB.
2021-03-12 19:54:35 -05:00
Lioncash
9cb4790428 thumb32: Implement POP
This can just be treated as an alias to LDMIA
2021-03-12 19:43:47 -05:00
Lioncash
39edee70ff thumb32: Implement LDMDB/LDMEA 2021-03-12 19:35:28 -05:00
Lioncash
ae83713f4f thumb32: Simplify existing store functions into helper function
We can also make a STM helper.
2021-03-12 19:30:29 -05:00
Lioncash
0d887d9ecd thumb32: Implement LDMIA/LDMFD 2021-03-12 19:26:03 -05:00
Lioncash
714ccf13dd thumb32: Implement STMDB/STMFD 2021-03-12 19:05:39 -05:00
Lioncash
91c4d59da9 thumb32: Implement STMIA/STMEA 2021-03-12 19:05:15 -05:00
merry
543ba4e61f
Merge pull request #589 from lioncash/adr
thumb32: Implement plain binary immediate ADR variants
2021-03-12 23:10:23 +00:00
Lioncash
85b8adeb32 thumb32: Implement plain binary immediate ADR variants
Now all the plain binary immediate instructions are implemented.
2021-03-12 18:05:41 -05:00
merry
54c481c8bd
Merge pull request #588 from lioncash/store
thumb32: Implement STRB{T}/STRH{T}/STR{T} immediate variants
2021-03-12 21:30:00 +00:00
Lioncash
bd02d9e27f thumb32: Implement STR immediate variants 2021-03-12 14:03:40 -05:00
Lioncash
2521314384 thumb32: Implement STRH immediate variants 2021-03-12 13:55:39 -05:00
Lioncash
cbf9027278 thumb32: Implement STRB immediate variants 2021-03-12 13:33:11 -05:00
merry
2093d2b775
Merge pull request #587 from lioncash/8dot7
a64: Add v8.7 instruction additions to the decoder
2021-03-10 21:19:03 +00:00
merry
41bee2db3c
Merge pull request #586 from lioncash/halfword
thumb32: Implement halfword load instructions
2021-03-10 21:18:48 +00:00
Lioncash
035580abd2 a64: Add v8.7 instruction additions to the decoder
Adds the instructions introduced in FEAT_WFxT and FEAT_LS64/FEAT_LS64_V
in ARMv8.7
2021-03-09 18:41:20 -05:00
Lioncash
fb30922cd1 thumb32: Add supporting decoder entry for PLD (literal)
LDRH (literal)'s pseduocode indicates that cases where Rt specifies the
PC, that the instruction should be execured as if it were a PLD
instruction.

Curiously, however, within the ARM reference manual, the encodings in the case
that happens doesn't match up.

The bit pattern for LDRH (literal) has bit 21 set to 1, but the encoding
of PLD (literal) has bit 21 set to zero for it's only thumb encoding.
2021-03-09 18:16:08 -05:00
Lioncash
921998f6e9 thumb32: Implement LDRSH variants 2021-03-09 18:11:33 -05:00
Lioncash
7a9bdc8f21 thumb32: Implement LDRH variants 2021-03-09 17:12:46 -05:00
merry
1a5f4930b7
Merge pull request #585 from lioncash/word
thumb32: Implement Thumb-2 LDR variants
2021-03-09 19:16:13 +00:00
Lioncash
3d7e81e7d1 thumb32: Implement LDR variants 2021-03-09 13:12:15 -05:00
MerryMage
646fd05920 thumb32: Implement RSB (reg) 2021-03-06 19:49:44 +00:00
MerryMage
3f97cb1f9b thumb32: Implement SUB (reg) 2021-03-06 19:49:44 +00:00
MerryMage
17bdb54d30 thumb32: Implement CMP (reg) 2021-03-06 19:49:44 +00:00
MerryMage
a63271fd3b thumb32: Implement SBC (reg) 2021-03-06 19:49:44 +00:00
MerryMage
95189b78ef thumb32: Implement ADC (reg) 2021-03-06 19:49:44 +00:00
MerryMage
af33155ef8 thumb32: Implement ADD (reg) 2021-03-06 19:49:44 +00:00
MerryMage
41ac9971f4 thumb32: Implement CMN (reg) 2021-03-06 19:49:44 +00:00
MerryMage
e7ecd3a7ee thumb32: Implement PKHBT, PKHTB 2021-03-06 19:49:44 +00:00
MerryMage
d2d996e6ba thumb32: Implement EOR (reg) 2021-03-06 19:49:44 +00:00
MerryMage
158a13173c thumb32: Implement AND (reg) 2021-03-06 19:49:44 +00:00
MerryMage
c253b8fc51 thumb32: Implement TST (reg) 2021-03-06 19:49:44 +00:00
merry
ea5d8a3047
Merge pull request #584 from lioncash/loads
thumb32: Implement Thumb-2 Load Byte and Memory Hints instructions
2021-03-06 17:31:45 +00:00
MerryMage
531bb42ab5 thumb32: Implement B (T3) 2021-03-06 17:29:55 +00:00
MerryMage
86aa3f0701 thumb32: Implement B (T4) 2021-03-06 17:27:54 +00:00
Lioncash
52fdf801d0 thumb32: Implement LDRSB variants 2021-03-06 11:33:33 -05:00
Lioncash
fe892732cf thumb32: Implement LDRB variants 2021-03-06 11:06:30 -05:00
Lioncash
c66afadbc1 thumb32: Implement PLI variants 2021-03-06 09:55:29 -05:00
Lioncash
b2802aaf17 thumb32: Implement PLD variants 2021-03-06 09:36:51 -05:00
Lioncash
ee99fa69e9 thumb32: Add load source files
Places all the skeleton files in place.
2021-03-06 09:13:05 -05:00
Lioncash
47ab3a1450 CMakeLists: Add decoder .inc files
This makes them show up in IDE generators like XCode.
2021-03-05 21:00:31 -05:00
merry
f09e400858
Merge pull request #582 from lioncash/pbi
thumb32: Implement most plain binary immediate instructions
2021-03-05 23:20:58 +00:00
MerryMage
67e954a4cf thumb32_data_processing_plain_binary_immediate: Make invalid {S,U}SSAT16 decode undefined 2021-03-02 20:54:19 +00:00
MerryMage
52a9af3dca CMakeLists: Rework architecture detection
* Also only enable xybak/vixl on appropriate architectures
2021-03-02 20:41:38 +00:00
merry
3d418e9a4f
Merge pull request #583 from lioncash/str
thumb32: Implement STRB/STRH/STR (register)
2021-03-02 02:19:47 +00:00
Lioncash
2ac615b882 thumb32: Implement SSAT/USAT 2021-03-01 15:59:52 -05:00
Lioncash
5601aa554e thumb32: Implement STRB/STRH/STR (register) 2021-03-01 15:41:49 -05:00
MerryMage
2fbb79fdf2 externals: Build vixl 2021-03-01 20:36:21 +00:00
MerryMage
1ca401619d Merge commit 'e64a00a7fcc1cfa7ac5f81626f85075997f9d8a3' as 'externals/vixl/vixl' 2021-03-01 20:20:36 +00:00
MerryMage
170ab30b8e thumb32: Implement RSB (immediate) 2021-02-28 21:49:14 +00:00
MerryMage
8d33de2dcc thumb32: Implement SUB (immediate, T3) 2021-02-28 21:49:14 +00:00
MerryMage
8efb2a5b05 thumb32: Implement CMP (immediate) 2021-02-28 21:49:14 +00:00
MerryMage
78330e634f thumb32: Implement SBC (immediate) 2021-02-28 21:49:14 +00:00
MerryMage
e6b925146b thumb32: Implement ADC (immediate) 2021-02-28 21:49:14 +00:00
MerryMage
8f9e052c93 thumb32: Implement ADD (imm, T3) 2021-02-28 21:49:14 +00:00
MerryMage
30442ee1f4 thumb32: Implement CMN (immediate) 2021-02-28 21:49:14 +00:00
merry
421548ceef
Merge pull request #581 from lioncash/8dot6
a64: Add v8.6 instruction encoding additions
2021-02-27 21:54:08 +00:00
Lioncash
385f907463 a64: Add v8.6 instruction encoding additions
Keeps the instruction listing up to date.
2021-02-27 16:25:13 -05:00
merry
bf7d1a17ba
Merge pull request #580 from lioncash/shift
thumb32: Implement ASR, LSL, LSR, and ROR register variants
2021-02-26 19:07:12 +00:00
Lioncash
9d5505422f thumb32: Implement ADD/SUB (imm 2) 2021-02-25 09:56:05 -05:00
Lioncash
68885fdb3c thumb32: Implement SBFX/UBFX 2021-02-25 09:37:15 -05:00
Lioncash
7334914047 thumb32: Implement BFC/BFI 2021-02-25 09:27:05 -05:00
Lioncash
ba7cbe7cf6 thumb32: Implement SSAT16/USAT16 2021-02-25 09:13:46 -05:00
Lioncash
725d712c88 thumb32: Simplify register shift implementations to common function 2021-02-23 04:53:50 -05:00
Lioncash
a7a9ed69b7 thumb32: Implement ROR (register) 2021-02-23 04:52:29 -05:00
Lioncash
abf3548b2a thumb32: Implement ASR (register) 2021-02-23 04:43:11 -05:00
Lioncash
e06d4bcbb2 thumb32: Implement LSR (register) 2021-02-23 04:40:43 -05:00
Lioncash
fdd379a36c thumb32: Implement LSL (register) 2021-02-23 04:40:40 -05:00
merry
ac32175eff
Merge pull request #579 from lioncash/bxj
thumb32: Implement BXJ
2021-02-22 15:01:08 +00:00
merry
e753b223e2
Merge pull request #578 from lioncash/hint
thumb32: Implement hint instructions
2021-02-22 14:31:49 +00:00
Lioncash
89838c5ce4 thumb32: Implement BXJ
We handle this as a regular BX call, given we don't support Jazelle.
2021-02-22 07:45:21 -05:00
Lioncash
de8e977bb1 thumb32: Implement SEVL 2021-02-22 07:34:42 -05:00
Lioncash
a4c9ec645f thumb32: Implement SEV 2021-02-22 07:34:42 -05:00
Lioncash
565a20b096 thumb32: Implement WFI 2021-02-22 07:34:42 -05:00
Lioncash
3dc33c1257 thumb32: Implement WFE 2021-02-22 07:34:42 -05:00
Lioncash
48fe7afe72 thumb32: Implement YIELD 2021-02-22 07:34:42 -05:00
Lioncash
a73ea9e111 thumb32: Implement NOP 2021-02-22 07:34:39 -05:00
MerryMage
29d7cbd899 thumb32: Ensure CPSR.IT state is always up to date 2021-02-22 00:27:16 +00:00
MerryMage
f5dd7122a2 EmitFPVectorMulAdd: Correct optimization flag (Unsafe_UnfuseFMA -> Unsafe_InaccurateNaN) 2021-02-21 21:30:20 +00:00
merry
75f4978da5
Merge pull request #577 from lioncash/barrier
thumb32: Implement barrier instructions and CLREX
2021-02-19 22:51:13 +00:00
merry
4b43dd33c6
Merge pull request #576 from lioncash/pbi
thumb32: Implement MOVT/MOVW
2021-02-19 22:48:43 +00:00
Lioncash
3890590b4f thumb32: Implement CLREX 2021-02-19 00:02:57 -05:00
Lioncash
5543e4f9eb thumb32: Implement ISB 2021-02-19 00:01:24 -05:00
Lioncash
085147b5a4 thumb32: Implement DMB 2021-02-18 23:59:34 -05:00
Lioncash
368a8630e0 thumb32: Implement DSB 2021-02-18 23:58:12 -05:00
Lioncash
5602db88f4 thumb32: Implement MOVW 2021-02-18 23:52:06 -05:00
Lioncash
d05c706ff4 thumb32: Implement MOVT 2021-02-18 23:52:03 -05:00
MerryMage
f568687bd9 thumb32: Implement EOR (immediate) 2021-02-18 20:51:13 +00:00
MerryMage
8fd7ec3989 thumb32: Implement TEQ (immediate) 2021-02-18 20:49:06 +00:00
MerryMage
efbc8cef53 thumb32: Implement ORN (immediate) 2021-02-18 20:48:55 +00:00
MerryMage
08f046036c thumb32: Implement MVN (immediate) 2021-02-18 20:19:45 +00:00
MerryMage
cafa687684 thumb32: Implement ORR (immediate) 2021-02-18 01:28:03 +00:00
MerryMage
b2f0575fee thumb32: Implement MOV (immediate) 2021-02-18 01:28:03 +00:00
MerryMage
3dcc882fbf thumb32: Implement BIC (immediate) 2021-02-18 01:28:03 +00:00
MerryMage
6f3c5dc1d9 thumb32: Implement AND (immediate) 2021-02-18 01:28:03 +00:00
MerryMage
5bf676d93e thumb32: Implement TST (immediate) 2021-02-18 01:05:45 +00:00
Sunho Kim
069beb5228 A32: Add ThumbExpandImm and ThumbExpandImm_C
These are used by many thumb2 instructions
2021-02-17 23:45:51 +00:00
sunho
43a1a523f6 A32: Fix thumb32 BL and BLX
More fields required
2021-02-17 23:18:05 +00:00
MerryMage
df027a7998 thumb32: Split thumb32 file into branch and control 2021-02-17 23:18:05 +00:00
merry
6f54c9d0b6
Merge pull request #562 from emuplz/a64_ic_instructions
A64 IC Instructions
2021-02-17 21:51:58 +00:00
emuplz
6d4333c78e fixed data + instruction cache callbacks (w/ tests) 2021-02-17 20:38:08 +00:00
rufi
77621a8448 implemented other ic instructions 2021-02-17 20:38:08 +00:00
emuplz
8728444af8 added support for instruction ic ivau 2021-02-17 20:38:06 +00:00
merry
95a3e80ff6
Merge pull request #575 from lioncash/dpr
thumb32: Implement extension instructions
2021-02-17 00:37:25 +00:00
MerryMage
b841ce1df5 CMakeLists: Increase maximum bracket depth for Clang
See also: https://reviews.llvm.org/D86936
Bracket depth limits size of fold expression which in turn limits size of std::array initialization via CTAD
2021-02-16 20:12:10 +00:00
Lioncash
e0d6b60270 thumb32: Implement UXTAB 2021-02-10 16:23:54 -05:00
Lioncash
d97369c252 thumb32: Implement UXTB 2021-02-10 16:22:22 -05:00
Lioncash
ad5d0d7b77 thumb32: Implement SXTAB 2021-02-10 16:20:43 -05:00
Lioncash
75a28b00a7 thumb32: Implement SXTB 2021-02-10 16:18:26 -05:00
Lioncash
3cefdc3ab9 thumb32: Implement UXTAB16 2021-02-10 16:16:56 -05:00
Lioncash
eec16eea45 thumb32: Implement UXTB16 2021-02-10 16:15:28 -05:00
Lioncash
6733cdd706 thumb32: Implement SXTAB16 2021-02-10 16:13:34 -05:00
Lioncash
1b5fcfd8d1 thumb32: Implement SXTB16 2021-02-10 16:11:09 -05:00
Lioncash
39a75472e2 thumb32: Implement UXTAH 2021-02-10 16:09:37 -05:00
Lioncash
e12ee8d4d7 thumb32: Implement UXTH 2021-02-10 16:07:17 -05:00
Lioncash
c0871d4c18 thumb32: Implement SXTAH 2021-02-10 16:04:33 -05:00
Lioncash
273125e0b1 thumb32: Implement SXTH 2021-02-10 15:58:36 -05:00
merry
fe761b2c61
Merge pull request #574 from lioncash/multiply2
thumb32: Implement long multiply and divide instructions
2021-02-09 20:37:16 +00:00
Lioncash
8cd91a84d0 thumb32: Implement SDIV/UDIV 2021-02-07 17:53:34 -05:00
Lioncash
fb1405157b thumb32: Implement UMAAL 2021-02-07 17:45:00 -05:00
Lioncash
f9bbc25e29 thumb32: Implement SMLSLD{X} 2021-02-07 17:42:44 -05:00
Lioncash
fe3deb1831 thumb32: Implement SMLALD{X} 2021-02-07 17:40:36 -05:00
Lioncash
87cb771bd2 thumb32: Implement SMLALXY 2021-02-07 17:37:26 -05:00
Lioncash
8320c56a6e thumb32: Implement UMLAL 2021-02-07 17:34:05 -05:00
Lioncash
5859105a61 thumb32: Implement SMLAL 2021-02-07 17:32:11 -05:00
Lioncash
28108c7924 thumb32: Implement UMULL 2021-02-07 17:29:20 -05:00
Lioncash
6cf47e0ce0 thumb32: Implement SMULL 2021-02-07 17:22:43 -05:00
merry
7290ae1273
Merge pull request #573 from lioncash/multiply2
thumb32: Implement the rest of the thumb-2 multiply category instructions
2021-02-07 21:04:42 +00:00
MerryMage
f77b0e2fbe A32/thumb16: Implement IT instruction 2021-02-07 20:41:48 +00:00
MerryMage
97d8b50c25 A32: Ensure existing thumb code is ITState-correct 2021-02-07 20:41:48 +00:00
MerryMage
68bd9547c5 fuzz_arm: Correctly print thumb instruction listing 2021-02-07 20:41:48 +00:00
MerryMage
62003a2d89 A32/ir_emitter: Implement UpdateUpperLocationDescriptor 2021-02-07 20:41:48 +00:00
MerryMage
f229a68aed a32_emit_x64: Update upper_location_descriptor in BXWritePC based on final location 2021-02-07 20:41:48 +00:00
MerryMage
714b0b9a8b A32/translate: Factor conditional state handling out 2021-02-07 20:41:48 +00:00
Lioncash
b58cd3a996 thumb32: Implement SMLAWY 2021-02-07 13:34:56 -05:00
Lioncash
96895d2eb5 thumb32: Implement SMULWY 2021-02-07 13:32:39 -05:00
Lioncash
8a22bdff43 thumb32: Implement SMLSD{X} 2021-02-07 13:29:20 -05:00
Lioncash
ef3b77f8ae thumb32: Implement SMLAD{X} 2021-02-07 13:26:53 -05:00
Lioncash
53f1a52be9 thumb32: Implement SMMLS{R} 2021-02-07 13:23:21 -05:00
Lioncash
0c542777b0 thumb32: Implement SMMLA{R} 2021-02-07 13:14:47 -05:00
Lioncash
b6add0ddf4 thumb32: Implement SMMUL{R} 2021-02-07 13:11:25 -05:00
Lioncash
44f4f437a7 thumb32: Implement SMUSD 2021-02-07 13:07:38 -05:00
Lioncash
4d9a7308ac thumb32: Implement SMUAD 2021-02-07 13:04:18 -05:00
Lioncash
1e06231575 thumb32: Implement SMLAXY 2021-02-07 12:39:12 -05:00
Lioncash
1cd10e3214 thumb32: Implement SMULXY 2021-02-07 12:27:40 -05:00
MerryMage
1e29ef8b0e A32/location_descriptor: Implement SetIT 2021-02-07 14:18:03 +00:00
MerryMage
5e75bd41a4 ITState: Handle not-in-IT-block case in Cond 2021-02-07 14:17:46 +00:00
MerryMage
946dbb5818 ITSTate: Correct ITState::Advance 2021-02-07 13:21:45 +00:00
MerryMage
1c5f6882f0 A32/translate_thumb: Correct IsThumb16 2021-02-07 12:18:45 +00:00
MerryMage
7e5ae6076a A32: Add arch_version option 2021-02-07 12:13:14 +00:00
merry
51fa6a725a
Merge pull request #572 from lioncash/multiply
thumb32: Implement MLA/MLS/MUL/USAD8/USADA8
2021-02-07 10:15:57 +00:00
Lioncash
50d81f95e5 thumb32: Implement USADA8 2021-02-07 09:57:34 +00:00
Lioncash
ed453aa52d thumb32: Implement USAD8 2021-02-07 09:57:34 +00:00
Lioncash
b07fab604f thumb32: Implement MLS 2021-02-07 09:57:34 +00:00
Lioncash
cf5058bccb thumb32: Implement MLA 2021-02-07 09:57:34 +00:00
Lioncash
153d87c843 thumb32: Implement MUL 2021-02-07 09:57:34 +00:00
MerryMage
a599c29d9e testenv: Ignore warning C4309 2021-02-07 09:57:17 +00:00
MerryMage
b252636dc3 a32_unicorn: Halt when PC leaves code_mem 2021-02-06 22:15:02 +00:00
MerryMage
331a02e02e fuzz_arm: Add fuzzing for thumb instructions 2021-02-06 21:41:01 +00:00
MerryMage
8b612edb75 translate_thumb: Fix bug in TranslateSingleThumbInstruction 2021-02-06 21:26:44 +00:00
MerryMage
aa89418e8b bit_util: Add SwapHalves32 2021-02-06 21:26:44 +00:00
MerryMage
fa1b9545fd bit_util: Rename Swap{16,32,64} to SwapBytes{16,32,64} 2021-02-06 21:26:44 +00:00
MerryMage
39644d69ee A32/decode: Split thumb32 2021-02-06 21:26:42 +00:00
MerryMage
6d0a049fb2 A32/decode: Split thumb16 2021-02-06 21:25:24 +00:00
MerryMage
ac9e1ccb1c A32/thumb16: Fix bug in CBZ/CBNZ 2021-02-06 21:25:24 +00:00
wheremyfoodat
5918cd48e6
Fixed typo in readme (#571) 2021-02-04 11:29:39 +00:00
merry
644350c7e6
Merge pull request #570 from lioncash/parallel
thumb32: Implement parallel add/sub instructions
2021-02-01 23:17:19 +00:00
Lioncash
23619c8c6a thumb32: Implement SHSUB8/UHSUB8 2021-02-01 17:50:46 -05:00
Lioncash
9d2570470e thumb32: Implement SHADD8/UHADD8 2021-02-01 17:50:46 -05:00
Lioncash
afad76078d thumb32: Implement SHSUB16/UHSUB16 2021-02-01 17:50:46 -05:00
Lioncash
51b7c32d02 thumb32: Implement SHSAX/UHSAX 2021-02-01 17:50:46 -05:00
Lioncash
f0a219fcd0 thumb32: Implement SHASX/UHASX 2021-02-01 17:50:46 -05:00
Lioncash
94f8efbb03 thumb32: Implement SHADD16/UHADD16 2021-02-01 17:50:46 -05:00
Lioncash
aa49b0db89 thumb32: Implement QSUB8/UQSUB8 2021-02-01 17:50:46 -05:00
Lioncash
874ab6a7b6 thumb32: Implement QADD8/UQADD8 2021-02-01 17:50:46 -05:00
Lioncash
d923fb24c6 thumb32: Implement QSUB16/UQSUB16 2021-02-01 17:50:46 -05:00
Lioncash
416fe26df0 thumb32: Implement QSAX/UQSAX 2021-02-01 17:50:14 -05:00
Lioncash
ad7c8bd042 thumb32: Implement QASX/UQASX 2021-02-01 17:31:30 -05:00
Lioncash
f52b8f924c thumb32: Implement QADD16/UQADD16 2021-02-01 17:31:30 -05:00
Lioncash
6f593da41b thumb32: Implement SSUB8/USUB8 2021-02-01 17:31:27 -05:00
Lioncash
271354ee95 thumb32: Implement SADD8/UADD8 2021-02-01 16:44:11 -05:00
Lioncash
8f42fd5c0e thumb32: Implement SSUB16/USUB16 2021-02-01 16:41:02 -05:00
Lioncash
0e28c63456 thumb32: Implement SSAX/USAX 2021-02-01 16:36:18 -05:00
Lioncash
21e404d3ab thumb32: Implement SASX/UASX 2021-02-01 16:31:25 -05:00
Lioncash
d529417875 thumb32: Implement SADD16/UADD16 2021-02-01 16:19:33 -05:00
merry
0e26e8a531
Merge pull request #569 from lioncash/t32-misc
thumb32: Implement miscellaneous category instructions
2021-02-01 21:06:36 +00:00
Lioncash
36fc596a51 thumb32: Implement QADD 2021-02-01 15:44:09 -05:00
Lioncash
cd6e4c7afd thumb32: Implement QSUB 2021-02-01 15:42:14 -05:00
Lioncash
65365ad2a3 thumb32: Implement QDADD 2021-02-01 15:39:39 -05:00
Lioncash
d96c8c662b thumb32: Implement QDSUB 2021-02-01 15:35:09 -05:00
Lioncash
c60cf921ee thumb32: Implement REV 2021-02-01 15:30:40 -05:00
Lioncash
0304dc7ce4 thumb32: Implement REV16 2021-02-01 15:27:31 -05:00
Lioncash
cee31c5274 thumb32: Implement RBIT 2021-02-01 15:20:24 -05:00
Lioncash
e2bc7eeb93 thumb32: Implement REVSH 2021-02-01 15:16:53 -05:00
Lioncash
95dabcf48e fuzz_thumb: Allow running only Thumb-16 tests 2021-02-01 15:04:29 -05:00
MerryMage
e01583abba A64/system: Reorder fields of SystemRegisterEncoding
Matches manual, which allows for easier verification of correctness.
2021-02-01 20:01:39 +00:00
Lioncash
1ad99bb9b5 thumb32: Implement SEL 2021-02-01 15:01:21 -05:00
Lioncash
8d53048750 thumb32: Implement CLZ
Also fleshes out the generator to allow for generating thumb32
instructions as well.
2021-02-01 14:54:04 -05:00
MerryMage
f2345c1590 A64/system: Implement MSR/MRS for NZCV 2021-02-01 19:52:49 +00:00
LC
8c09da666a
Merge pull request #568 from bunnei/hook-isb-a32
A32: Add hook_isb option.
2021-01-29 06:52:09 -05:00
bunnei
de389968eb A32: Add hook_isb option. 2021-01-28 20:47:39 -08:00
MerryMage
0f27368fda A64: Add hook_isb option 2021-01-26 23:41:21 +00:00
MerryMage
3806284cbe emit_x64{,_vector}_floating_point: Fix non-FMA execution
Avoid repeated calls to GetArgumentInfo
2021-01-02 20:40:32 +00:00
MerryMage
6023bcd8ad emit_x64_data_processing: Fix signed/unsigned warning 2021-01-02 20:12:48 +00:00
MerryMage
c15917b350 backend/x64: Add further Unsafe_InaccurateNaN locations 2021-01-02 20:12:48 +00:00
MerryMage
f9ccf91b94 Add Unsafe_InaccurateNaN optimization to all fma instructions 2021-01-02 17:22:50 +00:00
MerryMage
8c4463a0c1 emit_x64_data_processing: EmitSub: Use cmp where possible 2021-01-01 19:37:47 +00:00
MerryMage
e926f0b393 emit_x64_data_processing: Minor optimization for immediates in EmitSub 2021-01-01 13:35:01 +00:00
MerryMage
eeeafaf5fb Introduce Unsafe_InaccurateNaN 2021-01-01 07:18:05 +00:00
ReinUsesLisp
4a9a0d07f7 backend/{a32,a64}_emit_x64: Add config entry to mask page table pointers
Add config entry to mask out the lower bits in page table pointers.
This is intended to allow users of Dynarmic to pack small integers
inside pointers and update the pair atomically without locks.
These lower bits can be masked out due to the expected alignment in
pointers inside the page table.

For the given usage, using AND on the pointer acts the same way as a
TEST instruction. That said when the mask value is zero, TEST is still
emitted to keep the same behavior.
2020-12-29 19:16:46 +00:00
MerryMage
42059edca4 decoder_detail: Fix bit_position and one unused warnings in GetArgInfo 2020-12-28 23:34:23 +00:00
MerryMage
b47e5ea1e1 emit_x64_data_processing: Use BMI2 shifts where possible 2020-12-28 22:42:51 +00:00
ReinUsesLisp
ba6654b0e7 location_descriptor: Fix compare operator for single stepping
Compare `single_stepping` with the other's value instead of comparing it
with the local value.
2020-12-01 09:11:40 +00:00
LC
96e9075804
Merge pull request #563 from Wunkolo/patch-1
emit_x64_vector: Fix ArithmeticShiftRightByte zero_extend constant
2020-11-09 20:31:21 -05:00
Wunk
3e932ca55d
emit_x64_vector: Fix ArithmeticShiftRightByte zero_extend constant
Should be shifting in _bytes_ of `0x80`. Not bits.
2020-11-09 09:47:51 -08:00
Wunkolo
ec52922dae emit_x64_vector: Use explicit 64-bit mask constant
Exchange `~0ull` with `0xFFFFFFFFFFFFFFFF` when generating
the `zero_extend` constant.
2020-11-07 15:29:12 +00:00
Wunkolo
490160ef43 emit_x64_vector: GNFI implementation of ArithmeticShiftRightByte
The bit-matrix is generated up-front and added to the constant-pool.
I'm using an embedded 64-bit broadcast here(m64bcst) which is the particular
EVEX encoded version of the instruction with AVX512VL+GNFI.

If it ever really matters, then we would ideally detect specific host
features like bare-GFNI and specific subsets of AVX512 and emit
the assembly based on that rather than by the entire Icelake uarch.
2020-11-07 15:29:12 +00:00
Wunkolo
7df235aefb emit_x64_vector: GNFI implementation of EmitVectorLogicalShiftLeft8
Same principle as EmitVectorLogicalShiftRight8. An 8x8 galois identity
matrix is bit-shfited to allow for arbitrary 8-bit-lane shifts.
2020-11-07 15:29:12 +00:00
Wunkolo
5cc646ffed emit_x64_vector: GNFI implementation of EmitVectorLogicalShiftRight8
Bitshifts of the GFNI identity matrix generates a new matrix that
applies lane-wise bitshifts as well. This allows for a fast
single-instruction implementation of a byte-lane bitshift.
2020-11-07 15:29:12 +00:00
MerryMage
46f96904db decoder_detail: Add check for N==0 to GetArgInfo 2020-10-11 22:12:21 +01:00
Wunkolo
6bb49726f4 emit_x64_vector: GNFI+SSSE3 implementation of EmitVectorReverseBits
Performs a full 128-bit bit-reversal using only two instructions.

First by reversing all the bits of each byte using a galois matrix
multiplication(vgf2p8affineqb, Icelake), and then by reversing the bytes
themselves(pshufb, ssse3).
2020-10-02 05:56:59 +01:00
ReinUsesLisp
eb00bea1ff backend/x64/exception_handler_posix: Fix signal stack memory leak in SigHandler
std::malloc was being called inside SigHandler's constructor without a
std::free. This doesn't really matter as SigHandler is used as a
singleton and the OS will reclaim that memory. That said, properly
freeing memory keeps -fsanitize=address quiet.
2020-10-02 05:56:07 +01:00
MerryMage
80adb289d0 print_info: Use std::nullopt instead of {} 2020-09-22 18:40:00 +01:00
Lioncash
7afcdabf11 externals: Update catch to v2.13.1
Keeps the library up to date.
2020-09-19 15:02:22 -04:00
Lioncash
63802395c7 externals: Update fmt to v7.0.3
Keeps the library up to date.
2020-09-19 14:25:31 -04:00
Lioncash
d4c6fa3122 Squashed 'externals/fmt/' changes from 9bdd1596c..cd4af11ef
cd4af11ef Update version
1ebc2f7cc Bump version
f4c997062 Fix changelog
72920ba30 Update changelog
0907c08ae Fix handling of default alignmment with locale (#1801)
37c8f4eaf Don't use 128 bit integers with clang-cl (#1800)
eaaaec999 Workaround a bug in msvc
ccf8561cb Workaround broken numeric_limites, part 2 (#1787)
0cc73ebf7 Report error on missing named argument (#1796)
33efc3c94 Fix handling of iterators in locale-specific formatting (#1782)
b9d749095 Update version
86b63bb71 Bump version
cbf6be960 Update changelog
229ee9b46 Workaround broken numeric_limits (#1725)
2b7a146fa Fix a regression in handling digit separators (#1782)
89d0c7124 Fix compatibility with CMake 3.4 (#1779)
f19b1a521 Update version
5c67fefb2 Fix a changelog entry
1d2a556e1 Fix undefined reference error
04c9b62fb Merge release branch
6be6762e5 Fix date
f1dd2eb3c Bump version
fbf3b943c Workaround a bug in gcc
a29a01d30 Fix docs
9f0b3afb7 Bump version in namespace
86b2f99f8 Fix the docs
c472ff12d Update version
5173a76ba Update version
1614af352 Minor corrections in the changelog
569a9b3a7 Bump version
4e7e3c65a Update docs
0f7a6bfa1 Add a section on std::format compatibility
4faec5a5e Update README.rst
7dbc8ac71 Update changelog
c87dd746f Update changelog
372175caf Revert changelog changes
904754876 Add ClickHouse to the list of projects (#1751)
d30bca64e Revert changelog conversion since GFM is not supported there
d6047cdc4 Update changelog
810241b36 Convert changlog to markdown
661c47473 Rename changelog
7c33059fa Update ChangeLog.rst
9e20883ab Update README.rst
41899d522 Update changelog
f42f45908 Update changelog
2381df654 Update readme
7ae816563 Update README.rst
c56cf3d07 Update changelog and readme
01309a34a Deprecate arg_formatter
a62d06055 Update changelog
23e3a2eee Update changelog
d8e0554b9 Disable numeric formatting by default
1e8eea4f4 Update changelog
44bd5384a Fix formatting
20e19387a Update changelog
56fed7814 FMT_NUMERIC_ALIGN -> FMT_DEPRECATED_NUMERIC_ALIGN
56e63078f Make the n specifier an opt-in
31ce6bc70 Fix a conversion warning with Clang10 on Windows (#1750)
c9c5b90da Fix a typo. Thanks Tracy Chapman from TripleChecker
1f3f84631 Fix a typo
5de62af60 Fix possible infinite recursion in FMT_ASSERT (#1744)
cbddab2fe Use consistent include style
f69b6eaab Add a simple buffered stream with no sync
ba363b3a2 Use digit pairs as in unrolledlut
a6f8e7d86 Update changelog
e753244ab Update changelog
98a7a8b40 Update changelog and disable internal
3135d95fd Don't use non-portable attribute
8630a8f5f Tweak the docs
cc3a88e6b Extract docs from compile.h
79c4b6bd7 Apply clang-format
d130ee070 Document format string compilation
d0f90b5be Spelling fixes
6e080660d Update README.rst
31c3a2426 Spelling fixes
613b3b459 Spelling fixes
978521bb8 Fix a compile error introduced in #1738
4e94c649f Deprecate compile
1a83443e6 Add user-defined type support to compilation
8bef1c3b3 Tweaks for EDG based compilers (Intel, nVidia, MCST/Elbrus, etc).
b287c37c6 Do not use -Wl,--as-needed with emscripten.
2cac8a9d2 Reintroduce UDT support to fmt::to_string and test ADL
9a4cc8842 Add FMT_COMPILE support to format_to
5ddf9ee1b Streamline default FP formatting
0b3a83f7f Update README.rst
5aa5c9873 Added  #define WIN32_LEAN_AND_MEAN before including windows.h (#1729)
397ad1bec Optimize common case
7431165f3 Make to_string bypass format
ee4d4c7fd Inline compiled format
ab2f8484e Finish text::format
e900d735b Re-enable assert in format_decimal
f4de7b684 Fix ambiguity
1f8f5450b Reuse format_decimal
d702a68df Fix formatting of bool with FMT_COMPILE and add more tests
e956a14e9 Use write instead of format_int in to_string
98dcc251e Undo branching reduction
5b8641ddd Undo branching reduction
8c88abde6 Fix sign handling in 'L'
23b976a61 Reduce branching
9edee0e72 Optimize small string parsing
a909d42b7 Fix a warning
16637341b Enable compilation for all types
2d71d7e03 Add a simple format string compilation API
d259fcfb0 Tweak comments
704ed557a Move project in order to solve a CMake warning
8603bd20d Update README.rst
547f12ae6 Fix a warning (#1722)
f904e8a1b c++11 use formatting user-defined types (#1721)
100e8af08 Update README.rst
c11d0f056 Update README.rst
2453ee576 Improve default formatting
47ae52155 MINGW cross compiler fixes
936a1833c Add default_arg_formatter
f2c9cb624 Fix a UB
d3107f855 Cleanup arg_formatter_base
5e7c70e20 Simplify arg_formatter_base
38cc68b3e Inline visitor
6732ea500 Make symbols readable
57ddc77ce Make advance_to a noop for back_insert_iterator
50bad7d62 Optimize format string parsing
8f7a824e4 Inline visit
f11e96870 Optimize format string parsing
09737dd83 Optimize format handler
d9e3d6e6e Move format_handler to detail
795b47a7b Fix a warning (#1712)
95c6ac0cc fix typo which caused the loss of the counting information when using a printf context with a truncating_iterator
21409cfdd Fix warnings
88c8d534e Move digits10 to where they belong and add comments
0f3eaeac0 Fix a warning
344218510 Ignore /doc/node_modules directory
16aec0617 Cleanup arg_formatter_base
1e1193590 Fix format_decimal overloads
0893c9c2e Inline parse_format_string
3245145a4 Remove undocumented buffer_range and output_range
57fc44907 Increase VM disk size
7d22bebb6 Remove uses of buffer_range
8f2b5fe74 Don't install sphinx cache files
f095c67b6 Remove uses of buffer_range
5aabf1f71 Simplify copy_str
19c5b5d15 Simplify arg_formatter
519571ede Simplify arg_formatter_base
ac8dfd841 Improve handling of separators
2c6165a22 Reduce the number of comparisons
28639969e Use memcpy for copying digits
f5fa1dee5 Support custom FMT_INC_DIR in pkgconfig and cmake configs (#1702)
51bf9cfac Fix Mingw support
1a716caf5 Optimize common case
98d4bbf81 Update README.rst
8c8f74a87 fix zero flag for char types and make zero flag ignored if a precision is specified
bc1b89da2 Temporarily revert parsing changes
a7fb321ac Remove a redundant branch
8cadb9650 fix max/min macro (#1697)
297c3b2ed Fix an example (thanks Alexey Kuzmenko)
943532fec Make ostream formatter work with compile-time format strings (#1692)
bd8804019 Update README.rst
f230300ac Knuth is using fmt library (#1691)
a265e25b7 Optimize small string parsing
2aa2526f6 Optimize small string concatenation
8d78045e7 Move void_t to where it's used
7aafa6bc6 Update analytics
c66aae165 Adding sentinel support to fmt::join(). (#1689)
6d66de380 Add c specifier support to integral types (#1652)
6b219a58d fix interaction of space flag and '+' flag, as well as '-' flag and '0' flag (#1687)
eee2023c2 Update signatures
c5ed73aab Add fmt::detail::buffer to the docs (#704)
ea1cd9638 Fix apidoc
d3964d7b1 Merge branch 'master' of github.com:fmtlib/fmt
d18c6723a Update docs
96c18b26c make plus flag for printf not be ignored for char argument (#1683)
ba25baeb9 Apply doc patch to 6.2.1
981b517cc nested replacement fields may omit arg_id (#1681)
922ea924b Make dynamic_format_arg_store reusable and add reserve() (#1677)
e0d98923c Update version
806926537 internal -> detail (#1538)
963ee0831 Simplify named arguments
02a6fe59f Named arguments go brrr
de290f5c4 Ditch internal::arg_map
d0623de51 Bump version
73e335ed3 Make implicit capture explicit for C++20 (#1669)
b4d46e398 Update changelog
a182f7341 Update changelog
68201831a Support named args in dynamic_format_arg_store (#1655). (#1663)
7f723fbcb Consistently namespace qualify size_t
c06851456 Purge basic_writer
2f05054dd Purge basic_writer
f0ce21164 Revert enum change
44639b11f Fix some warnings (#1667)
1c86a99e8 Purge basic_writer
8f511fc12 Make copyfmt not throw (#1666)
59fe455f3 Remove compatibility stubs
b0f47a13e Separate nonfinite formatting
d6cea50d0 Remove deprecated APIs
40bc7163f Move FMT_MAYBE_UNUSED to where it's actually used
080e44d0b Fix inconsistent type detection (#1662)
7e57cace5 Exclude std::abort from compilation when compiling CUDA with Clang (#1661)
7b66e2f21 Inherit arg_formatter_base from basic_writer
bab3f5800 Refactor pointer formatting
9cc7edfdd Move int_writer to the namespace scope
8d9d528bf Improve handling of alignment
8efd1a8ef Improve handling of alignment
a71bc9c82 Use '0' fill with numeric align for consistency with std::format
60d85d598 Suppress ubsan warning
c3099beb6 Cleanup
cbb4cb899 Remove undocumented deprecated APIs
b85e9ac38 Simplify vformat_to
e3710ab97 FMT_CONSTEXPR -> constexpr
d59751f0f Update date formatting example to use threadsafe localtime
d6abb2fa0 Reduce library size
e9fdea90b Update README.rst
44b6584f2 Update README.rst
78f041ab5 build: Fix installation paths
7ca89bf87 Reduce template bloat in write_int
3c114d091 Fix a shadowing warning (#1658)
e2ef12a8c Allow to avoid inclusion of os.cc in fmt target
bca82719a Pass iterator by value
99da38962 Make write_padded non-members
f19d66794 Bump fuzzer allocation limit
3e6984761 Reduce branching in write_padded
9ac1eebd4 Reduce library size
e2ff91067 Replace FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION  with fmt-specific macro (#1650)
f2ed03b91 Fix a warning (#1649)
9dde9f013 Reduce library size
b1af642d1 Reduce library size
4a617f25c Clarify encoding conversion in chrono
6f435f55c Improve compile time by using extern template (#1452)
cb475cb88 Clarify why we don't check argument id
1e1ac6e96 Check dynamic width/precision id at compile time (#1614)
e51c449fe Revert "Check dynamic widht/precision id at compile time (#1614)"
0463665ef Don't access a C string past precision in printf (#1595)
7d748a6f8 Check dynamic widht/precision id at compile time (#1614)
2b75bd7ce Get rid of do_check_format_string
4a1d5931c Simplify udl_formatter with FMT_STRING
811b0f905 Enable compile-time error tests
450e8eed9 Fix markup
b8fbcec1b Clarify formatter reuse
56bc86ffa Suppress bogus MSVC analysis warnings
3f79357ef Fix a recent regression in handling max packed arguments
8a11148f9 Add Facebook Folly to the list of projects
e371e8b68 Tweak readme
813732fed Improve readme formatting
3670d5b3f README: add vectorized.io/redpanda in the list of users
9e2ad7cf6 Add windows terminal to the projects using {fmt}
63479c851 Use a delegating ctor and add inlines
5944fcad3 Remove remaining wchar_t instantiation
e253b371b Don't generate RTTI for allocator
0c86f467b Fix build on ancient gcc
1929df4bc Simplify format_args
a13822181 Always inline arg_data functions
04e0dfd4b Always inline value ctors
04cde756b Simplify checks
c9a57b9a8 Fix incorrect assumptions about nul termination
f46f5ecaf Reenable constexpr _compile on GCC 9
6e8d7e277 Don't use constexpr on Intel compiler (#1628)
567ed03f8 Merge arg overloads and cleanup
c3fa33314 Remove warning in core.h with when compiling with gcc and -Wshadow
84898b462 Remove warning in format.h when compiling with gcc and -Wshadow
538d83fd0 Cleanup named arguments
8a4630686 Improve handling of named arguments
a9d62d3f3 Add check for CompiledFormat to avoid ambiguous call
fdcf7870a Add stack-based named argument storage
5899267c4 Fix a clang-tidy warning
07b4c246e Fix a typo
e99809f29 Fix ostream support in sprintf (#1631)
3cd5179f3 Fixed clang tidy warning -multiple declarations in a single statement reduces readability
7404e33a7 Fix clang warning about explicit ctor
3aab2171e Clean up basic_format_args
7645ca072 Clean up printf
e30d8391e Suppress an MSVC warning (#1622)
8cd8ef03e Simplify warning suppression
bbb6b357c Add floating-point L specifier (#1624)
36ea32640 Suppress a bogus MSVC warning
141a00d64 Define FMT_EXTERN_TEMPLATE_API on export
3860edc5d Bump version
7d01859ef Fix handling of unsigned char strings in printf
63b23e786 Merge branch 'master' of github.com:fmtlib/fmt
4999796c1 Fix the docs
34b3f7b7a Avoid windows issue with min() max() macros
27e3c0fe9 Update signature in the docs

git-subtree-dir: externals/fmt
git-subtree-split: cd4af11efc9c622896a3e4cb599fa28668ca3d05
2020-09-19 14:25:26 -04:00
Lioncash
8a7a4cb672 Update xbyak to 5.97
Keeps the library up to date.
2020-09-19 11:28:09 -04:00
Lioncash
8042dc93e8 Squashed 'externals/xbyak/' changes from 73ac5866..0140eeff
0140eeff Merge branch 'dev'
1efe14b2 change the original behavior of SetError
83c89c7a rename and fix indent
8be7ca93 Merge branch 'sbogusev-master' into dev
070b4c09 make l_err() inline with block scope static TLS l_error
9a4e6579 v5.97
d0ced1bc XBYAK_ONLY_CLASS_CPU is for only util::Cpu
bb967ae7 replace uint32 with uint32_t etc.
c306b8e5 update to v5.95
605e4224 use noexcept if C++11 or later
7a17c2c8 remove warning
5dfa4462 use constexpr if c++14 or later
18c9caaa Merge branch 'densamoilov-fix-mov-interface' into dev
3966ba9d fix mov interface
be492be1 change the behavior of push((byte|word), imm) to cast imm to int8_t/int16_t
d9696b54 Merge pull request #102 from igorsafo/master
ea73267f Cpu: make getNumCores constant
ff0b10e9 Merge pull request #101 from densamoilov/use-thread_local-when-supported
0c4eafc3 use thread_local for XBYAK_TLS when supported
c1aea35e CodeGenerator::reset() calls ClearError()
b4df97b1 Merge branch 'cursey-no-winsock2-header'
6a47bb0e v5.94
9a1749e6 define WIN32_LEAN_AND_MEAN for including winsock2.h after xbyak.h
42dddb74 Remove #include <winsock2.h>
615b85fa update doc
9cd796a9 rename XBYAK_NOEXCEPTION to XBYAK_NO_EXCEPTION
7cdf227f use static to avoid multiple instance
38a28dec test_nm.bat supports noexcept
0fdffc6b XBYAK_NOEXCEPTION for -fno-exceptions
eda6e2a3 v5.92
5c26c8bb mov(rax, imm64) on 32-bit env with XBYAK64
6208e3ae throw exception if not supported amx sibmem 2
c6737d14 mov amx insts from avx512
34ea5c16 throw exception if not supported amx sibmem
6f93fe35 fix test of sizeof(Operand)
5b89c3b2 remove T_TMM
5ce32858 gen_amx.cpp is merged into gen_avx512.cpp
fe4f965f remove my alias for tmm registers
92f904d8 bit_ contains 8192
98b51da9 extend mnemonics with Intel(R) AMX ISA
8d1b4c9e add generation of Intel(R) AMX ISA mnemonics
8ded45d1 add support of Intel(R) AMX ISA
b23c4b02 v5.912
ffe32a60 Merge branch 'rsdubtso-master'
e7b7fd2f use MAP_JIT on macOS regardless of Xcode version
82b70e66 v5.911 ; XBYAK_USE_MMAP_ALLOCATOR is defined
2f6d9e34 fix test for mac
a7d10a1e add link to GitHub Sponsor
96076265 accept k0 mask register (it means no mask)
7e3167e4 kmov{b,w,d,q} throws for unsupported reg
f487d7b7 Merge pull request #91 from marcelotrevisani/patch-1
dc9e6a79 Possibility to specify a different PREFIX
5fc69fc8 remove warning of test
e69e0b42 fix typo of type of Zmi
34f797e8 perf does not recognize too short function name
6cc0f4df Consider max defined as a macro on Windows
5722393d fix for zeroed-out 0xb leaf
6a4459a8 Merge branch 'tyfkda-feature/fix-segfault-in-calc'
47922ed9 Fix segmentation fault in calc sample
8f696e93 add test_avx512 to bat
00114d79 add .travis.yml
a29fa27b refactor test
508b543c fix error of vfpclasspd
0d54f1b1 fix for windows
4da8fd4e add setDefaultJmpNEAR
da7f7317 revert to the behavior before v5.84 if -fno-operator-names is defined
7dac9f61 update to v5.85
fe639332 enable MAP_JIT only if mojave or later
4443d791 specify MAP_JIT mmap flag on macOS
20ee4c2d update doc
ca0e8395 [changed] XBYAK_NO_OP_NAMES is defined
f32836da remove exit(1)
a1e9adf2 v5.82
08b8b1ba Support AMD Zen New Instructions.
2501ba9a remove *.user and *.vcproj
5c2ea988 Merge branch 'jrmwng-feature/upgrade-to-vs2017/jrmwng'
35847f7a Merge branch 'feature/upgrade-to-vs2017/jrmwng' of https://github.com/jrmwng/xbyak into jrmwng-feature/upgrade-to-vs2017/jrmwng
ef267775 address "warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification"
4a6c59bb address a conflict of sharing intermediate directory by different projects
9577cbf3 inherit "some output locations" from parent or project defaults
6c5f7186 upgrade projects from VS2018 to VS2017
4ca0434b v5.81
72b4e95d add lds/lss/les/lfs/lgs
cc8f037c fix ; move ERR_INTERNAL to the end
9e9ec1c3 add repe, repne, repne, prez
eea0edc3 add some fpu mnemonics
06235fa6 add loop/loope/loopne
7fc0c2bb add enter/leave
9fa2ef3c add in_, out_
df208648 add lods{b,w,d,q}, outs{b,w,d}
4672d2cb add int3, int_, into
431977cb add pushfq, popfq
81c4749f syscall, sysenter, sysexit, sysret
1f1b53c4 add clflushopt, fldenv, fnstw
b765db33 Profiler uses append mode
44dc3546 add Profiler class
42949334 update version to v5.802
91cb919b Merge branch 'vpirogov-master'
a6452f82 fixed avx512_bf16 detection
f41da5aa tweak ; vcvtneps2bf16 calls opCvt2
b12460ba [sample] fix typo of quantize.cpp
b22f5881 add set_opt.bat for test on Windows
f402faad add vp2intersectd/vp2intersectq
4cfd5208 add avx512_bf16
4033564c fix vcmppd/vcmpps for ptr_b

git-subtree-dir: externals/xbyak
git-subtree-split: 0140eeff1fffcf5069dea3abb57095695320971c
2020-09-19 11:27:42 -04:00
Wunkolo
c2d5f6da90 block_of_code: Add HasAVX512_Icelake
Detect AVX512 feature support up to the [Icelake-level featureset](https://en.wikipedia.org/wiki/AVX-512#CPUs_with_AVX-512)
2020-09-19 15:20:40 +01:00
Lioncash
0e1112b7df Revert "basic_block: Mark move constructor and assignment as noexcept"
This reverts commit 4f12e86ebb6f27a6ffd10449a6c82f42a4774892.

Big fan of MSVC preventing standard behavior.
2020-08-14 16:49:40 -04:00
Lioncash
889635d17d general: Resolve -Wmissing-prototypes warnings 2020-08-14 14:50:09 -04:00
Lioncash
68fea20020 common/assert: Resolve several -Wextra-semi warnings
Resolves 200+ warnings.
2020-08-14 14:45:53 -04:00
Lioncash
4f12e86ebb basic_block: Mark move constructor and assignment as noexcept
Allows the type to play nicely with standard library facilities better
(also we shouldn't be throwing in move operations to begin with).
2020-08-14 14:38:28 -04:00
Lioncash
34f4d99454 block_of_code: Remove unused variables in GenRunCode()
These aren't used, so they can be removed.
2020-08-14 14:35:17 -04:00
Lioncash
29d1758923 ir_matcher: Add missing header guard 2020-08-14 14:32:34 -04:00
MerryMage
6bbc53839f Unsafe Optimization: Extend Unsafe_UnfuseFMA to all FMA-related instructions 2020-07-12 12:45:12 +01:00
MerryMage
d05d95c132 Improve documentation of unsafe optimizations 2020-07-12 12:41:11 +01:00
MerryMage
82417da780 emit_x64{_vector}_floating_point: Add unsafe optimizations for RSqrtEstimate and RecipEstimate 2020-07-11 14:05:57 +01:00
MerryMage
761e95eec0 A64: Add unsafe_optimizations option
* Strength reduce FMA unsafely
2020-07-06 21:02:30 +01:00
MerryMage
82868034d3 A32/ASIMD: Ensure decoder table is correct
* Raise a DecoderError instead of ASSERT-ing on a decode error
* Correct ASIMD decode table
* Write a test which verifies every possible ASIMD instruction
2020-07-05 18:45:42 +01:00
MerryMage
3c742960a9 simd_three_same: Ensure zero in upper for PairedMinMaxOperation 2020-07-04 11:25:36 +01:00
MerryMage
735738c7b6 A32: Implement ASIMD VPMAX, VPMIN (floating-point) 2020-07-04 11:04:10 +01:00
MerryMage
88e74cb2ba A32: Implement ASIMD VPMAX, VPMIN (integer) 2020-07-04 11:04:10 +01:00
MerryMage
d9914b1d51 simd_permute: Implement VectorUnzip with deinterleave lower 2020-07-04 11:04:10 +01:00
MerryMage
f35aaa017c IR: Add VectorDeinterleave{Even,Odd}Lower 2020-07-04 11:04:10 +01:00
MerryMage
df477c46c2 asimd_load_store_structures: VST1 undef correction 2020-07-04 11:04:10 +01:00
MerryMage
4ba1f8b9e7 Add optimization flags to disable specific optimizations 2020-07-04 11:04:10 +01:00
MerryMage
3eed024caf asimd_three_same: Ignore Q=1 for VPADD (floating-point) 2020-07-04 11:04:10 +01:00
MerryMage
896cb46c89 asimd_*: Standardize order of n and m to reduce confusion 2020-07-04 11:04:10 +01:00
MerryMage
4b8a781c04 emit_x64_floating_point: Introduce ICODE 2020-07-04 11:04:10 +01:00
MerryMage
7022281a0b emit_x64_vector_floating_point: Introduce ICODE 2020-07-04 11:04:10 +01:00
Merry
4f967387c0 asimd_three_regs: Reimplement asimd_VMLAL in terms of WideInstruction 2020-06-27 13:06:46 +01:00
Merry
7997404ee7 A32: Implement ASIMD V{ADD,SUB}{W,L} 2020-06-27 12:58:47 +01:00
Merry
868bd00ab5 A32: Rearrange translators for ASIMD Three Registers
* Separate Three Registers with Different Lengths from Same Lengths decoders
2020-06-27 11:15:07 +01:00
Merry
b1ff971a92 backend/x64: Temporarily avoid use of DefineValue(Argument&)
Issues with inappropriate values in upper bits of values
2020-06-27 10:52:59 +01:00
Merry
337498823c FindUnicorn: Fix find_package_handle_standard_args warning 2020-06-27 10:06:39 +01:00
MerryMage
8a1f106dba decoder/asimd: Correct names of scalar exceptions 2020-06-25 17:40:11 +01:00
MerryMage
495f58eed8 A32: Implement ASIMD VSHLL 2020-06-24 23:47:13 +01:00
MerryMage
ed48a9d7d5 A32: Implement VFPv5 VRINTX 2020-06-24 22:31:58 +01:00
MerryMage
46445d0866 A64: Remove NaN accuracy setting
Always do accuracte NaN handling.
2020-06-24 22:26:10 +01:00
Lioncash
b5df8d1ef8 A32: Implement ASIMD VQDMULL (scalar) 2020-06-23 18:19:42 +01:00
Lioncash
20a2bf29fc A32: Implement ASIMD VQRDMULH (scalar) 2020-06-23 18:19:42 +01:00
Lioncash
ab5efe8632 A32: Implement ASIMD VQDMULH (scalar) 2020-06-23 18:19:42 +01:00
MerryMage
2008fda88b emit_x64_floating_point: Correct error in s16 rounding in EmitFPToFixed 2020-06-22 22:54:38 +01:00
MerryMage
3ea49fc6d6 A32: Implement VFPv3 VCT (between floating-point and fixed-point) 2020-06-22 22:08:58 +01:00
MerryMage
48b2ffdde9 A32: Implement ASIMD VQMOVUN, VQMOVN 2020-06-22 20:02:52 +01:00
MerryMage
52b8039367 A32: Implement VFPv5 VRINT{R,Z} 2020-06-22 19:35:32 +01:00
MerryMage
47bc99ad9f asimd_load_store_structures: Fix 2-byte aligned vld1.16
Previously incorrectly undefined
2020-06-22 18:46:22 +01:00
Lioncash
dd8d5497da A32: Implement ASIMD VQRDMULH 2020-06-22 17:31:57 +01:00
Lioncash
0b7a111b54 A32: Implement ASIMD VQDMULH 2020-06-22 17:31:57 +01:00
Lioncash
39488e4aad A32: Implement ASIMD VRSHRN 2020-06-21 23:15:43 +01:00
Lioncash
86b0e5c1c5 A32: Implement ASIMD VQSHRN 2020-06-21 23:15:43 +01:00
Lioncash
85222e3e65 A32: Implement ASIMD VQSHRUN
We can leverage ShiftRightNarrowing() to implement this.
2020-06-21 23:15:43 +01:00
MerryMage
562a98bcf9 A32: Implement ASIMD VCVT (between floating-point and fixed-point) 2020-06-21 20:23:40 +01:00
MerryMage
6f56043a73 A32: Implement ASIMD VFMA, VFMS 2020-06-21 20:21:53 +01:00
Lioncash
aa0358d324 A32: Implement ASIMD VMLAL/VMLSL (integer) 2020-06-21 20:03:19 +01:00
Lioncash
eab26b404a A32: Implement ASIMD VABAL 2020-06-21 20:01:08 +01:00
Lioncash
98581839ca A32: Implement ASIMD VABDL 2020-06-21 19:55:00 +01:00
MerryMage
db85e7ced5 asimd: Add missing three registers of different lengths instructions 2020-06-21 19:54:32 +01:00
Lioncash
95919594d1 A32: Implement ASIMD VQSHL/VQSHLU (immediate) 2020-06-21 19:26:30 +01:00
MerryMage
3557576ece A32: Implement ASIMD AESD, AESE, AESIMC, AESMC 2020-06-21 18:39:57 +01:00
Fernando Sahmkow
2fa1c1d13c A32: Allow cleaning up exclusive state from the interface.
This function is normally required for emulating certain OS mechanisms.
2020-06-21 18:18:33 +01:00
MerryMage
df58a429ee A32: Implement ASIMD VQRSHRN 2020-06-21 17:41:18 +01:00
MerryMage
589d717af5 A32: Implement ASIMD VQRSHRUN 2020-06-21 17:41:18 +01:00
MerryMage
e009d99924 A32: Implement ASIMD VSHRN 2020-06-21 17:41:18 +01:00
MerryMage
473949d486 asimd_load_store_structures: Suppress MSVC shift warning 2020-06-21 17:41:18 +01:00
MerryMage
8f0f1cfd66 A32: Implement ASIMD VST{1,2,3,4} (single n-element structure from one lane) 2020-06-21 16:27:33 +01:00
MerryMage
fa145ae401 a32_unicorn: Print code on unicorn error 2020-06-21 16:23:01 +01:00
MerryMage
5a597f415c A32: Implement A32 VLD{1,2,3,4} (single n-element structure to one lane) 2020-06-21 16:22:43 +01:00
MerryMage
f221912409 bit_util: Bits without template arguments 2020-06-21 16:07:59 +01:00
MerryMage
3202e4c539 A32: Implement ASIMD VLD{1,2,3,4} (single n-element structure to all lanes) 2020-06-21 15:25:26 +01:00
MerryMage
d7197745ac emit_x64_vector_floating_point: fpcr_controlled is unused when fsize == 16 in EmitFPVectorToFixed 2020-06-21 14:46:06 +01:00
MerryMage
b32fc5ab0f a64_emit_x64: EmitVAddrLookup: Use bzhi instruction when silently_mirror_page_table is active and BMI2 is available 2020-06-21 14:46:06 +01:00
MerryMage
809dfe9c54 A32: Implement ASIMD VCVT (between floating-point and integer) 2020-06-21 14:28:25 +01:00
MerryMage
43a4b2a0b8 ir_emitter: Remove dummy fpcr_controlled arguments from scalar FP instructions 2020-06-21 14:28:25 +01:00
MerryMage
c836b389c8 emit_x64_vector_floating_point: Add fpcr_controlled argument to all IR instructions 2020-06-21 14:28:25 +01:00
MerryMage
33a81dae68 asimd: VEXT was being shadowed 2020-06-21 13:12:19 +01:00
MerryMage
bf093395d8 A32: Implement ASIMD VMOVN 2020-06-21 12:35:39 +01:00
MerryMage
c7785cd982 A32: Implement ASIMD VUZP and VZIP 2020-06-21 12:34:55 +01:00
MerryMage
603cd09c8f A32: Implement ASIMD VTRN 2020-06-21 12:14:13 +01:00
MerryMage
a8b481ab63 simd_permute: Implement TRN{1,2} in terms of VectorTranspose 2020-06-21 12:14:13 +01:00
MerryMage
7d1e103ff5 IR: Implement VectorTranspose 2020-06-21 12:14:13 +01:00
MerryMage
9cc11681dc A32: Implement ASIMD VMLAL, VMLSL, VMULL (scalar) 2020-06-21 10:31:30 +01:00
MerryMage
69a1d58a2b A32: Implement ASIMD VMULL 2020-06-21 10:00:24 +01:00
Lioncash
8c23f02330 A32: Implement ASIMD VABD 2020-06-21 07:54:21 +01:00
Lioncash
fc1633a2ea A32: Implement ASIMD VABA 2020-06-21 07:54:21 +01:00
Lioncash
bdb92f7055 asimd: Split out VABA/VABD decoders
These differ in bit encodings anyway
2020-06-21 07:54:21 +01:00
Lioncash
230fa02648 A32: Implement ASIMD VMLA/VMLS (scalar)
While we're at it, we can join the implementation of VMUL into a common
function.
2020-06-21 07:51:17 +01:00
MerryMage
70d071e6ab fuzz_arm: Test large random blocks 2020-06-21 00:41:54 +01:00
MerryMage
239ee289cf A32: Implement VDUP (scalar) 2020-06-21 00:22:42 +01:00
Lioncash
a8efe3f0f5 A32: Implement ASIMD VACGE/VACGT 2020-06-21 00:02:48 +01:00
Lioncash
e319257ec0 A32: Implement VCEQ/VCGE/VCGT (floating point) 2020-06-21 00:02:48 +01:00
Lioncash
faefb264a6 A32: Implement ASIMD VCEQ (integer) 2020-06-21 00:02:48 +01:00
Lioncash
7276993352 A32: Implement ASIMD VCGE (integer) 2020-06-21 00:02:48 +01:00
Lioncash
7292320445 A32: Implement ASIMD VCGT (integer) 2020-06-21 00:02:48 +01:00
MerryMage
fda4e11887 A32: Implement ASIMD VMOV (general-purpose register to scalar) 2020-06-20 23:40:48 +01:00
MerryMage
7ec22b4e1d A32: Implement ASIMD VMOV (scalar to general-purpose register) 2020-06-20 23:30:56 +01:00
MerryMage
8bbc9fdbb6 A32: Implement ASIMD VTBX 2020-06-20 22:35:31 +01:00
Lioncash
06f7229c57 A32: Implement ASIMD VPADAL (integer) 2020-06-20 22:28:47 +01:00
Lioncash
266c6a2000 A32: Implement ASIMD VPADDL (integer) 2020-06-20 22:28:47 +01:00
Lioncash
4bb286ac23 A32: Implement ASIMD VPADD (integer) 2020-06-20 21:22:14 +01:00
Lioncash
1ffeeeb6a2 A32: Implement ASIMD VMAX/VMIN (integer) 2020-06-20 21:20:47 +01:00
Lioncash
945b757b6c A32: Implement ASIMD VMLA/VMLS (integer) 2020-06-20 21:20:21 +01:00
MerryMage
715db8381f A32: Implement ASIMD VMUL (scalar) 2020-06-20 20:34:08 +01:00
MerryMage
b0beecdd41 A32: Implement ASIMD VTBL 2020-06-20 19:25:14 +01:00
MerryMage
28f27bc19d A32: Implement ASIMD VEXT 2020-06-20 19:05:14 +01:00
MerryMage
e8c460c167 A32: Implement ASIMD VDUP (ARM core register) 2020-06-20 16:02:43 +01:00
MerryMage
15ee562dd0 decoder/asimd: Add misc data-processing instructions 2020-06-20 15:39:00 +01:00
MerryMage
214c1d6002 fuzz_arm: Test testable parts of ASIMD VRECPE and VRSQRTE 2020-06-20 15:17:39 +01:00
MerryMage
92cb4a5a34 A32: Implement ASIMD VRSQRTE 2020-06-20 15:13:22 +01:00
MerryMage
8912496206 fuzz_arm: Unicorn has incorrect VRSQRTS implementation 2020-06-20 15:07:50 +01:00
MerryMage
6f59c2cd8e A32: Implement ASIMD VRECPE 2020-06-20 15:07:06 +01:00
MerryMage
d3dc50d718 A32: Implement ASIMD VRSQRTS 2020-06-20 15:06:06 +01:00
MerryMage
8f506c80c3 A32: Implement ASIMD VRECPS 2020-06-20 14:39:05 +01:00
MerryMage
9eef4f7471 A32: Implement ASIMD VMLA, VMLS (floating-point) 2020-06-20 14:31:06 +01:00
MerryMage
60f6e729ac A32: Implement ASIMD VABD (floating-point) 2020-06-20 14:25:04 +01:00
MerryMage
f58e247ef3 A32: Implement ASIMD VPADD (floating-point) 2020-06-20 14:25:04 +01:00
MerryMage
e006f0a205 A32: Implement ASIMD VSUB (floating-point) 2020-06-20 14:20:28 +01:00
MerryMage
4c939b9d0a A32: Implement ASIMD VADD (floating-point) 2020-06-20 14:20:28 +01:00
MerryMage
5ec8e48593 A32: Implement ASIMD VMUL (floating-point)
* Also add fpcr_controlled arguments to FPVectorMul IR instruction
* Merge ASIMD floating-point instruction implementations
2020-06-20 14:20:28 +01:00
1317 changed files with 226138 additions and 72605 deletions

View File

@ -1,32 +0,0 @@
# shallow clone
clone_depth: 5
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
cmake_generator: "Visual Studio 15 2017 Win64"
platform:
- x64
configuration:
- Release
install:
- git submodule update --init --recursive
- cd externals
- git clone https://github.com/MerryMage/ext-boost boost
- cd ..
before_build:
- mkdir build
- cd build
- cmake .. -G "%cmake_generator%" -DBoost_INCLUDE_DIRS=%cd%/../externals/boost
- cd ..
build:
project: build/dynarmic.sln
parallel: true
test_script:
- cd build && ctest -VV -C Release && cd ..

218
.clang-format Normal file
View File

@ -0,0 +1,218 @@
---
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: None
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignConsecutiveMacros: None
AlignEscapedNewlines: Right
AlignOperands: AlignAfterOperator
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: false
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBinaryOperators: All
BreakBeforeBraces: Custom
BreakBeforeConceptDeclarations: true
BreakBeforeTernaryOperators: true
BreakBeforeInheritanceComma: false
BreakConstructorInitializersBeforeComma: true
BreakConstructorInitializers: BeforeComma
BreakInheritanceList: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 0
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
# EmptyLineAfterAccessModifier: Leave
EmptyLineBeforeAccessModifier: Always
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<mach/'
Priority: 1
SortPriority: 0
CaseSensitive: false
- Regex: '^<windows.h>'
Priority: 1
SortPriority: 0
CaseSensitive: false
- Regex: '(^<signal.h>)|(^<sys/ucontext.h>)|(^<ucontext.h>)'
Priority: 1
SortPriority: 0
CaseSensitive: false
- Regex: '^<([^\.])*>$'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*\.'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 4
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
# IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExternBlock: NoIndent
IndentGotoLabels: false
IndentPPDirectives: AfterHash
IndentRequires: false
IndentWidth: 4
IndentWrappedFunctionNames: false
# InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
NamespaceMacros:
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PenaltyIndentedWhitespace: 0
PointerAlignment: Left
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
- ParseTestProto
- ParsePartialTestProto
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
# ShortNamespaceLines: 5
SortIncludes: true
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInCStyleCastParentheses: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
# SpacesInLineCommentPrefix: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
TypenameMacros:
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
- FCODE
- ICODE
...

84
.github/workflows/aarch64.yml vendored Normal file
View File

@ -0,0 +1,84 @@
name: AArch64
on: [ push, pull_request ]
env:
BUILD_TYPE: Release
jobs:
build:
strategy:
matrix:
os: [ ubuntu-latest ]
fail-fast: false
runs-on: ${{matrix.os}}
steps:
- name: Install build dependencies
if: ${{matrix.os == 'ubuntu-latest'}}
run: >
sudo apt-get install
gcc-10-aarch64-linux-gnu
g++-10-aarch64-linux-gnu
ninja-build
qemu-user
- name: Checkout dynarmic repo
uses: actions/checkout@v2
- name: Ccache
uses: hendrikmuhs/ccache-action@v1.2
- name: Checkout ext-boost repo
uses: actions/checkout@v2
with:
repository: MerryMage/ext-boost
path: externals/ext-boost
- name: Configure CMake for AArch64
env:
CC: aarch64-linux-gnu-gcc-10
CXX: aarch64-linux-gnu-g++-10
run: >
cmake
-B ${{github.workspace}}/build-arm64
-DBoost_INCLUDE_DIRS=${{github.workspace}}/externals/ext-boost
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
-DDYNARMIC_TESTS_USE_UNICORN=0
-DDYNARMIC_USE_LLVM=0
-DDYNARMIC_FRONTENDS=A32
-G Ninja
- name: Build AArch64
working-directory: ${{github.workspace}}/build-arm64
run: cmake --build . --config Release
- name: Configure CMake for x86_64
env:
CC: gcc-10
CXX: g++-10
run: >
cmake
-B ${{github.workspace}}/build-x64
-DBoost_INCLUDE_DIRS=${{github.workspace}}/externals/ext-boost
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
-DCMAKE_C_COMPILER_LAUNCHER=ccache
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
-DDYNARMIC_FRONTENDS=A32
-DDYNARMIC_TESTS_USE_UNICORN=0
-DDYNARMIC_USE_LLVM=0
-G Ninja
- name: Build x86_64
working-directory: ${{github.workspace}}/build-x64
run: cmake --build . --config Release
- name: Basic tests
working-directory: ${{github.workspace}}
run: qemu-aarch64 -L /usr/aarch64-linux-gnu ./build-arm64/tests/dynarmic_tests -d yes
- name: Test against x86_64 implementation
working-directory: ${{github.workspace}}
run: diff <(qemu-aarch64 -L /usr/aarch64-linux-gnu ./build-arm64/tests/dynarmic_test_generator) <(./build-x64/tests/dynarmic_test_generator)

18
.github/workflows/clang-format.yml vendored Normal file
View File

@ -0,0 +1,18 @@
name: clang-format
on: [push, pull_request]
jobs:
clang-format:
runs-on: ubuntu-latest
steps:
- name: Checkout dynarmic repo
uses: actions/checkout@v2
- uses: DoozyX/clang-format-lint-action@v0.12
with:
source: 'src tests'
clangFormatVersion: 12

146
.github/workflows/x86-64.yml vendored Normal file
View File

@ -0,0 +1,146 @@
name: x86-64
on: [ push, pull_request ]
env:
BUILD_TYPE: Release
jobs:
build:
strategy:
matrix:
os: [ windows-latest, ubuntu-latest, macos-latest ]
cpu_detection: [ 0, 1 ]
arch: [ x64, arm64]
exclude:
- cpu_detection: 1
arch: arm64
fail-fast: false
runs-on: ${{matrix.os}}
steps:
- name: Install build dependencies
if: ${{matrix.os == 'ubuntu-latest'}}
run: sudo apt-get install llvm ninja-build
- name: Install cross-compile dependencies
if: ${{matrix.os == 'ubuntu-latest' && matrix.arch == 'arm64' }}
run: sudo apt-get install gcc-10-aarch64-linux-gnu g++-10-aarch64-linux-gnu qemu-user
- name: Install build dependencies
if: ${{matrix.os == 'macos-latest'}}
run: |
brew install llvm ninja
echo "/usr/local/opt/llvm/bin" >> $GITHUB_PATH
- name: Checkout dynarmic repo
uses: actions/checkout@v2
- name: Checkout ext-boost repo
uses: actions/checkout@v2
with:
repository: MerryMage/ext-boost
path: externals/ext-boost
- name: Checkout unicorn repo
if: ${{matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'}}
uses: actions/checkout@v2
with:
repository: MerryMage/unicorn
path: externals/unicorn
- name: Build unicorn
if: ${{matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'}}
working-directory: externals/unicorn
run: UNICORN_ARCHS=aarch64,arm ./make.sh
- name: Configure CMake
if: ${{matrix.os == 'ubuntu-latest' && matrix.arch != 'arm64'}}
env:
CC: gcc-10
CXX: g++-10
CXXFLAGS: -Wp,-D_GLIBCXX_ASSERTIONS
run: >
cmake
-B ${{github.workspace}}/build
-DBoost_INCLUDE_DIRS=${{github.workspace}}/externals/ext-boost
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
-DDYNARMIC_ENABLE_CPU_FEATURE_DETECTION=${{matrix.cpu_detection}}
-DDYNARMIC_TESTS_USE_UNICORN=1
-DDYNARMIC_USE_LLVM=1
-DLIBUNICORN_INCLUDE_DIR=${{github.workspace}}/externals/unicorn/include
-DLIBUNICORN_LIBRARY=${{github.workspace}}/externals/unicorn/libunicorn.a
-G Ninja
- name: Configure CMake
if: ${{matrix.os == 'ubuntu-latest' && matrix.arch == 'arm64'}}
env:
CC: aarch64-linux-gnu-gcc-10
CXX: aarch64-linux-gnu-g++-10
run: >
cmake
-B ${{github.workspace}}/build
-DBoost_INCLUDE_DIRS=${{github.workspace}}/externals/ext-boost
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
-DDYNARMIC_FRONTENDS="A32"
-G Ninja
- name: Configure CMake
if: ${{matrix.os == 'macos-latest' && matrix.arch == 'x64'}}
run: >
cmake
-B ${{github.workspace}}/build
-DBoost_INCLUDE_DIRS=${{github.workspace}}/externals/ext-boost
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
-DDYNARMIC_ENABLE_CPU_FEATURE_DETECTION=${{matrix.cpu_detection}}
-DDYNARMIC_TESTS_USE_UNICORN=1
-DDYNARMIC_USE_LLVM=1
-DLIBUNICORN_INCLUDE_DIR=${{github.workspace}}/externals/unicorn/include
-DLIBUNICORN_LIBRARY=${{github.workspace}}/externals/unicorn/libunicorn.a
-G Ninja
- name: Configure CMake
if: ${{matrix.os == 'macos-latest' && matrix.arch == 'arm64'}}
run: >
cmake
-B ${{github.workspace}}/build
-DBoost_INCLUDE_DIRS=${{github.workspace}}/externals/ext-boost
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
-DDYNARMIC_FRONTENDS="A32"
-DCMAKE_OSX_ARCHITECTURES=arm64
-G Ninja
- name: Configure CMake
if: ${{matrix.os == 'windows-latest' && matrix.arch == 'x64'}}
run: >
cmake
-B ${{github.workspace}}/build
-DBoost_INCLUDE_DIRS=${{github.workspace}}/externals/ext-boost
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
-DDYNARMIC_ENABLE_CPU_FEATURE_DETECTION=${{matrix.cpu_detection}}
-G "Visual Studio 17 2022"
-A x64
- name: Configure CMake
if: ${{matrix.os == 'windows-latest' && matrix.arch == 'arm64'}}
run: >
cmake
-B ${{github.workspace}}/build
-DBoost_INCLUDE_DIRS=${{github.workspace}}/externals/ext-boost
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
-DDYNARMIC_FRONTENDS="A32"
-G "Visual Studio 17 2022"
-A arm64
- name: Build
working-directory: ${{github.workspace}}/build
run: cmake --build . --config Release
- name: Test
if: ${{matrix.arch == 'x64'}}
env:
DYLD_FALLBACK_LIBRARY_PATH: ${{github.workspace}}/externals/unicorn
working-directory: ${{github.workspace}}/build
run: ctest --extra-verbose -C ${{env.BUILD_TYPE}}

6
.gitignore vendored
View File

@ -1,6 +1,10 @@
# Built files
build/
build-*/
cmake-build-*/
.idea/
docs/Doxygen/
# Generated files
src/backend/x64/mig/
src/dynarmic/backend/x64/mig/
# System files
.DS_Store

View File

@ -1,66 +0,0 @@
language: cpp
cache: ccache
matrix:
include:
- env: NAME="Linux Build" GCC_VERSION=7
os: linux
dist: trusty
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-7
- g++-7
- ninja-build
install: ./.travis/build-x86_64-linux/deps.sh
script: ./.travis/build-x86_64-linux/build.sh
- env: NAME="Linux Build" GCC_VERSION=8
os: linux
dist: trusty
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-8
- g++-8
- ninja-build
install: ./.travis/build-x86_64-linux/deps.sh
script: ./.travis/build-x86_64-linux/build.sh
- env: NAME="macOS Build"
os: osx
sudo: false
osx_image: xcode10.2
install: ./.travis/build-x86_64-macos/deps.sh
script: ./.travis/build-x86_64-macos/build.sh
- env: NAME="Test - Fuzz against Unicorn"
os: linux
dist: bionic
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-7
- g++-7
- llvm-dev
- ninja-build
install: ./.travis/test-with-unicorn-on-x86_64-linux/deps.sh
script: ./.travis/test-with-unicorn-on-x86_64-linux/build.sh
- env: NAME="Test - SSE3 only"
os: linux
dist: bionic
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-7
- g++-7
- llvm-dev
- ninja-build
install: ./.travis/sse3-only-on-x86_64-linux/deps.sh
script: ./.travis/sse3-only-on-x86_64-linux/build.sh

View File

@ -1,14 +0,0 @@
#!/bin/sh
set -e
set -x
export CC=gcc-${GCC_VERSION}
export CXX=g++-${GCC_VERSION}
export PKG_CONFIG_PATH=$HOME/.local/lib/pkgconfig:$PKG_CONFIG_PATH
mkdir build && cd build
cmake .. -DBoost_INCLUDE_DIRS=${PWD}/../externals/ext-boost -DCMAKE_BUILD_TYPE=Release -G Ninja
ninja
./tests/dynarmic_tests --durations yes

View File

@ -1,13 +0,0 @@
#!/bin/sh
set -e
set -x
# TODO: This isn't ideal.
cd externals
git clone https://github.com/MerryMage/ext-boost
cd ..
mkdir -p $HOME/.local
curl -L https://cmake.org/files/v3.8/cmake-3.8.0-Linux-x86_64.tar.gz \
| tar -xz -C $HOME/.local --strip-components=1

View File

@ -1,11 +0,0 @@
#!/bin/sh
set -e
set -x
set -o pipefail
export MACOSX_DEPLOYMENT_TARGET=10.12
mkdir build && cd build
cmake .. -GXcode -DBoost_INCLUDE_DIRS=${PWD}/../externals/ext-boost -DDYNARMIC_TESTS=0
xcodebuild -configuration Release

View File

@ -1,9 +0,0 @@
#!/bin/sh
set -e
set -x
# TODO: This isn't ideal.
cd externals
git clone https://github.com/MerryMage/ext-boost
cd ..

View File

@ -1,15 +0,0 @@
#!/bin/sh
set -e
set -x
export CC=gcc-7
export CXX=g++-7
export PKG_CONFIG_PATH=$HOME/.local/lib/pkgconfig:$PKG_CONFIG_PATH
export UNICORNDIR=$(pwd)/externals/unicorn
mkdir build && cd build
cmake .. -DBoost_INCLUDE_DIRS=${PWD}/../externals/ext-boost -DCMAKE_BUILD_TYPE=Release -DDYNARMIC_USE_LLVM=1 -DDYNARMIC_TESTS_USE_UNICORN=1 -DDYNARMIC_ENABLE_CPU_FEATURE_DETECTION=0 -G Ninja
ninja
./tests/dynarmic_tests --durations yes

View File

@ -1,18 +0,0 @@
#!/bin/sh
set -e
set -x
python3 --version
# TODO: This isn't ideal.
cd externals
git clone https://github.com/MerryMage/ext-boost
git clone https://github.com/MerryMage/unicorn
cd unicorn
UNICORN_ARCHS=aarch64,arm ./make.sh
cd ../..
mkdir -p $HOME/.local
curl -L https://cmake.org/files/v3.8/cmake-3.8.0-Linux-x86_64.tar.gz \
| tar -xz -C $HOME/.local --strip-components=1

View File

@ -1,15 +0,0 @@
#!/bin/sh
set -e
set -x
export CC=gcc-7
export CXX=g++-7
export PKG_CONFIG_PATH=$HOME/.local/lib/pkgconfig:$PKG_CONFIG_PATH
export UNICORNDIR=$(pwd)/externals/unicorn
mkdir build && cd build
cmake .. -DBoost_INCLUDE_DIRS=${PWD}/../externals/ext-boost -DCMAKE_BUILD_TYPE=Release -DDYNARMIC_USE_LLVM=1 -DDYNARMIC_TESTS_USE_UNICORN=1 -G Ninja
ninja
./tests/dynarmic_tests --durations yes

View File

@ -1,18 +0,0 @@
#!/bin/sh
set -e
set -x
python3 --version
# TODO: This isn't ideal.
cd externals
git clone https://github.com/MerryMage/ext-boost
git clone https://github.com/MerryMage/unicorn
cd unicorn
UNICORN_ARCHS="arm aarch64" ./make.sh
cd ../..
mkdir -p $HOME/.local
curl -L https://cmake.org/files/v3.8/cmake-3.8.0-Linux-x86_64.tar.gz \
| tar -xz -C $HOME/.local --strip-components=1

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.8)
project(dynarmic C CXX)
cmake_minimum_required(VERSION 3.12)
project(dynarmic LANGUAGES C CXX ASM VERSION 6.3.0)
# Determine if we're built as a subproject (using add_subdirectory)
# or if this is the master project.
@ -8,10 +8,27 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(MASTER_PROJECT ON)
endif()
# Add the module directory to the list of paths
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules")
# Arch detection
include(DetectArchitecture)
if (NOT DEFINED ARCHITECTURE)
message(FATAL_ERROR "Unsupported architecture encountered. Ending CMake generation.")
endif()
message(STATUS "Target architecture: ${ARCHITECTURE}")
set(REQUIRES_NO_EXECUTE_SUPPORT OFF)
# Apple Silicon chips require W^X
if(APPLE AND ARCHITECTURE STREQUAL "arm64")
set(REQUIRES_NO_EXECUTE_SUPPORT ON)
endif()
# Dynarmic project options
option(DYNARMIC_ENABLE_CPU_FEATURE_DETECTION "Turning this off causes dynarmic to assume the host CPU doesn't support anything later than SSE3" ON)
option(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT "Enables support for systems that require W^X" OFF)
option(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT "Enables support for systems that require W^X" ${REQUIRES_NO_EXECUTE_SUPPORT})
option(DYNARMIC_FATAL_ERRORS "Errors are fatal" OFF)
option(DYNARMIC_IGNORE_ASSERTS "Ignore asserts" OFF)
option(DYNARMIC_TESTS "Build tests" ${MASTER_PROJECT})
option(DYNARMIC_TESTS_USE_UNICORN "Enable fuzzing tests against unicorn" OFF)
option(DYNARMIC_USE_LLVM "Support disassembly of jitted x86_64 code using LLVM" OFF)
@ -27,7 +44,7 @@ if (NOT CMAKE_BUILD_TYPE)
endif()
# Set hard requirements for C++
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
@ -38,13 +55,9 @@ if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
message(SEND_ERROR "In-source builds are not allowed.")
endif()
# Add the module directory to the list of paths
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules")
# Compiler flags
if (MSVC)
set(DYNARMIC_CXX_FLAGS
/std:c++latest # CMAKE_CXX_STANDARD has no effect on MSVC until CMake 3.10.
/experimental:external
/external:W0
/external:anglebrackets
@ -97,21 +110,13 @@ else()
list(APPEND DYNARMIC_CXX_FLAGS
-Wfatal-errors)
endif()
endif()
# Arch detection
include(DetectArchitecture)
if (MSVC)
detect_architecture("_M_AMD64" x86_64)
detect_architecture("_M_ARM64" Aarch64)
else()
detect_architecture("__x86_64__" x86_64)
detect_architecture("__aarch64__" Aarch64)
if (CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang")
# Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6.
# And this in turns limits the size of a std::array.
list(APPEND DYNARMIC_CXX_FLAGS -fbracket-depth=1024)
endif()
endif()
if (NOT DEFINED ARCHITECTURE)
message(FATAL_ERROR "Unsupported architecture encountered. Ending CMake generation.")
endif()
message(STATUS "Target architecture: ${ARCHITECTURE}")
# Include Boost
if (NOT TARGET boost)
@ -122,6 +127,27 @@ if (NOT TARGET boost)
target_include_directories(boost SYSTEM INTERFACE ${Boost_INCLUDE_DIRS})
endif()
if (DYNARMIC_NO_BUNDLED_FMT AND NOT TARGET fmt AND NOT TARGET fmt::fmt)
find_package(fmt REQUIRED)
add_library(fmt ALIAS fmt::fmt)
endif()
if (DYNARMIC_NO_BUNDLED_ROBIN_MAP AND NOT TARGET tsl::robin_map)
find_package(tsl-robin-map REQUIRED)
endif()
if (DYNARMIC_NO_BUNDLED_XBYAK AND NOT TARGET xbyak)
if (ARCHITECTURE STREQUAL "x86" OR ARCHITECTURE STREQUAL "x86_64")
find_package(xbyak REQUIRED)
add_library(xbyak ALIAS xbyak::xbyak)
endif()
endif()
if (DYNARMIC_NO_BUNDLED_ZYDIS AND NOT TARGET Zydis)
find_package(Zydis REQUIRED)
add_library(Zydis ALIAS Zydis::Zydis)
endif()
# Enable unit-testing.
enable_testing(true)
@ -133,15 +159,49 @@ if (DYNARMIC_USE_LLVM)
llvm_map_components_to_libnames(llvm_libs armdesc armdisassembler aarch64desc aarch64disassembler x86desc x86disassembler)
endif()
if (DYNARMIC_TESTS_USE_UNICORN)
if (DYNARMIC_TESTS_USE_UNICORN AND DYNARMIC_TESTS)
find_package(Unicorn REQUIRED)
endif()
if (DYNARMIC_TESTS AND DYNARMIC_NO_BUNDLED_CATCH AND NOT TARGET catch)
find_package(Catch2 REQUIRED)
add_library(catch ALIAS Catch2::Catch2)
endif()
# Pull in externals CMakeLists for libs where available
add_subdirectory(externals)
# Dynarmic project files
add_subdirectory(src)
add_subdirectory(src/dynarmic)
if (DYNARMIC_TESTS)
add_subdirectory(tests)
endif()
#
# Install
#
if (MASTER_PROJECT)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
install(TARGETS dynarmic EXPORT dynarmicTargets)
install(EXPORT dynarmicTargets
NAMESPACE dynarmic::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/dynarmic"
)
configure_package_config_file(CMakeModules/dynarmicConfig.cmake.in
dynarmicConfig.cmake
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/dynarmic"
)
write_basic_package_version_file(dynarmicConfigVersion.cmake
COMPATIBILITY SameMajorVersion
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/dynarmicConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/dynarmicConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/dynarmic"
)
install(DIRECTORY src/dynarmic TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
endif()

View File

@ -1,16 +1,56 @@
include(CheckSymbolExists)
function(detect_architecture symbol arch)
if (NOT DEFINED ARCHITECTURE)
set(CMAKE_REQUIRED_QUIET 1)
check_symbol_exists("${symbol}" "" ARCHITECTURE_${arch})
set(CMAKE_REQUIRED_QUIET YES)
check_symbol_exists("${symbol}" "" DETECT_ARCHITECTURE_${arch})
unset(CMAKE_REQUIRED_QUIET)
# The output variable needs to be unique across invocations otherwise
# CMake's crazy scope rules will keep it defined
if (ARCHITECTURE_${arch})
if (DETECT_ARCHITECTURE_${arch})
set(ARCHITECTURE "${arch}" PARENT_SCOPE)
set(ARCHITECTURE_${arch} 1 PARENT_SCOPE)
add_definitions(-DARCHITECTURE_${arch}=1)
endif()
unset(DETECT_ARCHITECTURE_${arch} CACHE)
endif()
endfunction()
detect_architecture("__ARM64__" arm64)
detect_architecture("__aarch64__" arm64)
detect_architecture("_M_ARM64" arm64)
detect_architecture("__arm__" arm)
detect_architecture("__TARGET_ARCH_ARM" arm)
detect_architecture("_M_ARM" arm)
detect_architecture("__x86_64" x86_64)
detect_architecture("__x86_64__" x86_64)
detect_architecture("__amd64" x86_64)
detect_architecture("_M_X64" x86_64)
detect_architecture("__i386" x86)
detect_architecture("__i386__" x86)
detect_architecture("_M_IX86" x86)
detect_architecture("__ia64" ia64)
detect_architecture("__ia64__" ia64)
detect_architecture("_M_IA64" ia64)
detect_architecture("__mips" mips)
detect_architecture("__mips__" mips)
detect_architecture("_M_MRX000" mips)
detect_architecture("__ppc64__" ppc64)
detect_architecture("__powerpc64__" ppc64)
detect_architecture("__ppc__" ppc)
detect_architecture("__ppc" ppc)
detect_architecture("__powerpc__" ppc)
detect_architecture("_ARCH_COM" ppc)
detect_architecture("_ARCH_PWR" ppc)
detect_architecture("_ARCH_PPC" ppc)
detect_architecture("_M_MPPC" ppc)
detect_architecture("_M_PPC" ppc)
detect_architecture("__riscv" riscv)
detect_architecture("__EMSCRIPTEN__" wasm)

View File

@ -19,7 +19,7 @@ find_library(LIBUNICORN_LIBRARY
HINTS $ENV{UNICORNDIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(unicorn DEFAULT_MSG LIBUNICORN_LIBRARY LIBUNICORN_INCLUDE_DIR)
find_package_handle_standard_args(Unicorn DEFAULT_MSG LIBUNICORN_LIBRARY LIBUNICORN_INCLUDE_DIR)
if (UNICORN_FOUND)
set(THREADS_PREFER_PTHREAD_FLAG ON)

View File

@ -0,0 +1,5 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
check_required_components(@PROJECT_NAME@)

View File

@ -1,13 +1,14 @@
Dynarmic
========
[![Travis CI Build Status](https://api.travis-ci.org/MerryMage/dynarmic.svg?branch=master)](https://travis-ci.org/MerryMage/dynarmic/branches) [![Appveyor CI Build status](https://ci.appveyor.com/api/projects/status/maeiqr41rgm1innm/branch/master?svg=true)](https://ci.appveyor.com/project/MerryMage/dynarmic/branch/master)
[![Github Actions Build Status](https://github.com/MerryMage/dynarmic/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/MerryMage/dynarmic/actions/workflows/build-and-test.yml)
A dynamic recompiler for ARM.
### Supported guest architectures
* ARMv6K
* ARMv6K, ARMv7A
* 32-bit ARMv8
* 64-bit ARMv8
### Supported host architectures
@ -16,6 +17,15 @@ A dynamic recompiler for ARM.
There are no plans to support x86-32.
Projects using Dynarmic
-----------------------
* [Citra - Nintendo 3DS emulator](https://citra-emu.org)
* [yuzu - Nintendo Switch emulator](https://yuzu-emu.org)
* [EKA2L1 - An Experimental Symbian OS emulator](https://github.com/EKA2L1/EKA2L1)
* [Vita3K - An Experimental PSVita emulator](https://vita3k.org)
* [unidbg - Android native library emulation, with experimental iOS emulation](https://github.com/zhkl0228/unidbg)
Alternatives to Dynarmic
------------------------
@ -34,7 +44,7 @@ More general alternatives:
* [VisUAL](https://salmanarif.bitbucket.io/visual/index.html) - Visual ARM UAL emulator intended for education
* A wide variety of other recompilers, interpreters and emulators can be found embedded in other projects, here are some we would recommend looking at:
* [firebird's recompiler](https://github.com/nspire-emus/firebird) - Takes more of a call-threaded approach to recompilation
* [higan's arm7tdmi emulator](https://gitlab.com/higan/higan/tree/master/higan/component/processor/arm7tdmi) - Very clean code-style
* [higan's arm7tdmi emulator](https://github.com/higan-emu/higan/tree/master/higan/component/processor/arm7tdmi) - Very clean code-style
* [arm-js by ozaki-r](https://github.com/ozaki-r/arm-js) - Emulates ARMv7A and some peripherals of Versatile Express, in the browser
Disadvantages of Dynarmic
@ -84,8 +94,8 @@ The below is a minimal example. Bring-your-own memory system.
#include <cstdio>
#include <exception>
#include <dynarmic/A32/a32.h>
#include <dynarmic/A32/config.h>
#include "dynarmic/interface/A32/a32.h"
#include "dynarmic/interface/A32/config.h"
using u8 = std::uint8_t;
using u16 = std::uint16_t;
@ -199,7 +209,7 @@ Legal
dynarmic is under a 0BSD license. See LICENSE.txt for more details.
dynarmic uses several other libraries, whose licenes are included below:
dynarmic uses several other libraries, whose licenses are included below:
### catch
@ -257,21 +267,30 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
### mp
### mcl & oaknut
```
Copyright (C) 2017 MerryMage
MIT License
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted.
Copyright (c) 2022 merryhime <https://mary.rs>
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
### robin-map
@ -350,3 +369,30 @@ THE POSSIBILITY OF SUCH DAMAGE.
損害、間接損害、偶発的な損害、特別損害、懲罰的損害、または結果損害について、
一切責任を負わないものとします。
```
### zydis
```
The MIT License (MIT)
Copyright (c) 2014-2020 Florian Bernd
Copyright (c) 2014-2020 Joel Höner
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```

View File

@ -5,14 +5,14 @@ support for other versions of the ARM architecture, having a interpreter mode, a
for other architectures.
Users of this library interact with it primarily through the interface provided in
[`include/dynarmic`](../include/dynarmic). Users specify how dynarmic's CPU core interacts with
[`src/dynarmic/interface`](../src/dynarmic/interface). Users specify how dynarmic's CPU core interacts with
the rest of their system providing an implementation of the relevant `UserCallbacks` interface.
Users setup the CPU state using member functions of `Jit`, then call `Jit::Execute` to start CPU
execution. The callbacks defined on `UserCallbacks` may be called from dynamically generated code,
so users of the library should not depend on the stack being in a walkable state for unwinding.
* A32: [`Jit`](../include/dynarmic/A32/a32.h), [`UserCallbacks`](../include/dynarmic/A32/config.h)
* A64: [`Jit`](../include/dynarmic/A64/a64.h), [`UserCallbacks`](../include/dynarmic/A64/config.h)
* A32: [`Jit`](../src/dynarmic/interface/A32/a32.h), [`UserCallbacks`](../src/dynarmic/interface/A32/config.h)
* A64: [`Jit`](../src/dynarmic/interface/A64/a64.h), [`UserCallbacks`](../src/dynarmic/interface/A64/config.h)
Dynarmic reads instructions from memory by calling `UserCallbacks::MemoryReadCode`. These
instructions then pass through several stages:
@ -26,19 +26,19 @@ instructions then pass through several stages:
Using the A32 frontend with the x64 backend as an example:
* Decoding is done by [double dispatch](https://en.wikipedia.org/wiki/Visitor_pattern) in
[`src/frontend/A32/decoder/{arm.h,thumb16.h,thumb32.h}`](../src/frontend/A32/decoder/).
* Translation is done by the visitors in `src/frontend/A32/translate/translate_{arm,thumb}.cpp`.
The function [`Translate`](../src/frontend/A32/translate/translate.h) takes a starting memory location,
[`src/frontend/A32/decoder/{arm.h,thumb16.h,thumb32.h}`](../src/dynarmic/frontend/A32/decoder/).
* Translation is done by the visitors in [`src/dynarmic/frontend/A32/translate/translate_{arm,thumb}.cpp`](../src/dynarmic/frontend/A32/translate/).
The function [`Translate`](../src/dynarmic/frontend/A32/translate/translate.h) takes a starting memory location,
some CPU state, and memory reader callback and returns a basic block of IR.
* The IR can be found under [`src/frontend/ir/`](../src/frontend/ir/).
* Optimizations can be found under [`src/ir_opt/`](../src/ir_opt/).
* Emission is done by `EmitX64` which can be found in `src/backend_x64/emit_x64.{h,cpp}`.
* Execution is performed by calling `BlockOfCode::RunCode` in `src/backend_x64/block_of_code.{h,cpp}`.
* The IR can be found under [`src/frontend/ir/`](../src/dynarmic/ir/).
* Optimizations can be found under [`src/ir_opt/`](../src/dynarmic/ir/opt/).
* Emission is done by `EmitX64` which can be found in [`src/dynarmic/backend/x64/emit_x64.{h,cpp}`](../src/dynarmic/backend/x64/).
* Execution is performed by calling `BlockOfCode::RunCode` in [`src/dynarmic/backend/x64/block_of_code.{h,cpp}`](../src/dynarmic/backend/x64/).
## Decoder
The decoder is a double dispatch decoder. Each instruction is represented by a line in the relevant
instruction table. Here is an example line from [`arm.h`](../src/frontend/A32/decoder/arm.h):
instruction table. Here is an example line from [`arm.h`](../src/dynarmic/frontend/A32/decoder/arm.h):
INST(&V::arm_ADC_imm, "ADC (imm)", "cccc0010101Snnnnddddrrrrvvvvvvvv")
@ -61,7 +61,7 @@ error results.
## Translator
The translator is a visitor that uses the decoder to decode instructions. The translator generates IR code with the
help of the [`IREmitter` class](../src/frontend/ir/ir_emitter.h). An example of a translation function follows:
help of the [`IREmitter` class](../src/dynarmic/ir/ir_emitter.h). An example of a translation function follows:
bool ArmTranslatorVisitor::arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
u32 imm32 = ArmExpandImm(rotate, imm8);
@ -107,7 +107,7 @@ function analyser in the medium-term future.
Dynarmic's intermediate representation is typed. Each microinstruction may take zero or more arguments and may
return zero or more arguments. A subset of the microinstructions available is documented below.
A complete list of microinstructions can be found in [src/frontend/ir/opcodes.inc](../src/frontend/ir/opcodes.inc).
A complete list of microinstructions can be found in [src/dynarmic/ir/opcodes.inc](../src/dynarmic/ir/opcodes.inc).
The below lists some commonly used microinstructions.

View File

@ -1,36 +1,64 @@
# Always build externals as static libraries, even when dynarmic is built as shared
if (BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
# For libraries that already come with a CMakeLists file,
# simply add the directory to that file as a subdirectory
# to have CMake automatically recognize them.
# catch
add_library(catch INTERFACE)
target_include_directories(catch INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/catch>)
if (DYNARMIC_TESTS AND NOT TARGET catch)
add_library(catch INTERFACE)
target_include_directories(catch INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/catch/include>)
endif()
# fmt
if (NOT DYNARMIC_NO_BUNDLED_FMT)
if (NOT TARGET fmt AND NOT TARGET fmt::fmt)
# fmtlib formatting library
add_subdirectory(fmt)
endif()
# mp
# mcl
add_library(mp INTERFACE)
target_include_directories(mp INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/mp/include>)
if (NOT TARGET merry::mcl)
add_subdirectory(mcl)
endif()
# oaknut
if (NOT TARGET merry::oaknut)
if (ARCHITECTURE STREQUAL "arm64")
add_subdirectory(oaknut)
endif()
endif()
# robin-map
add_library(robin_map INTERFACE)
add_library(tsl::robin_map ALIAS robin_map)
target_include_directories(robin_map SYSTEM INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/robin-map/include>")
if (NOT TARGET tsl::robin_map)
add_subdirectory(robin-map)
endif()
# xbyak
if (NOT TARGET xbyak)
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
if (ARCHITECTURE STREQUAL "x86" OR ARCHITECTURE STREQUAL "x86_64")
add_library(xbyak INTERFACE)
target_include_directories(xbyak SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/xbyak/xbyak)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/xbyak/include)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/xbyak/xbyak DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/xbyak/include)
target_include_directories(xbyak SYSTEM INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/xbyak/include)
target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES)
endif()
endif()
# zydis
if (NOT TARGET Zydis)
option(ZYDIS_BUILD_TOOLS "" OFF)
option(ZYDIS_BUILD_EXAMPLES "" OFF)
set(ZYDIS_ZYCORE_PATH "${CMAKE_CURRENT_LIST_DIR}/zycore" CACHE PATH "")
add_subdirectory(zydis EXCLUDE_FROM_ALL)
endif()

15
externals/README.md vendored
View File

@ -4,9 +4,12 @@ This repository uses subtrees to manage some of its externals.
```
git remote add externals-fmt https://github.com/fmtlib/fmt.git --no-tags
git remote add externals-mp https://github.com/MerryMage/mp.git --no-tags
git remote add externals-mcl https://github.com/merryhime/mcl.git --no-tags
git remote add externals-oaknut https://github.com/merryhime/oaknut.git --no-tags
git remote add externals-robin-map https://github.com/Tessil/robin-map.git --no-tags
git remote add externals-xbyak https://github.com/herumi/xbyak.git --no-tags
git remote add externals-zycore https://github.com/zyantific/zycore-c.git --no-tags
git remote add externals-zydis https://github.com/zyantific/zydis.git --no-tags
```
## Updating
@ -15,11 +18,17 @@ Change `<ref>` to refer to the appropriate git reference.
```
git fetch externals-fmt
git fetch externals-mp
git fetch externals-mcl
git fetch externals-oaknut
git fetch externals-robin-map
git fetch externals-xbyak
git fetch externals-zycore
git fetch externals-zydis
git subtree pull --squash --prefix=externals/fmt externals-fmt <ref>
git subtree pull --squash --prefix=externals/mp externals-mp <ref>
git subtree pull --squash --prefix=externals/mcl externals-mcl <ref>
git subtree pull --squash --prefix=externals/oaknut externals-oaknut <ref>
git subtree pull --squash --prefix=externals/robin-map externals-robin-map <ref>
git subtree pull --squash --prefix=externals/xbyak externals-xbyak <ref>
git subtree pull --squash --prefix=externals/zycore externals-zycore <ref>
git subtree pull --squash --prefix=externals/zydis externals-zydis <ref>
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
<!--
Please make sure that the problem reproduces on the current master before
submitting an issue.
If possible please provide a repro on Compiler Explorer:
https://godbolt.org/z/fxccbh53W.
-->

View File

@ -1,6 +1,6 @@
<!-- Please read the contribution guidelines before submitting a pull request. -->
<!-- By submitting this pull request, you agree that your contributions are licensed under the {fmt} license,
and agree to future changes to the licensing. -->
<!-- If you're a first-time contributor, please acknowledge it by leaving the statement below. -->
I agree that my contributions are licensed under the {fmt} license, and agree to future changes to the licensing.
<!--
Please read the contribution guidelines before submitting a pull request:
https://github.com/fmtlib/fmt/blob/master/CONTRIBUTING.md.
By submitting this pull request, you agree that your contributions are licensed
under the {fmt} license, and agree to future changes to the licensing.
-->

27
externals/fmt/.github/workflows/doc.yml vendored Normal file
View File

@ -0,0 +1,27 @@
name: doc
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
# Use Ubuntu 20.04 because doxygen 1.8.13 from Ubuntu 18.04 is broken.
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Create Build Environment
run: |
sudo apt update
sudo apt install doxygen python3-virtualenv
sudo npm install -g less clean-css
cmake -E make_directory ${{runner.workspace}}/build
- name: Build
working-directory: ${{runner.workspace}}/build
env:
KEY: ${{secrets.KEY}}
run: $GITHUB_WORKSPACE/support/build-docs.py

View File

@ -0,0 +1,94 @@
name: linux
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
cxx: [g++-4.8, g++-10, clang++-9]
build_type: [Debug, Release]
std: [11]
os: [ubuntu-18.04]
include:
- cxx: g++-4.8
install: sudo apt install g++-4.8
os: ubuntu-18.04
- cxx: g++-8
build_type: Debug
std: 14
install: sudo apt install g++-8
os: ubuntu-18.04
- cxx: g++-8
build_type: Debug
std: 17
install: sudo apt install g++-8
os: ubuntu-18.04
- cxx: g++-10
build_type: Debug
std: 17
os: ubuntu-18.04
- cxx: g++-11
build_type: Debug
std: 20
os: ubuntu-20.04
install: sudo apt install g++-11
- cxx: clang++-8
build_type: Debug
std: 17
cxxflags: -stdlib=libc++
os: ubuntu-18.04
install: sudo apt install clang-8 libc++-8-dev libc++abi-8-dev
- cxx: clang++-9
build_type: Debug
fuzz: -DFMT_FUZZ=ON -DFMT_FUZZ_LINKMAIN=ON
std: 17
os: ubuntu-18.04
- cxx: clang++-11
build_type: Debug
std: 20
os: ubuntu-20.04
- cxx: clang++-11
build_type: Debug
std: 20
cxxflags: -stdlib=libc++
os: ubuntu-20.04
install: sudo apt install libc++-11-dev libc++abi-11-dev
- shared: -DBUILD_SHARED_LIBS=ON
steps:
- uses: actions/checkout@v2
- name: Create Build Environment
run: |
${{matrix.install}}
sudo apt update
sudo apt install locales-all
cmake -E make_directory ${{runner.workspace}}/build
- name: Configure
working-directory: ${{runner.workspace}}/build
env:
CXX: ${{matrix.cxx}}
CXXFLAGS: ${{matrix.cxxflags}}
run: |
cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ${{matrix.fuzz}} ${{matrix.shared}} \
-DCMAKE_CXX_STANDARD=${{matrix.std}} -DFMT_DOC=OFF \
-DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON \
-DFMT_PEDANTIC=ON -DFMT_WERROR=ON $GITHUB_WORKSPACE
- name: Build
working-directory: ${{runner.workspace}}/build
run: |
threads=`nproc`
cmake --build . --config ${{matrix.build_type}} --parallel $threads
- name: Test
working-directory: ${{runner.workspace}}/build
run: ctest -C ${{matrix.build_type}}
env:
CTEST_OUTPUT_ON_FAILURE: True

View File

@ -0,0 +1,40 @@
name: macos
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: macos-10.15
strategy:
matrix:
build_type: [Debug, Release]
include:
- shared: -DBUILD_SHARED_LIBS=ON
steps:
- uses: actions/checkout@v2
- name: Create Build Environment
run: cmake -E make_directory ${{runner.workspace}}/build
- name: Configure
working-directory: ${{runner.workspace}}/build
run: |
cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ${{matrix.shared}} \
-DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON \
-DFMT_DOC=OFF -DFMT_PEDANTIC=ON -DFMT_WERROR=ON $GITHUB_WORKSPACE
- name: Build
working-directory: ${{runner.workspace}}/build
run: |
threads=`sysctl -n hw.logicalcpu`
cmake --build . --config ${{matrix.build_type}} --parallel $threads
- name: Test
working-directory: ${{runner.workspace}}/build
run: ctest -C ${{matrix.build_type}}
env:
CTEST_OUTPUT_ON_FAILURE: True

View File

@ -0,0 +1,63 @@
name: windows
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ${{matrix.os}}
strategy:
matrix:
# windows-2019 has MSVC 2019 installed;
# windows-2022 has MSVC 2022 installed:
# https://github.com/actions/virtual-environments.
os: [windows-2019]
platform: [Win32, x64]
build_type: [Debug, Release]
standard: [11, 17, 20]
include:
- os: windows-2019
platform: Win32
build_type: Debug
shared: -DBUILD_SHARED_LIBS=ON
- os: windows-2022
platform: x64
build_type: Debug
standard: 20
exclude:
- os: windows-2019
standard: 11
platform: Win32
- os: windows-2019
standard: 20
platform: Win32
steps:
- uses: actions/checkout@v2
- name: Create Build Environment
run: cmake -E make_directory ${{runner.workspace}}/build
- name: Configure
# Use a bash shell for $GITHUB_WORKSPACE.
shell: bash
working-directory: ${{runner.workspace}}/build
run: |
cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ${{matrix.shared}} \
-A ${{matrix.platform}} \
-DCMAKE_CXX_STANDARD=${{matrix.standard}} \
$GITHUB_WORKSPACE
- name: Build
working-directory: ${{runner.workspace}}/build
run: |
$threads = (Get-CimInstance Win32_ComputerSystem).NumberOfLogicalProcessors
cmake --build . --config ${{matrix.build_type}} --parallel $threads
- name: Test
working-directory: ${{runner.workspace}}/build
run: ctest -C ${{matrix.build_type}} -V
env:
CTEST_OUTPUT_ON_FAILURE: True

View File

@ -9,12 +9,14 @@ gradle/
gradlew*
local.properties
build/
support/.cxx
bin/
/_CPack_Packages
/CMakeScripts
/doc/doxyxml
/doc/html
/doc/node_modules
virtualenv
/Testing
/install_manifest.txt

View File

@ -1,101 +0,0 @@
language: cpp
dist: trusty
sudo: false
os: linux
git:
depth: 1
env:
global:
- secure: |-
a1eovNn4uol9won7ghr67eD3/59oeESN+G9bWE+ecI1V6yRseG9whniGhIpC/YfMW/Qz5I
5sxSmFjaw9bxCISNwUIrL1O5x2AmRYTnFcXk4dFsUvlZg+WeF/aKyBYCNRM8C2ndbBmtAO
o1F2EwFbiso0EmtzhAPs19ujiVxkLn4=
matrix:
include:
# Documentation
- env: BUILD=Doc
sudo: required
# g++ 6 on Linux with C++14
- env: COMPILER=g++-6 BUILD=Debug STANDARD=14
compiler: gcc
addons:
apt:
update: true
sources:
- ubuntu-toolchain-r-test
packages:
- g++-6
- env: COMPILER=g++-6 BUILD=Release STANDARD=14
compiler: gcc
addons:
apt:
update: true
sources:
- ubuntu-toolchain-r-test
packages:
- g++-6
# g++ 8 on Linux with C++17
- env: COMPILER=g++-8 BUILD=Debug STANDARD=17
compiler: gcc
addons:
apt:
update: true
sources:
- ubuntu-toolchain-r-test
packages:
- g++-8
- env: COMPILER=g++-8 BUILD=Release STANDARD=17
compiler: gcc
addons:
apt:
update: true
sources:
- ubuntu-toolchain-r-test
packages:
- g++-8
# Apple clang on OS X with C++14
- env: BUILD=Debug STANDARD=14
compiler: clang
os: osx
- env: BUILD=Release STANDARD=14
compiler: clang
os: osx
# clang 6.0 on Linux with C++14 (builds the fuzzers as well)
- env: COMPILER=clang++-6.0 BUILD=Debug STANDARD=14 ENABLE_FUZZING=1
compiler: clang
addons:
apt:
update: true
packages:
- clang-6.0
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty
- llvm-toolchain-trusty-6.0
# clang 4.0 on Linux with C++14
- env: COMPILER=clang++-4.0 BUILD=Debug STANDARD=11
compiler: clang
addons:
apt:
update: true
packages:
- clang-4.0
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty
- llvm-toolchain-trusty-4.0
# g++ 4.8 on Linux with C++11
- env: COMPILER=g++-4.8 BUILD=Debug STANDARD=11
compiler: gcc
before_script:
- if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then export CXX=${COMPILER}; fi
- if [[ "${BUILD}" != "Doc" ]]; then ${CXX} --version; fi
script:
- support/travis-build.py

View File

@ -1,61 +1,106 @@
cmake_minimum_required(VERSION 3.1.0)
cmake_minimum_required(VERSION 3.1...3.18)
# Use newer policies if available, up to most recent tested version of CMake.
if(${CMAKE_VERSION} VERSION_LESS 3.11)
# Fallback for using newer policies on CMake <3.12.
if(${CMAKE_VERSION} VERSION_LESS 3.12)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.11)
endif()
# Determine if fmt is built as a subproject (using add_subdirectory)
# or if it is the master project.
set(MASTER_PROJECT OFF)
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(MASTER_PROJECT ON)
message(STATUS "CMake version: ${CMAKE_VERSION}")
if (NOT DEFINED FMT_MASTER_PROJECT)
set(FMT_MASTER_PROJECT OFF)
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(FMT_MASTER_PROJECT ON)
message(STATUS "CMake version: ${CMAKE_VERSION}")
endif ()
endif ()
# Joins arguments and places the results in ${result_var}.
function(join result_var)
set(result )
set(result "")
foreach (arg ${ARGN})
set(result "${result}${arg}")
endforeach ()
set(${result_var} "${result}" PARENT_SCOPE)
endfunction()
function(enable_module target)
if (MSVC)
set(BMI ${CMAKE_CURRENT_BINARY_DIR}/${target}.ifc)
target_compile_options(${target}
PRIVATE /interface /ifcOutput ${BMI}
INTERFACE /reference fmt=${BMI})
endif ()
set_target_properties(${target} PROPERTIES ADDITIONAL_CLEAN_FILES ${BMI})
set_source_files_properties(${BMI} PROPERTIES GENERATED ON)
endfunction()
include(CMakeParseArguments)
# Sets a cache variable with a docstring joined from multiple arguments:
# set(<variable> <value>... CACHE <type> <docstring>...)
# This allows splitting a long docstring for readability.
function(set_verbose)
cmake_parse_arguments(SET_VERBOSE "" "" "CACHE" ${ARGN})
list(GET SET_VERBOSE_CACHE 0 type)
list(REMOVE_AT SET_VERBOSE_CACHE 0)
join(doc ${SET_VERBOSE_CACHE})
set(${SET_VERBOSE_UNPARSED_ARGUMENTS} CACHE ${type} ${doc})
# cmake_parse_arguments is broken in CMake 3.4 (cannot parse CACHE) so use
# list instead.
list(GET ARGN 0 var)
list(REMOVE_AT ARGN 0)
list(GET ARGN 0 val)
list(REMOVE_AT ARGN 0)
list(REMOVE_AT ARGN 0)
list(GET ARGN 0 type)
list(REMOVE_AT ARGN 0)
join(doc ${ARGN})
set(${var} ${val} CACHE ${type} ${doc})
endfunction()
# Set the default CMAKE_BUILD_TYPE to Release.
# This should be done before the project command since the latter can set
# CMAKE_BUILD_TYPE itself (it does so for nmake).
if (MASTER_PROJECT AND NOT CMAKE_BUILD_TYPE)
if (FMT_MASTER_PROJECT AND NOT CMAKE_BUILD_TYPE)
set_verbose(CMAKE_BUILD_TYPE Release CACHE STRING
"Choose the type of build, options are: None(CMAKE_CXX_FLAGS or "
"CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
endif ()
project(FMT CXX)
include(GNUInstallDirs)
set_verbose(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE STRING
"Installation directory for include files, a relative path that "
"will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute path.")
option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF)
option(FMT_WERROR "Halt the compilation with an error on compiler warnings."
OFF)
# Options that control generation of various targets.
option(FMT_DOC "Generate the doc target." ${MASTER_PROJECT})
option(FMT_INSTALL "Generate the install target." ${MASTER_PROJECT})
option(FMT_TEST "Generate the test target." ${MASTER_PROJECT})
option(FMT_DOC "Generate the doc target." ${FMT_MASTER_PROJECT})
option(FMT_INSTALL "Generate the install target." ${FMT_MASTER_PROJECT})
option(FMT_TEST "Generate the test target." ${FMT_MASTER_PROJECT})
option(FMT_FUZZ "Generate the fuzz target." OFF)
option(FMT_CUDA_TEST "Generate the cuda-test target." OFF)
option(FMT_OS "Include core requiring OS (Windows/Posix) " ON)
option(FMT_MODULE "Build a module instead of a traditional library." OFF)
option(FMT_SYSTEM_HEADERS "Expose headers with marking them as system." OFF)
project(FMT CXX)
set(FMT_CAN_MODULE OFF)
if (CMAKE_CXX_STANDARD GREATER 17 AND
# msvc 16.10-pre4
MSVC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.29.30035)
set(FMT_CAN_MODULE OFF)
endif ()
if (NOT FMT_CAN_MODULE)
set(FMT_MODULE OFF)
message(STATUS "Module support is disabled.")
endif ()
if (FMT_TEST AND FMT_MODULE)
# The tests require {fmt} to be compiled as traditional library
message(STATUS "Testing is incompatible with build mode 'module'.")
endif ()
set(FMT_SYSTEM_HEADERS_ATTRIBUTE "")
if (FMT_SYSTEM_HEADERS)
set(FMT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
endif ()
# Get version from core.h
file(READ include/fmt/core.h core_h)
@ -80,7 +125,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_SOURCE_DIR}/support/cmake")
include(cxx14)
include(CheckCXXCompilerFlag)
include(JoinPaths)
list(FIND CMAKE_CXX_COMPILE_FEATURES "cxx_variadic_templates" index)
if (${index} GREATER -1)
@ -90,24 +135,36 @@ if (${index} GREATER -1)
endif ()
message(STATUS "Required features: ${FMT_REQUIRED_FEATURES}")
if (FMT_MASTER_PROJECT AND NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET)
set_verbose(CMAKE_CXX_VISIBILITY_PRESET hidden CACHE STRING
"Preset for the export of private symbols")
set_property(CACHE CMAKE_CXX_VISIBILITY_PRESET PROPERTY STRINGS
hidden default)
endif ()
if (FMT_MASTER_PROJECT AND NOT DEFINED CMAKE_VISIBILITY_INLINES_HIDDEN)
set_verbose(CMAKE_VISIBILITY_INLINES_HIDDEN ON CACHE BOOL
"Whether to add a compile flag to hide symbols of inline functions")
endif ()
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(PEDANTIC_COMPILE_FLAGS -pedantic-errors -Wall -Wextra -pedantic
-Wold-style-cast -Wundef
-Wredundant-decls -Wwrite-strings -Wpointer-arith
-Wcast-qual -Wformat=2 -Wmissing-include-dirs
-Wcast-align -Wnon-virtual-dtor
-Wcast-align
-Wctor-dtor-privacy -Wdisabled-optimization
-Winvalid-pch -Woverloaded-virtual
-Wconversion -Wswitch-enum
-Wno-ctor-dtor-privacy -Wno-format-nonliteral -Wno-shadow)
-Wconversion -Wundef
-Wno-ctor-dtor-privacy -Wno-format-nonliteral)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnoexcept
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
-Wno-dangling-else -Wno-unused-local-typedefs)
endif ()
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wdouble-promotion
-Wtrampolines -Wzero-as-null-pointer-constant -Wuseless-cast
-Wvector-operation-performance -Wsized-deallocation)
-Wvector-operation-performance -Wsized-deallocation -Wshadow)
endif ()
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wshift-overflow=2
@ -117,8 +174,9 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
endif ()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -pedantic -Wconversion
-Wno-sign-conversion -Wdeprecated -Wweak-vtables)
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -pedantic -Wconversion -Wundef
-Wdeprecated -Wweak-vtables -Wshadow
-Wno-gnu-zero-variadic-macro-arguments)
check_cxx_compiler_flag(-Wzero-as-null-pointer-constant HAS_NULLPTR_WARNING)
if (HAS_NULLPTR_WARNING)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
@ -132,7 +190,7 @@ if (MSVC)
set(WERROR_FLAG /WX)
endif ()
if (MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
if (FMT_MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
# If Microsoft SDK is installed create script run-msbuild.bat that
# calls SetEnv.cmd to set up build environment and runs msbuild.
# It is useful when building Visual Studio projects with the SDK
@ -150,18 +208,6 @@ if (MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
endif ()
set(strtod_l_headers stdlib.h)
if (APPLE)
set(strtod_l_headers ${strtod_l_headers} xlocale.h)
endif ()
include(CheckSymbolExists)
if (WIN32)
check_symbol_exists(_strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
else ()
check_symbol_exists(strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
endif ()
function(add_headers VAR)
set(headers ${${VAR}})
foreach (header ${ARGN})
@ -171,34 +217,41 @@ function(add_headers VAR)
endfunction()
# Define the fmt library, its includes and the needed defines.
add_headers(FMT_HEADERS chrono.h color.h compile.h core.h format.h format-inl.h
locale.h os.h ostream.h posix.h printf.h ranges.h)
set(FMT_SOURCES src/format.cc src/os.cc)
add_headers(FMT_HEADERS args.h chrono.h color.h compile.h core.h format.h
format-inl.h os.h ostream.h printf.h ranges.h std.h
xchar.h)
if (FMT_MODULE)
set(FMT_SOURCES src/fmt.cc)
elseif (FMT_OS)
set(FMT_SOURCES src/format.cc src/os.cc)
else()
set(FMT_SOURCES src/format.cc)
endif ()
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
add_library(fmt::fmt ALIAS fmt)
if (HAVE_STRTOD_L)
target_compile_definitions(fmt PUBLIC FMT_LOCALE)
endif ()
if (FMT_WERROR)
target_compile_options(fmt PRIVATE ${WERROR_FLAG})
endif ()
if (FMT_PEDANTIC)
target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
if (FMT_MODULE)
enable_module(fmt)
endif ()
target_compile_features(fmt INTERFACE ${FMT_REQUIRED_FEATURES})
target_include_directories(fmt PUBLIC
target_include_directories(fmt ${FMT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
set(FMT_DEBUG_POSTFIX d CACHE STRING "Debug library postfix.")
set_target_properties(fmt PROPERTIES
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
PUBLIC_HEADER "${FMT_HEADERS}"
DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}")
# Set FMT_LIB_NAME for pkg-config fmt.pc. We cannot use the OUTPUT_NAME target
@ -209,7 +262,8 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
endif ()
if (BUILD_SHARED_LIBS)
if (UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
if (UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "SunOS" AND
NOT EMSCRIPTEN)
# Fix rpmlint warning:
# unused-direct-shlib-dependency /usr/lib/libformat.so.1.1.0 /lib/libm.so.6.
target_link_libraries(fmt -Wl,--as-needed)
@ -226,44 +280,40 @@ add_library(fmt::fmt-header-only ALIAS fmt-header-only)
target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
target_compile_features(fmt-header-only INTERFACE ${FMT_REQUIRED_FEATURES})
target_include_directories(fmt-header-only INTERFACE
target_include_directories(fmt-header-only ${FMT_SYSTEM_HEADERS_ATTRIBUTE} INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
# Install targets.
if (FMT_INSTALL)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
set_verbose(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING
"Installation directory for cmake files, relative to "
"${CMAKE_INSTALL_PREFIX}.")
"Installation directory for cmake files, a relative path that "
"will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute "
"path.")
set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake)
set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake)
set(pkgconfig ${PROJECT_BINARY_DIR}/fmt.pc)
set(targets_export_name fmt-targets)
set (INSTALL_TARGETS fmt)
if (TARGET fmt-header-only)
set(INSTALL_TARGETS ${INSTALL_TARGETS} fmt-header-only)
endif ()
set_verbose(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING
"Installation directory for libraries, relative to "
"${CMAKE_INSTALL_PREFIX}.")
set_verbose(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR}/fmt CACHE STRING
"Installation directory for include files, relative to "
"${CMAKE_INSTALL_PREFIX}.")
"Installation directory for libraries, a relative path that "
"will be joined to ${CMAKE_INSTALL_PREFIX} or an absolute path.")
set_verbose(FMT_PKGCONFIG_DIR ${CMAKE_INSTALL_LIBDIR}/pkgconfig CACHE PATH
"Installation directory for pkgconfig (.pc) files, relative to "
"${CMAKE_INSTALL_PREFIX}.")
"Installation directory for pkgconfig (.pc) files, a relative "
"path that will be joined with ${CMAKE_INSTALL_PREFIX} or an "
"absolute path.")
# Generate the version, config and target files into the build directory.
write_basic_package_version_file(
${version_config}
VERSION ${FMT_VERSION}
COMPATIBILITY AnyNewerVersion)
join_paths(libdir_for_pc_file "\${exec_prefix}" "${FMT_LIB_DIR}")
join_paths(includedir_for_pc_file "\${prefix}" "${FMT_INC_DIR}")
configure_file(
"${PROJECT_SOURCE_DIR}/support/cmake/fmt.pc.in"
"${pkgconfig}"
@ -272,6 +322,17 @@ if (FMT_INSTALL)
${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in
${project_config}
INSTALL_DESTINATION ${FMT_CMAKE_DIR})
set(INSTALL_TARGETS fmt fmt-header-only)
# Install the library and headers.
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
LIBRARY DESTINATION ${FMT_LIB_DIR}
ARCHIVE DESTINATION ${FMT_LIB_DIR}
PUBLIC_HEADER DESTINATION "${FMT_INC_DIR}/fmt"
FRAMEWORK DESTINATION "."
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
# Use a namespace because CMake provides better diagnostics for namespaced
# imported targets.
export(TARGETS ${INSTALL_TARGETS} NAMESPACE fmt::
@ -284,15 +345,8 @@ if (FMT_INSTALL)
install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR}
NAMESPACE fmt::)
# Install the library and headers.
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
LIBRARY DESTINATION ${FMT_LIB_DIR}
ARCHIVE DESTINATION ${FMT_LIB_DIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install(FILES $<TARGET_PDB_FILE:${INSTALL_TARGETS}>
DESTINATION ${FMT_LIB_DIR} OPTIONAL)
install(FILES ${FMT_HEADERS} DESTINATION ${FMT_INC_DIR})
install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}")
endif ()
@ -308,10 +362,17 @@ endif ()
# Control fuzzing independent of the unit tests.
if (FMT_FUZZ)
add_subdirectory(test/fuzzing)
# The FMT_FUZZ macro is used to prevent resource exhaustion in fuzzing
# mode and make fuzzing practically possible. It is similar to
# FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION but uses a different name to
# avoid interfering with fuzzing of projects that use {fmt}.
# See also https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode.
target_compile_definitions(fmt PUBLIC FMT_FUZZ)
endif ()
set(gitignore ${PROJECT_SOURCE_DIR}/.gitignore)
if (MASTER_PROJECT AND EXISTS ${gitignore})
if (FMT_MASTER_PROJECT AND EXISTS ${gitignore})
# Get the list of ignored files from .gitignore.
file (STRINGS ${gitignore} lines)
list(REMOVE_ITEM lines /doc/html)

View File

@ -14,4 +14,7 @@ exceptions:
* snake_case should be used instead of UpperCamelCase for function and type
names
All documentation must adhere to the [Google Developer Documentation Style
Guide](https://developers.google.com/style).
Thanks for contributing!

File diff suppressed because it is too large Load Diff

View File

@ -1,159 +1,189 @@
{fmt}
=====
.. image:: https://user-images.githubusercontent.com/
576385/156254208-f5b743a9-88cf-439d-b0c0-923d53e8d551.png
:width: 25%
:alt: {fmt}
.. image:: https://travis-ci.org/fmtlib/fmt.png?branch=master
:target: https://travis-ci.org/fmtlib/fmt
.. image:: https://github.com/fmtlib/fmt/workflows/linux/badge.svg
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux
.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v
.. image:: https://github.com/fmtlib/fmt/workflows/macos/badge.svg
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Amacos
.. image:: https://github.com/fmtlib/fmt/workflows/windows/badge.svg
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows
.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v?svg=true
:target: https://ci.appveyor.com/project/vitaut/fmt
.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/libfmt.svg
:alt: fmt is continuously fuzzed att oss-fuzz
:target: https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dlibfmt&can=1
.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg
:alt: fmt is continuously fuzzed at oss-fuzz
:target: https://bugs.chromium.org/p/oss-fuzz/issues/list?\
colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20\
Summary&q=proj%3Dfmt&can=1
.. image:: https://img.shields.io/badge/stackoverflow-fmt-blue.svg
:alt: Ask questions at StackOverflow with the tag fmt
:target: https://stackoverflow.com/questions/tagged/fmt
**{fmt}** is an open-source formatting library for C++.
It can be used as a safe and fast alternative to (s)printf and iostreams.
**{fmt}** is an open-source formatting library providing a fast and safe
alternative to C stdio and C++ iostreams.
`Documentation <https://fmt.dev/latest/>`__
If you like this project, please consider donating to one of the funds that
help victims of the war in Ukraine: https://www.stopputin.net/.
Q&A: ask questions on `StackOverflow with the tag fmt <https://stackoverflow.com/questions/tagged/fmt>`_.
`Documentation <https://fmt.dev>`__
`Cheat Sheets <https://hackingcpp.com/cpp/libs/fmt.html>`__
Q&A: ask questions on `StackOverflow with the tag fmt
<https://stackoverflow.com/questions/tagged/fmt>`_.
Try {fmt} in `Compiler Explorer <https://godbolt.org/z/Eq5763>`_.
Features
--------
* Replacement-based `format API <https://fmt.dev/dev/api.html>`_ with
positional arguments for localization.
* `Format string syntax <https://fmt.dev/dev/syntax.html>`_ similar to the one
of `str.format <https://docs.python.org/3/library/stdtypes.html#str.format>`_
in Python.
* Simple `format API <https://fmt.dev/latest/api.html>`_ with positional arguments
for localization
* Implementation of `C++20 std::format
<https://en.cppreference.com/w/cpp/utility/format>`__
* `Format string syntax <https://fmt.dev/latest/syntax.html>`_ similar to Python's
`format <https://docs.python.org/3/library/stdtypes.html#str.format>`_
* Fast IEEE 754 floating-point formatter with correct rounding, shortness and
round-trip guarantees
* Safe `printf implementation
<https://fmt.dev/latest/api.html#printf-formatting>`_ including
the POSIX extension for positional arguments.
* Implementation of `C++20 std::format <https://en.cppreference.com/w/cpp/utility/format>`__.
* Support for user-defined types.
<https://fmt.dev/latest/api.html#printf-formatting>`_ including the POSIX
extension for positional arguments
* Extensibility: `support for user-defined types
<https://fmt.dev/latest/api.html#formatting-user-defined-types>`_
* High performance: faster than common standard library implementations of
`printf <https://en.cppreference.com/w/cpp/io/c/fprintf>`_ and
iostreams. See `Speed tests`_ and `Fast integer to string conversion in C++
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
* Small code size both in terms of source code (the minimum configuration
consists of just three header files, ``core.h``, ``format.h`` and
``format-inl.h``) and compiled code. See `Compile time and code bloat`_.
* Reliability: the library has an extensive set of `unit tests
<https://github.com/fmtlib/fmt/tree/master/test>`_ and is continuously fuzzed.
``(s)printf``, iostreams, ``to_string`` and ``to_chars``, see `Speed tests`_
and `Converting a hundred million integers to strings per second
<http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html>`_
* Small code size both in terms of source code with the minimum configuration
consisting of just three files, ``core.h``, ``format.h`` and ``format-inl.h``,
and compiled code; see `Compile time and code bloat`_
* Reliability: the library has an extensive set of `tests
<https://github.com/fmtlib/fmt/tree/master/test>`_ and is `continuously fuzzed
<https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20
Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dfmt&can=1>`_
* Safety: the library is fully type safe, errors in format strings can be
reported at compile time, automatic memory management prevents buffer overflow
errors.
errors
* Ease of use: small self-contained code base, no external dependencies,
permissive MIT `license
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_
* `Portability <https://fmt.dev/latest/index.html#portability>`_ with
consistent output across platforms and support for older compilers.
* Clean warning-free codebase even on high warning levels
(``-Wall -Wextra -pedantic``).
* Support for wide strings.
* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro.
consistent output across platforms and support for older compilers
* Clean warning-free codebase even on high warning levels such as
``-Wall -Wextra -pedantic``
* Locale-independence by default
* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro
See the `documentation <https://fmt.dev/latest/>`_ for more details.
See the `documentation <https://fmt.dev>`_ for more details.
Examples
--------
Print ``Hello, world!`` to ``stdout``:
**Print to stdout** (`run <https://godbolt.org/z/Tevcjh>`_)
.. code:: c++
fmt::print("Hello, {}!", "world"); // Python-like format string syntax
fmt::printf("Hello, %s!", "world"); // printf format string syntax
#include <fmt/core.h>
int main() {
fmt::print("Hello, world!\n");
}
Format a string and use positional arguments:
**Format a string** (`run <https://godbolt.org/z/oK8h33>`_)
.. code:: c++
std::string s = fmt::format("The answer is {}.", 42);
// s == "The answer is 42."
**Format a string using positional arguments** (`run <https://godbolt.org/z/Yn7Txe>`_)
.. code:: c++
std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");
// s == "I'd rather be happy than right."
Check a format string at compile time:
**Print chrono durations** (`run <https://godbolt.org/z/K8s4Mc>`_)
.. code:: c++
// test.cc
#include <fmt/format.h>
std::string s = format(FMT_STRING("{2}"), 42);
#include <fmt/chrono.h>
.. code::
$ c++ -Iinclude -std=c++14 test.cc
...
test.cc:4:17: note: in instantiation of function template specialization 'fmt::v5::format<S, int>' requested here
std::string s = format(FMT_STRING("{2}"), 42);
^
include/fmt/core.h:778:19: note: non-constexpr function 'on_error' cannot be used in a constant expression
ErrorHandler::on_error(message);
^
include/fmt/format.h:2226:16: note: in call to '&checker.context_->on_error(&"argument index out of range"[0])'
context_.on_error("argument index out of range");
^
Use {fmt} as a safe portable replacement for ``itoa``
(`godbolt <https://godbolt.org/g/NXmpU4>`_):
.. code:: c++
fmt::memory_buffer buf;
format_to(buf, "{}", 42); // replaces itoa(42, buffer, 10)
format_to(buf, "{:x}", 42); // replaces itoa(42, buffer, 16)
// access the string with to_string(buf) or buf.data()
Format objects of user-defined types via a simple `extension API
<https://fmt.dev/latest/api.html#formatting-user-defined-types>`_:
.. code:: c++
#include "fmt/format.h"
struct date {
int year, month, day;
};
template <>
struct fmt::formatter<date> {
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const date& d, FormatContext& ctx) {
return format_to(ctx.out(), "{}-{}-{}", d.year, d.month, d.day);
}
};
std::string s = fmt::format("The date is {}", date{2012, 12, 9});
// s == "The date is 2012-12-9"
Create your own functions similar to `format
<https://fmt.dev/latest/api.html#format>`_ and
`print <https://fmt.dev/latest/api.html#print>`_
which take arbitrary arguments (`godbolt <https://godbolt.org/g/MHjHVf>`_):
.. code:: c++
// Prints formatted error message.
void vreport_error(const char* format, fmt::format_args args) {
fmt::print("Error: ");
fmt::vprint(format, args);
}
template <typename... Args>
void report_error(const char* format, const Args & ... args) {
vreport_error(format, fmt::make_format_args(args...));
int main() {
using namespace std::literals::chrono_literals;
fmt::print("Default format: {} {}\n", 42s, 100ms);
fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s);
}
report_error("file not found: {}", path);
Output::
Note that ``vreport_error`` is not parameterized on argument types which can
improve compile times and reduce code size compared to a fully parameterized
version.
Default format: 42s 100ms
strftime-like format: 03:15:30
**Print a container** (`run <https://godbolt.org/z/MxM1YqjE7>`_)
.. code:: c++
#include <vector>
#include <fmt/ranges.h>
int main() {
std::vector<int> v = {1, 2, 3};
fmt::print("{}\n", v);
}
Output::
[1, 2, 3]
**Check a format string at compile time**
.. code:: c++
std::string s = fmt::format("{:d}", "I am not a number");
This gives a compile-time error in C++20 because ``d`` is an invalid format
specifier for a string.
**Write a file from a single thread**
.. code:: c++
#include <fmt/os.h>
int main() {
auto out = fmt::output_file("guide.txt");
out.print("Don't {}", "Panic");
}
This can be `5 to 9 times faster than fprintf
<http://www.zverovich.net/2020/08/04/optimal-file-buffer-size.html>`_.
**Print with colors and text styles**
.. code:: c++
#include <fmt/color.h>
int main() {
fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold,
"Hello, {}!\n", "world");
fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) |
fmt::emphasis::underline, "Hello, {}!\n", "мир");
fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic,
"Hello, {}!\n", "世界");
}
Output on a modern terminal:
.. image:: https://user-images.githubusercontent.com/
576385/88485597-d312f600-cf2b-11ea-9cbe-61f535a86e28.png
Benchmarks
----------
@ -174,18 +204,20 @@ Folly Format folly::format 2.23
{fmt} is the fastest of the benchmarked methods, ~35% faster than ``printf``.
The above results were generated by building ``tinyformat_test.cpp`` on macOS
10.14.6 with ``clang++ -O3 -DSPEED_TEST -DHAVE_FORMAT``, and taking the best of
three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"``
10.14.6 with ``clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT``, and taking the
best of three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"``
or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for
further details refer to the `source
<https://github.com/fmtlib/format-benchmark/blob/master/tinyformat_test.cpp>`_.
<https://github.com/fmtlib/format-benchmark/blob/master/src/tinyformat-test.cc>`_.
{fmt} is 10x faster than ``std::ostringstream`` and ``sprintf`` on floating-point
formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
and as fast as `double-conversion <https://github.com/google/double-conversion>`_:
{fmt} is up to 20-30x faster than ``std::ostringstream`` and ``sprintf`` on
floating-point formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
and faster than `double-conversion <https://github.com/google/double-conversion>`_ and
`ryu <https://github.com/ulfjack/ryu>`_:
.. image:: https://user-images.githubusercontent.com/576385/69767160-cdaca400-112f-11ea-9fc5-347c9f83caad.png
:target: https://fmt.dev/unknown_mac64_clang10.0.html
.. image:: https://user-images.githubusercontent.com/576385/
95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png
:target: https://fmt.dev/unknown_mac64_clang12.0.html
Compile time and code bloat
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -260,40 +292,46 @@ Then you can run the speed test::
or the bloat test::
$ make bloat-test
Migrating code
--------------
`clang-tidy-fmt <https://github.com/mikecrowe/clang-tidy-fmt>`_ provides clang
tidy checks for converting occurrences of ``printf`` and ``fprintf`` to
``fmt::print``.
Projects using this library
---------------------------
* `0 A.D. <https://play0ad.com/>`_: A free, open-source, cross-platform real-time
strategy game
* `0 A.D. <https://play0ad.com/>`_: a free, open-source, cross-platform
real-time strategy game
* `2GIS <https://2gis.ru/>`_: free business listings with a city map
* `AMPL/MP <https://github.com/ampl/mp>`_:
An open-source library for mathematical programming
* `AvioBook <https://www.aviobook.aero/en>`_: A comprehensive aircraft
an open-source library for mathematical programming
* `Aseprite <https://github.com/aseprite/aseprite>`_:
animated sprite editor & pixel art tool
* `AvioBook <https://www.aviobook.aero/en>`_: a comprehensive aircraft
operations suite
* `Celestia <https://celestia.space/>`_: Real-time 3D visualization of space
* `Blizzard Battle.net <https://battle.net/>`_: an online gaming platform
* `Celestia <https://celestia.space/>`_: real-time 3D visualization of space
* `Ceph <https://ceph.com/>`_: A scalable distributed storage system
* `Ceph <https://ceph.com/>`_: a scalable distributed storage system
* `ccache <https://ccache.dev/>`_: A compiler cache
* `ccache <https://ccache.dev/>`_: a compiler cache
* `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater
* `ClickHouse <https://github.com/ClickHouse/ClickHouse>`_: analytical database
management system
* `CUAUV <https://cuauv.org/>`_: Cornell University's autonomous underwater
vehicle
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
Player vs Player Gaming Network with tweaks
* `KBEngine <https://kbengine.org/>`_: An open-source MMOG server engine
* `Keypirinha <https://keypirinha.com/>`_: A semantic launcher for Windows
* `Kodi <https://kodi.tv/>`_ (formerly xbmc): Home theater software
* `Lifeline <https://github.com/peter-clark/lifeline>`_: A 2D game
* `Drake <https://drake.mit.edu/>`_: A planning, control, and analysis toolbox
* `Drake <https://drake.mit.edu/>`_: a planning, control, and analysis toolbox
for nonlinear dynamical systems (MIT)
* `Envoy <https://lyft.github.io/envoy/>`_: C++ L7 proxy and communication bus
@ -301,49 +339,86 @@ Projects using this library
* `FiveM <https://fivem.net/>`_: a modification framework for GTA V
* `MongoDB <https://mongodb.com/>`_: Distributed document database
* `fmtlog <https://github.com/MengRao/fmtlog>`_: a performant fmtlib-style
logging library with latency in nanoseconds
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to
* `Folly <https://github.com/facebook/folly>`_: Facebook open-source library
* `GemRB <https://gemrb.org/>`_: a portable open-source implementation of
Biowares Infinity Engine
* `Grand Mountain Adventure
<https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/>`_:
a beautiful open-world ski & snowboarding game
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
Player vs Player Gaming Network with tweaks
* `KBEngine <https://github.com/kbengine/kbengine>`_: an open-source MMOG server
engine
* `Keypirinha <https://keypirinha.com/>`_: a semantic launcher for Windows
* `Kodi <https://kodi.tv/>`_ (formerly xbmc): home theater software
* `Knuth <https://kth.cash/>`_: high-performance Bitcoin full-node
* `Microsoft Verona <https://github.com/microsoft/verona>`_:
research programming language for concurrent ownership
* `MongoDB <https://mongodb.com/>`_: distributed document database
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: a small tool to
generate randomized datasets
* `OpenSpace <https://openspaceproject.com/>`_: An open-source astrovisualization
framework
* `OpenSpace <https://openspaceproject.com/>`_: an open-source
astrovisualization framework
* `PenUltima Online (POL) <https://www.polserver.com/>`_:
An MMO server, compatible with most Ultima Online clients
an MMO server, compatible with most Ultima Online clients
* `quasardb <https://www.quasardb.net/>`_: A distributed, high-performance,
* `PyTorch <https://github.com/pytorch/pytorch>`_: an open-source machine
learning library
* `quasardb <https://www.quasardb.net/>`_: a distributed, high-performance,
associative database
* `Quill <https://github.com/odygrd/quill>`_: asynchronous low-latency logging library
* `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable
* `QKW <https://github.com/ravijanjam/qkw>`_: generalizing aliasing to simplify
navigation, and executing complex multi-line terminal command sequences
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: a Redis cluster
proxy
* `rpclib <http://rpclib.net/>`_: A modern C++ msgpack-RPC server and client
* `redpanda <https://vectorized.io/redpanda>`_: a 10x faster Kafka® replacement
for mission critical systems written in C++
* `rpclib <http://rpclib.net/>`_: a modern C++ msgpack-RPC server and client
library
* `Saddy <https://github.com/mamontov-cpp/saddy-graphics-engine-2d>`_:
Small crossplatform 2D graphic engine
* `Salesforce Analytics Cloud
<https://www.salesforce.com/analytics-cloud/overview/>`_:
business intelligence software
* `Salesforce Analytics Cloud <https://www.salesforce.com/analytics-cloud/overview/>`_:
Business intelligence software
* `Scylla <https://www.scylladb.com/>`_: A Cassandra-compatible NoSQL data store
* `Scylla <https://www.scylladb.com/>`_: a Cassandra-compatible NoSQL data store
that can handle 1 million transactions per second on a single server
* `Seastar <http://www.seastar-project.org/>`_: An advanced, open-source C++
* `Seastar <http://www.seastar-project.org/>`_: an advanced, open-source C++
framework for high-performance server applications on modern hardware
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library
* `spdlog <https://github.com/gabime/spdlog>`_: super fast C++ logging library
* `Stellar <https://www.stellar.org/>`_: Financial platform
* `Stellar <https://www.stellar.org/>`_: financial platform
* `Touch Surgery <https://www.touchsurgery.com/>`_: Surgery simulator
* `Touch Surgery <https://www.touchsurgery.com/>`_: surgery simulator
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: Open-source
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: open-source
MMORPG framework
* `Windows Terminal <https://github.com/microsoft/terminal>`_: the new Windows
terminal
`More... <https://github.com/search?q=fmtlib&type=Code>`_
If you are aware of other projects using this library, please let me know
@ -400,15 +475,15 @@ Boost Format
This is a very powerful library which supports both ``printf``-like format
strings and positional arguments. Its main drawback is performance. According to
various benchmarks it is much slower than other methods considered here. Boost
various benchmarks, it is much slower than other methods considered here. Boost
Format also has excessive build times and severe code bloat issues (see
`Benchmarks`_).
FastFormat
~~~~~~~~~~
This is an interesting library which is fast, safe and has positional
arguments. However it has significant limitations, citing its author:
This is an interesting library which is fast, safe and has positional arguments.
However, it has significant limitations, citing its author:
Three features that have no hope of being accommodated within the
current design are:
@ -417,8 +492,8 @@ arguments. However it has significant limitations, citing its author:
* Octal/hexadecimal encoding
* Runtime width/alignment specification
It is also quite big and has a heavy dependency, STLSoft, which might be
too restrictive for using it in some projects.
It is also quite big and has a heavy dependency, STLSoft, which might be too
restrictive for using it in some projects.
Boost Spirit.Karma
~~~~~~~~~~~~~~~~~~
@ -426,32 +501,9 @@ Boost Spirit.Karma
This is not really a formatting library but I decided to include it here for
completeness. As iostreams, it suffers from the problem of mixing verbatim text
with arguments. The library is pretty fast, but slower on integer formatting
than ``fmt::format_int`` on Karma's own benchmark,
see `Fast integer to string conversion in C++
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
FAQ
---
Q: how can I capture formatting arguments and format them later?
A: use ``std::tuple``:
.. code:: c++
template <typename... Args>
auto capture(const Args&... args) {
return std::make_tuple(args...);
}
auto print_message = [](const auto&... args) {
fmt::print(args...);
};
// Capture and store arguments:
auto args = capture("{} {}", 42, "foo");
// Do formatting:
std::apply(print_message, args);
than ``fmt::format_to`` with format string compilation on Karma's own benchmark,
see `Converting a hundred million integers to strings per second
<http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html>`_.
License
-------
@ -459,18 +511,19 @@ License
{fmt} is distributed under the MIT `license
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_.
The `Format String Syntax
<https://fmt.dev/latest/syntax.html>`_
section in the documentation is based on the one from Python `string module
documentation <https://docs.python.org/3/library/string.html#module-string>`_
adapted for the current library. For this reason the documentation is
distributed under the Python Software Foundation license available in
`doc/python-license.txt
<https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt>`_.
It only applies if you distribute the documentation of fmt.
Documentation License
---------------------
Acknowledgments
---------------
The `Format String Syntax <https://fmt.dev/latest/syntax.html>`_
section in the documentation is based on the one from Python `string module
documentation <https://docs.python.org/3/library/string.html#module-string>`_.
For this reason the documentation is distributed under the Python Software
Foundation license available in `doc/python-license.txt
<https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt>`_.
It only applies if you distribute the documentation of {fmt}.
Maintainers
-----------
The {fmt} library is maintained by Victor Zverovich (`vitaut
<https://github.com/vitaut>`_) and Jonathan Müller (`foonathan
@ -479,23 +532,3 @@ See `Contributors <https://github.com/fmtlib/fmt/graphs/contributors>`_ and
`Releases <https://github.com/fmtlib/fmt/releases>`_ for some of the names.
Let us know if your contribution is not listed or mentioned incorrectly and
we'll make it right.
The benchmark section of this readme file and the performance tests are taken
from the excellent `tinyformat <https://github.com/c42f/tinyformat>`_ library
written by Chris Foster. Boost Format library is acknowledged transitively
since it had some influence on tinyformat.
Some ideas used in the implementation are borrowed from `Loki
<http://loki-lib.sourceforge.net/>`_ SafeFormat and `Diagnostic API
<https://clang.llvm.org/doxygen/classclang_1_1Diagnostic.html>`_ in
`Clang <https://clang.llvm.org/>`_.
Format string syntax and the documentation are based on Python's `str.format
<https://docs.python.org/3/library/stdtypes.html#str.format>`_.
Thanks `Doug Turnbull <https://github.com/softwaredoug>`_ for his valuable
comments and contribution to the design of the type-safe API and
`Gregory Czajkowski <https://github.com/gcflymoto>`_ for implementing binary
formatting. Thanks `Ruslan Baratov <https://github.com/ruslo>`_ for comprehensive
`comparison of integer formatting algorithms <https://github.com/ruslo/int-dec-format-tests>`_
and useful comments regarding performance, `Boris Kaul <https://github.com/localvoid>`_ for
`C++ counting digits benchmark <https://github.com/localvoid/cxx-benchmark-count-digits>`_.
Thanks to `CarterLi <https://github.com/CarterLi>`_ for contributing various
improvements to the code.

View File

@ -4,9 +4,14 @@ if (NOT DOXYGEN)
return ()
endif ()
find_package(PythonInterp QUIET REQUIRED)
add_custom_target(doc
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.py ${FMT_VERSION}
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/build.py
${FMT_VERSION}
SOURCES api.rst syntax.rst usage.rst build.py conf.py _templates/layout.html)
include(GNUInstallDirs)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/
DESTINATION share/doc/fmt OPTIONAL)
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/doc/fmt OPTIONAL
PATTERN ".doctrees" EXCLUDE)

View File

@ -6,14 +6,13 @@
<meta name="author" content="Victor Zverovich">
<link rel="stylesheet" href="_static/fmt.css">
{# Google Analytics #}
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-20116650-4"></script>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();
a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;
a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-20116650-4', 'fmtlib.net');
ga('send', 'pageview');
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-20116650-4');
</script>
{% endblock %}

View File

@ -6,15 +6,19 @@ API Reference
The {fmt} library API consists of the following parts:
* :ref:`fmt/core.h <core-api>`: the core API providing argument handling
facilities and a lightweight subset of formatting functions
* :ref:`fmt/format.h <format-api>`: the full format API providing compile-time
format string checks, output iterator and user-defined type support
* :ref:`fmt/ranges.h <ranges-api>`: additional formatting support for ranges
and tuples
* :ref:`fmt/core.h <core-api>`: the core API providing main formatting functions
for ``char``/UTF-8 with compile-time checks and minimal dependencies
* :ref:`fmt/format.h <format-api>`: the full format API providing additional
formatting functions and locale support
* :ref:`fmt/ranges.h <ranges-api>`: formatting of ranges and tuples
* :ref:`fmt/chrono.h <chrono-api>`: date and time formatting
* :ref:`fmt/std.h <std-api>`: formatters for standard library types
* :ref:`fmt/compile.h <compile-api>`: format string compilation
* :ref:`fmt/color.h <color-api>`: terminal color and text style
* :ref:`fmt/os.h <os-api>`: system APIs
* :ref:`fmt/ostream.h <ostream-api>`: ``std::ostream`` support
* :ref:`fmt/printf.h <printf-api>`: ``printf`` formatting
* :ref:`fmt/xchar.h <xchar-api>`: optional ``wchar_t`` support
All functions and types provided by the library reside in namespace ``fmt`` and
macros have prefix ``FMT_``.
@ -24,34 +28,66 @@ macros have prefix ``FMT_``.
Core API
========
``fmt/core.h`` defines the core API which provides argument handling facilities
and a lightweight subset of formatting functions. In the header-only mode
include ``fmt/format.h`` instead of ``fmt/core.h``.
``fmt/core.h`` defines the core API which provides main formatting functions for
``char``/UTF-8 with compile-time checks. It has minimal include dependencies for
better compile times. This header is only beneficial when using {fmt} as a
library and not in the header-only mode.
The following functions use :ref:`format string syntax <syntax>`
similar to that of Python's `str.format
<http://docs.python.org/3/library/stdtypes.html#str.format>`_.
They take *format_str* and *args* as arguments.
<https://docs.python.org/3/library/stdtypes.html#str.format>`_.
They take *fmt* and *args* as arguments.
*format_str* is a format string that contains literal text and replacement
fields surrounded by braces ``{}``. The fields are replaced with formatted
arguments in the resulting string. A function taking *format_str* doesn't
participate in an overload resolution if the latter is not a string.
*fmt* is a format string that contains literal text and replacement fields
surrounded by braces ``{}``. The fields are replaced with formatted arguments
in the resulting string. `~fmt::format_string` is a format string which can be
implicitly constructed from a string literal or a ``constexpr`` string and is
checked at compile time in C++20. To pass a runtime format string wrap it in
`fmt::runtime`.
*args* is an argument list representing objects to be formatted.
.. _format:
.. doxygenfunction:: format(const S&, Args&&...)
.. doxygenfunction:: vformat(const S&, basic_format_args<buffer_context<Char>>)
.. doxygenfunction:: format(format_string<T...> fmt, T&&... args) -> std::string
.. doxygenfunction:: vformat(string_view fmt, format_args args) -> std::string
.. doxygenfunction:: format_to(OutputIt out, format_string<T...> fmt, T&&... args) -> OutputIt
.. doxygenfunction:: format_to_n(OutputIt out, size_t n, format_string<T...> fmt, T&&... args) -> format_to_n_result<OutputIt>
.. doxygenfunction:: formatted_size(format_string<T...> fmt, T&&... args) -> size_t
.. doxygenstruct:: fmt::format_to_n_result
:members:
.. _print:
.. doxygenfunction:: print(const S&, Args&&...)
.. doxygenfunction:: vprint(string_view, format_args)
.. doxygenfunction:: fmt::print(format_string<T...> fmt, T&&... args)
.. doxygenfunction:: fmt::vprint(string_view fmt, format_args args)
.. doxygenfunction:: print(std::FILE *, const S&, Args&&...)
.. doxygenfunction:: vprint(std::FILE *, string_view, format_args)
.. doxygenfunction:: print(std::FILE *f, format_string<T...> fmt, T&&... args)
.. doxygenfunction:: vprint(std::FILE *f, string_view fmt, format_args args)
Compile-Time Format String Checks
---------------------------------
Compile-time checks are enabled when using ``FMT_STRING``. They support built-in
and string types as well as user-defined types with ``constexpr`` ``parse``
functions in their ``formatter`` specializations.
Requires C++14 and is a no-op in C++11.
.. doxygendefine:: FMT_STRING
To force the use of compile-time checks, define the preprocessor variable
``FMT_ENFORCE_COMPILE_STRING``. When set, functions accepting ``FMT_STRING``
will fail to compile with regular strings. Runtime-checked
formatting is still possible using ``fmt::vformat``, ``fmt::vprint``, etc.
.. doxygenclass:: fmt::basic_format_string
:members:
.. doxygentypedef:: fmt::format_string
.. doxygenfunction:: fmt::runtime(const S&)
Named Arguments
---------------
@ -63,19 +99,56 @@ Named arguments are not supported in compile-time checks at the moment.
Argument Lists
--------------
You can create your own formatting function with compile-time checks and small
binary footprint, for example (https://godbolt.org/z/oba4Mc):
.. code:: c++
#include <fmt/format.h>
void vlog(const char* file, int line, fmt::string_view format,
fmt::format_args args) {
fmt::print("{}: {}: ", file, line);
fmt::vprint(format, args);
}
template <typename S, typename... Args>
void log(const char* file, int line, const S& format, Args&&... args) {
vlog(file, line, format, fmt::make_format_args(args...));
}
#define MY_LOG(format, ...) \
log(__FILE__, __LINE__, FMT_STRING(format), __VA_ARGS__)
MY_LOG("invalid squishiness: {}", 42);
Note that ``vlog`` is not parameterized on argument types which improves compile
times and reduces binary code size compared to a fully parameterized version.
.. doxygenfunction:: fmt::make_format_args(const Args&...)
.. doxygenclass:: fmt::format_arg_store
:members:
.. doxygenclass:: fmt::dynamic_format_arg_store
:members:
.. doxygenclass:: fmt::basic_format_args
:members:
.. doxygenstruct:: fmt::format_args
.. doxygentypedef:: fmt::format_args
.. doxygenclass:: fmt::basic_format_arg
:members:
.. doxygenclass:: fmt::basic_format_parse_context
:members:
.. doxygenclass:: fmt::basic_format_context
:members:
.. doxygentypedef:: fmt::format_context
Compatibility
-------------
@ -83,12 +156,11 @@ Compatibility
:members:
.. doxygentypedef:: fmt::string_view
.. doxygentypedef:: fmt::wstring_view
Locale
------
All formatting is locale-independent by default. Use the ``'n'`` format
All formatting is locale-independent by default. Use the ``'L'`` format
specifier to insert the appropriate number separator characters from the
locale::
@ -96,42 +168,42 @@ locale::
#include <locale>
std::locale::global(std::locale("en_US.UTF-8"));
auto s = fmt::format("{:n}", 1000000); // s == "1,000,000"
auto s = fmt::format("{:L}", 1000000); // s == "1,000,000"
.. _format-api:
Format API
==========
``fmt/format.h`` defines the full format API providing compile-time format
string checks, output iterator and user-defined type support.
``fmt/format.h`` defines the full format API providing additional formatting
functions and locale support.
Compile-time Format String Checks
---------------------------------
.. _udt:
Compile-time checks are supported for built-in and string types as well as
user-defined types with ``constexpr`` ``parse`` functions in their ``formatter``
specializations.
.. doxygendefine:: FMT_STRING
Formatting User-defined Types
Formatting User-Defined Types
-----------------------------
The {fmt} library provides formatters for many standard C++ types.
See :ref:`fmt/ranges.h <ranges-api>` for ranges and tuples including standard
containers such as ``std::vector``, :ref:`fmt/chrono.h <chrono-api>` for date
and time formatting and :ref:`fmt/std.h <std-api>` for path and variant
formatting.
To make a user-defined type formattable, specialize the ``formatter<T>`` struct
template and implement ``parse`` and ``format`` methods::
#include <fmt/format.h>
struct point { double x, y; };
struct point {
double x, y;
};
template <>
struct fmt::formatter<point> {
template <> struct fmt::formatter<point> {
// Presentation format: 'f' - fixed, 'e' - exponential.
char presentation = 'f';
// Parses format specifications of the form ['f' | 'e'].
constexpr auto parse(format_parse_context& ctx) {
constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
// [ctx.begin(), ctx.end()) is a character range that contains a part of
// the format string starting from the format specifications to be parsed,
// e.g. in
@ -142,14 +214,17 @@ template and implement ``parse`` and ``format`` methods::
// parse specifiers until '}' or the end of the range. In this example
// the formatter should parse the 'f' specifier and return an iterator
// pointing to '}'.
// Please also note that this character range may be empty, in case of
// the "{}" format string, so therefore you should check ctx.begin()
// for equality with ctx.end().
// Parse the presentation format and store it in the formatter:
auto it = ctx.begin(), end = ctx.end();
if (it != end && (*it == 'f' || *it == 'e')) presentation = *it++;
// Check if reached the end of the range:
if (it != end && *it != '}')
throw format_error("invalid format");
if (it != end && *it != '}') throw format_error("invalid format");
// Return an iterator past the end of the parsed range:
return it;
@ -158,12 +233,11 @@ template and implement ``parse`` and ``format`` methods::
// Formats the point p using the parsed format specification (presentation)
// stored in this formatter.
template <typename FormatContext>
auto format(const point& p, FormatContext& ctx) {
auto format(const point& p, FormatContext& ctx) const -> decltype(ctx.out()) {
// ctx.out() is an output iterator to write to.
return format_to(
ctx.out(),
presentation == 'f' ? "({:.1f}, {:.1f})" : "({:.1e}, {:.1e})",
p.x, p.y);
return presentation == 'f'
? fmt::format_to(ctx.out(), "({:.1f}, {:.1f})", p.x, p.y)
: fmt::format_to(ctx.out(), "({:.1e}, {:.1e})", p.x, p.y);
}
};
@ -178,11 +252,10 @@ example::
enum class color {red, green, blue};
template <>
struct fmt::formatter<color>: formatter<string_view> {
template <> struct fmt::formatter<color>: formatter<string_view> {
// parse is inherited from formatter<string_view>.
template <typename FormatContext>
auto format(color c, FormatContext& ctx) {
auto format(color c, FormatContext& ctx) const {
string_view name = "unknown";
switch (c) {
case color::red: name = "red"; break;
@ -193,6 +266,15 @@ example::
}
};
Since ``parse`` is inherited from ``formatter<string_view>`` it will recognize
all string format specifications, for example
.. code-block:: c++
fmt::format("{:>10}", color::blue)
will return ``" blue"``.
You can also write a formatter for a hierarchy of classes::
#include <type_traits>
@ -211,7 +293,7 @@ You can also write a formatter for a hierarchy of classes::
struct fmt::formatter<T, std::enable_if_t<std::is_base_of<A, T>::value, char>> :
fmt::formatter<std::string> {
template <typename FormatCtx>
auto format(const A& a, FormatCtx& ctx) {
auto format(const A& a, FormatCtx& ctx) const {
return fmt::formatter<std::string>::format(a.name(), ctx);
}
};
@ -222,44 +304,56 @@ You can also write a formatter for a hierarchy of classes::
fmt::print("{}", a); // prints "B"
}
.. doxygenclass:: fmt::basic_format_parse_context
:members:
If a type provides both a ``formatter`` specialization and an implicit
conversion to a formattable type, the specialization takes precedence over the
conversion.
Output Iterator Support
-----------------------
For enums {fmt} also provides the ``format_as`` extension API. To format an enum
via this API define ``format_as`` that takes this enum and converts it to the
underlying type. ``format_as`` should be defined in the same namespace as the
enum.
.. doxygenfunction:: fmt::format_to(OutputIt, const S&, Args&&...)
.. doxygenfunction:: fmt::format_to_n(OutputIt, std::size_t, string_view, Args&&...)
.. doxygenstruct:: fmt::format_to_n_result
:members:
Example (https://godbolt.org/z/r7vvGE1v7)::
Literal-based API
#include <fmt/format.h>
namespace kevin_namespacy {
enum class film {
house_of_cards, american_beauty, se7en = 7
};
auto format_as(film f) { return fmt::underlying(f); }
}
int main() {
fmt::print("{}\n", kevin_namespacy::film::se7en); // prints "7"
}
Literal-Based API
-----------------
The following user-defined literals are defined in ``fmt/format.h``.
.. doxygenfunction:: operator""_format(const char *, std::size_t)
.. doxygenfunction:: operator""_a(const char *, std::size_t)
.. doxygenfunction:: operator""_a()
Utilities
---------
.. doxygenstruct:: fmt::is_char
.. doxygenfunction:: fmt::ptr(T p) -> const void*
.. doxygenfunction:: fmt::ptr(const std::unique_ptr<T> &p) -> const void*
.. doxygenfunction:: fmt::ptr(const std::shared_ptr<T> &p) -> const void*
.. doxygentypedef:: fmt::char_t
.. doxygenfunction:: fmt::underlying(Enum e) -> typename std::underlying_type<Enum>::type
.. doxygenfunction:: fmt::formatted_size(string_view, const Args&...)
.. doxygenfunction:: fmt::to_string(const T &value) -> std::string
.. doxygenfunction:: fmt::to_string(const T&)
.. doxygenfunction:: fmt::join(Range &&range, string_view sep) -> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>>
.. doxygenfunction:: fmt::to_wstring(const T&)
.. doxygenfunction:: fmt::join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel>
.. doxygenfunction:: fmt::to_string_view(const Char *)
.. doxygenfunction:: fmt::group_digits(T value) -> group_digits_view<T>
.. doxygenfunction:: fmt::join(const Range&, string_view)
.. doxygenfunction:: fmt::join(It, It, string_view)
.. doxygenclass:: fmt::detail::buffer
:members:
.. doxygenclass:: fmt::basic_memory_buffer
:protected-members:
@ -268,20 +362,14 @@ Utilities
System Errors
-------------
fmt does not use ``errno`` to communicate errors to the user, but it may call
system functions which set ``errno``. Users should not make any assumptions about
the value of ``errno`` being preserved by library functions.
{fmt} does not use ``errno`` to communicate errors to the user, but it may call
system functions which set ``errno``. Users should not make any assumptions
about the value of ``errno`` being preserved by library functions.
.. doxygenclass:: fmt::system_error
:members:
.. doxygenfunction:: fmt::system_error
.. doxygenfunction:: fmt::format_system_error
.. doxygenclass:: fmt::windows_error
:members:
.. _formatstrings:
Custom Allocators
-----------------
@ -300,8 +388,8 @@ allocator::
custom_string vformat(custom_allocator alloc, fmt::string_view format_str,
fmt::format_args args) {
custom_memory_buffer buf(alloc);
fmt::vformat_to(buf, format_str, args);
auto buf = custom_memory_buffer(alloc);
fmt::vformat_to(std::back_inserter(buf), format_str, args);
return custom_string(buf.data(), buf.size(), alloc);
}
@ -312,59 +400,15 @@ allocator::
return vformat(alloc, format_str, fmt::make_format_args(args...));
}
The allocator will be used for the output container only. If you are using named
arguments, the container that stores pointers to them will be allocated using
the default allocator. Also floating-point formatting falls back on ``sprintf``
which may do allocations.
Custom Formatting of Built-in Types
-----------------------------------
It is possible to change the way arguments are formatted by providing a
custom argument formatter class::
using arg_formatter = fmt::arg_formatter<fmt::buffer_range<char>>;
// A custom argument formatter that formats negative integers as unsigned
// with the ``x`` format specifier.
class custom_arg_formatter : public arg_formatter {
public:
custom_arg_formatter(fmt::format_context& ctx,
fmt::format_parse_context* parse_ctx = nullptr,
fmt::format_specs* spec = nullptr)
: arg_formatter(ctx, parse_ctx, spec) {}
using arg_formatter::operator();
auto operator()(int value) {
if (specs() && specs()->type == 'x')
return (*this)(static_cast<unsigned>(value)); // convert to unsigned and format
return arg_formatter::operator()(value);
}
};
std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) {
fmt::memory_buffer buffer;
// Pass custom argument formatter as a template arg to vformat_to.
fmt::vformat_to<custom_arg_formatter>(buffer, format_str, args);
return fmt::to_string(buffer);
}
template <typename ...Args>
inline std::string custom_format(
fmt::string_view format_str, const Args&... args) {
return custom_vformat(format_str, fmt::make_format_args(args...));
}
std::string s = custom_format("{:x}", -42); // s == "ffffffd6"
.. doxygenclass:: fmt::arg_formatter
:members:
The allocator will be used for the output container only. Formatting functions
normally don't do any allocations for built-in and string types except for
non-default floating-point formatting that occasionally falls back on
``sprintf``.
.. _ranges-api:
Ranges and Tuple Formatting
===========================
Range and Tuple Formatting
==========================
The library also supports convenient formatting of ranges and tuples::
@ -391,18 +435,110 @@ Using ``fmt::join``, you can separate tuple elements with a custom separator::
Date and Time Formatting
========================
The library supports `strftime
<http://en.cppreference.com/w/cpp/chrono/c/strftime>`_-like date and time
formatting::
``fmt/chrono.h`` provides formatters for
* `std::chrono::duration <https://en.cppreference.com/w/cpp/chrono/duration>`_
* `std::chrono::time_point
<https://en.cppreference.com/w/cpp/chrono/time_point>`_
* `std::tm <https://en.cppreference.com/w/cpp/chrono/c/tm>`_
The format syntax is described in :ref:`chrono-specs`.
**Example**::
#include <fmt/chrono.h>
std::time_t t = std::time(nullptr);
// Prints "The date is 2016-04-29." (with the current date)
fmt::print("The date is {:%Y-%m-%d}.", *std::localtime(&t));
int main() {
std::time_t t = std::time(nullptr);
The format string syntax is described in the documentation of
`strftime <http://en.cppreference.com/w/cpp/chrono/c/strftime>`_.
// Prints "The date is 2020-11-07." (with the current date):
fmt::print("The date is {:%Y-%m-%d}.", fmt::localtime(t));
using namespace std::literals::chrono_literals;
// Prints "Default format: 42s 100ms":
fmt::print("Default format: {} {}\n", 42s, 100ms);
// Prints "strftime-like format: 03:15:30":
fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s);
}
.. doxygenfunction:: localtime(std::time_t time)
.. doxygenfunction:: gmtime(std::time_t time)
.. _std-api:
Standard Library Types Formatting
=================================
``fmt/std.h`` provides formatters for:
* `std::filesystem::path <std::filesystem::path>`_
* `std::thread::id <https://en.cppreference.com/w/cpp/thread/thread/id>`_
* `std::monostate <https://en.cppreference.com/w/cpp/utility/variant/monostate>`_
* `std::variant <https://en.cppreference.com/w/cpp/utility/variant/variant>`_
Formatting Variants
-------------------
A ``std::variant`` is only formattable if every variant alternative is formattable, and requires the
``__cpp_lib_variant`` `library feature <https://en.cppreference.com/w/cpp/feature_test>`_.
**Example**::
#include <fmt/std.h>
std::variant<char, float> v0{'x'};
// Prints "variant('x')"
fmt::print("{}", v0);
std::variant<std::monostate, char> v1;
// Prints "variant(monostate)"
.. _compile-api:
Format String Compilation
=========================
``fmt/compile.h`` provides format string compilation enabled via the
``FMT_COMPILE`` macro or the ``_cf`` user-defined literal. Format strings
marked with ``FMT_COMPILE`` or ``_cf`` are parsed, checked and converted into
efficient formatting code at compile-time. This supports arguments of built-in
and string types as well as user-defined types with ``constexpr`` ``parse``
functions in their ``formatter`` specializations. Format string compilation can
generate more binary code compared to the default API and is only recommended in
places where formatting is a performance bottleneck.
.. doxygendefine:: FMT_COMPILE
.. doxygenfunction:: operator""_cf()
.. _color-api:
Terminal Color and Text Style
=============================
``fmt/color.h`` provides support for terminal color and text style output.
.. doxygenfunction:: print(const text_style &ts, const S &format_str, const Args&... args)
.. doxygenfunction:: fg(detail::color_type)
.. doxygenfunction:: bg(detail::color_type)
.. doxygenfunction:: styled(const T& value, text_style ts)
.. _os-api:
System APIs
===========
.. doxygenclass:: fmt::ostream
:members:
.. doxygenfunction:: fmt::windows_error
:members:
.. _ostream-api:
@ -410,24 +546,28 @@ The format string syntax is described in the documentation of
========================
``fmt/ostream.h`` provides ``std::ostream`` support including formatting of
user-defined types that have overloaded ``operator<<``::
user-defined types that have an overloaded insertion operator (``operator<<``).
In order to make a type formattable via ``std::ostream`` you should provide a
``formatter`` specialization inherited from ``ostream_formatter``::
#include <fmt/ostream.h>
class date {
int year_, month_, day_;
public:
date(int year, int month, int day): year_(year), month_(month), day_(day) {}
struct date {
int year, month, day;
friend std::ostream& operator<<(std::ostream& os, const date& d) {
return os << d.year_ << '-' << d.month_ << '-' << d.day_;
return os << d.year << '-' << d.month << '-' << d.day;
}
};
std::string s = fmt::format("The date is {}", date(2012, 12, 9));
template <> struct fmt::formatter<date> : ostream_formatter {};
std::string s = fmt::format("The date is {}", date{2012, 12, 9});
// s == "The date is 2012-12-9"
.. doxygenfunction:: print(std::basic_ostream<Char>&, const S&, Args&&...)
.. doxygenfunction:: streamed(const T &)
.. doxygenfunction:: print(std::ostream &os, format_string<T...> fmt, T&&... args)
.. _printf-api:
@ -436,15 +576,42 @@ user-defined types that have overloaded ``operator<<``::
The header ``fmt/printf.h`` provides ``printf``-like formatting functionality.
The following functions use `printf format string syntax
<http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html>`_ with
<https://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html>`_ with
the POSIX extension for positional arguments. Unlike their standard
counterparts, the ``fmt`` functions are type-safe and throw an exception if an
argument type doesn't match its format specification.
.. doxygenfunction:: printf(const S&, const Args&...)
.. doxygenfunction:: printf(const S &format_str, const T&... args)
.. doxygenfunction:: fprintf(std::FILE *, const S&, const Args&...)
.. doxygenfunction:: fprintf(std::FILE *f, const S &fmt, const T&... args) -> int
.. doxygenfunction:: fprintf(std::basic_ostream<Char>&, const S&, const Args&...)
.. doxygenfunction:: sprintf(const S&, const T&...)
.. doxygenfunction:: sprintf(const S&, const Args&...)
.. _xchar-api:
``wchar_t`` Support
===================
The optional header ``fmt/xchar.h`` provides support for ``wchar_t`` and exotic
character types.
.. doxygenstruct:: fmt::is_char
.. doxygentypedef:: fmt::wstring_view
.. doxygentypedef:: fmt::wformat_context
.. doxygenfunction:: fmt::to_wstring(const T &value)
Compatibility with C++20 ``std::format``
========================================
{fmt} implements nearly all of the `C++20 formatting library
<https://en.cppreference.com/w/cpp/utility/format>`_ with the following
differences:
* Names are defined in the ``fmt`` namespace instead of ``std`` to avoid
collisions with standard library implementations.
* Width calculation doesn't use grapheme clusterization. The latter has been
implemented in a separate branch but hasn't been integrated yet.
* Most C++20 chrono types are not supported yet.

View File

@ -90,12 +90,14 @@
VERSION: '{{ release|e }}',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
LINK_SUFFIX: '{{ link_suffix }}',
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}',
HAS_SOURCE: {{ has_source|lower }},
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
};
</script>
{%- for scriptfile in script_files %}
<script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
{{ js_tag(scriptfile) }}
{%- endfor %}
{%- endmacro %}

View File

@ -1,63 +1,38 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# Build the documentation.
from __future__ import print_function
import errno, os, shutil, sys, tempfile
from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE
from distutils.version import LooseVersion
import errno, os, re, sys
from subprocess import check_call, CalledProcessError, Popen, PIPE, STDOUT
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0', '5.1.0', '5.2.0', '5.2.1', '5.3.0', '6.0.0', '6.1.0', '6.1.1', '6.1.2', '6.2.0']
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0', '5.1.0', '5.2.0', '5.2.1', '5.3.0', '6.0.0', '6.1.0', '6.1.1', '6.1.2', '6.2.0', '6.2.1', '7.0.0', '7.0.1', '7.0.2', '7.0.3', '7.1.0', '7.1.1', '7.1.2', '7.1.3', '8.0.0', '8.0.1', '8.1.0', '8.1.1', '9.0.0']
def pip_install(package, commit=None, **kwargs):
"Install package using pip."
min_version = kwargs.get('min_version')
if min_version:
from pkg_resources import get_distribution, DistributionNotFound
try:
installed_version = get_distribution(os.path.basename(package)).version
if LooseVersion(installed_version) >= min_version:
print('{} {} already installed'.format(package, min_version))
return
except DistributionNotFound:
pass
if commit:
package = 'git+https://github.com/{0}.git@{1}'.format(package, commit)
print('Installing {0}'.format(package))
check_call(['pip', 'install', package])
class Pip:
def __init__(self, venv_dir):
self.path = os.path.join(venv_dir, 'bin', 'pip')
def create_build_env(dirname='virtualenv'):
def install(self, package, commit=None):
"Install package using pip."
if commit:
package = 'git+https://github.com/{0}.git@{1}'.format(package, commit)
print('Installing {0}'.format(package))
check_call([self.path, 'install', package])
def create_build_env(venv_dir='virtualenv'):
# Create virtualenv.
if not os.path.exists(dirname):
check_call(['virtualenv', dirname])
import sysconfig
scripts_dir = os.path.basename(sysconfig.get_path('scripts'))
activate_this_file = os.path.join(dirname, scripts_dir, 'activate_this.py')
with open(activate_this_file) as f:
exec(f.read(), dict(__file__=activate_this_file))
# Import get_distribution after activating virtualenv to get info about
# the correct packages.
from pkg_resources import get_distribution, DistributionNotFound
# Upgrade pip because installation of sphinx with pip 1.1 available on Travis
# is broken (see #207) and it doesn't support the show command.
pip_version = get_distribution('pip').version
if LooseVersion(pip_version) < LooseVersion('1.5.4'):
print("Updating pip")
check_call(['pip', 'install', '--upgrade', 'pip'])
# Upgrade distribute because installation of sphinx with distribute 0.6.24
# available on Travis is broken (see #207).
try:
distribute_version = get_distribution('distribute').version
if LooseVersion(distribute_version) <= LooseVersion('0.6.24'):
print("Updating distribute")
check_call(['pip', 'install', '--upgrade', 'distribute'])
except DistributionNotFound:
pass
# Install Sphinx and Breathe.
pip_install('sphinx-doc/sphinx', '12b83372ac9316e8cbe86e7fed889296a4cc29ee',
min_version='1.4.1.dev20160531')
pip_install('michaeljones/breathe',
'129222318f7c8f865d2631e7da7b033567e7f56a',
min_version='4.2.0')
if not os.path.exists(venv_dir):
check_call(['python3', '-m', 'venv', venv_dir])
# Install Sphinx and Breathe. Require the exact version of Sphinx which is
# compatible with Breathe.
pip = Pip(venv_dir)
pip.install('wheel')
pip.install('six')
# See: https://github.com/sphinx-doc/sphinx/issues/9777
pip.install('docutils==0.17.1')
# Jinja2 >= 3.1 incompatible with sphinx 3.3.0
# See: https://github.com/sphinx-doc/sphinx/issues/10291
pip.install('Jinja2<3.1')
pip.install('sphinx-doc/sphinx', 'v3.3.0')
pip.install('michaeljones/breathe', 'v4.25.0')
def build_docs(version='dev', **kwargs):
doc_dir = kwargs.get('doc_dir', os.path.dirname(os.path.realpath(__file__)))
@ -66,16 +41,17 @@ def build_docs(version='dev', **kwargs):
'include_dir', os.path.join(os.path.dirname(doc_dir), 'include', 'fmt'))
# Build docs.
cmd = ['doxygen', '-']
p = Popen(cmd, stdin=PIPE)
p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
doxyxml_dir = os.path.join(work_dir, 'doxyxml')
p.communicate(input=r'''
out, _ = p.communicate(input=r'''
PROJECT_NAME = fmt
GENERATE_LATEX = NO
GENERATE_MAN = NO
GENERATE_RTF = NO
CASE_SENSE_NAMES = NO
INPUT = {0}/core.h {0}/format.h {0}/os.h {0}/ostream.h \
{0}/printf.h {0}/time.h
INPUT = {0}/chrono.h {0}/color.h {0}/core.h {0}/compile.h \
{0}/format.h {0}/os.h {0}/ostream.h {0}/printf.h \
{0}/xchar.h
QUIET = YES
JAVADOC_AUTOBRIEF = YES
AUTOLINK_SUPPORT = NO
@ -86,28 +62,50 @@ def build_docs(version='dev', **kwargs):
ALIASES += "endrst=\endverbatim"
MACRO_EXPANSION = YES
PREDEFINED = _WIN32=1 \
__linux__=1 \
FMT_ENABLE_IF(...)= \
FMT_USE_VARIADIC_TEMPLATES=1 \
FMT_USE_RVALUE_REFERENCES=1 \
FMT_USE_USER_DEFINED_LITERALS=1 \
FMT_USE_ALIAS_TEMPLATES=1 \
FMT_USE_NONTYPE_TEMPLATE_ARGS=1 \
FMT_API= \
"FMT_BEGIN_NAMESPACE=namespace fmt {{" \
"FMT_END_NAMESPACE=}}" \
"FMT_STRING_ALIAS=1" \
"FMT_ENABLE_IF(B)="
EXCLUDE_SYMBOLS = fmt::internal::* StringValue write_str
"FMT_VARIADIC(...)=" \
"FMT_VARIADIC_W(...)=" \
"FMT_DOC=1"
EXCLUDE_SYMBOLS = fmt::formatter fmt::printf_formatter fmt::arg_join \
fmt::basic_format_arg::handle
'''.format(include_dir, doxyxml_dir).encode('UTF-8'))
out = out.decode('utf-8')
internal_symbols = [
'fmt::detail::.*',
'basic_data<>',
'fmt::type_identity',
'fmt::dynamic_formatter'
]
noisy_warnings = [
'warning: (Compound|Member .* of class) (' + '|'.join(internal_symbols) + \
') is not documented.',
'warning: Internal inconsistency: .* does not belong to any container!'
]
for w in noisy_warnings:
out = re.sub('.*' + w + '\n', '', out)
print(out)
if p.returncode != 0:
raise CalledProcessError(p.returncode, cmd)
html_dir = os.path.join(work_dir, 'html')
main_versions = reversed(versions[-3:])
check_call(['sphinx-build',
check_call([os.path.join(work_dir, 'virtualenv', 'bin', 'sphinx-build'),
'-Dbreathe_projects.format=' + os.path.abspath(doxyxml_dir),
'-Dversion=' + version, '-Drelease=' + version,
'-Aversion=' + version, '-Aversions=' + ','.join(main_versions),
'-b', 'html', doc_dir, html_dir])
try:
check_call(['lessc', '--clean-css',
check_call(['lessc', '--verbose', '--clean-css',
'--include-path=' + os.path.join(doc_dir, 'bootstrap'),
os.path.join(doc_dir, 'fmt.less'),
os.path.join(html_dir, '_static', 'fmt.css')])

View File

@ -56,6 +56,11 @@ div.sphinxsidebar {
padding: 0;
}
// Override center alignment in tables.
td {
text-align: left;
}
p.rubric {
margin-top: 10px;
}

View File

@ -22,25 +22,27 @@ Format API
----------
The format API is similar in spirit to the C ``printf`` family of function but
is safer, simpler and serveral times `faster
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_
is safer, simpler and several times `faster
<https://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html>`_
than common standard library implementations.
The `format string syntax <syntax.html>`_ is similar to the one used by
`str.format <http://docs.python.org/3/library/stdtypes.html#str.format>`_ in
`str.format <https://docs.python.org/3/library/stdtypes.html#str.format>`_ in
Python:
.. code:: c++
fmt::format("The answer is {}.", 42);
std::string s = fmt::format("The answer is {}.", 42);
The ``fmt::format`` function returns a string "The answer is 42.". You can use
``fmt::memory_buffer`` to avoid constructing ``std::string``:
.. code:: c++
fmt::memory_buffer out;
format_to(out, "For a moment, {} happened.", "nothing");
out.data(); // returns a pointer to the formatted data
auto out = fmt::memory_buffer();
format_to(std::back_inserter(out),
"For a moment, {} happened.", "nothing");
auto data = out.data(); // pointer to the formatted data
auto size = out.size(); // size of the formatted data
The ``fmt::print`` function performs formatting and writes the result to a stream:
@ -48,21 +50,19 @@ The ``fmt::print`` function performs formatting and writes the result to a strea
fmt::print(stderr, "System error code = {}\n", errno);
The file argument can be omitted in which case the function prints to
``stdout``:
If you omit the file argument the function will print to ``stdout``:
.. code:: c++
fmt::print("Don't {}\n", "panic");
The Format API also supports positional arguments useful for localization:
The format API also supports positional arguments useful for localization:
.. code:: c++
fmt::print("I'd rather be {1} than {0}.", "right", "happy");
Named arguments can be created with ``fmt::arg``. This makes it easier to track
what goes where when multiple arguments are being formatted:
You can pass named arguments with ``fmt::arg``:
.. code:: c++
@ -91,16 +91,17 @@ time. For example, the code
fmt::format("The answer is {:d}", "forty-two");
throws a ``format_error`` exception with description "unknown format code 'd' for
string", because the argument ``"forty-two"`` is a string while the format code
``d`` only applies to integers, while
throws the ``format_error`` exception because the argument ``"forty-two"`` is a
string while the format code ``d`` only applies to integers.
The code
.. code:: c++
format(FMT_STRING("The answer is {:d}"), "forty-two");
reports a compile-time error for the same reason on compilers that support
relaxed ``constexpr``. See `here <api.html#c.fmt>`_ for details.
reports a compile-time error on compilers that support relaxed ``constexpr``.
See `here <api.html#compile-time-format-string-checks>`_ for details.
The following code
@ -109,21 +110,15 @@ The following code
fmt::format("Cyrillic letter {}", L'\x42e');
produces a compile-time error because wide character ``L'\x42e'`` cannot be
formatted into a narrow string. You can use a wide format string instead:
.. code:: c++
fmt::format(L"Cyrillic letter {}", L'\x42e');
For comparison, writing a wide character to ``std::ostream`` results in
its numeric value being written to the stream (i.e. 1070 instead of letter 'ю'
which is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is
needed.
formatted into a narrow string. For comparison, writing a wide character to
``std::ostream`` results in its numeric value being written to the stream
(i.e. 1070 instead of letter 'ю' which is represented by ``L'\x42e'`` if we
use Unicode) which is rarely desirable.
Compact Binary Code
-------------------
The library is designed to produce compact per-call compiled code. For example
The library produces compact per-call compiled code. For example
(`godbolt <https://godbolt.org/g/TZU4KF>`_),
.. code:: c++
@ -144,8 +139,8 @@ compiles to just
mov rcx, rsp
mov edi, offset .L.str
mov esi, 17
mov edx, 2
call fmt::v5::vprint(fmt::v5::basic_string_view<char>, fmt::v5::format_args)
mov edx, 1
call fmt::v7::vprint(fmt::v7::basic_string_view<char>, fmt::v7::format_args)
xor eax, eax
add rsp, 24
ret
@ -167,20 +162,19 @@ The library is highly portable and relies only on a small set of C++11 features:
* deleted functions
* alias templates
These are available since GCC 4.8, Clang 3.0 and MSVC 19.0 (2015). For older
compilers use {fmt} `version 4.x
<https://github.com/fmtlib/fmt/releases/tag/4.1.0>`_ which continues to be
maintained and only requires C++98.
These are available in GCC 4.8, Clang 3.4, MSVC 19.0 (2015) and more recent
compiler version. For older compilers use {fmt} `version 4.x
<https://github.com/fmtlib/fmt/releases/tag/4.1.0>`_ which is maintained and
only requires C++98.
The output of all formatting functions is consistent across platforms. In
particular, formatting a floating-point infinity always gives ``inf`` while the
output of ``printf`` is platform-dependent. For example,
The output of all formatting functions is consistent across platforms.
For example,
.. code::
fmt::print("{}", std::numeric_limits<double>::infinity());
always prints ``inf``.
always prints ``inf`` while the output of ``printf`` is platform-dependent.
.. _ease-of-use:
@ -192,11 +186,13 @@ just three header files and no external dependencies.
A permissive MIT `license <https://github.com/fmtlib/fmt#license>`_ allows
using the library both in open-source and commercial projects.
`Learn more... <contents.html>`_
.. raw:: html
<a class="btn btn-success" href="https://github.com/fmtlib/fmt">GitHub Repository</a>
<div class="section footer">
<iframe src="http://ghbtns.com/github-btn.html?user=fmtlib&amp;repo=fmt&amp;type=watch&amp;count=true"
<iframe src="https://ghbtns.com/github-btn.html?user=fmtlib&amp;repo=fmt&amp;type=watch&amp;count=true"
class="github-btn" width="100" height="20"></iframe>
</div>

View File

@ -16,7 +16,7 @@ literal text, it can be escaped by doubling: ``{{`` and ``}}``.
The grammar for a replacement field is as follows:
.. productionlist:: sf
replacement_field: "{" [`arg_id`] [":" `format_spec`] "}"
replacement_field: "{" [`arg_id`] [":" (`format_spec` | `chrono_format_spec`)] "}"
arg_id: `integer` | `identifier`
integer: `digit`+
digit: "0"..."9"
@ -27,8 +27,8 @@ The grammar for a replacement field is as follows:
In less formal terms, the replacement field can start with an *arg_id*
that specifies the argument whose value is to be formatted and inserted into
the output instead of the replacement field.
The *arg_id* is optionally followed by a *format_spec*, which is preceded
by a colon ``':'``. These specify a non-default format for the replacement value.
The *arg_id* is optionally followed by a *format_spec*, which is preceded by a
colon ``':'``. These specify a non-default format for the replacement value.
See also the :ref:`formatspec` section.
@ -75,14 +75,14 @@ although some of the formatting options are only supported by the numeric types.
The general form of a *standard format specifier* is:
.. productionlist:: sf
format_spec: [[`fill`]`align`][`sign`]["#"]["0"][`width`]["." `precision`][`type`]
format_spec: [[`fill`]`align`][`sign`]["#"]["0"][`width`]["." `precision`]["L"][`type`]
fill: <a character other than '{' or '}'>
align: "<" | ">" | "^"
sign: "+" | "-" | " "
width: `integer` | "{" `arg_id` "}"
precision: `integer` | "{" `arg_id` "}"
type: `int_type` | "a" | "A" | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "L" | "p" | "s"
int_type: "b" | "B" | "d" | "o" | "x" | "X"
width: `integer` | "{" [`arg_id`] "}"
precision: `integer` | "{" [`arg_id`] "}"
type: "a" | "A" | "b" | "B" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" |
: "o" | "p" | "s" | "x" | "X"
The *fill* character can be any Unicode code point other than ``'{'`` or
``'}'``. The presence of a fill character is signaled by the character following
@ -112,18 +112,18 @@ meaning in this case.
The *sign* option is only valid for number types, and can be one of the
following:
+---------+----------------------------------------------------------+
| Option | Meaning |
+=========+==========================================================+
| ``'+'`` | indicates that a sign should be used for both |
| | positive as well as negative numbers. |
+---------+----------------------------------------------------------+
| ``'-'`` | indicates that a sign should be used only for negative |
| | numbers (this is the default behavior). |
+---------+----------------------------------------------------------+
| space | indicates that a leading space should be used on |
| | positive numbers, and a minus sign on negative numbers. |
+---------+----------------------------------------------------------+
+---------+------------------------------------------------------------+
| Option | Meaning |
+=========+============================================================+
| ``'+'`` | indicates that a sign should be used for both |
| | nonnegative as well as negative numbers. |
+---------+------------------------------------------------------------+
| ``'-'`` | indicates that a sign should be used only for negative |
| | numbers (this is the default behavior). |
+---------+------------------------------------------------------------+
| space | indicates that a leading space should be used on |
| | nonnegative numbers, and a minus sign on negative numbers. |
+---------+------------------------------------------------------------+
The ``'#'`` option causes the "alternate form" to be used for the
conversion. The alternate form is defined differently for different
@ -161,7 +161,11 @@ displayed after the decimal point for a floating-point value formatted with
value formatted with ``'g'`` or ``'G'``. For non-number types the field
indicates the maximum field size - in other words, how many characters will be
used from the field content. The *precision* is not allowed for integer,
character, Boolean, and pointer values.
character, Boolean, and pointer values. Note that a C string must be
null-terminated even if precision is specified.
The ``'L'`` option uses the current locale setting to insert the appropriate
number separator characters. This option is only valid for numeric types.
Finally, the *type* determines how the data should be presented.
@ -200,6 +204,8 @@ The available integer presentation types are:
| | ``'#'`` option with this type adds the prefix ``"0B"`` |
| | to the output value. |
+---------+----------------------------------------------------------+
| ``'c'`` | Character format. Outputs the number as a character. |
+---------+----------------------------------------------------------+
| ``'d'`` | Decimal integer. Outputs the number in base 10. |
+---------+----------------------------------------------------------+
| ``'o'`` | Octal format. Outputs the number in base 8. |
@ -214,10 +220,6 @@ The available integer presentation types are:
| | ``'#'`` option with this type adds the prefix ``"0X"`` |
| | to the output value. |
+---------+----------------------------------------------------------+
| ``'L'`` | Locale-specific format. This is the same as ``'d'``, |
| | except that it uses the current locale setting to insert |
| | the appropriate number separator characters. |
+---------+----------------------------------------------------------+
| none | The same as ``'d'``. |
+---------+----------------------------------------------------------+
@ -261,14 +263,8 @@ The available presentation types for floating-point values are:
| | ``'E'`` if the number gets too large. The |
| | representations of infinity and NaN are uppercased, too. |
+---------+----------------------------------------------------------+
| ``'L'`` | Locale-specific format. This is the same as ``'g'``, |
| | except that it uses the current locale setting to insert |
| | the appropriate number separator characters. |
+---------+----------------------------------------------------------+
| none | Similar to ``'g'``, except that fixed-point notation, |
| | when used, has at least one digit past the decimal |
| | point. The default precision is as high as needed to |
| | represent the particular value. |
| none | Similar to ``'g'``, except that the default precision is |
| | as high as needed to represent the particular value. |
+---------+----------------------------------------------------------+
.. ifconfig:: False
@ -303,6 +299,86 @@ The available presentation types for pointers are:
| none | The same as ``'p'``. |
+---------+----------------------------------------------------------+
.. _chrono-specs:
Chrono Format Specifications
============================
Format specifications for chrono types and ``std::tm`` have the following
syntax:
.. productionlist:: sf
chrono_format_spec: [[`fill`]`align`][`width`]["." `precision`][`chrono_specs`]
chrono_specs: [`chrono_specs`] `conversion_spec` | `chrono_specs` `literal_char`
conversion_spec: "%" [`modifier`] `chrono_type`
literal_char: <a character other than '{', '}' or '%'>
modifier: "E" | "O"
chrono_type: "a" | "A" | "b" | "B" | "c" | "C" | "d" | "D" | "e" | "F" |
: "g" | "G" | "h" | "H" | "I" | "j" | "m" | "M" | "n" | "p" |
: "q" | "Q" | "r" | "R" | "S" | "t" | "T" | "u" | "U" | "V" |
: "w" | "W" | "x" | "X" | "y" | "Y" | "z" | "Z" | "%"
Literal chars are copied unchanged to the output. Precision is valid only for
``std::chrono::duration`` types with a floating-point representation type.
The available presentation types (*chrono_type*) for chrono durations and time
points are:
+---------+--------------------------------------------------------------------+
| Type | Meaning |
+=========+====================================================================+
| ``'H'`` | The hour (24-hour clock) as a decimal number. If the result is a |
| | single digit, it is prefixed with 0. The modified command ``%OH`` |
| | produces the locale's alternative representation. |
+---------+--------------------------------------------------------------------+
| ``'M'`` | The minute as a decimal number. If the result is a single digit, |
| | it is prefixed with 0. The modified command ``%OM`` produces the |
| | locale's alternative representation. |
+---------+--------------------------------------------------------------------+
| ``'S'`` | Seconds as a decimal number. If the number of seconds is less than |
| | 10, the result is prefixed with 0. If the precision of the input |
| | cannot be exactly represented with seconds, then the format is a |
| | decimal floating-point number with a fixed format and a precision |
| | matching that of the precision of the input (or to a microseconds |
| | precision if the conversion to floating-point decimal seconds |
| | cannot be made within 18 fractional digits). The character for the |
| | decimal point is localized according to the locale. The modified |
| | command ``%OS`` produces the locale's alternative representation. |
+---------+--------------------------------------------------------------------+
Specifiers that have a calendaric component such as ``'d'`` (the day of month)
are valid only for ``std::tm`` and not durations or time points.
.. range-specs:
Range Format Specifications
===========================
Format specifications for range types have the following syntax:
..productionlist:: sf
range_format_spec: [":" [`underlying_spec`]]
The `underlying_spec` is parsed based on the formatter of the range's
reference type.
By default, a range of characters or strings is printed escaped and quoted. But
if any `underlying_spec` is provided (even if it is empty), then the characters
or strings are printed according to the provided specification.
Examples:
fmt::format("{}", std::vector{10, 20, 30});
// Result: [10, 20, 30]
fmt::format("{::#x}", std::vector{10, 20, 30});
// Result: [0xa, 0x14, 0x13]
fmt::format("{}", vector{'h', 'e', 'l', 'l', 'o'});
// Result: ['h', 'e', 'l', 'l', 'o']
fmt::format("{::}", vector{'h', 'e', 'l', 'l', 'o'});
// Result: [h, e, l, l, o]
fmt::format("{::d}", vector{'h', 'e', 'l', 'l', 'o'});
// Result: [104, 101, 108, 108, 111]
.. _formatexamples:
Format Examples
@ -391,7 +467,7 @@ Using type-specific formatting::
auto t = tm();
t.tm_year = 2010 - 1900;
t.tm_mon = 6;
t.tm_mon = 7;
t.tm_mday = 4;
t.tm_hour = 12;
t.tm_min = 15;
@ -401,7 +477,7 @@ Using type-specific formatting::
Using the comma as a thousands separator::
#include <fmt/locale.h>
#include <fmt/format.h>
auto s = fmt::format(std::locale("en_US.UTF-8"), "{:L}", 1234567890);
// s == "1,234,567,890"

View File

@ -15,7 +15,7 @@ Building the Library
The included `CMake build script`__ can be used to build the fmt
library on a wide range of platforms. CMake is freely available for
download from http://www.cmake.org/download/.
download from https://www.cmake.org/download/.
__ https://github.com/fmtlib/fmt/blob/master/CMakeLists.txt
@ -50,7 +50,15 @@ To build a `shared library`__ set the ``BUILD_SHARED_LIBS`` CMake variable to
cmake -DBUILD_SHARED_LIBS=TRUE ...
__ http://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries
__ https://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries
To build a `static library` with position independent code (required if the main
consumer of the fmt library is a shared library i.e. a Python extension) set the
``CMAKE_POSITION_INDEPENDENT_CODE`` CMake variable to ``TRUE``::
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ...
Installing the Library
======================
@ -83,6 +91,49 @@ Setting up your target to use a header-only version of ``fmt`` is equally easy::
target_link_libraries(<your-target> PRIVATE fmt::fmt-header-only)
Usage with build2
=================
You can use `build2 <https://build2.org>`_, a dependency manager and a
build-system combined, to use ``fmt``.
Currently this package is available in these package repositories:
- **https://cppget.org/fmt/** for released and published versions.
- `The git repository with the sources of the build2 package of fmt <https://github.com/build2-packaging/fmt.git>`_
for unreleased or custom revisions of ``fmt``.
**Usage:**
- ``build2`` package name: ``fmt``
- Library target name : ``lib{fmt}``
For example, to make your ``build2`` project depend on ``fmt``:
- Add one of the repositories to your configurations, or in your
``repositories.manifest``, if not already there::
:
role: prerequisite
location: https://pkg.cppget.org/1/stable
- Add this package as a dependency to your ``./manifest`` file
(example for ``v7.0.x``)::
depends: fmt ~7.0.0
- Import the target and use it as a prerequisite to your own target
using `fmt` in the appropriate ``buildfile``::
import fmt = fmt%lib{fmt}
lib{mylib} : cxx{**} ... $fmt
Then build your project as usual with `b` or `bdep update`.
For ``build2`` newcomers or to get more details and use cases, you can read the
``build2``
`toolchain introduction <https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml>`_.
Building the Documentation
==========================
@ -130,6 +181,18 @@ The fmt port in vcpkg is kept up to date by Microsoft team members and community
contributors. If the version is out of date, please `create an issue or pull
request <https://github.com/Microsoft/vcpkg>`__ on the vcpkg repository.
LHelper
=======
You can download and install fmt using
`lhelper <https://github.com/franko/lhelper>`__ dependency manager::
lhelper activate <some-environment>
lhelper install fmt
All the recipes for lhelper are kept in the
`lhelper's recipe <https://github.com/franko/lhelper-recipes>`__ repository.
Android NDK
===========
@ -139,11 +202,11 @@ For an example of using fmt with Android NDK, see the
`android-ndk-example <https://github.com/fmtlib/android-ndk-example>`_
repository.
__ https://github.com/fmtlib/fmt/blob/master/Android.mk
__ https://github.com/fmtlib/fmt/blob/master/support/Android.mk
Homebrew
========
fmt can be installed on OS X using `Homebrew <http://brew.sh/>`_::
fmt can be installed on OS X using `Homebrew <https://brew.sh/>`_::
brew install fmt

234
externals/fmt/include/fmt/args.h vendored Normal file
View File

@ -0,0 +1,234 @@
// Formatting library for C++ - dynamic format arguments
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_ARGS_H_
#define FMT_ARGS_H_
#include <functional> // std::reference_wrapper
#include <memory> // std::unique_ptr
#include <vector>
#include "core.h"
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename T> struct is_reference_wrapper : std::false_type {};
template <typename T>
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
template <typename T> const T& unwrap(const T& v) { return v; }
template <typename T> const T& unwrap(const std::reference_wrapper<T>& v) {
return static_cast<const T&>(v);
}
class dynamic_arg_list {
// Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
// templates it doesn't complain about inability to deduce single translation
// unit for placing vtable. So storage_node_base is made a fake template.
template <typename = void> struct node {
virtual ~node() = default;
std::unique_ptr<node<>> next;
};
template <typename T> struct typed_node : node<> {
T value;
template <typename Arg>
FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
template <typename Char>
FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
: value(arg.data(), arg.size()) {}
};
std::unique_ptr<node<>> head_;
public:
template <typename T, typename Arg> const T& push(const Arg& arg) {
auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
auto& value = new_node->value;
new_node->next = std::move(head_);
head_ = std::move(new_node);
return value;
}
};
} // namespace detail
/**
\rst
A dynamic version of `fmt::format_arg_store`.
It's equipped with a storage to potentially temporary objects which lifetimes
could be shorter than the format arguments object.
It can be implicitly converted into `~fmt::basic_format_args` for passing
into type-erased formatting functions such as `~fmt::vformat`.
\endrst
*/
template <typename Context>
class dynamic_format_arg_store
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround a GCC template argument substitution bug.
: public basic_format_args<Context>
#endif
{
private:
using char_type = typename Context::char_type;
template <typename T> struct need_copy {
static constexpr detail::type mapped_type =
detail::mapped_type_constant<T, Context>::value;
enum {
value = !(detail::is_reference_wrapper<T>::value ||
std::is_same<T, basic_string_view<char_type>>::value ||
std::is_same<T, detail::std_string_view<char_type>>::value ||
(mapped_type != detail::type::cstring_type &&
mapped_type != detail::type::string_type &&
mapped_type != detail::type::custom_type))
};
};
template <typename T>
using stored_type = conditional_t<
std::is_convertible<T, std::basic_string<char_type>>::value &&
!detail::is_reference_wrapper<T>::value,
std::basic_string<char_type>, T>;
// Storage of basic_format_arg must be contiguous.
std::vector<basic_format_arg<Context>> data_;
std::vector<detail::named_arg_info<char_type>> named_info_;
// Storage of arguments not fitting into basic_format_arg must grow
// without relocation because items in data_ refer to it.
detail::dynamic_arg_list dynamic_args_;
friend class basic_format_args<Context>;
unsigned long long get_types() const {
return detail::is_unpacked_bit | data_.size() |
(named_info_.empty()
? 0ULL
: static_cast<unsigned long long>(detail::has_named_args_bit));
}
const basic_format_arg<Context>* data() const {
return named_info_.empty() ? data_.data() : data_.data() + 1;
}
template <typename T> void emplace_arg(const T& arg) {
data_.emplace_back(detail::make_arg<Context>(arg));
}
template <typename T>
void emplace_arg(const detail::named_arg<char_type, T>& arg) {
if (named_info_.empty()) {
constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr};
data_.insert(data_.begin(), {zero_ptr, 0});
}
data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value)));
auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
data->pop_back();
};
std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
guard{&data_, pop_one};
named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
data_[0].value_.named_args = {named_info_.data(), named_info_.size()};
guard.release();
}
public:
constexpr dynamic_format_arg_store() = default;
/**
\rst
Adds an argument into the dynamic store for later passing to a formatting
function.
Note that custom types and string types (but not string views) are copied
into the store dynamically allocating memory if necessary.
**Example**::
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(42);
store.push_back("abc");
store.push_back(1.5f);
std::string result = fmt::vformat("{} and {} and {}", store);
\endrst
*/
template <typename T> void push_back(const T& arg) {
if (detail::const_check(need_copy<T>::value))
emplace_arg(dynamic_args_.push<stored_type<T>>(arg));
else
emplace_arg(detail::unwrap(arg));
}
/**
\rst
Adds a reference to the argument into the dynamic store for later passing to
a formatting function.
**Example**::
fmt::dynamic_format_arg_store<fmt::format_context> store;
char band[] = "Rolling Stones";
store.push_back(std::cref(band));
band[9] = 'c'; // Changing str affects the output.
std::string result = fmt::vformat("{}", store);
// result == "Rolling Scones"
\endrst
*/
template <typename T> void push_back(std::reference_wrapper<T> arg) {
static_assert(
need_copy<T>::value,
"objects of built-in types and string views are always copied");
emplace_arg(arg.get());
}
/**
Adds named argument into the dynamic store for later passing to a formatting
function. ``std::reference_wrapper`` is supported to avoid copying of the
argument. The name is always copied into the store.
*/
template <typename T>
void push_back(const detail::named_arg<char_type, T>& arg) {
const char_type* arg_name =
dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str();
if (detail::const_check(need_copy<T>::value)) {
emplace_arg(
fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value)));
} else {
emplace_arg(fmt::arg(arg_name, arg.value));
}
}
/** Erase all elements from the store */
void clear() {
data_.clear();
named_info_.clear();
dynamic_args_ = detail::dynamic_arg_list();
}
/**
\rst
Reserves space to store at least *new_cap* arguments including
*new_cap_named* named arguments.
\endrst
*/
void reserve(size_t new_cap, size_t new_cap_named) {
FMT_ASSERT(new_cap >= new_cap_named,
"Set of arguments includes set of named arguments");
data_.reserve(new_cap);
named_info_.reserve(new_cap_named);
}
};
FMT_END_NAMESPACE
#endif // FMT_ARGS_H_

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@
#include "format.h"
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT_BEGIN
enum class color : uint32_t {
alice_blue = 0xF0F8FF, // rgb(240,248,255)
@ -177,9 +178,13 @@ enum class terminal_color : uint8_t {
enum class emphasis : uint8_t {
bold = 1,
italic = 1 << 1,
underline = 1 << 2,
strikethrough = 1 << 3
faint = 1 << 1,
italic = 1 << 2,
underline = 1 << 3,
blink = 1 << 4,
reverse = 1 << 5,
conceal = 1 << 6,
strikethrough = 1 << 7,
};
// rgb is a struct for red, green and blue colors.
@ -198,21 +203,20 @@ struct rgb {
uint8_t b;
};
namespace internal {
FMT_BEGIN_DETAIL_NAMESPACE
// color is a struct of either a rgb color or a terminal color.
struct color_type {
FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {}
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true),
value{} {
FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {}
FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} {
value.rgb_color = static_cast<uint32_t>(rgb_color);
}
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} {
FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} {
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
}
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(),
value{} {
FMT_CONSTEXPR color_type(terminal_color term_color) noexcept
: is_rgb(), value{} {
value.term_color = static_cast<uint8_t>(term_color);
}
bool is_rgb;
@ -221,15 +225,14 @@ struct color_type {
uint32_t rgb_color;
} value;
};
} // namespace internal
// Experimental text formatting support.
FMT_END_DETAIL_NAMESPACE
/** A text style consisting of foreground and background colors and emphasis. */
class text_style {
public:
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
: set_foreground_color(),
set_background_color(),
ems(em) {}
FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept
: set_foreground_color(), set_background_color(), ems(em) {}
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
if (!set_foreground_color) {
@ -260,63 +263,32 @@ class text_style {
return lhs |= rhs;
}
FMT_CONSTEXPR text_style& operator&=(const text_style& rhs) {
if (!set_foreground_color) {
set_foreground_color = rhs.set_foreground_color;
foreground_color = rhs.foreground_color;
} else if (rhs.set_foreground_color) {
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
FMT_THROW(format_error("can't AND a terminal color"));
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
}
if (!set_background_color) {
set_background_color = rhs.set_background_color;
background_color = rhs.background_color;
} else if (rhs.set_background_color) {
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
FMT_THROW(format_error("can't AND a terminal color"));
background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
}
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
static_cast<uint8_t>(rhs.ems));
return *this;
}
friend FMT_CONSTEXPR text_style operator&(text_style lhs,
const text_style& rhs) {
return lhs &= rhs;
}
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
FMT_CONSTEXPR bool has_foreground() const noexcept {
return set_foreground_color;
}
FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
FMT_CONSTEXPR bool has_background() const noexcept {
return set_background_color;
}
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
FMT_CONSTEXPR bool has_emphasis() const noexcept {
return static_cast<uint8_t>(ems) != 0;
}
FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT {
FMT_CONSTEXPR detail::color_type get_foreground() const noexcept {
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
return foreground_color;
}
FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT {
FMT_CONSTEXPR detail::color_type get_background() const noexcept {
FMT_ASSERT(has_background(), "no background specified for this style");
return background_color;
}
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
FMT_CONSTEXPR emphasis get_emphasis() const noexcept {
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
return ems;
}
private:
FMT_CONSTEXPR text_style(bool is_foreground,
internal::color_type text_color) FMT_NOEXCEPT
: set_foreground_color(),
set_background_color(),
ems() {
detail::color_type text_color) noexcept
: set_foreground_color(), set_background_color(), ems() {
if (is_foreground) {
foreground_color = text_color;
set_foreground_color = true;
@ -326,45 +298,46 @@ class text_style {
}
}
friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground)
FMT_NOEXCEPT;
friend FMT_CONSTEXPR_DECL text_style bg(internal::color_type background)
FMT_NOEXCEPT;
friend FMT_CONSTEXPR text_style fg(detail::color_type foreground) noexcept;
internal::color_type foreground_color;
internal::color_type background_color;
friend FMT_CONSTEXPR text_style bg(detail::color_type background) noexcept;
detail::color_type foreground_color;
detail::color_type background_color;
bool set_foreground_color;
bool set_background_color;
emphasis ems;
};
FMT_CONSTEXPR text_style fg(internal::color_type foreground) FMT_NOEXCEPT {
return text_style(/*is_foreground=*/true, foreground);
/** Creates a text style from the foreground (text) color. */
FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) noexcept {
return text_style(true, foreground);
}
FMT_CONSTEXPR text_style bg(internal::color_type background) FMT_NOEXCEPT {
return text_style(/*is_foreground=*/false, background);
/** Creates a text style from the background color. */
FMT_CONSTEXPR inline text_style bg(detail::color_type background) noexcept {
return text_style(false, background);
}
FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
FMT_CONSTEXPR inline text_style operator|(emphasis lhs, emphasis rhs) noexcept {
return text_style(lhs) | rhs;
}
namespace internal {
FMT_BEGIN_DETAIL_NAMESPACE
template <typename Char> struct ansi_color_escape {
FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,
const char* esc) FMT_NOEXCEPT {
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
const char* esc) noexcept {
// If we have a terminal color, we need to output another escape code
// sequence.
if (!text_color.is_rgb) {
bool is_background = esc == internal::data::background_color;
bool is_background = esc == string_view("\x1b[48;2;");
uint32_t value = text_color.value.term_color;
// Background ASCII codes are the same as the foreground ones but with
// 10 more.
if (is_background) value += 10u;
std::size_t index = 0;
size_t index = 0;
buffer[index++] = static_cast<Char>('\x1b');
buffer[index++] = static_cast<Char>('[');
@ -389,17 +362,19 @@ template <typename Char> struct ansi_color_escape {
to_esc(color.b, buffer + 15, 'm');
buffer[19] = static_cast<Char>(0);
}
FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
uint8_t em_codes[4] = {};
uint8_t em_bits = static_cast<uint8_t>(em);
if (em_bits & static_cast<uint8_t>(emphasis::bold)) em_codes[0] = 1;
if (em_bits & static_cast<uint8_t>(emphasis::italic)) em_codes[1] = 3;
if (em_bits & static_cast<uint8_t>(emphasis::underline)) em_codes[2] = 4;
if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))
em_codes[3] = 9;
FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept {
uint8_t em_codes[num_emphases] = {};
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3;
if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4;
if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5;
if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7;
if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8;
if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9;
std::size_t index = 0;
for (int i = 0; i < 4; ++i) {
size_t index = 0;
for (size_t i = 0; i < num_emphases; ++i) {
if (!em_codes[i]) continue;
buffer[index++] = static_cast<Char>('\x1b');
buffer[index++] = static_cast<Char>('[');
@ -408,129 +383,147 @@ template <typename Char> struct ansi_color_escape {
}
buffer[index++] = static_cast<Char>(0);
}
FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; }
FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; }
FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT {
FMT_CONSTEXPR const Char* begin() const noexcept { return buffer; }
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const noexcept {
return buffer + std::char_traits<Char>::length(buffer);
}
private:
Char buffer[7u + 3u * 4u + 1u];
static constexpr size_t num_emphases = 8;
Char buffer[7u + 3u * num_emphases + 1u];
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
char delimiter) FMT_NOEXCEPT {
char delimiter) noexcept {
out[0] = static_cast<Char>('0' + c / 100);
out[1] = static_cast<Char>('0' + c / 10 % 10);
out[2] = static_cast<Char>('0' + c % 10);
out[3] = static_cast<Char>(delimiter);
}
static FMT_CONSTEXPR bool has_emphasis(emphasis em, emphasis mask) noexcept {
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
}
};
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
internal::color_type foreground) FMT_NOEXCEPT {
return ansi_color_escape<Char>(foreground, internal::data::foreground_color);
detail::color_type foreground) noexcept {
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
}
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
internal::color_type background) FMT_NOEXCEPT {
return ansi_color_escape<Char>(background, internal::data::background_color);
detail::color_type background) noexcept {
return ansi_color_escape<Char>(background, "\x1b[48;2;");
}
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) FMT_NOEXCEPT {
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) noexcept {
return ansi_color_escape<Char>(em);
}
template <typename Char>
inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT {
std::fputs(chars, stream);
template <typename Char> inline void fputs(const Char* chars, FILE* stream) {
int result = std::fputs(chars, stream);
if (result < 0)
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
}
template <>
inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT {
std::fputws(chars, stream);
template <> inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) {
int result = std::fputws(chars, stream);
if (result < 0)
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
}
template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
fputs(internal::data::reset_color, stream);
template <typename Char> inline void reset_color(FILE* stream) {
fputs("\x1b[0m", stream);
}
template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
fputs(internal::data::wreset_color, stream);
template <> inline void reset_color<wchar_t>(FILE* stream) {
fputs(L"\x1b[0m", stream);
}
template <typename Char> inline void reset_color(buffer<Char>& buffer) {
auto reset_color = string_view("\x1b[0m");
buffer.append(reset_color.begin(), reset_color.end());
}
template <typename T> struct styled_arg {
const T& value;
text_style style;
};
template <typename Char>
inline void reset_color(basic_memory_buffer<Char>& buffer) FMT_NOEXCEPT {
const char* begin = data::reset_color;
const char* end = begin + sizeof(data::reset_color) - 1;
buffer.append(begin, end);
}
template <typename Char>
void vformat_to(basic_memory_buffer<Char>& buf, const text_style& ts,
void vformat_to(buffer<Char>& buf, const text_style& ts,
basic_string_view<Char> format_str,
basic_format_args<buffer_context<Char>> args) {
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
bool has_style = false;
if (ts.has_emphasis()) {
has_style = true;
auto emphasis = internal::make_emphasis<Char>(ts.get_emphasis());
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
buf.append(emphasis.begin(), emphasis.end());
}
if (ts.has_foreground()) {
has_style = true;
auto foreground =
internal::make_foreground_color<Char>(ts.get_foreground());
auto foreground = detail::make_foreground_color<Char>(ts.get_foreground());
buf.append(foreground.begin(), foreground.end());
}
if (ts.has_background()) {
has_style = true;
auto background =
internal::make_background_color<Char>(ts.get_background());
auto background = detail::make_background_color<Char>(ts.get_background());
buf.append(background.begin(), background.end());
}
internal::vformat_to(buf, format_str, args);
if (has_style) internal::reset_color<Char>(buf);
detail::vformat_to(buf, format_str, args, {});
if (has_style) detail::reset_color<Char>(buf);
}
} // namespace internal
FMT_END_DETAIL_NAMESPACE
template <typename S, typename Char = char_t<S>>
void vprint(std::FILE* f, const text_style& ts, const S& format,
basic_format_args<buffer_context<Char>> args) {
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
basic_memory_buffer<Char> buf;
internal::vformat_to(buf, ts, to_string_view(format), args);
buf.push_back(Char(0));
internal::fputs(buf.data(), f);
detail::vformat_to(buf, ts, detail::to_string_view(format), args);
if (detail::is_utf8()) {
detail::print(f, basic_string_view<Char>(buf.begin(), buf.size()));
} else {
buf.push_back(Char(0));
detail::fputs(buf.data(), f);
}
}
/**
\rst
Formats a string and prints it to the specified file stream using ANSI
escape sequences to specify text formatting.
Example:
**Example**::
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
template <typename S, typename... Args,
FMT_ENABLE_IF(internal::is_string<S>::value)>
FMT_ENABLE_IF(detail::is_string<S>::value)>
void print(std::FILE* f, const text_style& ts, const S& format_str,
const Args&... args) {
internal::check_format_string<Args...>(format_str);
using context = buffer_context<char_t<S>>;
format_arg_store<context, Args...> as{args...};
vprint(f, ts, format_str, basic_format_args<context>(as));
vprint(f, ts, format_str,
fmt::make_format_args<buffer_context<char_t<S>>>(args...));
}
/**
\rst
Formats a string and prints it to stdout using ANSI escape sequences to
specify text formatting.
Example:
**Example**::
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
template <typename S, typename... Args,
FMT_ENABLE_IF(internal::is_string<S>::value)>
FMT_ENABLE_IF(detail::is_string<S>::value)>
void print(const text_style& ts, const S& format_str, const Args&... args) {
return print(stdout, ts, format_str, args...);
}
@ -540,7 +533,7 @@ inline std::basic_string<Char> vformat(
const text_style& ts, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
basic_memory_buffer<Char> buf;
internal::vformat_to(buf, ts, to_string_view(format_str), args);
detail::vformat_to(buf, ts, detail::to_string_view(format_str), args);
return fmt::to_string(buf);
}
@ -559,10 +552,100 @@ inline std::basic_string<Char> vformat(
template <typename S, typename... Args, typename Char = char_t<S>>
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
const Args&... args) {
return vformat(ts, to_string_view(format_str),
internal::make_args_checked<Args...>(format_str, args...));
return fmt::vformat(ts, detail::to_string_view(format_str),
fmt::make_format_args<buffer_context<Char>>(args...));
}
/**
Formats a string with the given text_style and writes the output to ``out``.
*/
template <typename OutputIt, typename Char,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
OutputIt vformat_to(
OutputIt out, const text_style& ts, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
auto&& buf = detail::get_buffer<Char>(out);
detail::vformat_to(buf, ts, format_str, args);
return detail::get_iterator(buf);
}
/**
\rst
Formats arguments with the given text_style, writes the result to the output
iterator ``out`` and returns the iterator past the end of the output range.
**Example**::
std::vector<char> out;
fmt::format_to(std::back_inserter(out),
fmt::emphasis::bold | fg(fmt::color::red), "{}", 42);
\endrst
*/
template <typename OutputIt, typename S, typename... Args,
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value&&
detail::is_string<S>::value>
inline auto format_to(OutputIt out, const text_style& ts, const S& format_str,
Args&&... args) ->
typename std::enable_if<enable, OutputIt>::type {
return vformat_to(out, ts, detail::to_string_view(format_str),
fmt::make_format_args<buffer_context<char_t<S>>>(args...));
}
template <typename T, typename Char>
struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> {
template <typename FormatContext>
auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const
-> decltype(ctx.out()) {
const auto& ts = arg.style;
const auto& value = arg.value;
auto out = ctx.out();
bool has_style = false;
if (ts.has_emphasis()) {
has_style = true;
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
out = std::copy(emphasis.begin(), emphasis.end(), out);
}
if (ts.has_foreground()) {
has_style = true;
auto foreground =
detail::make_foreground_color<Char>(ts.get_foreground());
out = std::copy(foreground.begin(), foreground.end(), out);
}
if (ts.has_background()) {
has_style = true;
auto background =
detail::make_background_color<Char>(ts.get_background());
out = std::copy(background.begin(), background.end(), out);
}
out = formatter<T, Char>::format(value, ctx);
if (has_style) {
auto reset_color = string_view("\x1b[0m");
out = std::copy(reset_color.begin(), reset_color.end(), out);
}
return out;
}
};
/**
\rst
Returns an argument that will be formatted using ANSI escape sequences,
to be used in a formatting function.
**Example**::
fmt::print("Elapsed time: {s:.2f} seconds",
fmt::styled(1.23, fmt::fg(fmt::color::green) |
fmt::bg(fmt::color::blue)));
\endrst
*/
template <typename T>
FMT_CONSTEXPR auto styled(const T& value, text_style ts)
-> detail::styled_arg<remove_cvref_t<T>> {
return detail::styled_arg<remove_cvref_t<T>>{value, ts};
}
FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
#endif // FMT_COLOR_H_

View File

@ -8,344 +8,162 @@
#ifndef FMT_COMPILE_H_
#define FMT_COMPILE_H_
#include <vector>
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace internal {
namespace detail {
// Part of a compiled format string. It can be either literal text or a
// replacement field.
template <typename Char> struct format_part {
enum class kind { arg_index, arg_name, text, replacement };
struct replacement {
arg_ref<Char> arg_id;
dynamic_format_specs<Char> specs;
};
kind part_kind;
union value {
int arg_index;
basic_string_view<Char> str;
replacement repl;
FMT_CONSTEXPR value(int index = 0) : arg_index(index) {}
FMT_CONSTEXPR value(basic_string_view<Char> s) : str(s) {}
FMT_CONSTEXPR value(replacement r) : repl(r) {}
} val;
// Position past the end of the argument id.
const Char* arg_id_end = nullptr;
FMT_CONSTEXPR format_part(kind k = kind::arg_index, value v = {})
: part_kind(k), val(v) {}
static FMT_CONSTEXPR format_part make_arg_index(int index) {
return format_part(kind::arg_index, index);
}
static FMT_CONSTEXPR format_part make_arg_name(basic_string_view<Char> name) {
return format_part(kind::arg_name, name);
}
static FMT_CONSTEXPR format_part make_text(basic_string_view<Char> text) {
return format_part(kind::text, text);
}
static FMT_CONSTEXPR format_part make_replacement(replacement repl) {
return format_part(kind::replacement, repl);
}
};
template <typename Char> struct part_counter {
unsigned num_parts = 0;
FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
if (begin != end) ++num_parts;
}
FMT_CONSTEXPR void on_arg_id() { ++num_parts; }
FMT_CONSTEXPR void on_arg_id(int) { ++num_parts; }
FMT_CONSTEXPR void on_arg_id(basic_string_view<Char>) { ++num_parts; }
FMT_CONSTEXPR void on_replacement_field(const Char*) {}
FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
const Char* end) {
// Find the matching brace.
unsigned brace_counter = 0;
for (; begin != end; ++begin) {
if (*begin == '{') {
++brace_counter;
} else if (*begin == '}') {
if (brace_counter == 0u) break;
--brace_counter;
}
}
return begin;
}
FMT_CONSTEXPR void on_error(const char*) {}
};
// Counts the number of parts in a format string.
template <typename Char>
FMT_CONSTEXPR unsigned count_parts(basic_string_view<Char> format_str) {
part_counter<Char> counter;
parse_format_string<true>(format_str, counter);
return counter.num_parts;
template <typename Char, typename InputIt>
inline counting_iterator copy_str(InputIt begin, InputIt end,
counting_iterator it) {
return it + (end - begin);
}
template <typename Char, typename PartHandler>
class format_string_compiler : public error_handler {
private:
using part = format_part<Char>;
template <typename OutputIt> class truncating_iterator_base {
protected:
OutputIt out_;
size_t limit_;
size_t count_ = 0;
PartHandler handler_;
part part_;
basic_string_view<Char> format_str_;
basic_format_parse_context<Char> parse_context_;
truncating_iterator_base() : out_(), limit_(0) {}
truncating_iterator_base(OutputIt out, size_t limit)
: out_(out), limit_(limit) {}
public:
FMT_CONSTEXPR format_string_compiler(basic_string_view<Char> format_str,
PartHandler handler)
: handler_(handler),
format_str_(format_str),
parse_context_(format_str) {}
using iterator_category = std::output_iterator_tag;
using value_type = typename std::iterator_traits<OutputIt>::value_type;
using difference_type = std::ptrdiff_t;
using pointer = void;
using reference = void;
FMT_UNCHECKED_ITERATOR(truncating_iterator_base);
FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
if (begin != end)
handler_(part::make_text({begin, to_unsigned(end - begin)}));
OutputIt base() const { return out_; }
size_t count() const { return count_; }
};
// An output iterator that truncates the output and counts the number of objects
// written to it.
template <typename OutputIt,
typename Enable = typename std::is_void<
typename std::iterator_traits<OutputIt>::value_type>::type>
class truncating_iterator;
template <typename OutputIt>
class truncating_iterator<OutputIt, std::false_type>
: public truncating_iterator_base<OutputIt> {
mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_;
public:
using value_type = typename truncating_iterator_base<OutputIt>::value_type;
truncating_iterator() = default;
truncating_iterator(OutputIt out, size_t limit)
: truncating_iterator_base<OutputIt>(out, limit) {}
truncating_iterator& operator++() {
if (this->count_++ < this->limit_) ++this->out_;
return *this;
}
FMT_CONSTEXPR void on_arg_id() {
part_ = part::make_arg_index(parse_context_.next_arg_id());
}
FMT_CONSTEXPR void on_arg_id(int id) {
parse_context_.check_arg_id(id);
part_ = part::make_arg_index(id);
}
FMT_CONSTEXPR void on_arg_id(basic_string_view<Char> id) {
part_ = part::make_arg_name(id);
}
FMT_CONSTEXPR void on_replacement_field(const Char* ptr) {
part_.arg_id_end = ptr;
handler_(part_);
}
FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
const Char* end) {
auto repl = typename part::replacement();
dynamic_specs_handler<basic_format_parse_context<Char>> handler(
repl.specs, parse_context_);
auto it = parse_format_specs(begin, end, handler);
if (*it != '}') on_error("missing '}' in format string");
repl.arg_id = part_.part_kind == part::kind::arg_index
? arg_ref<Char>(part_.val.arg_index)
: arg_ref<Char>(part_.val.str);
auto part = part::make_replacement(repl);
part.arg_id_end = begin;
handler_(part);
truncating_iterator operator++(int) {
auto it = *this;
++*this;
return it;
}
value_type& operator*() const {
return this->count_ < this->limit_ ? *this->out_ : blackhole_;
}
};
// Compiles a format string and invokes handler(part) for each parsed part.
template <bool IS_CONSTEXPR, typename Char, typename PartHandler>
FMT_CONSTEXPR void compile_format_string(basic_string_view<Char> format_str,
PartHandler handler) {
parse_format_string<IS_CONSTEXPR>(
format_str,
format_string_compiler<Char, PartHandler>(format_str, handler));
}
template <typename OutputIt>
class truncating_iterator<OutputIt, std::true_type>
: public truncating_iterator_base<OutputIt> {
public:
truncating_iterator() = default;
template <typename Range, typename Context, typename Id>
void format_arg(
basic_format_parse_context<typename Range::value_type>& parse_ctx,
Context& ctx, Id arg_id) {
ctx.advance_to(
visit_format_arg(arg_formatter<Range>(ctx, &parse_ctx), ctx.arg(arg_id)));
}
truncating_iterator(OutputIt out, size_t limit)
: truncating_iterator_base<OutputIt>(out, limit) {}
// vformat_to is defined in a subnamespace to prevent ADL.
namespace cf {
template <typename Context, typename Range, typename CompiledFormat>
auto vformat_to(Range out, CompiledFormat& cf, basic_format_args<Context> args)
-> typename Context::iterator {
using char_type = typename Context::char_type;
basic_format_parse_context<char_type> parse_ctx(
to_string_view(cf.format_str_));
Context ctx(out.begin(), args);
const auto& parts = cf.parts();
for (auto part_it = std::begin(parts); part_it != std::end(parts);
++part_it) {
const auto& part = *part_it;
const auto& value = part.val;
using format_part_t = format_part<char_type>;
switch (part.part_kind) {
case format_part_t::kind::text: {
const auto text = value.str;
auto output = ctx.out();
auto&& it = reserve(output, text.size());
it = std::copy_n(text.begin(), text.size(), it);
ctx.advance_to(output);
break;
}
case format_part_t::kind::arg_index:
advance_to(parse_ctx, part.arg_id_end);
internal::format_arg<Range>(parse_ctx, ctx, value.arg_index);
break;
case format_part_t::kind::arg_name:
advance_to(parse_ctx, part.arg_id_end);
internal::format_arg<Range>(parse_ctx, ctx, value.str);
break;
case format_part_t::kind::replacement: {
const auto& arg_id_value = value.repl.arg_id.val;
const auto arg = value.repl.arg_id.kind == arg_id_kind::index
? ctx.arg(arg_id_value.index)
: ctx.arg(arg_id_value.name);
auto specs = value.repl.specs;
handle_dynamic_spec<width_checker>(specs.width, specs.width_ref, ctx);
handle_dynamic_spec<precision_checker>(specs.precision,
specs.precision_ref, ctx);
error_handler h;
numeric_specs_checker<error_handler> checker(h, arg.type());
if (specs.align == align::numeric) checker.require_numeric_argument();
if (specs.sign != sign::none) checker.check_sign();
if (specs.alt) checker.require_numeric_argument();
if (specs.precision >= 0) checker.check_precision();
advance_to(parse_ctx, part.arg_id_end);
ctx.advance_to(
visit_format_arg(arg_formatter<Range>(ctx, nullptr, &specs), arg));
break;
}
}
}
return ctx.out();
}
} // namespace cf
struct basic_compiled_format {};
template <typename S, typename = void>
struct compiled_format_base : basic_compiled_format {
using char_type = char_t<S>;
using parts_container = std::vector<internal::format_part<char_type>>;
parts_container compiled_parts;
explicit compiled_format_base(basic_string_view<char_type> format_str) {
compile_format_string<false>(format_str,
[this](const format_part<char_type>& part) {
compiled_parts.push_back(part);
});
template <typename T> truncating_iterator& operator=(T val) {
if (this->count_++ < this->limit_) *this->out_++ = val;
return *this;
}
const parts_container& parts() const { return compiled_parts; }
truncating_iterator& operator++() { return *this; }
truncating_iterator& operator++(int) { return *this; }
truncating_iterator& operator*() { return *this; }
};
template <typename Char, unsigned N> struct format_part_array {
format_part<Char> data[N] = {};
FMT_CONSTEXPR format_part_array() = default;
};
template <typename Char, unsigned N>
FMT_CONSTEXPR format_part_array<Char, N> compile_to_parts(
basic_string_view<Char> format_str) {
format_part_array<Char, N> parts;
unsigned counter = 0;
// This is not a lambda for compatibility with older compilers.
struct {
format_part<Char>* parts;
unsigned* counter;
FMT_CONSTEXPR void operator()(const format_part<Char>& part) {
parts[(*counter)++] = part;
}
} collector{parts.data, &counter};
compile_format_string<true>(format_str, collector);
if (counter < N) {
parts.data[counter] =
format_part<Char>::make_text(basic_string_view<Char>());
}
return parts;
}
template <typename T> constexpr const T& constexpr_max(const T& a, const T& b) {
return (a < b) ? b : a;
}
// A compile-time string which is compiled into fast formatting code.
class compiled_string {};
template <typename S>
struct compiled_format_base<S, enable_if_t<is_compile_string<S>::value>>
: basic_compiled_format {
using char_type = char_t<S>;
struct is_compiled_string : std::is_base_of<compiled_string, S> {};
FMT_CONSTEXPR explicit compiled_format_base(basic_string_view<char_type>) {}
/**
\rst
Converts a string literal *s* into a format string that will be parsed at
compile time and converted into efficient formatting code. Requires C++17
``constexpr if`` compiler support.
// Workaround for old compilers. Format string compilation will not be
// performed there anyway.
#if FMT_USE_CONSTEXPR
static FMT_CONSTEXPR_DECL const unsigned num_format_parts =
constexpr_max(count_parts(to_string_view(S())), 1u);
**Example**::
// Converts 42 into std::string using the most efficient method and no
// runtime format string processing.
std::string s = fmt::format(FMT_COMPILE("{}"), 42);
\endrst
*/
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
# define FMT_COMPILE(s) \
FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit)
#else
static const unsigned num_format_parts = 1;
# define FMT_COMPILE(s) FMT_STRING(s)
#endif
using parts_container = format_part<char_type>[num_format_parts];
const parts_container& parts() const {
static FMT_CONSTEXPR_DECL const auto compiled_parts =
compile_to_parts<char_type, num_format_parts>(
internal::to_string_view(S()));
return compiled_parts.data;
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
template <typename Char, size_t N,
fmt::detail_exported::fixed_string<Char, N> Str>
struct udl_compiled_string : compiled_string {
using char_type = Char;
explicit constexpr operator basic_string_view<char_type>() const {
return {Str.data, N - 1};
}
};
#endif
template <typename S, typename... Args>
class compiled_format : private compiled_format_base<S> {
public:
using typename compiled_format_base<S>::char_type;
template <typename T, typename... Tail>
const T& first(const T& value, const Tail&...) {
return value;
}
private:
basic_string_view<char_type> format_str_;
template <typename Context, typename Range, typename CompiledFormat>
friend auto cf::vformat_to(Range out, CompiledFormat& cf,
basic_format_args<Context> args) ->
typename Context::iterator;
public:
compiled_format() = delete;
explicit constexpr compiled_format(basic_string_view<char_type> format_str)
: compiled_format_base<S>(format_str), format_str_(format_str) {}
};
#ifdef __cpp_if_constexpr
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
template <typename... Args> struct type_list {};
// Returns a reference to the argument at index N from [first, rest...].
template <int N, typename T, typename... Args>
constexpr const auto& get(const T& first, const Args&... rest) {
constexpr const auto& get([[maybe_unused]] const T& first,
[[maybe_unused]] const Args&... rest) {
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
if constexpr (N == 0)
return first;
else
return get<N - 1>(rest...);
return detail::get<N - 1>(rest...);
}
template <typename Char, typename... Args>
constexpr int get_arg_index_by_name(basic_string_view<Char> name,
type_list<Args...>) {
return get_arg_index_by_name<Args...>(name);
}
template <int N, typename> struct get_type_impl;
template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
using type = remove_cvref_t<decltype(get<N>(std::declval<Args>()...))>;
using type =
remove_cvref_t<decltype(detail::get<N>(std::declval<Args>()...))>;
};
template <int N, typename T>
@ -358,9 +176,8 @@ template <typename Char> struct text {
using char_type = Char;
template <typename OutputIt, typename... Args>
OutputIt format(OutputIt out, const Args&...) const {
// TODO: reserve
return copy_str<Char>(data.begin(), data.end(), out);
constexpr OutputIt format(OutputIt out, const Args&...) const {
return write<Char>(out, data);
}
};
@ -373,55 +190,100 @@ constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
return {{&s[pos], size}};
}
template <typename Char, typename OutputIt, typename T,
std::enable_if_t<std::is_integral_v<T>, int> = 0>
OutputIt format_default(OutputIt out, T value) {
// TODO: reserve
format_int fi(value);
return std::copy(fi.data(), fi.data() + fi.size(), out);
template <typename Char> struct code_unit {
Char value;
using char_type = Char;
template <typename OutputIt, typename... Args>
constexpr OutputIt format(OutputIt out, const Args&...) const {
return write<Char>(out, value);
}
};
// This ensures that the argument type is convertible to `const T&`.
template <typename T, int N, typename... Args>
constexpr const T& get_arg_checked(const Args&... args) {
const auto& arg = detail::get<N>(args...);
if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) {
return arg.value;
} else {
return arg;
}
}
template <typename Char, typename OutputIt>
OutputIt format_default(OutputIt out, double value) {
writer w(out);
w.write(value);
return w.out();
}
template <typename Char, typename OutputIt>
OutputIt format_default(OutputIt out, Char value) {
*out++ = value;
return out;
}
template <typename Char, typename OutputIt>
OutputIt format_default(OutputIt out, const Char* value) {
auto length = std::char_traits<Char>::length(value);
return copy_str<Char>(value, value + length, out);
}
template <typename Char>
struct is_compiled_format<code_unit<Char>> : std::true_type {};
// A replacement field that refers to argument N.
template <typename Char, typename T, int N> struct field {
using char_type = Char;
template <typename OutputIt, typename... Args>
OutputIt format(OutputIt out, const Args&... args) const {
// This ensures that the argument type is convertile to `const T&`.
const T& arg = get<N>(args...);
return format_default<Char>(out, arg);
constexpr OutputIt format(OutputIt out, const Args&... args) const {
return write<Char>(out, get_arg_checked<T, N>(args...));
}
};
template <typename Char, typename T, int N>
struct is_compiled_format<field<Char, T, N>> : std::true_type {};
// A replacement field that refers to argument with name.
template <typename Char> struct runtime_named_field {
using char_type = Char;
basic_string_view<Char> name;
template <typename OutputIt, typename T>
constexpr static bool try_format_argument(
OutputIt& out,
// [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9
[[maybe_unused]] basic_string_view<Char> arg_name, const T& arg) {
if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) {
if (arg_name == arg.name) {
out = write<Char>(out, arg.value);
return true;
}
}
return false;
}
template <typename OutputIt, typename... Args>
constexpr OutputIt format(OutputIt out, const Args&... args) const {
bool found = (try_format_argument(out, name, args) || ...);
if (!found) {
FMT_THROW(format_error("argument with specified name is not found"));
}
return out;
}
};
template <typename Char>
struct is_compiled_format<runtime_named_field<Char>> : std::true_type {};
// A replacement field that refers to argument N and has format specifiers.
template <typename Char, typename T, int N> struct spec_field {
using char_type = Char;
formatter<T, Char> fmt;
template <typename OutputIt, typename... Args>
constexpr FMT_INLINE OutputIt format(OutputIt out,
const Args&... args) const {
const auto& vargs =
fmt::make_format_args<basic_format_context<OutputIt, Char>>(args...);
basic_format_context<OutputIt, Char> ctx(out, vargs);
return fmt.format(get_arg_checked<T, N>(args...), ctx);
}
};
template <typename Char, typename T, int N>
struct is_compiled_format<spec_field<Char, T, N>> : std::true_type {};
template <typename L, typename R> struct concat {
L lhs;
R rhs;
using char_type = typename L::char_type;
template <typename OutputIt, typename... Args>
OutputIt format(OutputIt out, const Args&... args) const {
constexpr OutputIt format(OutputIt out, const Args&... args) const {
out = lhs.format(out, args...);
return rhs.format(out, args...);
}
@ -450,7 +312,8 @@ constexpr auto compile_format_string(S format_str);
template <typename Args, size_t POS, int ID, typename T, typename S>
constexpr auto parse_tail(T head, S format_str) {
if constexpr (POS != to_string_view(format_str).size()) {
if constexpr (POS !=
basic_string_view<typename S::char_type>(format_str).size()) {
constexpr auto tail = compile_format_string<Args, POS, ID>(format_str);
if constexpr (std::is_same<remove_cvref_t<decltype(tail)>,
unknown_format>())
@ -462,134 +325,279 @@ constexpr auto parse_tail(T head, S format_str) {
}
}
template <typename T, typename Char> struct parse_specs_result {
formatter<T, Char> fmt;
size_t end;
int next_arg_id;
};
constexpr int manual_indexing_id = -1;
template <typename T, typename Char>
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
size_t pos, int next_arg_id) {
str.remove_prefix(pos);
auto ctx = compile_parse_context<Char>(str, max_value<int>(), nullptr, {},
next_arg_id);
auto f = formatter<T, Char>();
auto end = f.parse(ctx);
return {f, pos + fmt::detail::to_unsigned(end - str.data()) + 1,
next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()};
}
template <typename Char> struct arg_id_handler {
arg_ref<Char> arg_id;
constexpr int operator()() {
FMT_ASSERT(false, "handler cannot be used with automatic indexing");
return 0;
}
constexpr int operator()(int id) {
arg_id = arg_ref<Char>(id);
return 0;
}
constexpr int operator()(basic_string_view<Char> id) {
arg_id = arg_ref<Char>(id);
return 0;
}
constexpr void on_error(const char* message) {
FMT_THROW(format_error(message));
}
};
template <typename Char> struct parse_arg_id_result {
arg_ref<Char> arg_id;
const Char* arg_id_end;
};
template <int ID, typename Char>
constexpr auto parse_arg_id(const Char* begin, const Char* end) {
auto handler = arg_id_handler<Char>{arg_ref<Char>{}};
auto arg_id_end = parse_arg_id(begin, end, handler);
return parse_arg_id_result<Char>{handler.arg_id, arg_id_end};
}
template <typename T, typename Enable = void> struct field_type {
using type = remove_cvref_t<T>;
};
template <typename T>
struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> {
using type = remove_cvref_t<decltype(T::value)>;
};
template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID,
typename S>
constexpr auto parse_replacement_field_then_tail(S format_str) {
using char_type = typename S::char_type;
constexpr auto str = basic_string_view<char_type>(format_str);
constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type();
if constexpr (c == '}') {
return parse_tail<Args, END_POS + 1, NEXT_ID>(
field<char_type, typename field_type<T>::type, ARG_INDEX>(),
format_str);
} else if constexpr (c == ':') {
constexpr auto result = parse_specs<typename field_type<T>::type>(
str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID);
return parse_tail<Args, result.end, result.next_arg_id>(
spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
result.fmt},
format_str);
}
}
// Compiles a non-empty format string and returns the compiled representation
// or unknown_format() on unrecognized input.
template <typename Args, size_t POS, int ID, typename S>
constexpr auto compile_format_string(S format_str) {
using char_type = typename S::char_type;
constexpr basic_string_view<char_type> str = format_str;
constexpr auto str = basic_string_view<char_type>(format_str);
if constexpr (str[POS] == '{') {
if (POS + 1 == str.size())
throw format_error("unmatched '{' in format string");
if constexpr (POS + 1 == str.size())
FMT_THROW(format_error("unmatched '{' in format string"));
if constexpr (str[POS + 1] == '{') {
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
} else if constexpr (str[POS + 1] == '}') {
using type = get_type<ID, Args>;
if constexpr (std::is_same<type, int>::value) {
return parse_tail<Args, POS + 2, ID + 1>(field<char_type, type, ID>(),
format_str);
} else {
return unknown_format();
}
} else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') {
static_assert(ID != manual_indexing_id,
"cannot switch from manual to automatic argument indexing");
constexpr auto next_id =
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
return parse_replacement_field_then_tail<get_type<ID, Args>, Args,
POS + 1, ID, next_id>(
format_str);
} else {
return unknown_format();
constexpr auto arg_id_result =
parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size());
constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data();
constexpr char_type c =
arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type();
static_assert(c == '}' || c == ':', "missing '}' in format string");
if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) {
static_assert(
ID == manual_indexing_id || ID == 0,
"cannot switch from automatic to manual argument indexing");
constexpr auto arg_index = arg_id_result.arg_id.val.index;
return parse_replacement_field_then_tail<get_type<arg_index, Args>,
Args, arg_id_end_pos,
arg_index, manual_indexing_id>(
format_str);
} else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) {
constexpr auto arg_index =
get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{});
if constexpr (arg_index != invalid_arg_index) {
constexpr auto next_id =
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
return parse_replacement_field_then_tail<
decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos,
arg_index, next_id>(format_str);
} else {
if constexpr (c == '}') {
return parse_tail<Args, arg_id_end_pos + 1, ID>(
runtime_named_field<char_type>{arg_id_result.arg_id.val.name},
format_str);
} else if constexpr (c == ':') {
return unknown_format(); // no type info for specs parsing
}
}
}
}
} else if constexpr (str[POS] == '}') {
if (POS + 1 == str.size())
throw format_error("unmatched '}' in format string");
if constexpr (POS + 1 == str.size())
FMT_THROW(format_error("unmatched '}' in format string"));
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
} else {
constexpr auto end = parse_text(str, POS + 1);
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
format_str);
}
}
#endif // __cpp_if_constexpr
} // namespace internal
#if FMT_USE_CONSTEXPR
# ifdef __cpp_if_constexpr
template <typename... Args, typename S,
FMT_ENABLE_IF(is_compile_string<S>::value)>
constexpr auto compile(S format_str) {
constexpr basic_string_view<typename S::char_type> str = format_str;
if constexpr (str.size() == 0) {
return internal::make_text(str, 0, 0);
} else {
constexpr auto result =
internal::compile_format_string<internal::type_list<Args...>, 0, 0>(
format_str);
if constexpr (std::is_same<remove_cvref_t<decltype(result)>,
internal::unknown_format>()) {
return internal::compiled_format<S, Args...>(to_string_view(format_str));
if constexpr (end - POS > 1) {
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
format_str);
} else {
return result;
return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]},
format_str);
}
}
}
template <typename... Args, typename S,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
constexpr auto compile(S format_str) {
constexpr auto str = basic_string_view<typename S::char_type>(format_str);
if constexpr (str.size() == 0) {
return detail::make_text(str, 0, 0);
} else {
constexpr auto result =
detail::compile_format_string<detail::type_list<Args...>, 0, 0>(
format_str);
return result;
}
}
#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
} // namespace detail
FMT_MODULE_EXPORT_BEGIN
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
template <typename CompiledFormat, typename... Args,
typename Char = typename CompiledFormat::char_type,
FMT_ENABLE_IF(internal::is_compiled_format<CompiledFormat>::value)>
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
basic_memory_buffer<Char> buffer;
cf.format(std::back_inserter(buffer), args...);
return to_string(buffer);
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
const Args&... args) {
auto s = std::basic_string<Char>();
cf.format(std::back_inserter(s), args...);
return s;
}
template <typename OutputIt, typename CompiledFormat, typename... Args,
FMT_ENABLE_IF(internal::is_compiled_format<CompiledFormat>::value)>
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
const Args&... args) {
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf,
const Args&... args) {
return cf.format(out, args...);
}
# else
template <typename... Args, typename S,
FMT_ENABLE_IF(is_compile_string<S>::value)>
constexpr auto compile(S format_str) -> internal::compiled_format<S, Args...> {
return internal::compiled_format<S, Args...>(to_string_view(format_str));
}
# endif // __cpp_if_constexpr
#endif // FMT_USE_CONSTEXPR
// Compiles the format string which must be a string literal.
template <typename... Args, typename Char, size_t N>
auto compile(const Char (&format_str)[N])
-> internal::compiled_format<const Char*, Args...> {
return internal::compiled_format<const Char*, Args...>(
basic_string_view<Char>(format_str, N - 1));
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
Args&&... args) {
if constexpr (std::is_same<typename S::char_type, char>::value) {
constexpr auto str = basic_string_view<typename S::char_type>(S());
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {
const auto& first = detail::first(args...);
if constexpr (detail::is_named_arg<
remove_cvref_t<decltype(first)>>::value) {
return fmt::to_string(first.value);
} else {
return fmt::to_string(first);
}
}
}
constexpr auto compiled = detail::compile<Args...>(S());
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
detail::unknown_format>()) {
return fmt::format(
static_cast<basic_string_view<typename S::char_type>>(S()),
std::forward<Args>(args)...);
} else {
return fmt::format(compiled, std::forward<Args>(args)...);
}
}
template <typename CompiledFormat, typename... Args,
typename Char = typename CompiledFormat::char_type,
FMT_ENABLE_IF(std::is_base_of<internal::basic_compiled_format,
CompiledFormat>::value)>
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
basic_memory_buffer<Char> buffer;
using range = buffer_range<Char>;
using context = buffer_context<Char>;
internal::cf::vformat_to<context>(range(buffer), cf,
make_format_args<context>(args...));
return to_string(buffer);
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
constexpr auto compiled = detail::compile<Args...>(S());
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
detail::unknown_format>()) {
return fmt::format_to(
out, static_cast<basic_string_view<typename S::char_type>>(S()),
std::forward<Args>(args)...);
} else {
return fmt::format_to(out, compiled, std::forward<Args>(args)...);
}
}
#endif
template <typename OutputIt, typename CompiledFormat, typename... Args,
FMT_ENABLE_IF(std::is_base_of<internal::basic_compiled_format,
CompiledFormat>::value)>
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
const Args&... args) {
using char_type = typename CompiledFormat::char_type;
using range = internal::output_range<OutputIt, char_type>;
using context = format_context_t<OutputIt, char_type>;
return internal::cf::vformat_to<context>(range(out), cf,
make_format_args<context>(args...));
}
template <typename OutputIt, typename CompiledFormat, typename... Args,
FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value)>
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
const CompiledFormat& cf,
const Args&... args) {
auto it =
format_to(internal::truncating_iterator<OutputIt>(out, n), cf, args...);
const S& format_str, Args&&... args) {
auto it = fmt::format_to(detail::truncating_iterator<OutputIt>(out, n),
format_str, std::forward<Args>(args)...);
return {it.base(), it.count()};
}
template <typename CompiledFormat, typename... Args>
std::size_t formatted_size(const CompiledFormat& cf, const Args&... args) {
return format_to(internal::counting_iterator(), cf, args...).count();
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
size_t formatted_size(const S& format_str, const Args&... args) {
return fmt::format_to(detail::counting_iterator(), format_str, args...)
.count();
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
void print(std::FILE* f, const S& format_str, const Args&... args) {
memory_buffer buffer;
fmt::format_to(std::back_inserter(buffer), format_str, args...);
detail::print(f, {buffer.data(), buffer.size()});
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
void print(const S& format_str, const Args&... args) {
print(stdout, format_str, args...);
}
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
inline namespace literals {
template <detail_exported::fixed_string Str> constexpr auto operator""_cf() {
using char_t = remove_cvref_t<decltype(Str.data[0])>;
return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t),
Str>();
}
} // namespace literals
#endif
FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
#endif // FMT_COMPILE_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,78 +0,0 @@
// Formatting library for C++ - std::locale support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_LOCALE_H_
#define FMT_LOCALE_H_
#include <locale>
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace internal {
template <typename Char>
typename buffer_context<Char>::iterator vformat_to(
const std::locale& loc, buffer<Char>& buf,
basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
using range = buffer_range<Char>;
return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str), args,
internal::locale_ref(loc));
}
template <typename Char>
std::basic_string<Char> vformat(
const std::locale& loc, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
basic_memory_buffer<Char> buffer;
internal::vformat_to(loc, buffer, format_str, args);
return fmt::to_string(buffer);
}
} // namespace internal
template <typename S, typename Char = char_t<S>>
inline std::basic_string<Char> vformat(
const std::locale& loc, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
return internal::vformat(loc, to_string_view(format_str), args);
}
template <typename S, typename... Args, typename Char = char_t<S>>
inline std::basic_string<Char> format(const std::locale& loc,
const S& format_str, Args&&... args) {
return internal::vformat(
loc, to_string_view(format_str),
internal::make_args_checked<Args...>(format_str, args...));
}
template <typename S, typename OutputIt, typename... Args,
typename Char = enable_if_t<
internal::is_output_iterator<OutputIt>::value, char_t<S>>>
inline OutputIt vformat_to(
OutputIt out, const std::locale& loc, const S& format_str,
format_args_t<type_identity_t<OutputIt>, Char> args) {
using range = internal::output_range<OutputIt, Char>;
return vformat_to<arg_formatter<range>>(
range(out), to_string_view(format_str), args, internal::locale_ref(loc));
}
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value&&
internal::is_string<S>::value)>
inline OutputIt format_to(OutputIt out, const std::locale& loc,
const S& format_str, Args&&... args) {
internal::check_format_string<Args...>(format_str);
using context = format_context_t<OutputIt, char_t<S>>;
format_arg_store<context, Args...> as{args...};
return vformat_to(out, loc, to_string_view(format_str),
basic_format_args<context>(as));
}
FMT_END_NAMESPACE
#endif // FMT_LOCALE_H_

View File

@ -8,16 +8,10 @@
#ifndef FMT_OS_H_
#define FMT_OS_H_
#if defined(__MINGW32__) || defined(__CYGWIN__)
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
# undef __STRICT_ANSI__
#endif
#include <cerrno>
#include <clocale> // for locale_t
#include <cstddef>
#include <cstdio>
#include <cstdlib> // for strtod_l
#include <system_error> // std::system_error
#if defined __APPLE__ || defined(__FreeBSD__)
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
@ -25,16 +19,20 @@
#include "format.h"
#ifndef FMT_USE_FCNTL
// UWP doesn't provide _pipe.
#if FMT_HAS_INCLUDE("winapifamily.h")
# include <winapifamily.h>
#endif
#if FMT_HAS_INCLUDE("fcntl.h") && \
(!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
# include <fcntl.h> // for O_RDONLY
# define FMT_USE_FCNTL 1
#else
# define FMT_USE_FCNTL 0
# if FMT_HAS_INCLUDE("winapifamily.h")
# include <winapifamily.h>
# endif
# if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
defined(__linux__)) && \
(!defined(WINAPI_FAMILY) || \
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
# include <fcntl.h> // for O_RDONLY
# define FMT_USE_FCNTL 1
# else
# define FMT_USE_FCNTL 0
# endif
#endif
#ifndef FMT_POSIX
@ -50,7 +48,7 @@
#ifdef FMT_SYSTEM
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
#else
# define FMT_SYSTEM(call) call
# define FMT_SYSTEM(call) ::call
# ifdef _WIN32
// Fix warnings about deprecated symbols.
# define FMT_POSIX_CALL(call) ::_##call
@ -73,6 +71,7 @@
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT_BEGIN
/**
\rst
@ -121,19 +120,28 @@ template <typename Char> class basic_cstring_view {
using cstring_view = basic_cstring_view<char>;
using wcstring_view = basic_cstring_view<wchar_t>;
// An error code.
class error_code {
private:
int value_;
template <typename Char> struct formatter<std::error_code, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
public:
explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}
int get() const FMT_NOEXCEPT { return value_; }
template <typename FormatContext>
FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::write_bytes(out, ec.category().name(),
basic_format_specs<Char>());
out = detail::write<Char>(out, Char(':'));
out = detail::write<Char>(out, ec.value());
return out;
}
};
#ifdef _WIN32
namespace internal {
FMT_API const std::error_category& system_category() noexcept;
FMT_BEGIN_DETAIL_NAMESPACE
// A converter from UTF-16 to UTF-8.
// It is only provided for Windows since other systems support UTF-8 natively.
class utf16_to_utf8 {
@ -142,7 +150,7 @@ class utf16_to_utf8 {
public:
utf16_to_utf8() {}
FMT_API explicit utf16_to_utf8(wstring_view s);
FMT_API explicit utf16_to_utf8(basic_string_view<wchar_t> s);
operator string_view() const { return string_view(&buffer_[0], size()); }
size_t size() const { return buffer_.size() - 1; }
const char* c_str() const { return &buffer_[0]; }
@ -151,59 +159,67 @@ class utf16_to_utf8 {
// Performs conversion returning a system error code instead of
// throwing exception on conversion error. This method may still throw
// in case of memory allocation error.
FMT_API int convert(wstring_view s);
FMT_API int convert(basic_string_view<wchar_t> s);
};
FMT_API void format_windows_error(buffer<char>& out, int error_code,
string_view message) FMT_NOEXCEPT;
} // namespace internal
const char* message) noexcept;
FMT_END_DETAIL_NAMESPACE
/** A Windows error. */
class windows_error : public system_error {
private:
FMT_API void init(int error_code, string_view format_str, format_args args);
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
format_args args);
public:
/**
\rst
Constructs a :class:`fmt::windows_error` object with the description
of the form
/**
\rst
Constructs a :class:`std::system_error` object with the description
of the form
.. parsed-literal::
*<message>*: *<system-message>*
.. parsed-literal::
*<message>*: *<system-message>*
where *<message>* is the formatted message and *<system-message>* is the
system message corresponding to the error code.
*error_code* is a Windows error code as given by ``GetLastError``.
If *error_code* is not a valid error code such as -1, the system message
will look like "error -1".
where *<message>* is the formatted message and *<system-message>* is the
system message corresponding to the error code.
*error_code* is a Windows error code as given by ``GetLastError``.
If *error_code* is not a valid error code such as -1, the system message
will look like "error -1".
**Example**::
**Example**::
// This throws a windows_error with the description
// cannot open file 'madeup': The system cannot find the file specified.
// or similar (system message may vary).
const char *filename = "madeup";
LPOFSTRUCT of = LPOFSTRUCT();
HFILE file = OpenFile(filename, &of, OF_READ);
if (file == HFILE_ERROR) {
throw fmt::windows_error(GetLastError(),
"cannot open file '{}'", filename);
}
\endrst
*/
template <typename... Args>
windows_error(int error_code, string_view message, const Args&... args) {
init(error_code, message, make_format_args(args...));
}
};
// This throws a system_error with the description
// cannot open file 'madeup': The system cannot find the file specified.
// or similar (system message may vary).
const char *filename = "madeup";
LPOFSTRUCT of = LPOFSTRUCT();
HFILE file = OpenFile(filename, &of, OF_READ);
if (file == HFILE_ERROR) {
throw fmt::windows_error(GetLastError(),
"cannot open file '{}'", filename);
}
\endrst
*/
template <typename... Args>
std::system_error windows_error(int error_code, string_view message,
const Args&... args) {
return vwindows_error(error_code, message, fmt::make_format_args(args...));
}
// Reports a Windows error without throwing an exception.
// Can be used to report errors from destructors.
FMT_API void report_windows_error(int error_code,
string_view message) FMT_NOEXCEPT;
FMT_API void report_windows_error(int error_code, const char* message) noexcept;
#else
inline const std::error_category& system_category() noexcept {
return std::system_category();
}
#endif // _WIN32
// std::system is not available on some platforms such as iOS (#2248).
#ifdef __OSX__
template <typename S, typename... Args, typename Char = char_t<S>>
void say(const S& format_str, Args&&... args) {
std::system(format("say \"{}\"", format(format_str, args...)).c_str());
}
#endif
// A buffered file.
class buffered_file {
private:
@ -218,13 +234,13 @@ class buffered_file {
void operator=(const buffered_file&) = delete;
// Constructs a buffered_file object which doesn't represent any file.
buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
buffered_file() noexcept : file_(nullptr) {}
// Destroys the object closing the file it represents if any.
FMT_API ~buffered_file() FMT_NOEXCEPT;
FMT_API ~buffered_file() noexcept;
public:
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
buffered_file(buffered_file&& other) noexcept : file_(other.file_) {
other.file_ = nullptr;
}
@ -242,11 +258,9 @@ class buffered_file {
FMT_API void close();
// Returns the pointer to a FILE object representing this file.
FILE* get() const FMT_NOEXCEPT { return file_; }
FILE* get() const noexcept { return file_; }
// We place parentheses around fileno to workaround a bug in some versions
// of MinGW that define fileno as a macro.
FMT_API int(fileno)() const;
FMT_API int descriptor() const;
void vprint(string_view format_str, format_args args) {
fmt::vprint(file_, format_str, args);
@ -254,18 +268,18 @@ class buffered_file {
template <typename... Args>
inline void print(string_view format_str, const Args&... args) {
vprint(format_str, make_format_args(args...));
vprint(format_str, fmt::make_format_args(args...));
}
};
#if FMT_USE_FCNTL
// A file. Closed file is represented by a file object with descriptor -1.
// Methods that are not declared with FMT_NOEXCEPT may throw
// Methods that are not declared with noexcept may throw
// fmt::system_error in case of failure. Note that some errors such as
// closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler.
class file {
class FMT_API file {
private:
int fd_; // File descriptor.
@ -277,22 +291,26 @@ class file {
enum {
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing.
CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist.
APPEND = FMT_POSIX(O_APPEND), // Open in append mode.
TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file.
};
// Constructs a file object which doesn't represent any file.
file() FMT_NOEXCEPT : fd_(-1) {}
file() noexcept : fd_(-1) {}
// Opens a file and constructs a file object representing this file.
FMT_API file(cstring_view path, int oflag);
file(cstring_view path, int oflag);
public:
file(const file&) = delete;
void operator=(const file&) = delete;
file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
file& operator=(file&& other) FMT_NOEXCEPT {
// Move assignment is not noexcept because close may throw.
file& operator=(file&& other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
@ -300,93 +318,161 @@ class file {
}
// Destroys the object closing the file it represents if any.
FMT_API ~file() FMT_NOEXCEPT;
~file() noexcept;
// Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT { return fd_; }
int descriptor() const noexcept { return fd_; }
// Closes the file.
FMT_API void close();
void close();
// Returns the file size. The size has signed type for consistency with
// stat::st_size.
FMT_API long long size() const;
long long size() const;
// Attempts to read count bytes from the file into the specified buffer.
FMT_API std::size_t read(void* buffer, std::size_t count);
size_t read(void* buffer, size_t count);
// Attempts to write count bytes from the specified buffer to the file.
FMT_API std::size_t write(const void* buffer, std::size_t count);
size_t write(const void* buffer, size_t count);
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
FMT_API static file dup(int fd);
static file dup(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
FMT_API void dup2(int fd);
void dup2(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
FMT_API void dup2(int fd, error_code& ec) FMT_NOEXCEPT;
void dup2(int fd, std::error_code& ec) noexcept;
// Creates a pipe setting up read_end and write_end file objects for reading
// and writing respectively.
FMT_API static void pipe(file& read_end, file& write_end);
static void pipe(file& read_end, file& write_end);
// Creates a buffered_file object associated with this file and detaches
// this file object from the file.
FMT_API buffered_file fdopen(const char* mode);
buffered_file fdopen(const char* mode);
};
// Returns the memory page size.
long getpagesize();
#endif // FMT_USE_FCNTL
#ifdef FMT_LOCALE
// A "C" numeric locale.
class locale {
private:
# ifdef _WIN32
using locale_t = _locale_t;
FMT_BEGIN_DETAIL_NAMESPACE
static void freelocale(locale_t loc) { _free_locale(loc); }
static double strtod_l(const char* nptr, char** endptr, _locale_t loc) {
return _strtod_l(nptr, endptr, loc);
}
# endif
locale_t locale_;
public:
using type = locale_t;
locale(const locale&) = delete;
void operator=(const locale&) = delete;
locale() {
# ifndef _WIN32
locale_ = FMT_SYSTEM(newlocale(LC_NUMERIC_MASK, "C", nullptr));
# else
locale_ = _create_locale(LC_NUMERIC, "C");
# endif
if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
}
~locale() { freelocale(locale_); }
type get() const { return locale_; }
// Converts string to floating-point number and advances str past the end
// of the parsed input.
double strtod(const char*& str) const {
char* end = nullptr;
double result = strtod_l(str, &end, locale_);
str = end;
return result;
struct buffer_size {
buffer_size() = default;
size_t value = 0;
buffer_size operator=(size_t val) const {
auto bs = buffer_size();
bs.value = val;
return bs;
}
};
using Locale FMT_DEPRECATED_ALIAS = locale;
#endif // FMT_LOCALE
struct ostream_params {
int oflag = file::WRONLY | file::CREATE | file::TRUNC;
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;
ostream_params() {}
template <typename... T>
ostream_params(T... params, int new_oflag) : ostream_params(params...) {
oflag = new_oflag;
}
template <typename... T>
ostream_params(T... params, detail::buffer_size bs)
: ostream_params(params...) {
this->buffer_size = bs.value;
}
// Intel has a bug that results in failure to deduce a constructor
// for empty parameter packs.
# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000
ostream_params(int new_oflag) : oflag(new_oflag) {}
ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {}
# endif
};
FMT_END_DETAIL_NAMESPACE
// Added {} below to work around default constructor error known to
// occur in Xcode versions 7.2.1 and 8.2.1.
constexpr detail::buffer_size buffer_size{};
/** A fast output stream which is not thread-safe. */
class FMT_API ostream final : private detail::buffer<char> {
private:
file file_;
void grow(size_t) override;
ostream(cstring_view path, const detail::ostream_params& params)
: file_(path, params.oflag) {
set(new char[params.buffer_size], params.buffer_size);
}
public:
ostream(ostream&& other)
: detail::buffer<char>(other.data(), other.size(), other.capacity()),
file_(std::move(other.file_)) {
other.clear();
other.set(nullptr, 0);
}
~ostream() {
flush();
delete[] data();
}
void flush() {
if (size() == 0) return;
file_.write(data(), size());
clear();
}
template <typename... T>
friend ostream output_file(cstring_view path, T... params);
void close() {
flush();
file_.close();
}
/**
Formats ``args`` according to specifications in ``fmt`` and writes the
output to the file.
*/
template <typename... T> void print(format_string<T...> fmt, T&&... args) {
vformat_to(detail::buffer_appender<char>(*this), fmt,
fmt::make_format_args(args...));
}
};
/**
\rst
Opens a file for writing. Supported parameters passed in *params*:
* ``<integer>``: Flags passed to `open
<https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
(``file::WRONLY | file::CREATE | file::TRUNC`` by default)
* ``buffer_size=<integer>``: Output buffer size
**Example**::
auto out = fmt::output_file("guide.txt");
out.print("Don't {}", "Panic");
\endrst
*/
template <typename... T>
inline ostream output_file(cstring_view path, T... params) {
return {path, detail::ostream_params(params...)};
}
#endif // FMT_USE_FCNTL
FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
#endif // FMT_OS_H_

View File

@ -8,74 +8,97 @@
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
#include <fstream>
#include <ostream>
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace internal {
template <class Char> class formatbuf : public std::basic_streambuf<Char> {
private:
using int_type = typename std::basic_streambuf<Char>::int_type;
using traits_type = typename std::basic_streambuf<Char>::traits_type;
template <typename OutputIt, typename Char> class basic_printf_context;
buffer<Char>& buffer_;
namespace detail {
public:
formatbuf(buffer<Char>& buf) : buffer_(buf) {}
protected:
// The put-area is actually always empty. This makes the implementation
// simpler and has the advantage that the streambuf and the buffer are always
// in sync and sputc never writes into uninitialized memory. The obvious
// disadvantage is that each call to sputc always results in a (virtual) call
// to overflow. There is no disadvantage here for sputn since this always
// results in a call to xsputn.
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
if (!traits_type::eq_int_type(ch, traits_type::eof()))
buffer_.push_back(static_cast<Char>(ch));
return ch;
}
std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE {
buffer_.append(s, s + count);
return count;
}
};
template <typename Char> struct test_stream : std::basic_ostream<Char> {
private:
// Hide all operator<< from std::basic_ostream<Char>.
void_t<> operator<<(null<>);
void_t<> operator<<(const Char*);
template <typename T, FMT_ENABLE_IF(std::is_convertible<T, int>::value &&
!std::is_enum<T>::value)>
void_t<> operator<<(T);
};
// Checks if T has a user-defined operator<< (e.g. not a member of
// std::ostream).
template <typename T, typename Char> class is_streamable {
// Checks if T has a user-defined operator<<.
template <typename T, typename Char, typename Enable = void>
class is_streamable {
private:
template <typename U>
static bool_constant<!std::is_same<decltype(std::declval<test_stream<Char>&>()
<< std::declval<U>()),
void_t<>>::value>
test(int);
static auto test(int)
-> bool_constant<sizeof(std::declval<std::basic_ostream<Char>&>()
<< std::declval<U>()) != 0>;
template <typename> static std::false_type test(...);
template <typename> static auto test(...) -> std::false_type;
using result = decltype(test<T>(0));
public:
is_streamable() = default;
static const bool value = result::value;
};
// Formatting of built-in types and arrays is intentionally disabled because
// it's handled by standard (non-ostream) formatters.
template <typename T, typename Char>
struct is_streamable<
T, Char,
enable_if_t<
std::is_arithmetic<T>::value || std::is_array<T>::value ||
std::is_pointer<T>::value || std::is_same<T, char8_type>::value ||
std::is_convertible<T, fmt::basic_string_view<Char>>::value ||
std::is_same<T, std_string_view<Char>>::value ||
(std::is_convertible<T, int>::value && !std::is_enum<T>::value)>>
: std::false_type {};
template <typename Char> FILE* get_file(std::basic_filebuf<Char>&) {
return nullptr;
}
struct dummy_filebuf {
FILE* _Myfile;
};
template <typename T, typename U = int> struct ms_filebuf {
using type = dummy_filebuf;
};
template <typename T> struct ms_filebuf<T, decltype(T::_Myfile, 0)> {
using type = T;
};
using filebuf_type = ms_filebuf<std::filebuf>::type;
FILE* get_file(filebuf_type& buf);
// Generate a unique explicit instantion in every translation unit using a tag
// type in an anonymous namespace.
namespace {
struct filebuf_access_tag {};
} // namespace
template <typename Tag, typename FileMemberPtr, FileMemberPtr file>
class filebuf_access {
friend FILE* get_file(filebuf_type& buf) { return buf.*file; }
};
template class filebuf_access<filebuf_access_tag,
decltype(&filebuf_type::_Myfile),
&filebuf_type::_Myfile>;
inline bool write(std::filebuf& buf, fmt::string_view data) {
FILE* f = get_file(buf);
if (!f) return false;
print(f, data);
return true;
}
inline bool write(std::wfilebuf&, fmt::basic_string_view<wchar_t>) {
return false;
}
// Write the content of buf to os.
// It is a separate function rather than a part of vprint to simplify testing.
template <typename Char>
void write(std::basic_ostream<Char>& os, buffer<Char>& buf) {
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
if (const_check(FMT_MSC_VERSION)) {
auto filebuf = dynamic_cast<std::basic_filebuf<Char>*>(os.rdbuf());
if (filebuf && write(*filebuf, {buf.data(), buf.size()})) return;
}
const Char* buf_data = buf.data();
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
unsigned_streamsize size = buf.size();
@ -91,36 +114,76 @@ void write(std::basic_ostream<Char>& os, buffer<Char>& buf) {
template <typename Char, typename T>
void format_value(buffer<Char>& buf, const T& value,
locale_ref loc = locale_ref()) {
formatbuf<Char> format_buf(buf);
std::basic_ostream<Char> output(&format_buf);
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf);
auto&& output = std::basic_ostream<Char>(&format_buf);
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
if (loc) output.imbue(loc.get<std::locale>());
#endif
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
#endif
output << value;
buf.resize(buf.size());
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
}
template <typename T> struct streamed_view { const T& value; };
} // namespace detail
// Formats an object of type T that has an overloaded ostream operator<<.
template <typename Char>
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
template <typename T, typename OutputIt>
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const
-> OutputIt {
auto buffer = basic_memory_buffer<Char>();
format_value(buffer, value, ctx.locale());
return formatter<basic_string_view<Char>, Char>::format(
{buffer.data(), buffer.size()}, ctx);
}
};
using ostream_formatter = basic_ostream_formatter<char>;
template <typename T>
struct formatter<detail::streamed_view<T>> : ostream_formatter {
template <typename OutputIt>
auto format(detail::streamed_view<T> view,
basic_format_context<OutputIt, char>& ctx) const -> OutputIt {
return ostream_formatter::format(view.value, ctx);
}
};
/**
\rst
Returns a view that formats `value` via an ostream ``operator<<``.
**Example**::
fmt::print("Current thread id: {}\n",
fmt::streamed(std::this_thread::get_id()));
\endrst
*/
template <typename T>
auto streamed(const T& value) -> detail::streamed_view<T> {
return {value};
}
namespace detail {
// Formats an object of type T that has an overloaded ostream operator<<.
template <typename T, typename Char>
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
: formatter<basic_string_view<Char>, Char> {
template <typename Context>
auto format(const T& value, Context& ctx) -> decltype(ctx.out()) {
basic_memory_buffer<Char> buffer;
format_value(buffer, value, ctx.locale());
basic_string_view<Char> str(buffer.data(), buffer.size());
return formatter<basic_string_view<Char>, Char>::format(str, ctx);
}
: basic_ostream_formatter<Char> {
using basic_ostream_formatter<Char>::format;
};
} // namespace internal
template <typename Char>
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
} // namespace detail
FMT_MODULE_EXPORT template <typename Char>
void vprint(std::basic_ostream<Char>& os,
basic_string_view<type_identity_t<Char>> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
basic_memory_buffer<Char> buffer;
internal::vformat_to(buffer, format_str, args);
internal::write(os, buffer);
auto buffer = basic_memory_buffer<Char>();
detail::vformat_to(buffer, format_str, args);
detail::write_buffer(os, buffer);
}
/**
@ -132,12 +195,19 @@ void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
fmt::print(cerr, "Don't {}!", "panic");
\endrst
*/
template <typename S, typename... Args,
typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
vprint(os, to_string_view(format_str),
internal::make_args_checked<Args...>(format_str, args...));
FMT_MODULE_EXPORT template <typename... T>
void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
vprint(os, fmt, fmt::make_format_args(args...));
}
FMT_MODULE_EXPORT
template <typename... Args>
void print(std::wostream& os,
basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
Args&&... args) {
vprint(os, fmt, fmt::make_format_args<buffer_context<wchar_t>>(args...));
}
FMT_END_NAMESPACE
#endif // FMT_OSTREAM_H_

View File

@ -1,2 +0,0 @@
#include "os.h"
#warning "fmt/posix.h is deprecated; use fmt/os.h instead"

View File

@ -11,10 +11,52 @@
#include <algorithm> // std::max
#include <limits> // std::numeric_limits
#include "ostream.h"
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace internal {
FMT_MODULE_EXPORT_BEGIN
template <typename T> struct printf_formatter { printf_formatter() = delete; };
template <typename Char>
class basic_printf_parse_context : public basic_format_parse_context<Char> {
using basic_format_parse_context<Char>::basic_format_parse_context;
};
template <typename OutputIt, typename Char> class basic_printf_context {
private:
OutputIt out_;
basic_format_args<basic_printf_context> args_;
public:
using char_type = Char;
using format_arg = basic_format_arg<basic_printf_context>;
using parse_context_type = basic_printf_parse_context<Char>;
template <typename T> using formatter_type = printf_formatter<T>;
/**
\rst
Constructs a ``printf_context`` object. References to the arguments are
stored in the context object so make sure they have appropriate lifetimes.
\endrst
*/
basic_printf_context(OutputIt out,
basic_format_args<basic_printf_context> args)
: out_(out), args_(args) {}
OutputIt out() { return out_; }
void advance_to(OutputIt it) { out_ = it; }
detail::locale_ref locale() { return {}; }
format_arg arg(int id) const { return args_.get(id); }
FMT_CONSTEXPR void on_error(const char* message) {
detail::error_handler().on_error(message);
}
};
FMT_BEGIN_DETAIL_NAMESPACE
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
@ -90,11 +132,11 @@ template <typename T, typename Context> class arg_converter {
if (const_check(sizeof(target_type) <= sizeof(int))) {
// Extra casts are used to silence warnings.
if (is_signed) {
arg_ = internal::make_arg<Context>(
arg_ = detail::make_arg<Context>(
static_cast<int>(static_cast<target_type>(value)));
} else {
using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
arg_ = internal::make_arg<Context>(
arg_ = detail::make_arg<Context>(
static_cast<unsigned>(static_cast<unsigned_type>(value)));
}
} else {
@ -102,9 +144,9 @@ template <typename T, typename Context> class arg_converter {
// glibc's printf doesn't sign extend arguments of smaller types:
// std::printf("%lld", -42); // prints "4294967254"
// but we don't have to do the same because it's a UB.
arg_ = internal::make_arg<Context>(static_cast<long long>(value));
arg_ = detail::make_arg<Context>(static_cast<long long>(value));
} else {
arg_ = internal::make_arg<Context>(
arg_ = detail::make_arg<Context>(
static_cast<typename make_unsigned_or_bool<U>::type>(value));
}
}
@ -133,7 +175,7 @@ template <typename Context> class char_converter {
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
void operator()(T value) {
arg_ = internal::make_arg<Context>(
arg_ = detail::make_arg<Context>(
static_cast<typename Context::char_type>(value));
}
@ -141,6 +183,13 @@ template <typename Context> class char_converter {
void operator()(T) {} // No conversion needed for non-integral types.
};
// An argument visitor that return a pointer to a C string if argument is a
// string or null otherwise.
template <typename Char> struct get_cstring {
template <typename T> const Char* operator()(T) { return nullptr; }
const Char* operator()(const Char* s) { return s; }
};
// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
template <typename Char> class printf_width_handler {
@ -155,7 +204,7 @@ template <typename Char> class printf_width_handler {
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
unsigned operator()(T value) {
auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
if (internal::is_negative(value)) {
if (detail::is_negative(value)) {
specs_.align = align::left;
width = 0 - width;
}
@ -171,212 +220,88 @@ template <typename Char> class printf_width_handler {
}
};
template <typename Char, typename Context>
void printf(buffer<Char>& buf, basic_string_view<Char> format,
basic_format_args<Context> args) {
Context(std::back_inserter(buf), format, args).format();
}
template <typename OutputIt, typename Char, typename Context>
internal::truncating_iterator<OutputIt> printf(
internal::truncating_iterator<OutputIt> it, basic_string_view<Char> format,
basic_format_args<Context> args) {
return Context(it, format, args).format();
}
} // namespace internal
using internal::printf; // For printing into memory_buffer.
template <typename Range> class printf_arg_formatter;
template <typename OutputIt, typename Char> class basic_printf_context;
/**
\rst
The ``printf`` argument formatter.
\endrst
*/
template <typename Range>
class printf_arg_formatter : public internal::arg_formatter_base<Range> {
public:
using iterator = typename Range::iterator;
// The ``printf`` argument formatter.
template <typename OutputIt, typename Char>
class printf_arg_formatter : public arg_formatter<Char> {
private:
using char_type = typename Range::value_type;
using base = internal::arg_formatter_base<Range>;
using context_type = basic_printf_context<iterator, char_type>;
using base = arg_formatter<Char>;
using context_type = basic_printf_context<OutputIt, Char>;
using format_specs = basic_format_specs<Char>;
context_type& context_;
void write_null_pointer(char) {
this->specs()->type = 0;
this->write("(nil)");
}
void write_null_pointer(wchar_t) {
this->specs()->type = 0;
this->write(L"(nil)");
OutputIt write_null_pointer(bool is_string = false) {
auto s = this->specs;
s.type = presentation_type::none;
return write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
}
public:
using format_specs = typename base::format_specs;
printf_arg_formatter(OutputIt iter, format_specs& s, context_type& ctx)
: base{iter, s, locale_ref()}, context_(ctx) {}
/**
\rst
Constructs an argument formatter object.
*buffer* is a reference to the output buffer and *specs* contains format
specifier information for standard argument types.
\endrst
*/
printf_arg_formatter(iterator iter, format_specs& specs, context_type& ctx)
: base(Range(iter), &specs, internal::locale_ref()), context_(ctx) {}
OutputIt operator()(monostate value) { return base::operator()(value); }
template <typename T, FMT_ENABLE_IF(fmt::internal::is_integral<T>::value)>
iterator operator()(T value) {
// MSVC2013 fails to compile separate overloads for bool and char_type so
// use std::is_same instead.
if (std::is_same<T, bool>::value) {
format_specs& fmt_specs = *this->specs();
if (fmt_specs.type != 's') return base::operator()(value ? 1 : 0);
fmt_specs.type = 0;
this->write(value != 0);
} else if (std::is_same<T, char_type>::value) {
format_specs& fmt_specs = *this->specs();
if (fmt_specs.type && fmt_specs.type != 'c')
template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)>
OutputIt operator()(T value) {
// MSVC2013 fails to compile separate overloads for bool and Char so use
// std::is_same instead.
if (std::is_same<T, Char>::value) {
format_specs fmt_specs = this->specs;
if (fmt_specs.type != presentation_type::none &&
fmt_specs.type != presentation_type::chr) {
return (*this)(static_cast<int>(value));
}
fmt_specs.sign = sign::none;
fmt_specs.alt = false;
fmt_specs.align = align::right;
return base::operator()(value);
} else {
return base::operator()(value);
fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types.
// align::numeric needs to be overwritten here since the '0' flag is
// ignored for non-numeric types
if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
fmt_specs.align = align::right;
return write<Char>(this->out, static_cast<Char>(value), fmt_specs);
}
return this->out();
return base::operator()(value);
}
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
iterator operator()(T value) {
OutputIt operator()(T value) {
return base::operator()(value);
}
/** Formats a null-terminated C string. */
iterator operator()(const char* value) {
if (value)
base::operator()(value);
else if (this->specs()->type == 'p')
write_null_pointer(char_type());
else
this->write("(null)");
return this->out();
OutputIt operator()(const char* value) {
if (value) return base::operator()(value);
return write_null_pointer(this->specs.type != presentation_type::pointer);
}
/** Formats a null-terminated wide C string. */
iterator operator()(const wchar_t* value) {
if (value)
base::operator()(value);
else if (this->specs()->type == 'p')
write_null_pointer(char_type());
else
this->write(L"(null)");
return this->out();
OutputIt operator()(const wchar_t* value) {
if (value) return base::operator()(value);
return write_null_pointer(this->specs.type != presentation_type::pointer);
}
iterator operator()(basic_string_view<char_type> value) {
OutputIt operator()(basic_string_view<Char> value) {
return base::operator()(value);
}
iterator operator()(monostate value) { return base::operator()(value); }
/** Formats a pointer. */
iterator operator()(const void* value) {
if (value) return base::operator()(value);
this->specs()->type = 0;
write_null_pointer(char_type());
return this->out();
OutputIt operator()(const void* value) {
return value ? base::operator()(value) : write_null_pointer();
}
/** Formats an argument of a custom (user-defined) type. */
iterator operator()(typename basic_format_arg<context_type>::handle handle) {
handle.format(context_.parse_context(), context_);
return this->out();
OutputIt operator()(typename basic_format_arg<context_type>::handle handle) {
auto parse_ctx =
basic_printf_parse_context<Char>(basic_string_view<Char>());
handle.format(parse_ctx, context_);
return this->out;
}
};
template <typename T> struct printf_formatter {
printf_formatter() = delete;
template <typename ParseContext>
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const T& value, FormatContext& ctx) -> decltype(ctx.out()) {
internal::format_value(internal::get_container(ctx.out()), value);
return ctx.out();
}
};
/** This template formats data and writes the output to a writer. */
template <typename OutputIt, typename Char> class basic_printf_context {
public:
/** The character type for the output. */
using char_type = Char;
using iterator = OutputIt;
using format_arg = basic_format_arg<basic_printf_context>;
template <typename T> using formatter_type = printf_formatter<T>;
private:
using format_specs = basic_format_specs<char_type>;
OutputIt out_;
basic_format_args<basic_printf_context> args_;
basic_format_parse_context<Char> parse_ctx_;
static void parse_flags(format_specs& specs, const Char*& it,
const Char* end);
// Returns the argument with specified index or, if arg_index is -1, the next
// argument.
format_arg get_arg(int arg_index = -1);
// Parses argument index, flags and width and returns the argument index.
int parse_header(const Char*& it, const Char* end, format_specs& specs);
public:
/**
\rst
Constructs a ``printf_context`` object. References to the arguments and
the writer are stored in the context object so make sure they have
appropriate lifetimes.
\endrst
*/
basic_printf_context(OutputIt out, basic_string_view<char_type> format_str,
basic_format_args<basic_printf_context> args)
: out_(out), args_(args), parse_ctx_(format_str) {}
OutputIt out() { return out_; }
void advance_to(OutputIt it) { out_ = it; }
internal::locale_ref locale() { return {}; }
format_arg arg(int id) const { return args_.get(id); }
basic_format_parse_context<Char>& parse_context() { return parse_ctx_; }
FMT_CONSTEXPR void on_error(const char* message) {
parse_ctx_.on_error(message);
}
/** Formats stored arguments and writes the output to the range. */
template <typename ArgFormatter = printf_arg_formatter<buffer_range<Char>>>
OutputIt format();
};
template <typename OutputIt, typename Char>
void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs,
const Char*& it,
const Char* end) {
template <typename Char>
void parse_flags(basic_format_specs<Char>& specs, const Char*& it,
const Char* end) {
for (; it != end; ++it) {
switch (*it) {
case '-':
@ -389,7 +314,9 @@ void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs,
specs.fill[0] = '0';
break;
case ' ':
specs.sign = sign::space;
if (specs.sign != sign::plus) {
specs.sign = sign::space;
}
break;
case '#':
specs.alt = true;
@ -400,35 +327,24 @@ void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs,
}
}
template <typename OutputIt, typename Char>
typename basic_printf_context<OutputIt, Char>::format_arg
basic_printf_context<OutputIt, Char>::get_arg(int arg_index) {
if (arg_index < 0)
arg_index = parse_ctx_.next_arg_id();
else
parse_ctx_.check_arg_id(--arg_index);
return internal::get_arg(*this, arg_index);
}
template <typename OutputIt, typename Char>
int basic_printf_context<OutputIt, Char>::parse_header(const Char*& it,
const Char* end,
format_specs& specs) {
template <typename Char, typename GetArg>
int parse_header(const Char*& it, const Char* end,
basic_format_specs<Char>& specs, GetArg get_arg) {
int arg_index = -1;
char_type c = *it;
Char c = *it;
if (c >= '0' && c <= '9') {
// Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag(s).
internal::error_handler eh;
int value = parse_nonnegative_int(it, end, eh);
int value = parse_nonnegative_int(it, end, -1);
if (it != end && *it == '$') { // value is an argument index
++it;
arg_index = value;
arg_index = value != -1 ? value : max_value<int>();
} else {
if (c == '0') specs.fill[0] = '0';
if (value != 0) {
// Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now.
if (value == -1) FMT_THROW(format_error("number is too big"));
specs.width = value;
return arg_index;
}
@ -438,71 +354,104 @@ int basic_printf_context<OutputIt, Char>::parse_header(const Char*& it,
// Parse width.
if (it != end) {
if (*it >= '0' && *it <= '9') {
internal::error_handler eh;
specs.width = parse_nonnegative_int(it, end, eh);
specs.width = parse_nonnegative_int(it, end, -1);
if (specs.width == -1) FMT_THROW(format_error("number is too big"));
} else if (*it == '*') {
++it;
specs.width = static_cast<int>(visit_format_arg(
internal::printf_width_handler<char_type>(specs), get_arg()));
detail::printf_width_handler<Char>(specs), get_arg(-1)));
}
}
return arg_index;
}
template <typename OutputIt, typename Char>
template <typename ArgFormatter>
OutputIt basic_printf_context<OutputIt, Char>::format() {
auto out = this->out();
const Char* start = parse_ctx_.begin();
const Char* end = parse_ctx_.end();
template <typename Char, typename Context>
void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
basic_format_args<Context> args) {
using OutputIt = buffer_appender<Char>;
auto out = OutputIt(buf);
auto context = basic_printf_context<OutputIt, Char>(out, args);
auto parse_ctx = basic_printf_parse_context<Char>(format);
// Returns the argument with specified index or, if arg_index is -1, the next
// argument.
auto get_arg = [&](int arg_index) {
if (arg_index < 0)
arg_index = parse_ctx.next_arg_id();
else
parse_ctx.check_arg_id(--arg_index);
return detail::get_arg(context, arg_index);
};
const Char* start = parse_ctx.begin();
const Char* end = parse_ctx.end();
auto it = start;
while (it != end) {
char_type c = *it++;
if (c != '%') continue;
if (!detail::find<false, Char>(it, end, '%', it)) {
it = end; // detail::find leaves it == nullptr if it doesn't find '%'
break;
}
Char c = *it++;
if (it != end && *it == c) {
out = std::copy(start, it, out);
out = detail::write(
out, basic_string_view<Char>(start, detail::to_unsigned(it - start)));
start = ++it;
continue;
}
out = std::copy(start, it - 1, out);
out = detail::write(out, basic_string_view<Char>(
start, detail::to_unsigned(it - 1 - start)));
format_specs specs;
basic_format_specs<Char> specs;
specs.align = align::right;
// Parse argument index, flags and width.
int arg_index = parse_header(it, end, specs);
if (arg_index == 0) on_error("argument index out of range");
int arg_index = parse_header(it, end, specs, get_arg);
if (arg_index == 0) parse_ctx.on_error("argument not found");
// Parse precision.
if (it != end && *it == '.') {
++it;
c = it != end ? *it : 0;
if ('0' <= c && c <= '9') {
internal::error_handler eh;
specs.precision = parse_nonnegative_int(it, end, eh);
specs.precision = parse_nonnegative_int(it, end, 0);
} else if (c == '*') {
++it;
specs.precision = static_cast<int>(
visit_format_arg(internal::printf_precision_handler(), get_arg()));
visit_format_arg(detail::printf_precision_handler(), get_arg(-1)));
} else {
specs.precision = 0;
}
}
format_arg arg = get_arg(arg_index);
if (specs.alt && visit_format_arg(internal::is_zero_int(), arg))
auto arg = get_arg(arg_index);
// For d, i, o, u, x, and X conversion specifiers, if a precision is
// specified, the '0' flag is ignored
if (specs.precision >= 0 && arg.is_integral())
specs.fill[0] =
' '; // Ignore '0' flag for non-numeric types or if '-' present.
if (specs.precision >= 0 && arg.type() == detail::type::cstring_type) {
auto str = visit_format_arg(detail::get_cstring<Char>(), arg);
auto str_end = str + specs.precision;
auto nul = std::find(str, str_end, Char());
arg = detail::make_arg<basic_printf_context<OutputIt, Char>>(
basic_string_view<Char>(
str, detail::to_unsigned(nul != str_end ? nul - str
: specs.precision)));
}
if (specs.alt && visit_format_arg(detail::is_zero_int(), arg))
specs.alt = false;
if (specs.fill[0] == '0') {
if (arg.is_arithmetic())
if (arg.is_arithmetic() && specs.align != align::left)
specs.align = align::numeric;
else
specs.fill[0] = ' '; // Ignore '0' flag for non-numeric types.
specs.fill[0] = ' '; // Ignore '0' flag for non-numeric types or if '-'
// flag is also present.
}
// Parse length and convert the argument to the required type.
c = it != end ? *it++ : 0;
char_type t = it != end ? *it : 0;
using internal::convert_arg;
Char t = it != end ? *it : 0;
using detail::convert_arg;
switch (c) {
case 'h':
if (t == 'h') {
@ -526,7 +475,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
convert_arg<intmax_t>(arg, t);
break;
case 'z':
convert_arg<std::size_t>(arg, t);
convert_arg<size_t>(arg, t);
break;
case 't':
convert_arg<std::ptrdiff_t>(arg, t);
@ -542,33 +491,38 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
// Parse type.
if (it == end) FMT_THROW(format_error("invalid format string"));
specs.type = static_cast<char>(*it++);
char type = static_cast<char>(*it++);
if (arg.is_integral()) {
// Normalize type.
switch (specs.type) {
switch (type) {
case 'i':
case 'u':
specs.type = 'd';
type = 'd';
break;
case 'c':
visit_format_arg(internal::char_converter<basic_printf_context>(arg),
arg);
visit_format_arg(
detail::char_converter<basic_printf_context<OutputIt, Char>>(arg),
arg);
break;
}
}
specs.type = parse_presentation_type(type);
if (specs.type == presentation_type::none)
parse_ctx.on_error("invalid type specifier");
start = it;
// Format argument.
visit_format_arg(ArgFormatter(out, specs, *this), arg);
out = visit_format_arg(
detail::printf_arg_formatter<OutputIt, Char>(out, specs, context), arg);
}
return std::copy(start, it, out);
detail::write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
}
FMT_END_DETAIL_NAMESPACE
template <typename Char>
using basic_printf_context_t =
basic_printf_context<std::back_insert_iterator<internal::buffer<Char>>,
Char>;
basic_printf_context<detail::buffer_appender<Char>, Char>;
using printf_context = basic_printf_context_t<char>;
using wprintf_context = basic_printf_context_t<wchar_t>;
@ -582,9 +536,9 @@ using wprintf_args = basic_format_args<wprintf_context>;
arguments and can be implicitly converted to `~fmt::printf_args`.
\endrst
*/
template <typename... Args>
inline format_arg_store<printf_context, Args...> make_printf_args(
const Args&... args) {
template <typename... T>
inline auto make_printf_args(const T&... args)
-> format_arg_store<printf_context, T...> {
return {args...};
}
@ -594,18 +548,19 @@ inline format_arg_store<printf_context, Args...> make_printf_args(
arguments and can be implicitly converted to `~fmt::wprintf_args`.
\endrst
*/
template <typename... Args>
inline format_arg_store<wprintf_context, Args...> make_wprintf_args(
const Args&... args) {
template <typename... T>
inline auto make_wprintf_args(const T&... args)
-> format_arg_store<wprintf_context, T...> {
return {args...};
}
template <typename S, typename Char = char_t<S>>
inline std::basic_string<Char> vsprintf(
const S& format,
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
inline auto vsprintf(
const S& fmt,
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
-> std::basic_string<Char> {
basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args);
vprintf(buffer, detail::to_string_view(fmt), args);
return to_string(buffer);
}
@ -618,20 +573,22 @@ inline std::basic_string<Char> vsprintf(
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
*/
template <typename S, typename... Args,
typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
inline std::basic_string<Char> sprintf(const S& format, const Args&... args) {
template <typename S, typename... T,
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
using context = basic_printf_context_t<Char>;
return vsprintf(to_string_view(format), make_format_args<context>(args...));
return vsprintf(detail::to_string_view(fmt),
fmt::make_format_args<context>(args...));
}
template <typename S, typename Char = char_t<S>>
inline int vfprintf(
std::FILE* f, const S& format,
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
inline auto vfprintf(
std::FILE* f, const S& fmt,
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
-> int {
basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args);
std::size_t size = buffer.size();
vprintf(buffer, detail::to_string_view(fmt), args);
size_t size = buffer.size();
return std::fwrite(buffer.data(), sizeof(Char), size, f) < size
? -1
: static_cast<int>(size);
@ -646,19 +603,19 @@ inline int vfprintf(
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
template <typename S, typename... Args,
typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
inline int fprintf(std::FILE* f, const S& format, const Args&... args) {
template <typename S, typename... T, typename Char = char_t<S>>
inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int {
using context = basic_printf_context_t<Char>;
return vfprintf(f, to_string_view(format),
make_format_args<context>(args...));
return vfprintf(f, detail::to_string_view(fmt),
fmt::make_format_args<context>(args...));
}
template <typename S, typename Char = char_t<S>>
inline int vprintf(
const S& format,
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
return vfprintf(stdout, to_string_view(format), args);
inline auto vprintf(
const S& fmt,
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
-> int {
return vfprintf(stdout, detail::to_string_view(fmt), args);
}
/**
@ -670,52 +627,14 @@ inline int vprintf(
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
template <typename S, typename... Args,
FMT_ENABLE_IF(internal::is_string<S>::value)>
inline int printf(const S& format_str, const Args&... args) {
using context = basic_printf_context_t<char_t<S>>;
return vprintf(to_string_view(format_str),
make_format_args<context>(args...));
template <typename S, typename... T, FMT_ENABLE_IF(detail::is_string<S>::value)>
inline auto printf(const S& fmt, const T&... args) -> int {
return vprintf(
detail::to_string_view(fmt),
fmt::make_format_args<basic_printf_context_t<char_t<S>>>(args...));
}
template <typename S, typename Char = char_t<S>>
inline int vfprintf(
std::basic_ostream<Char>& os, const S& format,
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args);
internal::write(os, buffer);
return static_cast<int>(buffer.size());
}
/** Formats arguments and writes the output to the range. */
template <typename ArgFormatter, typename Char,
typename Context =
basic_printf_context<typename ArgFormatter::iterator, Char>>
typename ArgFormatter::iterator vprintf(
internal::buffer<Char>& out, basic_string_view<Char> format_str,
basic_format_args<type_identity_t<Context>> args) {
typename ArgFormatter::iterator iter(out);
Context(iter, format_str, args).template format<ArgFormatter>();
return iter;
}
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fmt::fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
template <typename S, typename... Args, typename Char = char_t<S>>
inline int fprintf(std::basic_ostream<Char>& os, const S& format_str,
const Args&... args) {
using context = basic_printf_context_t<Char>;
return vfprintf(os, to_string_view(format_str),
make_format_args<context>(args...));
}
FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
#endif // FMT_PRINTF_H_

View File

@ -13,48 +13,14 @@
#define FMT_RANGES_H_
#include <initializer_list>
#include <tuple>
#include <type_traits>
#include "format.h"
// output only up to N items from the range.
#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT
# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256
#endif
FMT_BEGIN_NAMESPACE
template <typename Char> struct formatting_base {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
};
template <typename Char, typename Enable = void>
struct formatting_range : formatting_base<Char> {
static FMT_CONSTEXPR_DECL const std::size_t range_length_limit =
FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the
// range.
Char prefix;
Char delimiter;
Char postfix;
formatting_range() : prefix('{'), delimiter(','), postfix('}') {}
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
};
template <typename Char, typename Enable = void>
struct formatting_tuple : formatting_base<Char> {
Char prefix;
Char delimiter;
Char postfix;
formatting_tuple() : prefix('('), delimiter(','), postfix(')') {}
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
};
namespace internal {
namespace detail {
template <typename RangeT, typename OutputIterator>
OutputIterator copy(const RangeT& range, OutputIterator out) {
@ -75,73 +41,194 @@ OutputIterator copy(char ch, OutputIterator out) {
return out;
}
/// Return true value if T has std::string interface, like std::string_view.
template <typename T> class is_like_std_string {
template <typename OutputIterator>
OutputIterator copy(wchar_t ch, OutputIterator out) {
*out++ = ch;
return out;
}
// Returns true if T has a std::string-like interface, like std::string_view.
template <typename T> class is_std_string_like {
template <typename U>
static auto check(U* p)
-> decltype((void)p->find('a'), p->length(), (void)p->data(), int());
template <typename> static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value =
is_string<T>::value || !std::is_void<decltype(check<T>(nullptr))>::value;
static constexpr const bool value =
is_string<T>::value ||
std::is_convertible<T, std_string_view<char>>::value ||
!std::is_void<decltype(check<T>(nullptr))>::value;
};
template <typename Char>
struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {};
struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
template <typename T> class is_map {
template <typename U> static auto check(U*) -> typename U::mapped_type;
template <typename> static void check(...);
public:
#ifdef FMT_FORMAT_MAP_AS_LIST
static constexpr const bool value = false;
#else
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
#endif
};
template <typename T> class is_set {
template <typename U> static auto check(U*) -> typename U::key_type;
template <typename> static void check(...);
public:
#ifdef FMT_FORMAT_SET_AS_LIST
static constexpr const bool value = false;
#else
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
#endif
};
template <typename... Ts> struct conditional_helper {};
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
#if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800
# define FMT_DECLTYPE_RETURN(val) \
->decltype(val) { return val; } \
static_assert( \
true, "") // This makes it so that a semicolon is required after the
// macro, which helps clang-format handle the formatting.
// C array overload
template <typename T, std::size_t N>
auto range_begin(const T (&arr)[N]) -> const T* {
return arr;
}
template <typename T, std::size_t N>
auto range_end(const T (&arr)[N]) -> const T* {
return arr + N;
}
template <typename T, typename Enable = void>
struct has_member_fn_begin_end_t : std::false_type {};
template <typename T>
struct is_range_<
T, conditional_t<false,
conditional_helper<decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end())>,
void>> : std::true_type {};
struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end())>>
: std::true_type {};
// Member function overload
template <typename T>
auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin());
template <typename T>
auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end());
// ADL overload. Only participates in overload resolution if member functions
// are not found.
template <typename T>
auto range_begin(T&& rng)
-> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
decltype(begin(static_cast<T&&>(rng)))> {
return begin(static_cast<T&&>(rng));
}
template <typename T>
auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
decltype(end(static_cast<T&&>(rng)))> {
return end(static_cast<T&&>(rng));
}
template <typename T, typename Enable = void>
struct has_const_begin_end : std::false_type {};
template <typename T, typename Enable = void>
struct has_mutable_begin_end : std::false_type {};
template <typename T>
struct has_const_begin_end<
T,
void_t<
decltype(detail::range_begin(std::declval<const remove_cvref_t<T>&>())),
decltype(detail::range_end(std::declval<const remove_cvref_t<T>&>()))>>
: std::true_type {};
template <typename T>
struct has_mutable_begin_end<
T, void_t<decltype(detail::range_begin(std::declval<T>())),
decltype(detail::range_end(std::declval<T>())),
enable_if_t<std::is_copy_constructible<T>::value>>>
: std::true_type {};
template <typename T>
struct is_range_<T, void>
: std::integral_constant<bool, (has_const_begin_end<T>::value ||
has_mutable_begin_end<T>::value)> {};
# undef FMT_DECLTYPE_RETURN
#endif
/// tuple_size and tuple_element check.
// tuple_size and tuple_element check.
template <typename T> class is_tuple_like_ {
template <typename U>
static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
template <typename> static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value =
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
};
// Check for integer_sequence
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900
template <typename T, T... N>
using integer_sequence = std::integer_sequence<T, N...>;
template <std::size_t... N> using index_sequence = std::index_sequence<N...>;
template <std::size_t N>
using make_index_sequence = std::make_index_sequence<N>;
template <size_t... N> using index_sequence = std::index_sequence<N...>;
template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
#else
template <typename T, T... N> struct integer_sequence {
using value_type = T;
static FMT_CONSTEXPR std::size_t size() { return sizeof...(N); }
static FMT_CONSTEXPR size_t size() { return sizeof...(N); }
};
template <std::size_t... N>
using index_sequence = integer_sequence<std::size_t, N...>;
template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
template <typename T, std::size_t N, T... Ns>
template <typename T, size_t N, T... Ns>
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
template <typename T, T... Ns>
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
template <std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
template <size_t N>
using make_index_sequence = make_integer_sequence<size_t, N>;
#endif
template <typename T>
using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>;
template <typename T, typename C, bool = is_tuple_like_<T>::value>
class is_tuple_formattable_ {
public:
static constexpr const bool value = false;
};
template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
template <std::size_t... I>
static std::true_type check2(index_sequence<I...>,
integer_sequence<bool, (I == I)...>);
static std::false_type check2(...);
template <std::size_t... I>
static decltype(check2(
index_sequence<I...>{},
integer_sequence<
bool, (is_formattable<typename std::tuple_element<I, T>::type,
C>::value)...>{})) check(index_sequence<I...>);
public:
static constexpr const bool value =
decltype(check(tuple_index_sequence<T>{}))::value;
};
template <class Tuple, class F, size_t... Is>
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT {
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) noexcept {
using std::get;
// using free function get<I>(T) now.
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
@ -159,183 +246,344 @@ template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
}
template <typename Arg, FMT_ENABLE_IF(!is_like_std_string<
typename std::decay<Arg>::type>::value)>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
return add_space ? " {}" : "{}";
#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920
// Older MSVC doesn't get the reference type correctly for arrays.
template <typename R> struct range_reference_type_impl {
using type = decltype(*detail::range_begin(std::declval<R&>()));
};
template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> {
using type = T&;
};
template <typename T>
using range_reference_type = typename range_reference_type_impl<T>::type;
#else
template <typename Range>
using range_reference_type =
decltype(*detail::range_begin(std::declval<Range&>()));
#endif
// We don't use the Range's value_type for anything, but we do need the Range's
// reference type, with cv-ref stripped.
template <typename Range>
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
template <typename Range>
using uncvref_first_type = remove_cvref_t<
decltype(std::declval<range_reference_type<Range>>().first)>;
template <typename Range>
using uncvref_second_type = remove_cvref_t<
decltype(std::declval<range_reference_type<Range>>().second)>;
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
*out++ = ',';
*out++ = ' ';
return out;
}
template <typename Arg, FMT_ENABLE_IF(is_like_std_string<
typename std::decay<Arg>::type>::value)>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
return add_space ? " \"{}\"" : "\"{}\"";
template <typename Char, typename OutputIt>
auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt {
return write_escaped_string(out, str);
}
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) {
return add_space ? " \"{}\"" : "\"{}\"";
}
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) {
return add_space ? L" \"{}\"" : L"\"{}\"";
template <typename Char, typename OutputIt, typename T,
FMT_ENABLE_IF(std::is_convertible<T, std_string_view<char>>::value)>
inline auto write_range_entry(OutputIt out, const T& str) -> OutputIt {
auto sv = std_string_view<Char>(str);
return write_range_entry<Char>(out, basic_string_view<Char>(sv));
}
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
return add_space ? " '{}'" : "'{}'";
}
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
return add_space ? L" '{}'" : L"'{}'";
template <typename Char, typename OutputIt, typename Arg,
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
OutputIt write_range_entry(OutputIt out, const Arg v) {
return write_escaped_char(out, v);
}
} // namespace internal
template <
typename Char, typename OutputIt, typename Arg,
FMT_ENABLE_IF(!is_std_string_like<typename std::decay<Arg>::type>::value &&
!std::is_same<Arg, Char>::value)>
OutputIt write_range_entry(OutputIt out, const Arg& v) {
return write<Char>(out, v);
}
} // namespace detail
template <typename T> struct is_tuple_like {
static FMT_CONSTEXPR_DECL const bool value =
internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value;
static constexpr const bool value =
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
};
template <typename T, typename C> struct is_tuple_formattable {
static constexpr const bool value =
detail::is_tuple_formattable_<T, C>::value;
};
template <typename TupleT, typename Char>
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
struct formatter<TupleT, Char,
enable_if_t<fmt::is_tuple_like<TupleT>::value &&
fmt::is_tuple_formattable<TupleT, Char>::value>> {
private:
// C++11 generic lambda for format()
// C++11 generic lambda for format().
template <typename FormatContext> struct format_each {
template <typename T> void operator()(const T& v) {
if (i > 0) {
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
out = internal::copy(formatting.delimiter, out);
}
out = format_to(out,
internal::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), v),
v);
if (i > 0) out = detail::write_delimiter(out);
out = detail::write_range_entry<Char>(out, v);
++i;
}
formatting_tuple<Char>& formatting;
std::size_t& i;
typename std::add_lvalue_reference<decltype(
std::declval<FormatContext>().out())>::type out;
int i;
typename FormatContext::iterator& out;
};
public:
formatting_tuple<Char> formatting;
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return formatting.parse(ctx);
}
template <typename FormatContext = format_context>
auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) {
auto out = ctx.out();
std::size_t i = 0;
internal::copy(formatting.prefix, out);
internal::for_each(values, format_each<FormatContext>{formatting, i, out});
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
internal::copy(formatting.postfix, out);
return ctx.out();
}
};
template <typename T, typename Char> struct is_range {
static FMT_CONSTEXPR_DECL const bool value =
internal::is_range_<T>::value &&
!internal::is_like_std_string<T>::value &&
!std::is_convertible<T, std::basic_string<Char>>::value &&
!std::is_constructible<internal::std_string_view<Char>, T>::value;
};
template <typename RangeT, typename Char>
struct formatter<RangeT, Char,
enable_if_t<fmt::is_range<RangeT, Char>::value>> {
formatting_range<Char> formatting;
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return formatting.parse(ctx);
}
template <typename FormatContext>
typename FormatContext::iterator format(const RangeT& values,
FormatContext& ctx) {
auto out = internal::copy(formatting.prefix, ctx.out());
std::size_t i = 0;
for (auto it = values.begin(), end = values.end(); it != end; ++it) {
if (i > 0) {
if (formatting.add_prepostfix_space) *out++ = ' ';
out = internal::copy(formatting.delimiter, out);
}
out = format_to(out,
internal::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), *it),
*it);
if (++i > formatting.range_length_limit) {
out = format_to(out, " ... <other elements>");
break;
}
}
if (formatting.add_prepostfix_space) *out++ = ' ';
return internal::copy(formatting.postfix, out);
}
};
template <typename Char, typename... T> struct tuple_arg_join : internal::view {
const std::tuple<T...>& tuple;
basic_string_view<Char> sep;
tuple_arg_join(const std::tuple<T...>& t, basic_string_view<Char> s)
: tuple{t}, sep{s} {}
};
template <typename Char, typename... T>
struct formatter<tuple_arg_join<Char, T...>, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext = format_context>
auto format(const TupleT& values, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
*out++ = '(';
detail::for_each(values, format_each<FormatContext>{0, out});
*out++ = ')';
return out;
}
};
template <typename T, typename Char> struct is_range {
static constexpr const bool value =
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
!detail::is_map<T>::value &&
!std::is_convertible<T, std::basic_string<Char>>::value &&
!std::is_constructible<detail::std_string_view<Char>, T>::value;
};
namespace detail {
template <typename Context> struct range_mapper {
using mapper = arg_mapper<Context>;
template <typename T,
FMT_ENABLE_IF(has_formatter<remove_cvref_t<T>, Context>::value)>
static auto map(T&& value) -> T&& {
return static_cast<T&&>(value);
}
template <typename T,
FMT_ENABLE_IF(!has_formatter<remove_cvref_t<T>, Context>::value)>
static auto map(T&& value)
-> decltype(mapper().map(static_cast<T&&>(value))) {
return mapper().map(static_cast<T&&>(value));
}
};
template <typename Char, typename Element>
using range_formatter_type = conditional_t<
is_formattable<Element, Char>::value,
formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
std::declval<Element>()))>,
Char>,
fallback_formatter<Element, Char>>;
template <typename R>
using maybe_const_range =
conditional_t<has_const_begin_end<R>::value, const R, R>;
} // namespace detail
template <typename R, typename Char>
struct formatter<
R, Char,
enable_if_t<
conjunction<fmt::is_range<R, Char>
// Workaround a bug in MSVC 2017 and earlier.
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1920
,
disjunction<
is_formattable<detail::uncvref_type<detail::maybe_const_range<R>>,
Char>,
detail::has_fallback_formatter<
detail::uncvref_type<detail::maybe_const_range<R>>, Char>
>
#endif
>::value
>> {
using range_type = detail::maybe_const_range<R>;
using formatter_type =
detail::range_formatter_type<Char, detail::uncvref_type<range_type>>;
formatter_type underlying_;
bool custom_specs_ = false;
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
auto it = ctx.begin();
auto end = ctx.end();
if (it == end || *it == '}') return it;
if (*it != ':')
FMT_THROW(format_error("no top-level range formatters supported"));
custom_specs_ = true;
++it;
ctx.advance_to(it);
return underlying_.parse(ctx);
}
template <typename FormatContext>
typename FormatContext::iterator format(
const tuple_arg_join<Char, T...>& value, FormatContext& ctx) {
return format(value, ctx, internal::make_index_sequence<sizeof...(T)>{});
auto format(range_type& range, FormatContext& ctx) const
-> decltype(ctx.out()) {
Char prefix = detail::is_set<R>::value ? '{' : '[';
Char postfix = detail::is_set<R>::value ? '}' : ']';
detail::range_mapper<buffer_context<Char>> mapper;
auto out = ctx.out();
*out++ = prefix;
int i = 0;
auto it = detail::range_begin(range);
auto end = detail::range_end(range);
for (; it != end; ++it) {
if (i > 0) out = detail::write_delimiter(out);
if (custom_specs_) {
ctx.advance_to(out);
out = underlying_.format(mapper.map(*it), ctx);
} else {
out = detail::write_range_entry<Char>(out, *it);
}
++i;
}
*out++ = postfix;
return out;
}
};
template <typename T, typename Char>
struct formatter<
T, Char,
enable_if_t<conjunction<detail::is_map<T>
// Workaround a bug in MSVC 2017 and earlier.
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1920
,
disjunction<
is_formattable<detail::uncvref_first_type<T>, Char>,
detail::has_fallback_formatter<detail::uncvref_first_type<T>, Char>
>,
disjunction<
is_formattable<detail::uncvref_second_type<T>, Char>,
detail::has_fallback_formatter<detail::uncvref_second_type<T>, Char>
>
#endif
>::value
>> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <
typename FormatContext, typename U,
FMT_ENABLE_IF(
std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
const T, T>>::value)>
auto format(U& map, FormatContext& ctx) const -> decltype(ctx.out()) {
auto out = ctx.out();
*out++ = '{';
int i = 0;
for (const auto& item : map) {
if (i > 0) out = detail::write_delimiter(out);
out = detail::write_range_entry<Char>(out, item.first);
*out++ = ':';
*out++ = ' ';
out = detail::write_range_entry<Char>(out, item.second);
++i;
}
*out++ = '}';
return out;
}
};
template <typename Char, typename... T> struct tuple_join_view : detail::view {
const std::tuple<T...>& tuple;
basic_string_view<Char> sep;
tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s)
: tuple(t), sep{s} {}
};
template <typename Char, typename... T>
using tuple_arg_join = tuple_join_view<Char, T...>;
// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
// support in tuple_join. It is disabled by default because of issues with
// the dynamic width and precision.
#ifndef FMT_TUPLE_JOIN_SPECIFIERS
# define FMT_TUPLE_JOIN_SPECIFIERS 0
#endif
template <typename Char, typename... T>
struct formatter<tuple_join_view<Char, T...>, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>());
}
template <typename FormatContext>
auto format(const tuple_join_view<Char, T...>& value,
FormatContext& ctx) const -> typename FormatContext::iterator {
return do_format(value, ctx,
std::integral_constant<size_t, sizeof...(T)>());
}
private:
template <typename FormatContext, size_t... N>
typename FormatContext::iterator format(
const tuple_arg_join<Char, T...>& value, FormatContext& ctx,
internal::index_sequence<N...>) {
return format_args(value, ctx, std::get<N>(value.tuple)...);
std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_;
template <typename ParseContext>
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
std::integral_constant<size_t, 0>)
-> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename ParseContext, size_t N>
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
std::integral_constant<size_t, N>)
-> decltype(ctx.begin()) {
auto end = ctx.begin();
#if FMT_TUPLE_JOIN_SPECIFIERS
end = std::get<sizeof...(T) - N>(formatters_).parse(ctx);
if (N > 1) {
auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
if (end != end1)
FMT_THROW(format_error("incompatible format specs for tuple elements"));
}
#endif
return end;
}
template <typename FormatContext>
typename FormatContext::iterator format_args(
const tuple_arg_join<Char, T...>&, FormatContext& ctx) {
// NOTE: for compilers that support C++17, this empty function instantiation
// can be replaced with a constexpr branch in the variadic overload.
auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx,
std::integral_constant<size_t, 0>) const ->
typename FormatContext::iterator {
return ctx.out();
}
template <typename FormatContext, typename Arg, typename... Args>
typename FormatContext::iterator format_args(
const tuple_arg_join<Char, T...>& value, FormatContext& ctx,
const Arg& arg, const Args&... args) {
using base = formatter<typename std::decay<Arg>::type, Char>;
auto out = ctx.out();
out = base{}.format(arg, ctx);
if (sizeof...(Args) > 0) {
template <typename FormatContext, size_t N>
auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
std::integral_constant<size_t, N>) const ->
typename FormatContext::iterator {
auto out = std::get<sizeof...(T) - N>(formatters_)
.format(std::get<sizeof...(T) - N>(value.tuple), ctx);
if (N > 1) {
out = std::copy(value.sep.begin(), value.sep.end(), out);
ctx.advance_to(out);
return format_args(value, ctx, args...);
return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
}
return out;
}
};
FMT_MODULE_EXPORT_BEGIN
/**
\rst
Returns an object that formats `tuple` with elements separated by `sep`.
@ -348,14 +596,15 @@ struct formatter<tuple_arg_join<Char, T...>, Char> {
\endrst
*/
template <typename... T>
FMT_CONSTEXPR tuple_arg_join<char, T...> join(const std::tuple<T...>& tuple,
string_view sep) {
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep)
-> tuple_join_view<char, T...> {
return {tuple, sep};
}
template <typename... T>
FMT_CONSTEXPR tuple_arg_join<wchar_t, T...> join(const std::tuple<T...>& tuple,
wstring_view sep) {
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple,
basic_string_view<wchar_t> sep)
-> tuple_join_view<wchar_t, T...> {
return {tuple, sep};
}
@ -371,17 +620,12 @@ FMT_CONSTEXPR tuple_arg_join<wchar_t, T...> join(const std::tuple<T...>& tuple,
\endrst
*/
template <typename T>
arg_join<internal::iterator_t<const std::initializer_list<T>>, char> join(
std::initializer_list<T> list, string_view sep) {
return join(std::begin(list), std::end(list), sep);
}
template <typename T>
arg_join<internal::iterator_t<const std::initializer_list<T>>, wchar_t> join(
std::initializer_list<T> list, wstring_view sep) {
auto join(std::initializer_list<T> list, string_view sep)
-> join_view<const T*, const T*> {
return join(std::begin(list), std::end(list), sep);
}
FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
#endif // FMT_RANGES_H_

176
externals/fmt/include/fmt/std.h vendored Normal file
View File

@ -0,0 +1,176 @@
// Formatting library for C++ - formatters for standard library types
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_STD_H_
#define FMT_STD_H_
#include <thread>
#include <type_traits>
#include <utility>
#include "ostream.h"
#if FMT_HAS_INCLUDE(<version>)
# include <version>
#endif
// Checking FMT_CPLUSPLUS for warning suppression in MSVC.
#if FMT_CPLUSPLUS >= 201703L
# if FMT_HAS_INCLUDE(<filesystem>)
# include <filesystem>
# endif
# if FMT_HAS_INCLUDE(<variant>)
# include <variant>
# endif
#endif
#ifdef __cpp_lib_filesystem
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename Char>
void write_escaped_path(basic_memory_buffer<Char>& quoted,
const std::filesystem::path& p) {
write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
}
# ifdef _WIN32
template <>
inline void write_escaped_path<char>(basic_memory_buffer<char>& quoted,
const std::filesystem::path& p) {
auto s = p.u8string();
write_escaped_string<char>(
std::back_inserter(quoted),
string_view(reinterpret_cast<const char*>(s.c_str()), s.size()));
}
# endif
template <>
inline void write_escaped_path<std::filesystem::path::value_type>(
basic_memory_buffer<std::filesystem::path::value_type>& quoted,
const std::filesystem::path& p) {
write_escaped_string<std::filesystem::path::value_type>(
std::back_inserter(quoted), p.native());
}
} // namespace detail
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1920
// For MSVC 2017 and earlier using the partial specialization
// would cause an ambiguity error, therefore we provide it only
// conditionally.
template <typename Char>
struct formatter<std::filesystem::path, Char>
: formatter<basic_string_view<Char>> {
template <typename FormatContext>
auto format(const std::filesystem::path& p, FormatContext& ctx) const ->
typename FormatContext::iterator {
basic_memory_buffer<Char> quoted;
detail::write_escaped_path(quoted, p);
return formatter<basic_string_view<Char>>::format(
basic_string_view<Char>(quoted.data(), quoted.size()), ctx);
}
};
#endif
FMT_END_NAMESPACE
#endif
FMT_BEGIN_NAMESPACE
template <typename Char>
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
FMT_END_NAMESPACE
#ifdef __cpp_lib_variant
FMT_BEGIN_NAMESPACE
template <typename Char> struct formatter<std::monostate, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const std::monostate&, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::write<Char>(out, "monostate");
return out;
}
};
namespace detail {
template <typename T>
using variant_index_sequence =
std::make_index_sequence<std::variant_size<T>::value>;
// variant_size and variant_alternative check.
template <typename T, typename U = void>
struct is_variant_like_ : std::false_type {};
template <typename T>
struct is_variant_like_<T, std::void_t<decltype(std::variant_size<T>::value)>>
: std::true_type {};
// formattable element check
template <typename T, typename C> class is_variant_formattable_ {
template <std::size_t... I>
static std::conjunction<
is_formattable<std::variant_alternative_t<I, T>, C>...>
check(std::index_sequence<I...>);
public:
static constexpr const bool value =
decltype(check(variant_index_sequence<T>{}))::value;
};
template <typename Char, typename OutputIt, typename T>
auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt {
if constexpr (is_string<T>::value)
return write_escaped_string<Char>(out, detail::to_string_view(v));
else if constexpr (std::is_same_v<T, Char>)
return write_escaped_char(out, v);
else
return write<Char>(out, v);
}
} // namespace detail
template <typename T> struct is_variant_like {
static constexpr const bool value = detail::is_variant_like_<T>::value;
};
template <typename T, typename C> struct is_variant_formattable {
static constexpr const bool value =
detail::is_variant_formattable_<T, C>::value;
};
template <typename Variant, typename Char>
struct formatter<
Variant, Char,
std::enable_if_t<std::conjunction_v<
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const Variant& value, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::write<Char>(out, "variant(");
std::visit(
[&](const auto& v) {
out = detail::write_variant_alternative<Char>(out, v);
},
value);
*out++ = ')';
return out;
}
};
FMT_END_NAMESPACE
#endif
#endif // FMT_STD_H_

232
externals/fmt/include/fmt/xchar.h vendored Normal file
View File

@ -0,0 +1,232 @@
// Formatting library for C++ - optional wchar_t and exotic character support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_XCHAR_H_
#define FMT_XCHAR_H_
#include <cwchar>
#include <tuple>
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename T>
using is_exotic_char = bool_constant<!std::is_same<T, char>::value>;
}
FMT_MODULE_EXPORT_BEGIN
using wstring_view = basic_string_view<wchar_t>;
using wformat_parse_context = basic_format_parse_context<wchar_t>;
using wformat_context = buffer_context<wchar_t>;
using wformat_args = basic_format_args<wformat_context>;
using wmemory_buffer = basic_memory_buffer<wchar_t>;
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround broken conversion on older gcc.
template <typename... Args> using wformat_string = wstring_view;
#else
template <typename... Args>
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
#endif
template <> struct is_char<wchar_t> : std::true_type {};
template <> struct is_char<detail::char8_type> : std::true_type {};
template <> struct is_char<char16_t> : std::true_type {};
template <> struct is_char<char32_t> : std::true_type {};
template <typename... Args>
constexpr format_arg_store<wformat_context, Args...> make_wformat_args(
const Args&... args) {
return {args...};
}
inline namespace literals {
#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS
constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) {
return {s};
}
#endif
} // namespace literals
template <typename It, typename Sentinel>
auto join(It begin, Sentinel end, wstring_view sep)
-> join_view<It, Sentinel, wchar_t> {
return {begin, end, sep};
}
template <typename Range>
auto join(Range&& range, wstring_view sep)
-> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>,
wchar_t> {
return join(std::begin(range), std::end(range), sep);
}
template <typename T>
auto join(std::initializer_list<T> list, wstring_view sep)
-> join_view<const T*, const T*, wchar_t> {
return join(std::begin(list), std::end(list), sep);
}
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
auto vformat(basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> std::basic_string<Char> {
basic_memory_buffer<Char> buffer;
detail::vformat_to(buffer, format_str, args);
return to_string(buffer);
}
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 409
template <typename... Args>
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
#endif
template <typename... T>
auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring {
return vformat(fmt, fmt::make_wformat_args(args...));
}
// Pass char_t as a default template parameter instead of using
// std::basic_string<char_t<S>> to reduce the symbol size.
template <typename S, typename... Args, typename Char = char_t<S>,
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
return vformat(detail::to_string_view(format_str),
fmt::make_format_args<buffer_context<Char>>(args...));
}
template <typename Locale, typename S, typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat(
const Locale& loc, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> std::basic_string<Char> {
return detail::vformat(loc, detail::to_string_view(format_str), args);
}
template <typename Locale, typename S, typename... Args,
typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto format(const Locale& loc, const S& format_str, Args&&... args)
-> std::basic_string<Char> {
return detail::vformat(loc, detail::to_string_view(format_str),
fmt::make_format_args<buffer_context<Char>>(args...));
}
template <typename OutputIt, typename S, typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
auto vformat_to(OutputIt out, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> OutputIt {
auto&& buf = detail::get_buffer<Char>(out);
detail::vformat_to(buf, detail::to_string_view(format_str), args);
return detail::get_iterator(buf);
}
template <typename OutputIt, typename S, typename... Args,
typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt {
return vformat_to(out, detail::to_string_view(fmt),
fmt::make_format_args<buffer_context<Char>>(args...));
}
template <typename Locale, typename S, typename OutputIt, typename... Args,
typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat_to(
OutputIt out, const Locale& loc, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt {
auto&& buf = detail::get_buffer<Char>(out);
vformat_to(buf, detail::to_string_view(format_str), args,
detail::locale_ref(loc));
return detail::get_iterator(buf);
}
template <
typename OutputIt, typename Locale, typename S, typename... Args,
typename Char = char_t<S>,
bool enable = detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_locale<Locale>::value&& detail::is_exotic_char<Char>::value>
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
Args&&... args) ->
typename std::enable_if<enable, OutputIt>::type {
return vformat_to(out, loc, to_string_view(format_str),
fmt::make_format_args<buffer_context<Char>>(args...));
}
template <typename OutputIt, typename Char, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat_to_n(
OutputIt out, size_t n, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> format_to_n_result<OutputIt> {
detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out,
n);
detail::vformat_to(buf, format_str, args);
return {buf.out(), buf.count()};
}
template <typename OutputIt, typename S, typename... Args,
typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
inline auto format_to_n(OutputIt out, size_t n, const S& fmt,
const Args&... args) -> format_to_n_result<OutputIt> {
return vformat_to_n(out, n, detail::to_string_view(fmt),
fmt::make_format_args<buffer_context<Char>>(args...));
}
template <typename S, typename... Args, typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
inline auto formatted_size(const S& fmt, Args&&... args) -> size_t {
detail::counting_buffer<Char> buf;
detail::vformat_to(buf, detail::to_string_view(fmt),
fmt::make_format_args<buffer_context<Char>>(args...));
return buf.count();
}
inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
wmemory_buffer buffer;
detail::vformat_to(buffer, fmt, args);
buffer.push_back(L'\0');
if (std::fputws(buffer.data(), f) == -1)
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
}
inline void vprint(wstring_view fmt, wformat_args args) {
vprint(stdout, fmt, args);
}
template <typename... T>
void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...));
}
template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
return vprint(wstring_view(fmt), fmt::make_wformat_args(args...));
}
/**
Converts *value* to ``std::wstring`` using the default format for type *T*.
*/
template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
return format(FMT_STRING(L"{}"), value);
}
FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
#endif // FMT_XCHAR_H_

99
externals/fmt/src/fmt.cc vendored Normal file
View File

@ -0,0 +1,99 @@
module;
#ifndef __cpp_modules
# error Module not supported.
#endif
// put all implementation-provided headers into the global module fragment
// to prevent attachment to this module
#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
# define _CRT_SECURE_NO_WARNINGS
#endif
#if !defined(WIN32_LEAN_AND_MEAN) && defined(_WIN32)
# define WIN32_LEAN_AND_MEAN
#endif
#include <algorithm>
#include <cctype>
#include <cerrno>
#include <chrono>
#include <climits>
#include <clocale>
#include <cmath>
#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cwchar>
#include <exception>
#include <functional>
#include <iterator>
#include <limits>
#include <locale>
#include <memory>
#include <ostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <system_error>
#include <type_traits>
#include <utility>
#include <vector>
#if _MSC_VER
# include <intrin.h>
#endif
#if defined __APPLE__ || defined(__FreeBSD__)
# include <xlocale.h>
#endif
#if __has_include(<winapifamily.h>)
# include <winapifamily.h>
#endif
#if (__has_include(<fcntl.h>) || defined(__APPLE__) || \
defined(__linux__)) && \
(!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
# include <fcntl.h>
# include <sys/stat.h>
# include <sys/types.h>
# ifndef _WIN32
# include <unistd.h>
# else
# include <io.h>
# endif
#endif
#ifdef _WIN32
# include <windows.h>
#endif
export module fmt;
#define FMT_MODULE_EXPORT export
#define FMT_MODULE_EXPORT_BEGIN export {
#define FMT_MODULE_EXPORT_END }
#define FMT_BEGIN_DETAIL_NAMESPACE \
} \
namespace detail {
#define FMT_END_DETAIL_NAMESPACE \
} \
export {
// all library-provided declarations and definitions
// must be in the module purview to be exported
#include "fmt/args.h"
#include "fmt/chrono.h"
#include "fmt/color.h"
#include "fmt/compile.h"
#include "fmt/format.h"
#include "fmt/os.h"
#include "fmt/printf.h"
#include "fmt/xchar.h"
// gcc doesn't yet implement private module fragments
#if !FMT_GCC_VERSION
module : private;
#endif
#include "format.cc"
#include "os.cc"

View File

@ -8,169 +8,40 @@
#include "fmt/format-inl.h"
FMT_BEGIN_NAMESPACE
namespace internal {
namespace detail {
template <typename T>
int format_float(char* buf, std::size_t size, const char* format, int precision,
T value) {
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if (precision > 100000)
throw std::runtime_error(
"fuzz mode - avoid large allocation inside snprintf");
#endif
// Suppress the warning about nonliteral format string.
int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF;
return precision < 0 ? snprintf_ptr(buf, size, format, value)
: snprintf_ptr(buf, size, format, precision, value);
}
struct sprintf_specs {
int precision;
char type;
bool alt : 1;
template <typename Char>
constexpr sprintf_specs(basic_format_specs<Char> specs)
: precision(specs.precision), type(specs.type), alt(specs.alt) {}
constexpr bool has_precision() const { return precision >= 0; }
};
// This is deprecated and is kept only to preserve ABI compatibility.
template <typename Double>
char* sprintf_format(Double value, internal::buffer<char>& buf,
sprintf_specs specs) {
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
FMT_ASSERT(buf.capacity() != 0, "empty buffer");
// Build format string.
enum { max_format_size = 10 }; // longest format: %#-*.*Lg
char format[max_format_size];
char* format_ptr = format;
*format_ptr++ = '%';
if (specs.alt || !specs.type) *format_ptr++ = '#';
if (specs.precision >= 0) {
*format_ptr++ = '.';
*format_ptr++ = '*';
}
if (std::is_same<Double, long double>::value) *format_ptr++ = 'L';
char type = specs.type;
if (type == '%')
type = 'f';
else if (type == 0 || type == 'n')
type = 'g';
#if FMT_MSC_VER
if (type == 'F') {
// MSVC's printf doesn't support 'F'.
type = 'f';
}
#endif
*format_ptr++ = type;
*format_ptr = '\0';
// Format using snprintf.
char* start = nullptr;
char* decimal_point_pos = nullptr;
for (;;) {
std::size_t buffer_size = buf.capacity();
start = &buf[0];
int result =
format_float(start, buffer_size, format, specs.precision, value);
if (result >= 0) {
unsigned n = internal::to_unsigned(result);
if (n < buf.capacity()) {
// Find the decimal point.
auto p = buf.data(), end = p + n;
if (*p == '+' || *p == '-') ++p;
if (specs.type != 'a' && specs.type != 'A') {
while (p < end && *p >= '0' && *p <= '9') ++p;
if (p < end && *p != 'e' && *p != 'E') {
decimal_point_pos = p;
if (!specs.type) {
// Keep only one trailing zero after the decimal point.
++p;
if (*p == '0') ++p;
while (p != end && *p >= '1' && *p <= '9') ++p;
char* where = p;
while (p != end && *p == '0') ++p;
if (p == end || *p < '0' || *p > '9') {
if (p != end) std::memmove(where, p, to_unsigned(end - p));
n -= static_cast<unsigned>(p - where);
}
}
}
}
buf.resize(n);
break; // The buffer is large enough - continue with formatting.
}
buf.reserve(n + 1);
} else {
// If result is negative we ask to increase the capacity by at least 1,
// but as std::vector, the buffer grows exponentially.
buf.reserve(buf.capacity() + 1);
}
}
return decimal_point_pos;
}
} // namespace internal
template FMT_API char* internal::sprintf_format(double, internal::buffer<char>&,
sprintf_specs);
template FMT_API char* internal::sprintf_format(long double,
internal::buffer<char>&,
sprintf_specs);
template struct FMT_INSTANTIATION_DEF_API internal::basic_data<void>;
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
int (*instantiate_format_float)(double, int, internal::float_specs,
internal::buffer<char>&) =
internal::format_float;
template FMT_API auto dragonbox::to_decimal(float x) noexcept
-> dragonbox::decimal_fp<float>;
template FMT_API auto dragonbox::to_decimal(double x) noexcept
-> dragonbox::decimal_fp<double>;
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
template FMT_API internal::locale_ref::locale_ref(const std::locale& loc);
template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
template FMT_API locale_ref::locale_ref(const std::locale& loc);
template FMT_API auto locale_ref::get<std::locale>() const -> std::locale;
#endif
// Explicit instantiations for char.
template FMT_API std::string internal::grouping_impl<char>(locale_ref);
template FMT_API char internal::thousands_sep_impl(locale_ref);
template FMT_API char internal::decimal_point_impl(locale_ref);
template FMT_API auto thousands_sep_impl(locale_ref)
-> thousands_sep_result<char>;
template FMT_API auto decimal_point_impl(locale_ref) -> char;
template FMT_API void internal::buffer<char>::append(const char*, const char*);
template FMT_API void buffer<char>::append(const char*, const char*);
template FMT_API void internal::arg_map<format_context>::init(
const basic_format_args<format_context>& args);
template FMT_API std::string internal::vformat<char>(
string_view, basic_format_args<format_context>);
template FMT_API format_context::iterator internal::vformat_to(
internal::buffer<char>&, string_view, basic_format_args<format_context>);
template FMT_API int internal::snprintf_float(double, int,
internal::float_specs,
internal::buffer<char>&);
template FMT_API int internal::snprintf_float(long double, int,
internal::float_specs,
internal::buffer<char>&);
template FMT_API int internal::format_float(double, int, internal::float_specs,
internal::buffer<char>&);
template FMT_API int internal::format_float(long double, int,
internal::float_specs,
internal::buffer<char>&);
// DEPRECATED!
// There is no correspondent extern template in format.h because of
// incompatibility between clang and gcc (#2377).
template FMT_API void vformat_to(buffer<char>&, string_view,
basic_format_args<FMT_BUFFER_CONTEXT(char)>,
locale_ref);
// Explicit instantiations for wchar_t.
template FMT_API std::string internal::grouping_impl<wchar_t>(locale_ref);
template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
template FMT_API wchar_t internal::decimal_point_impl(locale_ref);
template FMT_API auto thousands_sep_impl(locale_ref)
-> thousands_sep_result<wchar_t>;
template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
template FMT_API void internal::buffer<wchar_t>::append(const wchar_t*,
const wchar_t*);
template FMT_API void buffer<wchar_t>::append(const wchar_t*, const wchar_t*);
template FMT_API std::wstring internal::vformat<wchar_t>(
wstring_view, basic_format_args<wformat_context>);
} // namespace detail
FMT_END_NAMESPACE

View File

@ -25,21 +25,24 @@
# define WIN32_LEAN_AND_MEAN
# endif
# include <io.h>
# include <windows.h>
# define O_CREAT _O_CREAT
# define O_TRUNC _O_TRUNC
# ifndef S_IRUSR
# define S_IRUSR _S_IREAD
# endif
# ifndef S_IWUSR
# define S_IWUSR _S_IWRITE
# endif
# ifdef __MINGW32__
# define _SH_DENYNO 0x40
# ifndef S_IRGRP
# define S_IRGRP 0
# endif
# ifndef S_IWGRP
# define S_IWGRP 0
# endif
# ifndef S_IROTH
# define S_IROTH 0
# endif
# ifndef S_IWOTH
# define S_IWOTH 0
# endif
# endif // _WIN32
#endif // FMT_USE_FCNTL
@ -48,23 +51,19 @@
# include <windows.h>
#endif
#ifdef fileno
# undef fileno
#endif
namespace {
#ifdef _WIN32
// Return type of read and write functions.
using RWResult = int;
using rwresult = int;
// On Windows the count argument to read and write is unsigned, so convert
// it from size_t preventing integer overflow.
inline unsigned convert_rwcount(std::size_t count) {
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
}
#else
#elif FMT_USE_FCNTL
// Return type of read and write functions.
using RWResult = ssize_t;
using rwresult = ssize_t;
inline std::size_t convert_rwcount(std::size_t count) { return count; }
#endif
@ -73,14 +72,14 @@ inline std::size_t convert_rwcount(std::size_t count) { return count; }
FMT_BEGIN_NAMESPACE
#ifdef _WIN32
internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
detail::utf16_to_utf8::utf16_to_utf8(basic_string_view<wchar_t> s) {
if (int error_code = convert(s)) {
FMT_THROW(windows_error(error_code,
"cannot convert string from UTF-16 to UTF-8"));
}
}
int internal::utf16_to_utf8::convert(wstring_view s) {
int detail::utf16_to_utf8::convert(basic_string_view<wchar_t> s) {
if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER;
int s_size = static_cast<int>(s.size());
if (s_size == 0) {
@ -101,53 +100,90 @@ int internal::utf16_to_utf8::convert(wstring_view s) {
return 0;
}
void windows_error::init(int err_code, string_view format_str,
format_args args) {
error_code_ = err_code;
memory_buffer buffer;
internal::format_windows_error(buffer, err_code, vformat(format_str, args));
std::runtime_error& base = *this;
base = std::runtime_error(to_string(buffer));
namespace detail {
class system_message {
system_message(const system_message&) = delete;
void operator=(const system_message&) = delete;
unsigned long result_;
wchar_t* message_;
static bool is_whitespace(wchar_t c) noexcept {
return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0';
}
public:
explicit system_message(unsigned long error_code)
: result_(0), message_(nullptr) {
result_ = FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<wchar_t*>(&message_), 0, nullptr);
if (result_ != 0) {
while (result_ != 0 && is_whitespace(message_[result_ - 1])) {
--result_;
}
}
}
~system_message() { LocalFree(message_); }
explicit operator bool() const noexcept { return result_ != 0; }
operator basic_string_view<wchar_t>() const noexcept {
return basic_string_view<wchar_t>(message_, result_);
}
};
class utf8_system_category final : public std::error_category {
public:
const char* name() const noexcept override { return "system"; }
std::string message(int error_code) const override {
system_message msg(error_code);
if (msg) {
utf16_to_utf8 utf8_message;
if (utf8_message.convert(msg) == ERROR_SUCCESS) {
return utf8_message.str();
}
}
return "unknown error";
}
};
} // namespace detail
FMT_API const std::error_category& system_category() noexcept {
static const detail::utf8_system_category category;
return category;
}
void internal::format_windows_error(internal::buffer<char>& out, int error_code,
string_view message) FMT_NOEXCEPT {
std::system_error vwindows_error(int err_code, string_view format_str,
format_args args) {
auto ec = std::error_code(err_code, system_category());
return std::system_error(ec, vformat(format_str, args));
}
void detail::format_windows_error(detail::buffer<char>& out, int error_code,
const char* message) noexcept {
FMT_TRY {
wmemory_buffer buf;
buf.resize(inline_buffer_size);
for (;;) {
wchar_t* system_message = &buf[0];
int result = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message,
static_cast<uint32_t>(buf.size()), nullptr);
if (result != 0) {
utf16_to_utf8 utf8_message;
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
internal::writer w(out);
w.write(message);
w.write(": ");
w.write(utf8_message);
return;
}
break;
system_message msg(error_code);
if (msg) {
utf16_to_utf8 utf8_message;
if (utf8_message.convert(msg) == ERROR_SUCCESS) {
fmt::format_to(buffer_appender<char>(out), "{}: {}", message, utf8_message);
return;
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break; // Can't get error message, report error code instead.
buf.resize(buf.size() * 2);
}
}
FMT_CATCH(...) {}
format_error_code(out, error_code, message);
}
void report_windows_error(int error_code,
fmt::string_view message) FMT_NOEXCEPT {
report_error(internal::format_windows_error, error_code, message);
void report_windows_error(int error_code, const char* message) noexcept {
report_error(detail::format_windows_error, error_code, message);
}
#endif // _WIN32
buffered_file::~buffered_file() FMT_NOEXCEPT {
buffered_file::~buffered_file() noexcept {
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
report_system_error(errno, "cannot close file");
}
@ -166,18 +202,19 @@ void buffered_file::close() {
if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
}
// A macro used to prevent expansion of fileno on broken versions of MinGW.
#define FMT_ARGS
int buffered_file::fileno() const {
int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
int buffered_file::descriptor() const {
int fd = FMT_POSIX_CALL(fileno(file_));
if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor"));
return fd;
}
#if FMT_USE_FCNTL
file::file(cstring_view path, int oflag) {
int mode = S_IRUSR | S_IWUSR;
# ifdef _WIN32
using mode_t = int;
# endif
constexpr mode_t mode =
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
# if defined(_WIN32) && !defined(__MINGW32__)
fd_ = -1;
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
@ -188,7 +225,7 @@ file::file(cstring_view path, int oflag) {
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
}
file::~file() FMT_NOEXCEPT {
file::~file() noexcept {
// Don't retry close in case of EINTR!
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
@ -231,17 +268,17 @@ long long file::size() const {
}
std::size_t file::read(void* buffer, std::size_t count) {
RWResult result = 0;
rwresult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
if (result < 0) FMT_THROW(system_error(errno, "cannot read from file"));
return internal::to_unsigned(result);
return detail::to_unsigned(result);
}
std::size_t file::write(const void* buffer, std::size_t count) {
RWResult result = 0;
rwresult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
if (result < 0) FMT_THROW(system_error(errno, "cannot write to file"));
return internal::to_unsigned(result);
return detail::to_unsigned(result);
}
file file::dup(int fd) {
@ -262,10 +299,10 @@ void file::dup2(int fd) {
}
}
void file::dup2(int fd, error_code& ec) FMT_NOEXCEPT {
void file::dup2(int fd, std::error_code& ec) noexcept {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) ec = error_code(errno);
if (result == -1) ec = std::error_code(errno, std::generic_category());
}
void file::pipe(file& read_end, file& write_end) {
@ -291,8 +328,12 @@ void file::pipe(file& read_end, file& write_end) {
}
buffered_file file::fdopen(const char* mode) {
// Don't retry as fdopen doesn't return EINTR.
// Don't retry as fdopen doesn't return EINTR.
# if defined(__MINGW32__) && defined(_POSIX_)
FILE* f = ::fdopen(fd_, mode);
# else
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
# endif
if (!f)
FMT_THROW(
system_error(errno, "cannot associate stream with file descriptor"));
@ -312,5 +353,9 @@ long getpagesize() {
return size;
# endif
}
FMT_API void ostream::grow(size_t) {
if (this->size() == this->capacity()) flush();
}
#endif // FMT_USE_FCNTL
FMT_END_NAMESPACE

View File

@ -2,5 +2,3 @@ This directory contains build support files such as
* CMake modules
* Build scripts
* qmake (static build with dynamic libc only)

View File

@ -4,6 +4,7 @@
# A vagrant config for testing against gcc-4.8.
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/xenial64"
config.disksize.size = '15GB'
config.vm.provider "virtualbox" do |vb|
vb.memory = "4096"

View File

@ -6,11 +6,8 @@ clone_depth: 1
image:
- Visual Studio 2015
- Visual Studio 2019
- Visual Studio 2017
platform:
- Win32
- x64
environment:
@ -18,13 +15,6 @@ environment:
MSVC_DEFAULT_OPTIONS: ON
BUILD: msvc
matrix:
exclude:
- image: Visual Studio 2015
platform: Win32
- image: Visual Studio 2019
platform: Win32
before_build:
- mkdir build
- cd build

1
externals/fmt/support/bazel/.bazelrc vendored Normal file
View File

@ -0,0 +1 @@
build --symlink_prefix=/ # Out of source build

View File

@ -0,0 +1 @@
5.1.1

28
externals/fmt/support/bazel/BUILD.bazel vendored Normal file
View File

@ -0,0 +1,28 @@
cc_library(
name = "fmt",
srcs = [
#"src/fmt.cc", # No C++ module support
"src/format.cc",
"src/os.cc",
],
hdrs = [
"include/fmt/args.h",
"include/fmt/chrono.h",
"include/fmt/color.h",
"include/fmt/compile.h",
"include/fmt/core.h",
"include/fmt/format-inl.h",
"include/fmt/format.h",
"include/fmt/os.h",
"include/fmt/ostream.h",
"include/fmt/printf.h",
"include/fmt/ranges.h",
"include/fmt/std.h",
"include/fmt/xchar.h",
],
includes = [
"include",
],
strip_include_prefix = "include",
visibility = ["//visibility:public"],
)

73
externals/fmt/support/bazel/README.md vendored Normal file
View File

@ -0,0 +1,73 @@
# Bazel support
To get [Bazel](https://bazel.build/) working with {fmt} you can copy the files `BUILD.bazel`, `WORKSPACE.bazel`, `.bazelrc`, and `.bazelversion` from this folder (`support/bazel`) to the root folder of this project. This way {fmt} gets bazelized and can be used with Bazel (e.g. doing a `bazel build //...` on {fmt}).
## Using {fmt} as a dependency
The following minimal example shows how to use {fmt} as a dependency within a Bazel project.
The following file structure is assumed:
```
example
├── BUILD.bazel
├── main.cpp
└── WORKSPACE.bazel
```
*main.cpp*:
```c++
#include "fmt/core.h"
int main() {
fmt::print("The answer is {}\n", 42);
}
```
The expected output of this example is `The answer is 42`.
*WORKSPACE.bazel*:
```python
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "fmt",
branch = "master",
remote = "https://github.com/fmtlib/fmt",
patch_cmds = [
"mv support/bazel/.bazelrc .bazelrc",
"mv support/bazel/.bazelversion .bazelversion",
"mv support/bazel/BUILD.bazel BUILD.bazel",
"mv support/bazel/WORKSPACE.bazel WORKSPACE.bazel",
],
# Windows-related patch commands are only needed in the case MSYS2 is not installed.
# More details about the installation process of MSYS2 on Windows systems can be found here:
# https://docs.bazel.build/versions/main/install-windows.html#installing-compilers-and-language-runtimes
# Even if MSYS2 is installed the Windows related patch commands can still be used.
patch_cmds_win = [
"Move-Item -Path support/bazel/.bazelrc -Destination .bazelrc",
"Move-Item -Path support/bazel/.bazelversion -Destination .bazelversion",
"Move-Item -Path support/bazel/BUILD.bazel -Destination BUILD.bazel",
"Move-Item -Path support/bazel/WORKSPACE.bazel -Destination WORKSPACE.bazel",
],
)
```
In the *WORKSPACE* file, the {fmt} GitHub repository is fetched. Using the attribute `patch_cmds` the files `BUILD.bazel`, `WORKSPACE.bazel`, `.bazelrc`, and `.bazelversion` are moved to the root of the {fmt} repository. This way the {fmt} repository is recognized as a bazelized workspace.
*BUILD.bazel*:
```python
cc_binary(
name = "Demo",
srcs = ["main.cpp"],
deps = ["@fmt"],
)
```
The *BUILD* file defines a binary named `Demo` that has a dependency to {fmt}.
To execute the binary you can run `bazel run //:Demo`.

View File

@ -0,0 +1 @@
workspace(name = "fmt")

58
externals/fmt/support/build-docs.py vendored Executable file
View File

@ -0,0 +1,58 @@
#!/usr/bin/env python
# Build the documentation in CI.
from __future__ import print_function
import errno, os, shutil, subprocess, sys, urllib
from subprocess import call, check_call, Popen, PIPE, STDOUT
def rmtree_if_exists(dir):
try:
shutil.rmtree(dir)
except OSError as e:
if e.errno == errno.ENOENT:
pass
# Build the docs.
fmt_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.insert(0, os.path.join(fmt_dir, 'doc'))
import build
build.create_build_env()
html_dir = build.build_docs()
repo = 'fmtlib.github.io'
branch = os.environ['GITHUB_REF']
is_ci = 'CI' in os.environ
if is_ci and branch != 'refs/heads/master':
print('Branch: ' + branch)
exit(0) # Ignore non-master branches
if is_ci and 'KEY' not in os.environ:
# Don't update the repo if building in CI from an account that doesn't have
# push access.
print('Skipping update of ' + repo)
exit(0)
# Clone the fmtlib.github.io repo.
rmtree_if_exists(repo)
git_url = 'https://github.com/' if is_ci else 'git@github.com:'
check_call(['git', 'clone', git_url + 'fmtlib/{}.git'.format(repo)])
# Copy docs to the repo.
target_dir = os.path.join(repo, 'dev')
rmtree_if_exists(target_dir)
shutil.copytree(html_dir, target_dir, ignore=shutil.ignore_patterns('.*'))
if is_ci:
check_call(['git', 'config', '--global', 'user.name', 'fmtbot'])
check_call(['git', 'config', '--global', 'user.email', 'viz@fmt.dev'])
# Push docs to GitHub pages.
check_call(['git', 'add', '--all'], cwd=repo)
if call(['git', 'diff-index', '--quiet', 'HEAD'], cwd=repo):
check_call(['git', 'commit', '-m', 'Update documentation'], cwd=repo)
cmd = 'git push'
if is_ci:
cmd += ' https://$KEY@github.com/fmtlib/fmtlib.github.io.git master'
p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=repo)
# Print the output without the key.
print(p.communicate()[0].decode('utf-8').replace(os.environ['KEY'], '$KEY'))
if p.returncode != 0:
raise subprocess.CalledProcessError(p.returncode, cmd)

View File

@ -1,3 +1,4 @@
import java.nio.file.Paths
// General gradle arguments for root project
buildscript {
@ -7,24 +8,25 @@ buildscript {
}
dependencies {
//
// https://developer.android.com/studio/releases/gradle-plugin
// https://developer.android.com/studio/releases/gradle-plugin#updating-gradle
//
// Notice that 3.3.0 here is the version of [Android Gradle Plugin]
// Accroding to URL above you will need Gradle 5.0 or higher
// Notice that 4.0.0 here is the version of [Android Gradle Plugin]
// Accroding to URL above you will need Gradle 6.1 or higher
//
// If you are using Android Studio, and it is using Gradle's lower
// version, Use the plugin version 3.1.3 ~ 3.2.0 for Gradle 4.4 ~ 4.10
classpath 'com.android.tools.build:gradle:3.3.0'
classpath "com.android.tools.build:gradle:4.1.1"
}
}
repositories {
google()
jcenter()
}
// Output: Shared library (.so) for Android
apply plugin: 'com.android.library'
// Project's root where CMakeLists.txt exists: rootDir/support/.cxx -> rootDir
def rootDir = Paths.get(project.buildDir.getParent()).getParent()
println("rootDir: ${rootDir}")
// Output: Shared library (.so) for Android
apply plugin: "com.android.library"
android {
compileSdkVersion 25 // Android 7.0
@ -41,13 +43,13 @@ android {
include "arm64-v8a", "armeabi-v7a", "x86_64"
}
}
ndkVersion "21.3.6528147" // ANDROID_NDK_HOME is deprecated. Be explicit
defaultConfig {
minSdkVersion 21 // Android 5.0+
targetSdkVersion 25 // Follow Compile SDK
versionCode 21 // Follow release count
versionName "5.3.0" // Follow Official version
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
versionCode 34 // Follow release count
versionName "7.1.2" // Follow Official version
externalNativeBuild {
cmake {
@ -56,9 +58,9 @@ android {
arguments "-DFMT_TEST=false" // Skip test
arguments "-DFMT_DOC=false" // Skip document
cppFlags "-std=c++17"
targets "fmt"
}
}
println("Gradle CMake Plugin: ")
println(externalNativeBuild.cmake.cppFlags)
println(externalNativeBuild.cmake.arguments)
}
@ -69,16 +71,27 @@ android {
// neighbor of the top level cmake
externalNativeBuild {
cmake {
path "../CMakeLists.txt"
version "3.10.0+"
path "${rootDir}/CMakeLists.txt"
// buildStagingDirectory "./build" // Custom path for cmake output
}
//println(cmake.path)
}
sourceSets{
// Android Manifest for Gradle
main {
manifest.srcFile 'AndroidManifest.xml'
manifest.srcFile "AndroidManifest.xml"
}
}
// https://developer.android.com/studio/build/native-dependencies#build_system_configuration
buildFeatures {
prefab true
prefabPublishing true
}
prefab {
fmt {
headers "${rootDir}/include"
}
}
}
@ -88,20 +101,32 @@ assemble.doLast
// Instead of `ninja install`, Gradle will deploy the files.
// We are doing this since FMT is dependent to the ANDROID_STL after build
copy {
from 'build/intermediates/cmake'
into '../libs'
from "build/intermediates/cmake"
into "${rootDir}/libs"
}
// Copy debug binaries
copy {
from '../libs/debug/obj'
into '../libs/debug'
from "${rootDir}/libs/debug/obj"
into "${rootDir}/libs/debug"
}
// Copy Release binaries
copy {
from '../libs/release/obj'
into '../libs/release'
from "${rootDir}/libs/release/obj"
into "${rootDir}/libs/release"
}
// Remove empty directory
delete '../libs/debug/obj'
delete '../libs/release/obj'
delete "${rootDir}/libs/debug/obj"
delete "${rootDir}/libs/release/obj"
// Copy AAR files. Notice that the aar is named after the folder of this script.
copy {
from "build/outputs/aar/support-release.aar"
into "${rootDir}/libs"
rename "support-release.aar", "fmt-release.aar"
}
copy {
from "build/outputs/aar/support-debug.aar"
into "${rootDir}/libs"
rename "support-debug.aar", "fmt-debug.aar"
}
}

View File

@ -0,0 +1,26 @@
# This module provides function for joining paths
# known from from most languages
#
# Original license:
# SPDX-License-Identifier: (MIT OR CC0-1.0)
# Explicit permission given to distribute this module under
# the terms of the project as described in /LICENSE.rst.
# Copyright 2020 Jan Tojnar
# https://github.com/jtojnar/cmake-snips
#
# Modelled after Pythons os.path.join
# https://docs.python.org/3.7/library/os.path.html#os.path.join
# Windows not supported
function(join_paths joined_path first_path_segment)
set(temp_path "${first_path_segment}")
foreach(current_segment IN LISTS ARGN)
if(NOT ("${current_segment}" STREQUAL ""))
if(IS_ABSOLUTE "${current_segment}")
set(temp_path "${current_segment}")
else()
set(temp_path "${temp_path}/${current_segment}")
endif()
endif()
endforeach()
set(${joined_path} "${temp_path}" PARENT_SCOPE)
endfunction()

View File

@ -1,7 +1,11 @@
# C++14 feature support detection
include(CheckCXXSourceCompiles)
include(CheckCXXCompilerFlag)
function (fmt_check_cxx_compiler_flag flag result)
if (NOT MSVC)
check_cxx_compiler_flag("${flag}" ${result})
endif ()
endfunction ()
if (NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
@ -9,35 +13,38 @@ endif()
message(STATUS "CXX_STANDARD: ${CMAKE_CXX_STANDARD}")
if (CMAKE_CXX_STANDARD EQUAL 20)
check_cxx_compiler_flag(-std=c++20 has_std_20_flag)
check_cxx_compiler_flag(-std=c++2a has_std_2a_flag)
fmt_check_cxx_compiler_flag(-std=c++20 has_std_20_flag)
fmt_check_cxx_compiler_flag(-std=c++2a has_std_2a_flag)
if (has_std_20_flag)
set(CXX_STANDARD_FLAG -std=c++20)
elseif (has_std_2a_flag)
set(CXX_STANDARD_FLAG -std=c++2a)
endif ()
elseif (CMAKE_CXX_STANDARD EQUAL 17)
check_cxx_compiler_flag(-std=c++17 has_std_17_flag)
check_cxx_compiler_flag(-std=c++1z has_std_1z_flag)
fmt_check_cxx_compiler_flag(-std=c++17 has_std_17_flag)
fmt_check_cxx_compiler_flag(-std=c++1z has_std_1z_flag)
if (has_std_17_flag)
set(CXX_STANDARD_FLAG -std=c++17)
elseif (has_std_1z_flag)
set(CXX_STANDARD_FLAG -std=c++1z)
endif ()
elseif (CMAKE_CXX_STANDARD EQUAL 14)
check_cxx_compiler_flag(-std=c++14 has_std_14_flag)
check_cxx_compiler_flag(-std=c++1y has_std_1y_flag)
fmt_check_cxx_compiler_flag(-std=c++14 has_std_14_flag)
fmt_check_cxx_compiler_flag(-std=c++1y has_std_1y_flag)
if (has_std_14_flag)
set(CXX_STANDARD_FLAG -std=c++14)
elseif (has_std_1y_flag)
set(CXX_STANDARD_FLAG -std=c++1y)
endif ()
elseif (CMAKE_CXX_STANDARD EQUAL 11)
check_cxx_compiler_flag(-std=c++11 has_std_11_flag)
check_cxx_compiler_flag(-std=c++0x has_std_0x_flag)
fmt_check_cxx_compiler_flag(-std=c++11 has_std_11_flag)
fmt_check_cxx_compiler_flag(-std=c++0x has_std_0x_flag)
if (has_std_11_flag)
set(CXX_STANDARD_FLAG -std=c++11)
@ -45,26 +52,3 @@ elseif (CMAKE_CXX_STANDARD EQUAL 11)
set(CXX_STANDARD_FLAG -std=c++0x)
endif ()
endif ()
set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG})
# Check if user-defined literals are available
check_cxx_source_compiles("
void operator\"\" _udl(long double);
int main() {}"
SUPPORTS_USER_DEFINED_LITERALS)
if (NOT SUPPORTS_USER_DEFINED_LITERALS)
set (SUPPORTS_USER_DEFINED_LITERALS OFF)
endif ()
# Check if <variant> is available
set(CMAKE_REQUIRED_FLAGS -std=c++1z)
check_cxx_source_compiles("
#include <variant>
int main() {}"
FMT_HAS_VARIANT)
if (NOT FMT_HAS_VARIANT)
set (FMT_HAS_VARIANT OFF)
endif ()
set(CMAKE_REQUIRED_FLAGS )

View File

@ -1,4 +1,7 @@
@PACKAGE_INIT@
include(${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake)
if (NOT TARGET fmt::fmt)
include(${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake)
endif ()
check_required_components(fmt)

View File

@ -1,7 +1,7 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
libdir=@libdir_for_pc_file@
includedir=@includedir_for_pc_file@
Name: fmt
Description: A modern formatting library

View File

@ -1,27 +0,0 @@
# Staticlib configuration for qmake builds
# For some reason qmake 3.1 fails to identify source dependencies and excludes format.cc and printf.cc
# from compilation so it _MUST_ be called as qmake -nodepend
# A workaround is implemented below: a custom compiler is defined which does not track dependencies
TEMPLATE = lib
TARGET = fmt
QMAKE_EXT_CPP = .cc
CONFIG = staticlib warn_on c++11
FMT_SOURCES = \
../src/format.cc \
../src/posix.cc
fmt.name = libfmt
fmt.input = FMT_SOURCES
fmt.output = ${QMAKE_FILE_BASE}$$QMAKE_EXT_OBJ
fmt.clean = ${QMAKE_FILE_BASE}$$QMAKE_EXT_OBJ
fmt.depends = ${QMAKE_FILE_IN}
# QMAKE_RUN_CXX will not be expanded
fmt.commands = $$QMAKE_CXX -c $$QMAKE_CXXFLAGS $$QMAKE_CXXFLAGS_WARN_ON $$QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO $$QMAKE_CXXFLAGS_CXX11 ${QMAKE_FILE_IN}
fmt.variable_out = OBJECTS
fmt.CONFIG = no_dependencies no_link
QMAKE_EXTRA_COMPILERS += fmt

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
"""Manage site and releases.
@ -144,9 +144,40 @@ def update_site(env):
b.data = re.sub(pattern, r'doxygenfunction:: \1(int)', b.data)
b.data = b.data.replace('std::FILE*', 'std::FILE *')
b.data = b.data.replace('unsigned int', 'unsigned')
b.data = b.data.replace('operator""_', 'operator"" _')
b.data = b.data.replace(', size_t', ', std::size_t')
#b.data = b.data.replace('operator""_', 'operator"" _')
b.data = b.data.replace(
'format_to_n(OutputIt, size_t, string_view, Args&&',
'format_to_n(OutputIt, size_t, const S&, const Args&')
b.data = b.data.replace(
'format_to_n(OutputIt, std::size_t, string_view, Args&&',
'format_to_n(OutputIt, std::size_t, const S&, const Args&')
if version == ('3.0.2'):
b.data = b.data.replace(
'fprintf(std::ostream&', 'fprintf(std::ostream &')
if version == ('5.3.0'):
b.data = b.data.replace(
'format_to(OutputIt, const S&, const Args&...)',
'format_to(OutputIt, const S &, const Args &...)')
if version.startswith('5.') or version.startswith('6.'):
b.data = b.data.replace(', size_t', ', std::size_t')
if version.startswith('7.'):
b.data = b.data.replace(', std::size_t', ', size_t')
b.data = b.data.replace('join(It, It', 'join(It, Sentinel')
if version.startswith('7.1.'):
b.data = b.data.replace(', std::size_t', ', size_t')
b.data = b.data.replace('join(It, It', 'join(It, Sentinel')
b.data = b.data.replace(
'fmt::format_to(OutputIt, const S&, Args&&...)',
'fmt::format_to(OutputIt, const S&, Args&&...) -> ' +
'typename std::enable_if<enable, OutputIt>::type')
b.data = b.data.replace('aa long', 'a long')
b.data = b.data.replace('serveral', 'several')
if version.startswith('6.2.'):
b.data = b.data.replace(
'vformat(const S&, basic_format_args<' +
'buffer_context<Char>>)',
'vformat(const S&, basic_format_args<' +
'buffer_context<type_identity_t<Char>>>)')
# Fix a broken link in index.rst.
index = os.path.join(target_doc_dir, 'index.rst')
with rewrite(index) as b:
@ -209,7 +240,7 @@ def release(args):
# Update the version in the changelog.
title_len = 0
for line in fileinput.input(changelog_path, inplace=True):
if line.decode('utf-8').startswith(version + ' - TBD'):
if line.startswith(version + ' - TBD'):
line = version + ' - ' + datetime.date.today().isoformat()
title_len = len(line)
line += '\n'
@ -239,9 +270,9 @@ def release(args):
# Create a release on GitHub.
fmt_repo.push('origin', 'release')
params = {'access_token': os.getenv('FMT_TOKEN')}
auth_headers = {'Authorization': 'token ' + os.getenv('FMT_TOKEN')}
r = requests.post('https://api.github.com/repos/fmtlib/fmt/releases',
params=params,
headers=auth_headers,
data=json.dumps({'tag_name': version,
'target_commitish': 'release',
'body': changes, 'draft': True}))
@ -252,8 +283,8 @@ def release(args):
package = 'fmt-{}.zip'.format(version)
r = requests.post(
'{}/{}/assets?name={}'.format(uploads_url, id, package),
headers={'Content-Type': 'application/zip'},
params=params, data=open('build/fmt/' + package, 'rb'))
headers={'Content-Type': 'application/zip'} | auth_headers,
data=open('build/fmt/' + package, 'rb'))
if r.status_code != 201:
raise Exception('Failed to upload an asset ' + str(r))

201
externals/fmt/support/printable.py vendored Executable file
View File

@ -0,0 +1,201 @@
#!/usr/bin/env python3
# This script is based on
# https://github.com/rust-lang/rust/blob/master/library/core/src/unicode/printable.py
# distributed under https://github.com/rust-lang/rust/blob/master/LICENSE-MIT.
# This script uses the following Unicode tables:
# - UnicodeData.txt
from collections import namedtuple
import csv
import os
import subprocess
NUM_CODEPOINTS=0x110000
def to_ranges(iter):
current = None
for i in iter:
if current is None or i != current[1] or i in (0x10000, 0x20000):
if current is not None:
yield tuple(current)
current = [i, i + 1]
else:
current[1] += 1
if current is not None:
yield tuple(current)
def get_escaped(codepoints):
for c in codepoints:
if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord(' '):
yield c.value
def get_file(f):
try:
return open(os.path.basename(f))
except FileNotFoundError:
subprocess.run(["curl", "-O", f], check=True)
return open(os.path.basename(f))
Codepoint = namedtuple('Codepoint', 'value class_')
def get_codepoints(f):
r = csv.reader(f, delimiter=";")
prev_codepoint = 0
class_first = None
for row in r:
codepoint = int(row[0], 16)
name = row[1]
class_ = row[2]
if class_first is not None:
if not name.endswith("Last>"):
raise ValueError("Missing Last after First")
for c in range(prev_codepoint + 1, codepoint):
yield Codepoint(c, class_first)
class_first = None
if name.endswith("First>"):
class_first = class_
yield Codepoint(codepoint, class_)
prev_codepoint = codepoint
if class_first is not None:
raise ValueError("Missing Last after First")
for c in range(prev_codepoint + 1, NUM_CODEPOINTS):
yield Codepoint(c, None)
def compress_singletons(singletons):
uppers = [] # (upper, # items in lowers)
lowers = []
for i in singletons:
upper = i >> 8
lower = i & 0xff
if len(uppers) == 0 or uppers[-1][0] != upper:
uppers.append((upper, 1))
else:
upper, count = uppers[-1]
uppers[-1] = upper, count + 1
lowers.append(lower)
return uppers, lowers
def compress_normal(normal):
# lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f
# lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff
compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)]
prev_start = 0
for start, count in normal:
truelen = start - prev_start
falselen = count
prev_start = start + count
assert truelen < 0x8000 and falselen < 0x8000
entry = []
if truelen > 0x7f:
entry.append(0x80 | (truelen >> 8))
entry.append(truelen & 0xff)
else:
entry.append(truelen & 0x7f)
if falselen > 0x7f:
entry.append(0x80 | (falselen >> 8))
entry.append(falselen & 0xff)
else:
entry.append(falselen & 0x7f)
compressed.append(entry)
return compressed
def print_singletons(uppers, lowers, uppersname, lowersname):
print(" static constexpr singleton {}[] = {{".format(uppersname))
for u, c in uppers:
print(" {{{:#04x}, {}}},".format(u, c))
print(" };")
print(" static constexpr unsigned char {}[] = {{".format(lowersname))
for i in range(0, len(lowers), 8):
print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8])))
print(" };")
def print_normal(normal, normalname):
print(" static constexpr unsigned char {}[] = {{".format(normalname))
for v in normal:
print(" {}".format(" ".join("{:#04x},".format(i) for i in v)))
print(" };")
def main():
file = get_file("https://www.unicode.org/Public/UNIDATA/UnicodeData.txt")
codepoints = get_codepoints(file)
CUTOFF=0x10000
singletons0 = []
singletons1 = []
normal0 = []
normal1 = []
extra = []
for a, b in to_ranges(get_escaped(codepoints)):
if a > 2 * CUTOFF:
extra.append((a, b - a))
elif a == b - 1:
if a & CUTOFF:
singletons1.append(a & ~CUTOFF)
else:
singletons0.append(a)
elif a == b - 2:
if a & CUTOFF:
singletons1.append(a & ~CUTOFF)
singletons1.append((a + 1) & ~CUTOFF)
else:
singletons0.append(a)
singletons0.append(a + 1)
else:
if a >= 2 * CUTOFF:
extra.append((a, b - a))
elif a & CUTOFF:
normal1.append((a & ~CUTOFF, b - a))
else:
normal0.append((a, b - a))
singletons0u, singletons0l = compress_singletons(singletons0)
singletons1u, singletons1l = compress_singletons(singletons1)
normal0 = compress_normal(normal0)
normal1 = compress_normal(normal1)
print("""\
FMT_FUNC auto is_printable(uint32_t cp) -> bool {\
""")
print_singletons(singletons0u, singletons0l, 'singletons0', 'singletons0_lower')
print_singletons(singletons1u, singletons1l, 'singletons1', 'singletons1_lower')
print_normal(normal0, 'normal0')
print_normal(normal1, 'normal1')
print("""\
auto lower = static_cast<uint16_t>(cp);
if (cp < 0x10000) {
return is_printable(lower, singletons0,
sizeof(singletons0) / sizeof(*singletons0),
singletons0_lower, normal0, sizeof(normal0));
}
if (cp < 0x20000) {
return is_printable(lower, singletons1,
sizeof(singletons1) / sizeof(*singletons1),
singletons1_lower, normal1, sizeof(normal1));
}\
""")
for a, b in extra:
print(" if (0x{:x} <= cp && cp < 0x{:x}) return false;".format(a, a + b))
print("""\
return cp < 0x{:x};
}}\
""".format(NUM_CODEPOINTS))
if __name__ == '__main__':
main()

View File

@ -65,7 +65,7 @@ class Translator(nodes.NodeVisitor):
self.write('\n\n')
def visit_paragraph(self, node):
pass
self.write('\n\n')
def depart_paragraph(self, node):
pass

View File

@ -1,119 +0,0 @@
#!/usr/bin/env python
# Build the project on Travis CI.
from __future__ import print_function
import errno, os, shutil, subprocess, sys, urllib
from subprocess import call, check_call, Popen, PIPE, STDOUT
def rmtree_if_exists(dir):
try:
shutil.rmtree(dir)
except OSError as e:
if e.errno == errno.ENOENT:
pass
def makedirs_if_not_exist(dir):
try:
os.makedirs(dir)
except OSError as e:
if e.errno != errno.EEXIST:
raise
def install_dependencies():
branch = os.environ['TRAVIS_BRANCH']
if branch != 'master':
print('Branch: ' + branch)
exit(0) # Ignore non-master branches
check_call('curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key ' +
'| sudo apt-key add -', shell=True)
check_call('echo "deb https://deb.nodesource.com/node_0.10 precise main" ' +
'| sudo tee /etc/apt/sources.list.d/nodesource.list', shell=True)
check_call(['sudo', 'apt-get', 'update'])
check_call(['sudo', 'apt-get', 'install', 'python-virtualenv', 'nodejs'])
check_call(['sudo', 'npm', 'install', '-g', 'less@2.6.1', 'less-plugin-clean-css'])
deb_file = 'doxygen_1.8.6-2_amd64.deb'
urllib.urlretrieve('http://mirrors.kernel.org/ubuntu/pool/main/d/doxygen/' +
deb_file, deb_file)
check_call(['sudo', 'dpkg', '-i', deb_file])
fmt_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
build = os.environ['BUILD']
if build == 'Doc':
travis = 'TRAVIS' in os.environ
if travis:
install_dependencies()
sys.path.insert(0, os.path.join(fmt_dir, 'doc'))
import build
build.create_build_env()
html_dir = build.build_docs()
repo = 'fmtlib.github.io'
if travis and 'KEY' not in os.environ:
# Don't update the repo if building on Travis from an account that
# doesn't have push access.
print('Skipping update of ' + repo)
exit(0)
# Clone the fmtlib.github.io repo.
rmtree_if_exists(repo)
git_url = 'https://github.com/' if travis else 'git@github.com:'
check_call(['git', 'clone', git_url + 'fmtlib/{}.git'.format(repo)])
# Copy docs to the repo.
target_dir = os.path.join(repo, 'dev')
rmtree_if_exists(target_dir)
shutil.copytree(html_dir, target_dir, ignore=shutil.ignore_patterns('.*'))
if travis:
check_call(['git', 'config', '--global', 'user.name', 'amplbot'])
check_call(['git', 'config', '--global', 'user.email', 'viz@ampl.com'])
# Push docs to GitHub pages.
check_call(['git', 'add', '--all'], cwd=repo)
if call(['git', 'diff-index', '--quiet', 'HEAD'], cwd=repo):
check_call(['git', 'commit', '-m', 'Update documentation'], cwd=repo)
cmd = 'git push'
if travis:
cmd += ' https://$KEY@github.com/fmtlib/fmtlib.github.io.git master'
p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=repo)
# Print the output without the key.
print(p.communicate()[0].replace(os.environ['KEY'], '$KEY'))
if p.returncode != 0:
raise subprocess.CalledProcessError(p.returncode, cmd)
exit(0)
standard = os.environ['STANDARD']
install_dir = os.path.join(fmt_dir, "_install")
build_dir = os.path.join(fmt_dir, "_build")
test_build_dir = os.path.join(fmt_dir, "_build_test")
# Configure the library.
makedirs_if_not_exist(build_dir)
cmake_flags = [
'-DCMAKE_INSTALL_PREFIX=' + install_dir, '-DCMAKE_BUILD_TYPE=' + build,
'-DCMAKE_CXX_STANDARD=' + standard
]
# Make sure the fuzzers still compile.
main_cmake_flags = list(cmake_flags)
if 'ENABLE_FUZZING' in os.environ:
main_cmake_flags += ['-DFMT_FUZZ=ON', '-DFMT_FUZZ_LINKMAIN=On']
check_call(['cmake', '-DFMT_DOC=OFF', '-DFMT_PEDANTIC=ON', '-DFMT_WERROR=ON', fmt_dir] +
main_cmake_flags, cwd=build_dir)
# Build the library.
check_call(['cmake', '--build','.'], cwd=build_dir)
# Test the library.
env = os.environ.copy()
env['CTEST_OUTPUT_ON_FAILURE'] = '1'
if call(['make', 'test'], env=env, cwd=build_dir):
with open(os.path.join(build_dir, 'Testing', 'Temporary', 'LastTest.log'), 'r') as f:
print(f.read())
sys.exit(-1)
# Install the library.
check_call(['make', 'install'], cwd=build_dir)
# Test installation.
makedirs_if_not_exist(test_build_dir)
check_call(['cmake', os.path.join(fmt_dir, "test", "find-package-test")] +
cmake_flags, cwd=test_build_dir)
check_call(['make', '-j4'], cwd=test_build_dir)

View File

@ -1,30 +0,0 @@
#!/usr/bin/env python
# Update the coverity branch from the master branch.
# It is not done automatically because Coverity Scan limits
# the number of submissions per day.
from __future__ import print_function
import shutil, tempfile
from subprocess import check_output, STDOUT
class Git:
def __init__(self, dir):
self.dir = dir
def __call__(self, *args):
output = check_output(['git'] + list(args), cwd=self.dir, stderr=STDOUT)
print(output)
return output
dir = tempfile.mkdtemp()
try:
git = Git(dir)
git('clone', '-b', 'coverity', 'git@github.com:fmtlib/fmt.git', dir)
output = git('merge', '-X', 'theirs', '--no-commit', 'origin/master')
if 'Fast-forward' not in output:
git('reset', 'HEAD', '.travis.yml')
git('checkout', '--', '.travis.yml')
git('commit', '-m', 'Update coverity branch')
git('push')
finally:
shutil.rmtree(dir)

View File

@ -1,80 +1,48 @@
#------------------------------------------------------------------------------
# Build the google test library
# We compile Google Test ourselves instead of using pre-compiled libraries.
# See the Google Test FAQ "Why is it not recommended to install a
# pre-compiled copy of Google Test (for example, into /usr/local)?"
# at http://code.google.com/p/googletest/wiki/FAQ for more details.
add_library(gmock STATIC
gmock-gtest-all.cc gmock/gmock.h gtest/gtest.h gtest/gtest-spi.h)
target_compile_definitions(gmock PUBLIC GTEST_HAS_STD_WSTRING=1)
target_include_directories(gmock SYSTEM PUBLIC . gmock gtest)
find_package(Threads)
if (Threads_FOUND)
target_link_libraries(gmock ${CMAKE_THREAD_LIBS_INIT})
else ()
target_compile_definitions(gmock PUBLIC GTEST_HAS_PTHREAD=0)
endif ()
target_compile_definitions(gmock PUBLIC GTEST_LANG_CXX11=0)
if (MSVC)
# Workaround a bug in implementation of variadic templates in MSVC11.
target_compile_definitions(gmock PUBLIC _VARIADIC_MAX=10)
# Disable MSVC warnings of _CRT_INSECURE_DEPRECATE functions.
target_compile_definitions(gmock PRIVATE _CRT_SECURE_NO_WARNINGS)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# Disable MSVC warnings of POSIX functions.
target_compile_options(gmock PUBLIC -Wno-deprecated-declarations)
endif ()
endif ()
# GTest doesn't detect <tuple> with clang.
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_definitions(gmock PUBLIC GTEST_USE_OWN_TR1_TUPLE=1)
endif ()
# Silence MSVC tr1 deprecation warning in gmock.
target_compile_definitions(gmock
PUBLIC _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1)
#------------------------------------------------------------------------------
# Build the actual library tests
add_subdirectory(gtest)
set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc)
add_library(test-main STATIC ${TEST_MAIN_SRC})
target_include_directories(test-main SYSTEM PUBLIC gtest gmock)
target_link_libraries(test-main gmock fmt)
include(CheckCXXCompilerFlag)
# Workaround GTest bug https://github.com/google/googletest/issues/705.
check_cxx_compiler_flag(
-fno-delete-null-pointer-checks HAVE_FNO_DELETE_NULL_POINTER_CHECKS)
if (HAVE_FNO_DELETE_NULL_POINTER_CHECKS)
target_compile_options(test-main PUBLIC -fno-delete-null-pointer-checks)
endif ()
# Use less strict pedantic flags for the tests because GMock doesn't compile
# cleanly with -pedantic and -std=c++98.
if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
#set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wno-long-long -Wno-variadic-macros)
endif ()
target_include_directories(test-main PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
target_link_libraries(test-main gtest fmt)
function(add_fmt_executable name)
add_executable(${name} ${ARGN})
if (MINGW)
target_link_libraries(${name} -static-libgcc -static-libstdc++)
endif ()
# (Wstringop-overflow) - [meta-bug] bogus/missing -Wstringop-overflow warnings
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88443
# Bogus -Wstringop-overflow warning
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100395
# [10 Regression] spurious -Wstringop-overflow writing to a trailing array plus offset
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95353
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND
NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
target_link_libraries(${name} -Wno-stringop-overflow)
endif ()
endfunction()
# Adds a test.
# Usage: add_fmt_test(name srcs...)
function(add_fmt_test name)
add_fmt_executable(${name} ${name}.cc ${ARGN})
target_link_libraries(${name} test-main)
cmake_parse_arguments(ADD_FMT_TEST "HEADER_ONLY;MODULE" "" "" ${ARGN})
set(sources ${name}.cc ${ADD_FMT_TEST_UNPARSED_ARGUMENTS})
if (ADD_FMT_TEST_HEADER_ONLY)
set(sources ${sources} ${TEST_MAIN_SRC} ../src/os.cc)
set(libs gtest fmt-header-only)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wno-weak-vtables)
endif ()
elseif (ADD_FMT_TEST_MODULE)
set(libs gtest test-module)
set_source_files_properties(${name}.cc PROPERTIES OBJECT_DEPENDS test-module)
else ()
set(libs test-main fmt)
endif ()
add_fmt_executable(${name} ${sources})
target_link_libraries(${name} ${libs})
# Define if certain C++ features can be used.
if (FMT_PEDANTIC)
@ -83,83 +51,108 @@ function(add_fmt_test name)
if (FMT_WERROR)
target_compile_options(${name} PRIVATE ${WERROR_FLAG})
endif ()
target_include_directories(${name} SYSTEM PUBLIC gtest gmock)
add_test(NAME ${name} COMMAND ${name})
endfunction()
add_fmt_test(args-test)
add_fmt_test(assert-test)
add_fmt_test(chrono-test)
add_fmt_test(color-test)
add_fmt_test(core-test)
add_fmt_test(grisu-test)
target_compile_definitions(grisu-test PRIVATE FMT_USE_GRISU=1)
add_fmt_test(gtest-extra-test)
add_fmt_test(format-test mock-allocator.h)
if (MSVC)
target_compile_options(format-test PRIVATE /bigobj)
endif ()
if (NOT (MSVC AND BUILD_SHARED_LIBS))
add_fmt_test(format-impl-test)
add_fmt_test(format-impl-test HEADER_ONLY header-only-test.cc)
endif ()
add_fmt_test(locale-test)
add_fmt_test(ostream-test)
add_fmt_test(compile-test)
add_fmt_test(compile-fp-test HEADER_ONLY)
if (MSVC)
# Without this option, MSVC returns 199711L for the __cplusplus macro.
target_compile_options(compile-fp-test PRIVATE /Zc:__cplusplus)
endif()
add_fmt_test(printf-test)
add_fmt_test(custom-formatter-test)
add_fmt_test(ranges-test)
add_fmt_test(ranges-test ranges-odr-test.cc)
add_fmt_test(scan-test)
add_fmt_test(std-test)
try_compile(compile_result_unused
${CMAKE_CURRENT_BINARY_DIR}
SOURCES ${CMAKE_CURRENT_LIST_DIR}/detect-stdfs.cc
OUTPUT_VARIABLE RAWOUTPUT)
string(REGEX REPLACE ".*libfound \"([^\"]*)\".*" "\\1" STDLIBFS "${RAWOUTPUT}")
if (STDLIBFS)
target_link_libraries(std-test ${STDLIBFS})
endif ()
add_fmt_test(unicode-test HEADER_ONLY)
if (MSVC)
target_compile_options(unicode-test PRIVATE /utf-8)
endif ()
add_fmt_test(xchar-test)
add_fmt_test(enforce-checks-test)
target_compile_definitions(enforce-checks-test PRIVATE
-DFMT_ENFORCE_COMPILE_STRING)
if (NOT MSVC_BUILD_STATIC)
if (FMT_CAN_MODULE)
# The tests need {fmt} to be compiled as traditional library
# because of visibility of implementation details.
# If module support is present the module tests require a
# test-only module to be built from {fmt}
add_library(test-module OBJECT ${CMAKE_SOURCE_DIR}/src/fmt.cc)
target_compile_features(test-module PUBLIC ${FMT_REQUIRED_FEATURES})
target_include_directories(test-module PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
enable_module(test-module)
add_fmt_test(module-test MODULE test-main.cc)
if (MSVC)
target_compile_options(test-module PRIVATE /utf-8 /Zc:__cplusplus
/Zc:externConstexpr /Zc:inline)
target_compile_options(module-test PRIVATE /utf-8 /Zc:__cplusplus
/Zc:externConstexpr /Zc:inline)
endif ()
endif ()
if (NOT DEFINED MSVC_STATIC_RUNTIME AND MSVC)
foreach (flag_var
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if (${flag_var} MATCHES "^(/|-)(MT|MTd)")
set(MSVC_STATIC_RUNTIME ON)
break()
endif()
endforeach()
endif()
if (NOT MSVC_STATIC_RUNTIME)
add_fmt_executable(posix-mock-test
posix-mock-test.cc ../src/format.cc ${TEST_MAIN_SRC})
target_include_directories(
posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(posix-mock-test gmock)
target_include_directories(posix-mock-test SYSTEM PUBLIC gtest gmock)
target_link_libraries(posix-mock-test gtest)
if (FMT_PEDANTIC)
target_compile_options(posix-mock-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
if (HAVE_STRTOD_L)
target_compile_definitions(posix-mock-test PRIVATE FMT_LOCALE)
endif ()
add_test(NAME posix-mock-test COMMAND posix-mock-test)
add_fmt_test(os-test)
endif ()
add_fmt_executable(header-only-test
header-only-test.cc header-only-test2.cc test-main.cc)
target_link_libraries(header-only-test gmock)
target_include_directories(header-only-test SYSTEM PUBLIC gtest gmock)
if (TARGET fmt-header-only)
target_link_libraries(header-only-test fmt-header-only)
else ()
target_include_directories(
header-only-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_definitions(header-only-test PRIVATE FMT_HEADER_ONLY=1)
endif ()
message(STATUS "FMT_PEDANTIC: ${FMT_PEDANTIC}")
if (FMT_PEDANTIC)
# MSVC fails to compile GMock when C++17 is enabled.
if (FMT_HAS_VARIANT AND NOT MSVC)
add_fmt_test(std-format-test)
set_property(TARGET std-format-test PROPERTY CXX_STANDARD 17)
endif ()
# Test that the library can be compiled with exceptions disabled.
# -fno-exception is broken in icc: https://github.com/fmtlib/fmt/issues/822.
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG)
endif ()
if (HAVE_FNO_EXCEPTIONS_FLAG)
add_library(noexception-test ../src/format.cc)
add_library(noexception-test ../src/format.cc noexception-test.cc)
target_include_directories(
noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_options(noexception-test PRIVATE -fno-exceptions)
if (FMT_PEDANTIC)
target_compile_options(noexception-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
target_compile_options(noexception-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
# Test that the library compiles without locale.
@ -168,7 +161,11 @@ if (FMT_PEDANTIC)
nolocale-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_definitions(
nolocale-test PRIVATE FMT_STATIC_THOUSANDS_SEPARATOR=1)
endif ()
# These tests are disabled on Windows because they take too long.
if (FMT_PEDANTIC AND NOT WIN32)
# Test if incorrect API usages produce compilation error.
add_test(compile-error-test ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMAKE_CURRENT_SOURCE_DIR}/compile-error-test"
@ -177,14 +174,11 @@ if (FMT_PEDANTIC)
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DCXX_STANDARD_FLAG=${CXX_STANDARD_FLAG}"
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
"-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}")
endif ()
"-DFMT_DIR=${CMAKE_SOURCE_DIR}")
# These tests are disabled on Windows because they take too long.
if (FMT_PEDANTIC AND NOT WIN32)
# Test if the targets are found from the build directory.
add_test(find-package-test ${CMAKE_CTEST_COMMAND}
-C ${CMAKE_BUILD_TYPE}
@ -195,6 +189,7 @@ if (FMT_PEDANTIC AND NOT WIN32)
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DFMT_DIR=${PROJECT_BINARY_DIR}"
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
@ -215,6 +210,21 @@ if (FMT_PEDANTIC AND NOT WIN32)
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
endif ()
# This test are disabled on Windows because it is only *NIX issue.
if (FMT_PEDANTIC AND NOT WIN32)
add_test(static-export-test ${CMAKE_CTEST_COMMAND}
-C ${CMAKE_BUILD_TYPE}
--build-and-test
"${CMAKE_CURRENT_SOURCE_DIR}/static-export-test"
"${CMAKE_CURRENT_BINARY_DIR}/static-export-test"
--build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
endif ()
# Activate optional CUDA tests if CUDA is found. For version selection see
# https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#cpp14-language-features
if (FMT_CUDA_TEST)

View File

@ -1,17 +1,17 @@
cmake_minimum_required(VERSION 3.1.0)
cmake_minimum_required(VERSION 3.1...3.18)
project(fmt-test)
project(fmt-test CXX)
add_subdirectory(../.. fmt)
add_executable(library-test "main.cc")
target_link_libraries(library-test fmt::fmt)
target_compile_options(library-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
add_executable(library-test main.cc)
target_include_directories(library-test PUBLIC SYSTEM .)
target_compile_options(library-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
target_link_libraries(library-test fmt::fmt)
if (TARGET fmt::fmt-header-only)
add_executable(header-only-test "main.cc")
target_link_libraries(header-only-test fmt::fmt-header-only)
target_compile_options(header-only-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
add_executable(header-only-test main.cc)
target_include_directories(header-only-test PUBLIC SYSTEM .)
target_compile_options(header-only-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
target_link_libraries(header-only-test fmt::fmt-header-only)
endif ()

View File

@ -1,6 +1,5 @@
#include "fmt/format.h"
#include "fmt/core.h"
int main(int argc, char** argv) {
for(int i = 0; i < argc; ++i)
fmt::print("{}: {}\n", i, argv[i]);
for (int i = 0; i < argc; ++i) fmt::print("{}: {}\n", i, argv[i]);
}

186
externals/fmt/test/args-test.cc vendored Normal file
View File

@ -0,0 +1,186 @@
// Formatting library for C++ - dynamic argument store tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/args.h"
#include <memory>
#include "gtest/gtest.h"
TEST(args_test, basic) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(42);
store.push_back("abc1");
store.push_back(1.5f);
EXPECT_EQ("42 and abc1 and 1.5", fmt::vformat("{} and {} and {}", store));
}
TEST(args_test, strings_and_refs) {
// Unfortunately the tests are compiled with old ABI so strings use COW.
fmt::dynamic_format_arg_store<fmt::format_context> store;
char str[] = "1234567890";
store.push_back(str);
store.push_back(std::cref(str));
store.push_back(fmt::string_view{str});
str[0] = 'X';
auto result = fmt::vformat("{} and {} and {}", store);
EXPECT_EQ("1234567890 and X234567890 and X234567890", result);
}
struct custom_type {
int i = 0;
};
FMT_BEGIN_NAMESPACE
template <> struct formatter<custom_type> {
auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const custom_type& p, FormatContext& ctx) -> decltype(ctx.out()) {
return format_to(ctx.out(), "cust={}", p.i);
}
};
FMT_END_NAMESPACE
TEST(args_test, custom_format) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
auto c = custom_type();
store.push_back(c);
++c.i;
store.push_back(c);
++c.i;
store.push_back(std::cref(c));
++c.i;
auto result = fmt::vformat("{} and {} and {}", store);
EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
}
struct to_stringable {
friend fmt::string_view to_string_view(to_stringable) { return {}; }
};
FMT_BEGIN_NAMESPACE
template <> struct formatter<to_stringable> {
auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) {
return ctx.begin();
}
auto format(to_stringable, format_context& ctx) -> decltype(ctx.out()) {
return ctx.out();
}
};
FMT_END_NAMESPACE
TEST(args_test, to_string_and_formatter) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
auto s = to_stringable();
store.push_back(s);
store.push_back(std::cref(s));
fmt::vformat("", store);
}
TEST(args_test, named_int) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(fmt::arg("a1", 42));
EXPECT_EQ("42", fmt::vformat("{a1}", store));
}
TEST(args_test, named_strings) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
char str[] = "1234567890";
store.push_back(fmt::arg("a1", str));
store.push_back(fmt::arg("a2", std::cref(str)));
str[0] = 'X';
EXPECT_EQ("1234567890 and X234567890", fmt::vformat("{a1} and {a2}", store));
}
TEST(args_test, named_arg_by_ref) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
char band[] = "Rolling Stones";
store.push_back(fmt::arg("band", std::cref(band)));
band[9] = 'c'; // Changing band affects the output.
EXPECT_EQ(fmt::vformat("{band}", store), "Rolling Scones");
}
TEST(args_test, named_custom_format) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
auto c = custom_type();
store.push_back(fmt::arg("c1", c));
++c.i;
store.push_back(fmt::arg("c2", c));
++c.i;
store.push_back(fmt::arg("c_ref", std::cref(c)));
++c.i;
auto result = fmt::vformat("{c1} and {c2} and {c_ref}", store);
EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
}
TEST(args_test, clear) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(42);
auto result = fmt::vformat("{}", store);
EXPECT_EQ("42", result);
store.push_back(43);
result = fmt::vformat("{} and {}", store);
EXPECT_EQ("42 and 43", result);
store.clear();
store.push_back(44);
result = fmt::vformat("{}", store);
EXPECT_EQ("44", result);
}
TEST(args_test, reserve) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.reserve(2, 1);
store.push_back(1.5f);
store.push_back(fmt::arg("a1", 42));
auto result = fmt::vformat("{a1} and {}", store);
EXPECT_EQ("42 and 1.5", result);
}
struct copy_throwable {
copy_throwable() {}
copy_throwable(const copy_throwable&) { throw "deal with it"; }
};
FMT_BEGIN_NAMESPACE
template <> struct formatter<copy_throwable> {
auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) {
return ctx.begin();
}
auto format(copy_throwable, format_context& ctx) -> decltype(ctx.out()) {
return ctx.out();
}
};
FMT_END_NAMESPACE
TEST(args_test, throw_on_copy) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(std::string("foo"));
try {
store.push_back(copy_throwable());
} catch (...) {
}
EXPECT_EQ(fmt::vformat("{}", store), "foo");
}
TEST(args_test, move_constructor) {
using store_type = fmt::dynamic_format_arg_store<fmt::format_context>;
auto store = std::unique_ptr<store_type>(new store_type());
store->push_back(42);
store->push_back(std::string("foo"));
store->push_back(fmt::arg("a1", "foo"));
auto moved_store = std::move(*store);
store.reset();
EXPECT_EQ(fmt::vformat("{} {} {a1}", moved_store), "42 foo foo");
}

View File

@ -1,4 +1,8 @@
// Formatting library for C++ - assertion tests
// Formatting library for C++ - FMT_ASSERT test
//
// It is a separate test to minimize the number of EXPECT_DEBUG_DEATH checks
// which are slow on some platforms. In other tests FMT_ASSERT is made to throw
// an exception which is much faster and easier to check.
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
@ -6,9 +10,9 @@
// For the license information refer to format.h.
#include "fmt/core.h"
#include "gtest.h"
#include "gtest/gtest.h"
TEST(AssertTest, Fail) {
TEST(assert_test, fail) {
#if GTEST_HAS_DEATH_TEST
EXPECT_DEBUG_DEATH(FMT_ASSERT(false, "don't panic!"), "don't panic!");
#else
@ -16,9 +20,8 @@ TEST(AssertTest, Fail) {
#endif
}
bool test_condition = false;
TEST(AssertTest, DanglingElse) {
TEST(assert_test, dangling_else) {
bool test_condition = false;
bool executed_else = false;
if (test_condition)
FMT_ASSERT(true, "");

View File

@ -5,76 +5,221 @@
//
// For the license information refer to format.h.
#ifdef WIN32
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "fmt/chrono.h"
#include "gtest-extra.h"
#include <iomanip>
#include <ctime>
#include <vector>
std::tm make_tm() {
#include "gtest-extra.h" // EXPECT_THROW_MSG
#include "util.h" // get_locale
using fmt::runtime;
using testing::Contains;
auto make_tm() -> std::tm {
auto time = std::tm();
time.tm_mday = 1;
return time;
}
std::tm make_hour(int h) {
auto make_hour(int h) -> std::tm {
auto time = make_tm();
time.tm_hour = h;
return time;
}
std::tm make_minute(int m) {
auto make_minute(int m) -> std::tm {
auto time = make_tm();
time.tm_min = m;
return time;
}
std::tm make_second(int s) {
auto make_second(int s) -> std::tm {
auto time = make_tm();
time.tm_sec = s;
return time;
}
std::string format_tm(const std::tm& time, const char* spec,
const std::locale& loc) {
std::string system_strftime(const std::string& format, const std::tm* timeptr,
std::locale* locptr = nullptr) {
auto loc = locptr ? *locptr : std::locale::classic();
auto& facet = std::use_facet<std::time_put<char>>(loc);
std::ostringstream os;
os.imbue(loc);
facet.put(os, os, ' ', &time, spec, spec + std::strlen(spec));
facet.put(os, os, ' ', timeptr, format.c_str(),
format.c_str() + format.size());
#ifdef _WIN32
// Workaround a bug in older versions of Universal CRT.
auto str = os.str();
if (str == "-0000") str = "+0000";
return str;
#else
return os.str();
#endif
}
TEST(TimeTest, Format) {
std::tm tm = std::tm();
FMT_CONSTEXPR std::tm make_tm(int year, int mon, int mday, int hour, int min,
int sec) {
auto tm = std::tm();
tm.tm_sec = sec;
tm.tm_min = min;
tm.tm_hour = hour;
tm.tm_mday = mday;
tm.tm_mon = mon - 1;
tm.tm_year = year - 1900;
return tm;
}
TEST(chrono_test, format_tm) {
auto tm = std::tm();
tm.tm_year = 116;
tm.tm_mon = 3;
tm.tm_mday = 25;
EXPECT_EQ("The date is 2016-04-25.",
fmt::format("The date is {:%Y-%m-%d}.", tm));
tm.tm_hour = 11;
tm.tm_min = 22;
tm.tm_sec = 33;
EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm),
"The date is 2016-04-25 11:22:33.");
EXPECT_EQ(fmt::format("{:%Y}", tm), "2016");
EXPECT_EQ(fmt::format("{:%C}", tm), "20");
EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm));
EXPECT_EQ(fmt::format("{:%e}", tm), "25");
EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/16");
EXPECT_EQ(fmt::format("{:%F}", tm), "2016-04-25");
EXPECT_EQ(fmt::format("{:%T}", tm), "11:22:33");
// Short year
tm.tm_year = 999 - 1900;
tm.tm_mon = 0; // for %G
tm.tm_mday = 2; // for %G
tm.tm_wday = 3; // for %G
tm.tm_yday = 1; // for %G
EXPECT_EQ(fmt::format("{:%Y}", tm), "0999");
EXPECT_EQ(fmt::format("{:%C%y}", tm), "0999");
EXPECT_EQ(fmt::format("{:%G}", tm), "0999");
tm.tm_year = 27 - 1900;
EXPECT_EQ(fmt::format("{:%Y}", tm), "0027");
EXPECT_EQ(fmt::format("{:%C%y}", tm), "0027");
// Overflow year
tm.tm_year = 2147483647;
EXPECT_EQ(fmt::format("{:%Y}", tm), "2147485547");
tm.tm_year = -2147483648;
EXPECT_EQ(fmt::format("{:%Y}", tm), "-2147481748");
// for week on the year
// https://www.cl.cam.ac.uk/~mgk25/iso-time.html
std::vector<std::tm> tm_list = {
make_tm(1975, 12, 29, 12, 14, 16), // W01
make_tm(1977, 1, 2, 12, 14, 16), // W53
make_tm(1999, 12, 27, 12, 14, 16), // W52
make_tm(1999, 12, 31, 12, 14, 16), // W52
make_tm(2000, 1, 1, 12, 14, 16), // W52
make_tm(2000, 1, 2, 12, 14, 16), // W52
make_tm(2000, 1, 3, 12, 14, 16) // W1
};
const std::string iso_week_spec = "%Y-%m-%d: %G %g %V";
for (auto ctm : tm_list) {
// Calculate tm_yday, tm_wday, etc.
std::time_t t = std::mktime(&ctm);
tm = *std::localtime(&t);
auto fmt_spec = fmt::format("{{:{}}}", iso_week_spec);
EXPECT_EQ(system_strftime(iso_week_spec, &tm),
fmt::format(fmt::runtime(fmt_spec), tm));
}
// Every day from 1970-01-01
std::time_t time_now = std::time(nullptr);
for (std::time_t t = 6 * 3600; t < time_now; t += 86400) {
tm = *std::localtime(&t);
auto fmt_spec = fmt::format("{{:{}}}", iso_week_spec);
EXPECT_EQ(system_strftime(iso_week_spec, &tm),
fmt::format(fmt::runtime(fmt_spec), tm));
}
}
TEST(TimeTest, GrowBuffer) {
std::string s = "{:";
// MSVC:
// minkernel\crts\ucrt\src\appcrt\time\wcsftime.cpp(971) : Assertion failed:
// timeptr->tm_year >= -1900 && timeptr->tm_year <= 8099
#ifndef _WIN32
TEST(chrono_test, format_tm_future) {
auto tm = std::tm();
tm.tm_year = 10445; // 10000+ years
tm.tm_mon = 3;
tm.tm_mday = 25;
tm.tm_hour = 11;
tm.tm_min = 22;
tm.tm_sec = 33;
EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm),
"The date is 12345-04-25 11:22:33.");
EXPECT_EQ(fmt::format("{:%Y}", tm), "12345");
EXPECT_EQ(fmt::format("{:%C}", tm), "123");
EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm));
EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/45");
EXPECT_EQ(fmt::format("{:%F}", tm), "12345-04-25");
EXPECT_EQ(fmt::format("{:%T}", tm), "11:22:33");
}
TEST(chrono_test, format_tm_past) {
auto tm = std::tm();
tm.tm_year = -2001;
tm.tm_mon = 3;
tm.tm_mday = 25;
tm.tm_hour = 11;
tm.tm_min = 22;
tm.tm_sec = 33;
EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm),
"The date is -101-04-25 11:22:33.");
EXPECT_EQ(fmt::format("{:%Y}", tm), "-101");
// macOS %C - "-1"
// Linux %C - "-2"
// fmt %C - "-1"
EXPECT_EQ(fmt::format("{:%C}", tm), "-1");
EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm));
// macOS %D - "04/25/01" (%y)
// Linux %D - "04/25/99" (%y)
// fmt %D - "04/25/01" (%y)
EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/01");
EXPECT_EQ(fmt::format("{:%F}", tm), "-101-04-25");
EXPECT_EQ(fmt::format("{:%T}", tm), "11:22:33");
tm.tm_year = -1901; // -1
EXPECT_EQ(fmt::format("{:%Y}", tm), "-001");
EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm));
tm.tm_year = -1911; // -11
EXPECT_EQ(fmt::format("{:%Y}", tm), "-011");
EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm));
}
#endif
TEST(chrono_test, grow_buffer) {
auto s = std::string("{:");
for (int i = 0; i < 30; ++i) s += "%c";
s += "}\n";
std::time_t t = std::time(nullptr);
fmt::format(s, *std::localtime(&t));
auto t = std::time(nullptr);
(void)fmt::format(fmt::runtime(s), *std::localtime(&t));
}
TEST(TimeTest, FormatToEmptyContainer) {
std::string s;
TEST(chrono_test, format_to_empty_container) {
auto time = std::tm();
time.tm_sec = 42;
auto s = std::string();
fmt::format_to(std::back_inserter(s), "{:%S}", time);
EXPECT_EQ(s, "42");
}
TEST(TimeTest, EmptyResult) { EXPECT_EQ("", fmt::format("{}", std::tm())); }
TEST(chrono_test, empty_result) { EXPECT_EQ(fmt::format("{}", std::tm()), ""); }
static bool EqualTime(const std::tm& lhs, const std::tm& rhs) {
auto equal(const std::tm& lhs, const std::tm& rhs) -> bool {
return lhs.tm_sec == rhs.tm_sec && lhs.tm_min == rhs.tm_min &&
lhs.tm_hour == rhs.tm_hour && lhs.tm_mday == rhs.tm_mday &&
lhs.tm_mon == rhs.tm_mon && lhs.tm_year == rhs.tm_year &&
@ -82,28 +227,62 @@ static bool EqualTime(const std::tm& lhs, const std::tm& rhs) {
lhs.tm_isdst == rhs.tm_isdst;
}
TEST(TimeTest, LocalTime) {
std::time_t t = std::time(nullptr);
std::tm tm = *std::localtime(&t);
EXPECT_TRUE(EqualTime(tm, fmt::localtime(t)));
TEST(chrono_test, localtime) {
auto t = std::time(nullptr);
auto tm = *std::localtime(&t);
EXPECT_TRUE(equal(tm, fmt::localtime(t)));
}
TEST(TimeTest, GMTime) {
std::time_t t = std::time(nullptr);
std::tm tm = *std::gmtime(&t);
EXPECT_TRUE(EqualTime(tm, fmt::gmtime(t)));
TEST(chrono_test, gmtime) {
auto t = std::time(nullptr);
auto tm = *std::gmtime(&t);
EXPECT_TRUE(equal(tm, fmt::gmtime(t)));
}
#define EXPECT_TIME(spec, time, duration) \
{ \
std::locale loc("ja_JP.utf8"); \
EXPECT_EQ(format_tm(time, spec, loc), \
fmt::format(loc, "{:" spec "}", duration)); \
template <typename TimePoint> auto strftime_full(TimePoint tp) -> std::string {
auto t = std::chrono::system_clock::to_time_t(tp);
auto tm = *std::localtime(&t);
return system_strftime("%Y-%m-%d %H:%M:%S", &tm);
}
TEST(chrono_test, time_point) {
auto t1 = std::chrono::system_clock::now();
EXPECT_EQ(strftime_full(t1), fmt::format("{:%Y-%m-%d %H:%M:%S}", t1));
EXPECT_EQ(strftime_full(t1), fmt::format("{}", t1));
using time_point =
std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
auto t2 = time_point(std::chrono::seconds(42));
EXPECT_EQ(strftime_full(t2), fmt::format("{:%Y-%m-%d %H:%M:%S}", t2));
std::vector<std::string> spec_list = {
"%%", "%n", "%t", "%Y", "%EY", "%y", "%Oy", "%Ey", "%C",
"%EC", "%G", "%g", "%b", "%h", "%B", "%m", "%Om", "%U",
"%OU", "%W", "%OW", "%V", "%OV", "%j", "%d", "%Od", "%e",
"%Oe", "%a", "%A", "%w", "%Ow", "%u", "%Ou", "%H", "%OH",
"%I", "%OI", "%M", "%OM", "%S", "%OS", "%x", "%Ex", "%X",
"%EX", "%D", "%F", "%R", "%T", "%p", "%z", "%Z"};
spec_list.push_back("%Y-%m-%d %H:%M:%S");
#ifndef _WIN32
// Disabled on Windows because these formats are not consistent among
// platforms.
spec_list.insert(spec_list.end(), {"%c", "%Ec", "%r"});
#endif
for (const auto& spec : spec_list) {
auto t = std::chrono::system_clock::to_time_t(t1);
auto tm = *std::localtime(&t);
auto sys_output = system_strftime(spec, &tm);
auto fmt_spec = fmt::format("{{:{}}}", spec);
EXPECT_EQ(sys_output, fmt::format(fmt::runtime(fmt_spec), t1));
EXPECT_EQ(sys_output, fmt::format(fmt::runtime(fmt_spec), tm));
}
}
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
TEST(ChronoTest, FormatDefault) {
TEST(chrono_test, format_default) {
EXPECT_EQ("42s", fmt::format("{}", std::chrono::seconds(42)));
EXPECT_EQ("42as",
fmt::format("{}", std::chrono::duration<int, std::atto>(42)));
@ -145,49 +324,7 @@ TEST(ChronoTest, FormatDefault) {
fmt::format("{}", std::chrono::duration<int, std::ratio<15, 4>>(42)));
}
TEST(ChronoTest, FormatWide) {
EXPECT_EQ(L"42s", fmt::format(L"{}", std::chrono::seconds(42)));
EXPECT_EQ(L"42as",
fmt::format(L"{}", std::chrono::duration<int, std::atto>(42)));
EXPECT_EQ(L"42fs",
fmt::format(L"{}", std::chrono::duration<int, std::femto>(42)));
EXPECT_EQ(L"42ps",
fmt::format(L"{}", std::chrono::duration<int, std::pico>(42)));
EXPECT_EQ(L"42ns", fmt::format(L"{}", std::chrono::nanoseconds(42)));
EXPECT_EQ(L"42\u00B5s", fmt::format(L"{}", std::chrono::microseconds(42)));
EXPECT_EQ(L"42ms", fmt::format(L"{}", std::chrono::milliseconds(42)));
EXPECT_EQ(L"42cs",
fmt::format(L"{}", std::chrono::duration<int, std::centi>(42)));
EXPECT_EQ(L"42ds",
fmt::format(L"{}", std::chrono::duration<int, std::deci>(42)));
EXPECT_EQ(L"42s", fmt::format(L"{}", std::chrono::seconds(42)));
EXPECT_EQ(L"42das",
fmt::format(L"{}", std::chrono::duration<int, std::deca>(42)));
EXPECT_EQ(L"42hs",
fmt::format(L"{}", std::chrono::duration<int, std::hecto>(42)));
EXPECT_EQ(L"42ks",
fmt::format(L"{}", std::chrono::duration<int, std::kilo>(42)));
EXPECT_EQ(L"42Ms",
fmt::format(L"{}", std::chrono::duration<int, std::mega>(42)));
EXPECT_EQ(L"42Gs",
fmt::format(L"{}", std::chrono::duration<int, std::giga>(42)));
EXPECT_EQ(L"42Ts",
fmt::format(L"{}", std::chrono::duration<int, std::tera>(42)));
EXPECT_EQ(L"42Ps",
fmt::format(L"{}", std::chrono::duration<int, std::peta>(42)));
EXPECT_EQ(L"42Es",
fmt::format(L"{}", std::chrono::duration<int, std::exa>(42)));
EXPECT_EQ(L"42m", fmt::format(L"{}", std::chrono::minutes(42)));
EXPECT_EQ(L"42h", fmt::format(L"{}", std::chrono::hours(42)));
EXPECT_EQ(
L"42[15]s",
fmt::format(L"{}", std::chrono::duration<int, std::ratio<15, 1>>(42)));
EXPECT_EQ(
L"42[15/4]s",
fmt::format(L"{}", std::chrono::duration<int, std::ratio<15, 4>>(42)));
}
TEST(ChronoTest, Align) {
TEST(chrono_test, align) {
auto s = std::chrono::seconds(42);
EXPECT_EQ("42s ", fmt::format("{:5}", s));
EXPECT_EQ("42s ", fmt::format("{:{}}", s, 5));
@ -203,7 +340,7 @@ TEST(ChronoTest, Align) {
fmt::format("{:{}%H:%M:%S}", std::chrono::seconds(12345), 12));
}
TEST(ChronoTest, FormatSpecs) {
TEST(chrono_test, format_specs) {
EXPECT_EQ("%", fmt::format("{:%%}", std::chrono::seconds(0)));
EXPECT_EQ("\n", fmt::format("{:%n}", std::chrono::seconds(0)));
EXPECT_EQ("\t", fmt::format("{:%t}", std::chrono::seconds(0)));
@ -232,43 +369,64 @@ TEST(ChronoTest, FormatSpecs) {
EXPECT_EQ("s", fmt::format("{:%q}", std::chrono::seconds(12345)));
}
TEST(ChronoTest, InvalidSpecs) {
TEST(chrono_test, invalid_specs) {
auto sec = std::chrono::seconds(0);
EXPECT_THROW_MSG(fmt::format("{:%a}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%A}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%c}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%x}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%Ex}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%X}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%EX}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%D}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%F}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%Ec}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%w}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%u}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%b}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%B}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%z}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%Z}", sec), fmt::format_error, "no date");
EXPECT_THROW_MSG(fmt::format("{:%Eq}", sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%a}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%A}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%c}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%x}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Ex}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%X}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%EX}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%D}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%F}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Ec}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%w}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%u}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%b}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%B}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%z}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Z}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Eq}"), sec), fmt::format_error,
"invalid format");
EXPECT_THROW_MSG(fmt::format("{:%Oq}", sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Oq}"), sec), fmt::format_error,
"invalid format");
}
TEST(ChronoTest, Locale) {
const char* loc_name = "ja_JP.utf8";
bool has_locale = false;
std::locale loc;
try {
loc = std::locale(loc_name);
has_locale = true;
} catch (const std::runtime_error&) {
}
if (!has_locale) {
fmt::print("{} locale is missing.\n", loc_name);
return;
}
auto format_tm(const std::tm& time, fmt::string_view spec,
const std::locale& loc) -> std::string {
auto& facet = std::use_facet<std::time_put<char>>(loc);
std::ostringstream os;
os.imbue(loc);
facet.put(os, os, ' ', &time, spec.begin(), spec.end());
return os.str();
}
TEST(chrono_test, locale) {
auto loc = get_locale("ja_JP.utf8");
if (loc == std::locale::classic()) return;
# define EXPECT_TIME(spec, time, duration) \
{ \
auto jp_loc = std::locale("ja_JP.utf8"); \
EXPECT_EQ(format_tm(time, spec, jp_loc), \
fmt::format(jp_loc, "{:L" spec "}", duration)); \
}
EXPECT_TIME("%OH", make_hour(14), std::chrono::hours(14));
EXPECT_TIME("%OI", make_hour(14), std::chrono::hours(14));
EXPECT_TIME("%OM", make_minute(42), std::chrono::minutes(42));
@ -282,9 +440,9 @@ TEST(ChronoTest, Locale) {
EXPECT_TIME("%p", time, sec);
}
typedef std::chrono::duration<double, std::milli> dms;
using dms = std::chrono::duration<double, std::milli>;
TEST(ChronoTest, FormatDefaultFP) {
TEST(chrono_test, format_default_fp) {
typedef std::chrono::duration<float> fs;
EXPECT_EQ("1.234s", fmt::format("{}", fs(1.234)));
typedef std::chrono::duration<float, std::milli> fms;
@ -294,24 +452,37 @@ TEST(ChronoTest, FormatDefaultFP) {
EXPECT_EQ("1.234ms", fmt::format("{}", dms(1.234)));
}
TEST(ChronoTest, FormatPrecision) {
EXPECT_THROW_MSG(fmt::format("{:.2}", std::chrono::seconds(42)),
fmt::format_error,
"precision not allowed for this argument type");
TEST(chrono_test, format_precision) {
EXPECT_THROW_MSG(
(void)fmt::format(runtime("{:.2}"), std::chrono::seconds(42)),
fmt::format_error, "precision not allowed for this argument type");
EXPECT_EQ("1ms", fmt::format("{:.0}", dms(1.234)));
EXPECT_EQ("1.2ms", fmt::format("{:.1}", dms(1.234)));
EXPECT_EQ("1.23ms", fmt::format("{:.{}}", dms(1.234), 2));
EXPECT_EQ("13ms", fmt::format("{:.0}", dms(12.56)));
EXPECT_EQ("12.6ms", fmt::format("{:.1}", dms(12.56)));
EXPECT_EQ("12.56ms", fmt::format("{:.2}", dms(12.56)));
}
TEST(ChronoTest, FormatFullSpecs) {
TEST(chrono_test, format_full_specs) {
EXPECT_EQ("1ms ", fmt::format("{:6.0}", dms(1.234)));
EXPECT_EQ("1.2ms ", fmt::format("{:6.1}", dms(1.234)));
EXPECT_EQ(" 1.23ms", fmt::format("{:>8.{}}", dms(1.234), 2));
EXPECT_EQ(" 1.2ms ", fmt::format("{:^{}.{}}", dms(1.234), 7, 1));
EXPECT_EQ(" 1.23ms ", fmt::format("{0:^{2}.{1}}", dms(1.234), 2, 8));
EXPECT_EQ("=1.234ms=", fmt::format("{:=^{}.{}}", dms(1.234), 9, 3));
EXPECT_EQ("*1.2340ms*", fmt::format("{:*^10.4}", dms(1.234)));
EXPECT_EQ("13ms ", fmt::format("{:6.0}", dms(12.56)));
EXPECT_EQ(" 13ms", fmt::format("{:>8.{}}", dms(12.56), 0));
EXPECT_EQ(" 13ms ", fmt::format("{:^{}.{}}", dms(12.56), 6, 0));
EXPECT_EQ(" 13ms ", fmt::format("{0:^{2}.{1}}", dms(12.56), 0, 8));
EXPECT_EQ("==13ms===", fmt::format("{:=^{}.{}}", dms(12.56), 9, 0));
EXPECT_EQ("***13ms***", fmt::format("{:*^10.0}", dms(12.56)));
}
TEST(ChronoTest, FormatSimpleQq) {
TEST(chrono_test, format_simple_q) {
typedef std::chrono::duration<float> fs;
EXPECT_EQ("1.234 s", fmt::format("{:%Q %q}", fs(1.234)));
typedef std::chrono::duration<float, std::milli> fms;
@ -321,34 +492,42 @@ TEST(ChronoTest, FormatSimpleQq) {
EXPECT_EQ("1.234 ms", fmt::format("{:%Q %q}", dms(1.234)));
}
TEST(ChronoTest, FormatPrecisionQq) {
EXPECT_THROW_MSG(fmt::format("{:.2%Q %q}", std::chrono::seconds(42)),
fmt::format_error,
"precision not allowed for this argument type");
TEST(chrono_test, format_precision_q) {
EXPECT_THROW_MSG(
(void)fmt::format(runtime("{:.2%Q %q}"), std::chrono::seconds(42)),
fmt::format_error, "precision not allowed for this argument type");
EXPECT_EQ("1.2 ms", fmt::format("{:.1%Q %q}", dms(1.234)));
EXPECT_EQ("1.23 ms", fmt::format("{:.{}%Q %q}", dms(1.234), 2));
}
TEST(ChronoTest, FormatFullSpecsQq) {
TEST(chrono_test, format_full_specs_q) {
EXPECT_EQ("1 ms ", fmt::format("{:7.0%Q %q}", dms(1.234)));
EXPECT_EQ("1.2 ms ", fmt::format("{:7.1%Q %q}", dms(1.234)));
EXPECT_EQ(" 1.23 ms", fmt::format("{:>8.{}%Q %q}", dms(1.234), 2));
EXPECT_EQ(" 1.2 ms ", fmt::format("{:^{}.{}%Q %q}", dms(1.234), 8, 1));
EXPECT_EQ(" 1.23 ms ", fmt::format("{0:^{2}.{1}%Q %q}", dms(1.234), 2, 9));
EXPECT_EQ("=1.234 ms=", fmt::format("{:=^{}.{}%Q %q}", dms(1.234), 10, 3));
EXPECT_EQ("*1.2340 ms*", fmt::format("{:*^11.4%Q %q}", dms(1.234)));
EXPECT_EQ("13 ms ", fmt::format("{:7.0%Q %q}", dms(12.56)));
EXPECT_EQ(" 13 ms", fmt::format("{:>8.{}%Q %q}", dms(12.56), 0));
EXPECT_EQ(" 13 ms ", fmt::format("{:^{}.{}%Q %q}", dms(12.56), 8, 0));
EXPECT_EQ(" 13 ms ", fmt::format("{0:^{2}.{1}%Q %q}", dms(12.56), 0, 9));
EXPECT_EQ("==13 ms==", fmt::format("{:=^{}.{}%Q %q}", dms(12.56), 9, 0));
EXPECT_EQ("***13 ms***", fmt::format("{:*^11.0%Q %q}", dms(12.56)));
}
TEST(ChronoTest, InvalidWidthId) {
EXPECT_THROW(fmt::format("{:{o}", std::chrono::seconds(0)),
TEST(chrono_test, invalid_width_id) {
EXPECT_THROW((void)fmt::format(runtime("{:{o}"), std::chrono::seconds(0)),
fmt::format_error);
}
TEST(ChronoTest, InvalidColons) {
EXPECT_THROW(fmt::format("{0}=:{0::", std::chrono::seconds(0)),
TEST(chrono_test, invalid_colons) {
EXPECT_THROW((void)fmt::format(runtime("{0}=:{0::"), std::chrono::seconds(0)),
fmt::format_error);
}
TEST(ChronoTest, NegativeDurations) {
TEST(chrono_test, negative_durations) {
EXPECT_EQ("-12345", fmt::format("{:%Q}", std::chrono::seconds(-12345)));
EXPECT_EQ("-03:25:45",
fmt::format("{:%H:%M:%S}", std::chrono::seconds(-12345)));
@ -363,16 +542,13 @@ TEST(ChronoTest, NegativeDurations) {
fmt::format("{:%Q}", std::chrono::duration<int>(min)));
}
TEST(ChronoTest, SpecialDurations) {
EXPECT_EQ(
"40.",
fmt::format("{:%S}", std::chrono::duration<double>(1e20)).substr(0, 3));
TEST(chrono_test, special_durations) {
auto value = fmt::format("{:%S}", std::chrono::duration<double>(1e20));
EXPECT_EQ(value, "40");
auto nan = std::numeric_limits<double>::quiet_NaN();
EXPECT_EQ(
"nan nan nan nan nan:nan nan",
fmt::format("{:%I %H %M %S %R %r}", std::chrono::duration<double>(nan)));
fmt::format("{:%S}",
std::chrono::duration<float, std::atto>(1.79400457e+31f));
EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::exa>(1)),
"1Es");
EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::atto>(1)),
@ -381,6 +557,76 @@ TEST(ChronoTest, SpecialDurations) {
"03:33");
EXPECT_EQ(fmt::format("{:%T}", std::chrono::duration<char, std::mega>{2}),
"03:33:20");
EXPECT_EQ("44.000000000000",
fmt::format("{:%S}", std::chrono::duration<float, std::pico>(
1.54213895E+26)));
}
TEST(chrono_test, unsigned_duration) {
EXPECT_EQ("42s", fmt::format("{}", std::chrono::duration<unsigned>(42)));
}
TEST(chrono_test, weekday) {
auto loc = get_locale("ru_RU.UTF-8");
std::locale::global(loc);
auto mon = fmt::weekday(1);
auto tm = std::tm();
tm.tm_wday = static_cast<int>(mon.c_encoding());
EXPECT_EQ(fmt::format("{}", mon), "Mon");
EXPECT_EQ(fmt::format("{:%a}", tm), "Mon");
if (loc != std::locale::classic()) {
EXPECT_THAT((std::vector<std::string>{"пн", "Пн", "пнд", "Пнд"}),
Contains(fmt::format(loc, "{:L}", mon)));
EXPECT_THAT((std::vector<std::string>{"пн", "Пн", "пнд", "Пнд"}),
Contains(fmt::format(loc, "{:%a}", tm)));
}
}
TEST(chrono_test, cpp20_duration_subsecond_support) {
using attoseconds = std::chrono::duration<long long, std::atto>;
// Check that 18 digits of subsecond precision are supported.
EXPECT_EQ(fmt::format("{:%S}", attoseconds{999999999999999999}),
"00.999999999999999999");
EXPECT_EQ(fmt::format("{:%S}", attoseconds{673231113420148734}),
"00.673231113420148734");
EXPECT_EQ(fmt::format("{:%S}", attoseconds{-673231113420148734}),
"-00.673231113420148734");
EXPECT_EQ(fmt::format("{:%S}", std::chrono::nanoseconds{13420148734}),
"13.420148734");
EXPECT_EQ(fmt::format("{:%S}", std::chrono::nanoseconds{-13420148734}),
"-13.420148734");
EXPECT_EQ(fmt::format("{:%S}", std::chrono::milliseconds{1234}), "01.234");
{
// Check that {:%H:%M:%S} is equivalent to {:%T}.
auto dur = std::chrono::milliseconds{3601234};
auto formatted_dur = fmt::format("{:%T}", dur);
EXPECT_EQ(formatted_dur, "01:00:01.234");
EXPECT_EQ(fmt::format("{:%H:%M:%S}", dur), formatted_dur);
}
using nanoseconds_dbl = std::chrono::duration<double, std::nano>;
EXPECT_EQ(fmt::format("{:%S}", nanoseconds_dbl{-123456789}), "-00.123456789");
EXPECT_EQ(fmt::format("{:%S}", nanoseconds_dbl{9123456789}), "09.123456789");
// Verify that only the seconds part is extracted and printed.
EXPECT_EQ(fmt::format("{:%S}", nanoseconds_dbl{99123456789}), "39.123456789");
EXPECT_EQ(fmt::format("{:%S}", nanoseconds_dbl{99123000000}), "39.123000000");
{
// Now the hour is printed, and we also test if negative doubles work.
auto dur = nanoseconds_dbl{-99123456789};
auto formatted_dur = fmt::format("{:%T}", dur);
EXPECT_EQ(formatted_dur, "-00:01:39.123456789");
EXPECT_EQ(fmt::format("{:%H:%M:%S}", dur), formatted_dur);
}
// Check that durations with precision greater than std::chrono::seconds have
// fixed precision, and print zeros even if there is no fractional part.
EXPECT_EQ(fmt::format("{:%S}", std::chrono::microseconds{7000000}),
"07.000000");
EXPECT_EQ(fmt::format("{:%S}", std::chrono::duration<long long, std::ratio<1, 3>>(1)),
"00.333333");
EXPECT_EQ(fmt::format("{:%S}", std::chrono::duration<long long, std::ratio<1, 7>>(1)),
"00.142857");
}
#endif // FMT_STATIC_THOUSANDS_SEPARATOR

View File

@ -6,62 +6,30 @@
// For the license information refer to format.h.
#include "fmt/color.h"
#include "gtest-extra.h"
TEST(ColorsTest, ColorsPrint) {
EXPECT_WRITE(stdout, fmt::print(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"),
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
EXPECT_WRITE(stdout, fmt::print(fg(fmt::color::blue), "blue"),
"\x1b[38;2;000;000;255mblue\x1b[0m");
EXPECT_WRITE(
stdout,
fmt::print(fg(fmt::color::blue) | bg(fmt::color::red), "two color"),
"\x1b[38;2;000;000;255m\x1b[48;2;255;000;000mtwo color\x1b[0m");
EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::bold, "bold"),
"\x1b[1mbold\x1b[0m");
EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::italic, "italic"),
"\x1b[3mitalic\x1b[0m");
EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::underline, "underline"),
"\x1b[4munderline\x1b[0m");
EXPECT_WRITE(stdout,
fmt::print(fmt::emphasis::strikethrough, "strikethrough"),
"\x1b[9mstrikethrough\x1b[0m");
EXPECT_WRITE(
stdout,
fmt::print(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"),
"\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m");
EXPECT_WRITE(stderr, fmt::print(stderr, fmt::emphasis::bold, "bold error"),
"\x1b[1mbold error\x1b[0m");
EXPECT_WRITE(stderr, fmt::print(stderr, fg(fmt::color::blue), "blue log"),
"\x1b[38;2;000;000;255mblue log\x1b[0m");
EXPECT_WRITE(stdout, fmt::print(fmt::text_style(), "hi"), "hi");
EXPECT_WRITE(stdout, fmt::print(fg(fmt::terminal_color::red), "tred"),
"\x1b[31mtred\x1b[0m");
EXPECT_WRITE(stdout, fmt::print(bg(fmt::terminal_color::cyan), "tcyan"),
"\x1b[46mtcyan\x1b[0m");
EXPECT_WRITE(stdout,
fmt::print(fg(fmt::terminal_color::bright_green), "tbgreen"),
"\x1b[92mtbgreen\x1b[0m");
EXPECT_WRITE(stdout,
fmt::print(bg(fmt::terminal_color::bright_magenta), "tbmagenta"),
"\x1b[105mtbmagenta\x1b[0m");
}
#include <iterator> // std::back_inserter
TEST(ColorsTest, Format) {
#include "gtest-extra.h" // EXPECT_WRITE
TEST(color_test, format) {
EXPECT_EQ(fmt::format(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"),
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
EXPECT_EQ(fmt::format(fg(fmt::rgb(255, 20, 30)), L"rgb(255,20,30) wide"),
L"\x1b[38;2;255;020;030mrgb(255,20,30) wide\x1b[0m");
EXPECT_EQ(fmt::format(fg(fmt::color::blue), "blue"),
"\x1b[38;2;000;000;255mblue\x1b[0m");
EXPECT_EQ(
fmt::format(fg(fmt::color::blue) | bg(fmt::color::red), "two color"),
"\x1b[38;2;000;000;255m\x1b[48;2;255;000;000mtwo color\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold"), "\x1b[1mbold\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::faint, "faint"), "\x1b[2mfaint\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::italic, "italic"),
"\x1b[3mitalic\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::underline, "underline"),
"\x1b[4munderline\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::blink, "blink"), "\x1b[5mblink\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::reverse, "reverse"),
"\x1b[7mreverse\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::conceal, "conceal"),
"\x1b[8mconceal\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::strikethrough, "strikethrough"),
"\x1b[9mstrikethrough\x1b[0m");
EXPECT_EQ(
@ -82,4 +50,23 @@ TEST(ColorsTest, Format) {
"\x1b[105mtbmagenta\x1b[0m");
EXPECT_EQ(fmt::format(fg(fmt::terminal_color::red), "{}", "foo"),
"\x1b[31mfoo\x1b[0m");
EXPECT_EQ(fmt::format("{}{}", fmt::styled("red", fg(fmt::color::red)),
fmt::styled("bold", fmt::emphasis::bold)),
"\x1b[38;2;255;000;000mred\x1b[0m\x1b[1mbold\x1b[0m");
EXPECT_EQ(fmt::format("{}", fmt::styled("bar", fg(fmt::color::blue) |
fmt::emphasis::underline)),
"\x1b[4m\x1b[38;2;000;000;255mbar\x1b[0m");
}
TEST(color_test, format_to) {
auto out = std::string();
fmt::format_to(std::back_inserter(out), fg(fmt::rgb(255, 20, 30)),
"rgb(255,20,30){}{}{}", 1, 2, 3);
EXPECT_EQ(fmt::to_string(out),
"\x1b[38;2;255;020;030mrgb(255,20,30)123\x1b[0m");
}
TEST(color_test, print) {
EXPECT_WRITE(stdout, fmt::print(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"),
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
}

View File

@ -1,71 +1,182 @@
# Test if compile errors are produced where necessary.
cmake_minimum_required(VERSION 3.1.0)
cmake_minimum_required(VERSION 3.1...3.18)
project(compile-error-test CXX)
include(CheckCXXSourceCompiles)
include(CheckCXXCompilerFlag)
set(fmt_headers "
#include <fmt/format.h>
#include <fmt/xchar.h>
#include <fmt/ostream.h>
#include <iostream>
")
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG} ${PEDANTIC_COMPILE_FLAGS})
set(error_test_names "")
set(non_error_test_content "")
function (generate_source result fragment)
set(${result} "
#define FMT_HEADER_ONLY 1
#include \"fmt/format.h\"
int main() {
${fragment}
}
" PARENT_SCOPE)
# For error tests (we expect them to produce compilation error):
# * adds a name of test into `error_test_names` list
# * generates a single source file (with the same name) for each test
# For non-error tests (we expect them to compile successfully):
# * adds a code segment as separate function to `non_error_test_content`
function (expect_compile name code_fragment)
cmake_parse_arguments(EXPECT_COMPILE "ERROR" "" "" ${ARGN})
string(MAKE_C_IDENTIFIER "${name}" test_name)
if (EXPECT_COMPILE_ERROR)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/${test_name}.cc" "
${fmt_headers}
void ${test_name}() {
${code_fragment}
}
")
set(error_test_names_copy "${error_test_names}")
list(APPEND error_test_names_copy "${test_name}")
set(error_test_names "${error_test_names_copy}" PARENT_SCOPE)
else()
set(non_error_test_content "
${non_error_test_content}
void ${test_name}() {
${code_fragment}
}" PARENT_SCOPE)
endif()
endfunction ()
function (expect_compile code)
generate_source(source "${code}")
check_cxx_source_compiles("${source}" compiles)
if (NOT compiles)
set(error_msg "Compile error for: ${code}")
endif ()
# Unset the CMake cache variable compiles. Otherwise the compile test will
# just use cached information next time it runs.
unset(compiles CACHE)
if (error_msg)
message(FATAL_ERROR ${error_msg})
# Generates a source file for non-error test with `non_error_test_content` and
# CMake project file with all error and single non-error test targets.
function (run_tests)
set(cmake_targets "")
foreach(test_name IN LISTS error_test_names)
set(cmake_targets "
${cmake_targets}
add_library(test-${test_name} ${test_name}.cc)
target_link_libraries(test-${test_name} PRIVATE fmt::fmt)
")
endforeach()
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/non_error_test.cc" "
${fmt_headers}
${non_error_test_content}
")
set(cmake_targets "
${cmake_targets}
add_library(non-error-test non_error_test.cc)
target_link_libraries(non-error-test PRIVATE fmt::fmt)
")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/CMakeLists.txt" "
cmake_minimum_required(VERSION 3.1...3.18)
project(tests CXX)
add_subdirectory(${FMT_DIR} fmt)
${cmake_targets}
")
set(build_directory "${CMAKE_CURRENT_BINARY_DIR}/test/build")
file(MAKE_DIRECTORY "${build_directory}")
execute_process(
COMMAND
"${CMAKE_COMMAND}"
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DCMAKE_GENERATOR=${CMAKE_GENERATOR}"
"-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}"
"-DFMT_DIR=${FMT_DIR}"
"${CMAKE_CURRENT_BINARY_DIR}/test"
WORKING_DIRECTORY "${build_directory}"
RESULT_VARIABLE result_var
OUTPUT_VARIABLE output_var
ERROR_VARIABLE output_var)
if (NOT result_var EQUAL 0)
message(FATAL_ERROR "Unable to configure:\n${output_var}")
endif()
foreach(test_name IN LISTS error_test_names)
execute_process(
COMMAND
"${CMAKE_COMMAND}" --build "${build_directory}" --target "test-${test_name}"
WORKING_DIRECTORY "${build_directory}"
RESULT_VARIABLE result_var
OUTPUT_VARIABLE output_var
ERROR_QUIET)
if (result_var EQUAL 0)
message(SEND_ERROR "No compile error for \"${test_name}\":\n${output_var}")
endif ()
endforeach()
execute_process(
COMMAND
"${CMAKE_COMMAND}" --build "${build_directory}" --target "non-error-test"
WORKING_DIRECTORY "${build_directory}"
RESULT_VARIABLE result_var
OUTPUT_VARIABLE output_var
ERROR_VARIABLE output_var)
if (NOT result_var EQUAL 0)
message(SEND_ERROR "Compile error for combined non-error test:\n${output_var}")
endif ()
endfunction ()
function (expect_compile_error code)
generate_source(source "${code}")
check_cxx_source_compiles("${source}" compiles)
if (compiles)
set(error_msg "No compile error for: ${code}")
endif ()
# Unset the CMake cache variable compiles. Otherwise the compile test will
# just use cached information next time it runs.
unset(compiles CACHE)
if (error_msg)
message(FATAL_ERROR ${error_msg})
endif ()
endfunction ()
# check if the source file skeleton compiles
expect_compile("")
expect_compile(check "")
expect_compile(check-error "compilation_error" ERROR)
# Formatting a wide character with a narrow format string is forbidden.
expect_compile_error("fmt::format(\"{}\", L'a');")
expect_compile(wide-character-narrow-format-string "fmt::format(L\"{}\", L'a');")
expect_compile(wide-character-narrow-format-string-error "fmt::format(\"{}\", L'a');" ERROR)
# Formatting a wide string with a narrow format string is forbidden.
expect_compile_error("fmt::format(\"{}\", L\"foo\");")
expect_compile(wide-string-narrow-format-string "fmt::format(L\"{}\", L\"foo\");")
expect_compile(wide-string-narrow-format-string-error "fmt::format(\"{}\", L\"foo\");" ERROR)
# Formatting a narrow string with a wide format string is forbidden because
# mixing UTF-8 with UTF-16/32 can result in an invalid output.
expect_compile_error("fmt::format(L\"{}\", \"foo\");")
expect_compile(narrow-string-wide-format-string "fmt::format(L\"{}\", L\"foo\");")
expect_compile(narrow-string-wide-format-string-error "fmt::format(L\"{}\", \"foo\");" ERROR)
# Formatting a wide string with a narrow format string is forbidden.
expect_compile_error("
expect_compile(cast-to-string "
struct S {
operator std::string() const { return std::string(); }
};
fmt::format(\"{}\", std::string(S()));
")
expect_compile(cast-to-string-error "
struct S {
operator std::string() const { return std::string(); }
};
fmt::format(\"{}\", S());
" ERROR)
# Formatting a function
expect_compile(format-function "
void (*f)();
fmt::format(\"{}\", fmt::ptr(f));
")
expect_compile(format-function-error "
void (*f)();
fmt::format(\"{}\", f);
" ERROR)
# Formatting an unformattable argument should always be a compile time error
expect_compile(format-lots-of-arguments-with-unformattable "
struct E {};
fmt::format(\"\", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, E());
" ERROR)
expect_compile(format-lots-of-arguments-with-function "
void (*f)();
fmt::format(\"\", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, f);
" ERROR)
# Check if user-defined literals are available
include(CheckCXXSourceCompiles)
set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG})
check_cxx_source_compiles("
void operator\"\" _udl(long double);
int main() {}"
SUPPORTS_USER_DEFINED_LITERALS)
set(CMAKE_REQUIRED_FLAGS )
if (NOT SUPPORTS_USER_DEFINED_LITERALS)
set (SUPPORTS_USER_DEFINED_LITERALS OFF)
endif ()
# Make sure that compiler features detected in the header
# match the features detected in CMake.
@ -74,6 +185,57 @@ if (SUPPORTS_USER_DEFINED_LITERALS)
else ()
set(supports_udl 0)
endif ()
expect_compile("#if FMT_USE_USER_DEFINED_LITERALS != ${supports_udl}
# error
#endif")
expect_compile(udl-check "
#if FMT_USE_USER_DEFINED_LITERALS != ${supports_udl}
# error
#endif
")
if (CMAKE_CXX_STANDARD GREATER_EQUAL 20)
# Compile-time argument type check
expect_compile(format-string-number-spec "
#ifdef FMT_HAS_CONSTEVAL
fmt::format(\"{:d}\", 42);
#endif
")
expect_compile(format-string-number-spec-error "
#ifdef FMT_HAS_CONSTEVAL
fmt::format(\"{:d}\", \"I am not a number\");
#else
#error
#endif
" ERROR)
expect_compile(print-string-number-spec-error "
#ifdef FMT_HAS_CONSTEVAL
fmt::print(\"{:d}\", \"I am not a number\");
#else
#error
#endif
" ERROR)
expect_compile(print-stream-string-number-spec-error "
#ifdef FMT_HAS_CONSTEVAL
fmt::print(std::cout, \"{:d}\", \"I am not a number\");
#else
#error
#endif
" ERROR)
# Compile-time argument name check
expect_compile(format-string-name "
#if defined(FMT_HAS_CONSTEVAL) && FMT_USE_NONTYPE_TEMPLATE_ARGS
using namespace fmt::literals;
fmt::print(\"{foo}\", \"foo\"_a=42);
#endif
")
expect_compile(format-string-name-error "
#if defined(FMT_HAS_CONSTEVAL) && FMT_USE_NONTYPE_TEMPLATE_ARGS
using namespace fmt::literals;
fmt::print(\"{foo}\", \"bar\"_a=42);
#else
#error
#endif
" ERROR)
endif ()
# Run all tests
run_tests()

62
externals/fmt/test/compile-fp-test.cc vendored Normal file
View File

@ -0,0 +1,62 @@
// Formatting library for C++ - formatting library tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/compile.h"
#include "gmock/gmock.h"
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806 && \
defined(__cpp_constexpr) && __cpp_constexpr >= 201907 && \
defined(__cpp_constexpr_dynamic_alloc) && \
__cpp_constexpr_dynamic_alloc >= 201907 && FMT_CPLUSPLUS >= 202002L
template <size_t max_string_length, typename Char = char> struct test_string {
template <typename T> constexpr bool operator==(const T& rhs) const noexcept {
return fmt::basic_string_view<Char>(rhs).compare(buffer) == 0;
}
Char buffer[max_string_length]{};
};
template <size_t max_string_length, typename Char = char, typename... Args>
consteval auto test_format(auto format, const Args&... args) {
test_string<max_string_length, Char> string{};
fmt::format_to(string.buffer, format, args...);
return string;
}
TEST(compile_time_formatting_test, floating_point) {
EXPECT_EQ("0", test_format<2>(FMT_COMPILE("{}"), 0.0f));
EXPECT_EQ("392.500000", test_format<11>(FMT_COMPILE("{0:f}"), 392.5f));
EXPECT_EQ("0", test_format<2>(FMT_COMPILE("{:}"), 0.0));
EXPECT_EQ("0.000000", test_format<9>(FMT_COMPILE("{:f}"), 0.0));
EXPECT_EQ("0", test_format<2>(FMT_COMPILE("{:g}"), 0.0));
EXPECT_EQ("392.65", test_format<7>(FMT_COMPILE("{:}"), 392.65));
EXPECT_EQ("392.65", test_format<7>(FMT_COMPILE("{:g}"), 392.65));
EXPECT_EQ("392.65", test_format<7>(FMT_COMPILE("{:G}"), 392.65));
EXPECT_EQ("4.9014e+06", test_format<11>(FMT_COMPILE("{:g}"), 4.9014e6));
EXPECT_EQ("-392.650000", test_format<12>(FMT_COMPILE("{:f}"), -392.65));
EXPECT_EQ("-392.650000", test_format<12>(FMT_COMPILE("{:F}"), -392.65));
EXPECT_EQ("3.926500e+02", test_format<13>(FMT_COMPILE("{0:e}"), 392.65));
EXPECT_EQ("3.926500E+02", test_format<13>(FMT_COMPILE("{0:E}"), 392.65));
EXPECT_EQ("+0000392.6", test_format<11>(FMT_COMPILE("{0:+010.4g}"), 392.65));
EXPECT_EQ("9223372036854775808.000000",
test_format<27>(FMT_COMPILE("{:f}"), 9223372036854775807.0));
constexpr double nan = std::numeric_limits<double>::quiet_NaN();
EXPECT_EQ("nan", test_format<4>(FMT_COMPILE("{}"), nan));
EXPECT_EQ("+nan", test_format<5>(FMT_COMPILE("{:+}"), nan));
if (std::signbit(-nan))
EXPECT_EQ("-nan", test_format<5>(FMT_COMPILE("{}"), -nan));
else
fmt::print("Warning: compiler doesn't handle negative NaN correctly");
constexpr double inf = std::numeric_limits<double>::infinity();
EXPECT_EQ("inf", test_format<4>(FMT_COMPILE("{}"), inf));
EXPECT_EQ("+inf", test_format<5>(FMT_COMPILE("{:+}"), inf));
EXPECT_EQ("-inf", test_format<5>(FMT_COMPILE("{}"), -inf));
}
#endif

View File

@ -5,139 +5,384 @@
//
// For the license information refer to format.h.
#include <stdint.h>
#include <cctype>
#include <cfloat>
#include <climits>
#include <cmath>
#include <cstring>
#include <deque>
#include <list>
#include <memory>
#include <string>
// Check if fmt/compile.h compiles with windows.h included before it.
#ifdef _WIN32
# include <windows.h>
#endif
#include "fmt/compile.h"
#include "gmock.h"
#include <type_traits>
#include "fmt/chrono.h"
#include "gmock/gmock.h"
#include "gtest-extra.h"
#include "mock-allocator.h"
#include "util.h"
#undef ERROR
#undef min
#undef max
using testing::Return;
using testing::StrictMock;
// compiletime_prepared_parts_type_provider is useful only with relaxed
// constexpr.
#if FMT_USE_CONSTEXPR
template <unsigned EXPECTED_PARTS_COUNT, typename Format>
void check_prepared_parts_type(Format format) {
typedef fmt::internal::compiled_format_base<decltype(format)> provider;
typedef fmt::internal::format_part<char>
expected_parts_type[EXPECTED_PARTS_COUNT];
static_assert(std::is_same<typename provider::parts_container,
expected_parts_type>::value,
"CompileTimePreparedPartsTypeProvider test failed");
TEST(iterator_test, counting_iterator) {
auto it = fmt::detail::counting_iterator();
auto prev = it++;
EXPECT_EQ(prev.count(), 0);
EXPECT_EQ(it.count(), 1);
EXPECT_EQ((it + 41).count(), 42);
}
TEST(CompileTest, CompileTimePreparedPartsTypeProvider) {
check_prepared_parts_type<1u>(FMT_STRING("text"));
check_prepared_parts_type<1u>(FMT_STRING("{}"));
check_prepared_parts_type<2u>(FMT_STRING("text{}"));
check_prepared_parts_type<2u>(FMT_STRING("{}text"));
check_prepared_parts_type<3u>(FMT_STRING("text{}text"));
check_prepared_parts_type<3u>(FMT_STRING("{:{}.{}} {:{}}"));
TEST(iterator_test, truncating_iterator) {
char* p = nullptr;
auto it = fmt::detail::truncating_iterator<char*>(p, 3);
auto prev = it++;
EXPECT_EQ(prev.base(), p);
EXPECT_EQ(it.base(), p + 1);
}
check_prepared_parts_type<3u>(FMT_STRING("{{{}}}")); // '{', 'argument', '}'
check_prepared_parts_type<2u>(FMT_STRING("text{{")); // 'text', '{'
check_prepared_parts_type<3u>(FMT_STRING("text{{ ")); // 'text', '{', ' '
check_prepared_parts_type<2u>(FMT_STRING("}}text")); // '}', text
check_prepared_parts_type<2u>(FMT_STRING("text}}text")); // 'text}', 'text'
check_prepared_parts_type<4u>(
FMT_STRING("text{{}}text")); // 'text', '{', '}', 'text'
TEST(iterator_test, truncating_iterator_default_construct) {
auto it = fmt::detail::truncating_iterator<char*>();
EXPECT_EQ(nullptr, it.base());
EXPECT_EQ(std::size_t{0}, it.count());
}
#ifdef __cpp_lib_ranges
TEST(iterator_test, truncating_iterator_is_output_iterator) {
static_assert(
std::output_iterator<fmt::detail::truncating_iterator<char*>, char>);
}
#endif
TEST(CompileTest, PassStringLiteralFormat) {
const auto prepared = fmt::compile<int>("test {}");
EXPECT_EQ("test 42", fmt::format(prepared, 42));
const auto wprepared = fmt::compile<int>(L"test {}");
EXPECT_EQ(L"test 42", fmt::format(wprepared, 42));
TEST(iterator_test, truncating_back_inserter) {
auto buffer = std::string();
auto bi = std::back_inserter(buffer);
auto it = fmt::detail::truncating_iterator<decltype(bi)>(bi, 2);
*it++ = '4';
*it++ = '2';
*it++ = '1';
EXPECT_EQ(buffer.size(), 2);
EXPECT_EQ(buffer, "42");
}
#if FMT_USE_CONSTEXPR
TEST(CompileTest, PassCompileString) {
const auto prepared = fmt::compile<int>(FMT_STRING("test {}"));
EXPECT_EQ("test 42", fmt::format(prepared, 42));
const auto wprepared = fmt::compile<int>(FMT_STRING(L"test {}"));
EXPECT_EQ(L"test 42", fmt::format(wprepared, 42));
}
#endif
TEST(CompileTest, FormatToArrayOfChars) {
char buffer[32] = {0};
const auto prepared = fmt::compile<int>("4{}");
fmt::format_to(fmt::internal::make_checked(buffer, 32), prepared, 2);
EXPECT_EQ(std::string("42"), buffer);
wchar_t wbuffer[32] = {0};
const auto wprepared = fmt::compile<int>(L"4{}");
fmt::format_to(fmt::internal::make_checked(wbuffer, 32), wprepared, 2);
EXPECT_EQ(std::wstring(L"42"), wbuffer);
TEST(compile_test, compile_fallback) {
// FMT_COMPILE should fallback on runtime formatting when `if constexpr` is
// not available.
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42));
}
TEST(CompileTest, FormatToIterator) {
std::string s(2, ' ');
const auto prepared = fmt::compile<int>("4{}");
fmt::format_to(s.begin(), prepared, 2);
EXPECT_EQ("42", s);
std::wstring ws(2, L' ');
const auto wprepared = fmt::compile<int>(L"4{}");
fmt::format_to(ws.begin(), wprepared, 2);
EXPECT_EQ(L"42", ws);
}
TEST(CompileTest, FormatToN) {
char buf[5];
auto f = fmt::compile<int>("{:10}");
auto result = fmt::format_to_n(buf, 5, f, 42);
EXPECT_EQ(result.size, 10);
EXPECT_EQ(result.out, buf + 5);
EXPECT_EQ(fmt::string_view(buf, 5), " ");
}
TEST(CompileTest, FormattedSize) {
auto f = fmt::compile<int>("{:10}");
EXPECT_EQ(fmt::formatted_size(f, 42), 10);
}
TEST(CompileTest, MultipleTypes) {
auto f = fmt::compile<int, int>("{} {}");
EXPECT_EQ(fmt::format(f, 42, 42), "42 42");
}
struct formattable {};
struct type_with_get {
template <int> friend void get(type_with_get);
};
FMT_BEGIN_NAMESPACE
template <> struct formatter<formattable> : formatter<const char*> {
auto format(formattable, format_context& ctx) -> decltype(ctx.out()) {
return formatter<const char*>::format("foo", ctx);
template <> struct formatter<type_with_get> : formatter<int> {
template <typename FormatContext>
auto format(type_with_get, FormatContext& ctx) -> decltype(ctx.out()) {
return formatter<int>::format(42, ctx);
}
};
FMT_END_NAMESPACE
TEST(CompileTest, FormatUserDefinedType) {
auto f = fmt::compile<formattable>("{}");
EXPECT_EQ(fmt::format(f, formattable()), "foo");
TEST(compile_test, compile_type_with_get) {
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), type_with_get()));
}
TEST(CompileTest, EmptyFormatString) {
auto f = fmt::compile<>("");
EXPECT_EQ(fmt::format(f), "");
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
struct test_formattable {};
FMT_BEGIN_NAMESPACE
template <> struct formatter<test_formattable> : formatter<const char*> {
char word_spec = 'f';
constexpr auto parse(format_parse_context& ctx) {
auto it = ctx.begin(), end = ctx.end();
if (it == end || *it == '}') return it;
if (it != end && (*it == 'f' || *it == 'b')) word_spec = *it++;
if (it != end && *it != '}') throw format_error("invalid format");
return it;
}
template <typename FormatContext>
constexpr auto format(test_formattable, FormatContext& ctx) const
-> decltype(ctx.out()) {
return formatter<const char*>::format(word_spec == 'f' ? "foo" : "bar",
ctx);
}
};
FMT_END_NAMESPACE
TEST(compile_test, format_default) {
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42));
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42u));
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42ll));
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42ull));
EXPECT_EQ("true", fmt::format(FMT_COMPILE("{}"), true));
EXPECT_EQ("x", fmt::format(FMT_COMPILE("{}"), 'x'));
EXPECT_EQ("4.2", fmt::format(FMT_COMPILE("{}"), 4.2));
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), "foo"));
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), std::string("foo")));
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), test_formattable()));
auto t = std::chrono::system_clock::now();
EXPECT_EQ(fmt::format("{}", t), fmt::format(FMT_COMPILE("{}"), t));
# ifdef __cpp_lib_byte
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), std::byte{42}));
# endif
}
TEST(compile_test, format_wide_string) {
EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{}"), 42));
}
TEST(compile_test, format_specs) {
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42));
EXPECT_EQ("1.2 ms ",
fmt::format(FMT_COMPILE("{:7.1%Q %q}"),
std::chrono::duration<double, std::milli>(1.234)));
}
TEST(compile_test, dynamic_format_specs) {
EXPECT_EQ("foo ", fmt::format(FMT_COMPILE("{:{}}"), "foo", 5));
EXPECT_EQ(" 3.14", fmt::format(FMT_COMPILE("{:{}.{}f}"), 3.141592, 6, 2));
EXPECT_EQ(
"=1.234ms=",
fmt::format(FMT_COMPILE("{:=^{}.{}}"),
std::chrono::duration<double, std::milli>(1.234), 9, 3));
}
TEST(compile_test, manual_ordering) {
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{0}"), 42));
EXPECT_EQ(" -42", fmt::format(FMT_COMPILE("{0:4}"), -42));
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{0} {1}"), 41, 43));
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{1} {0}"), 43, 41));
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{0} {2}"), 41, 42, 43));
EXPECT_EQ(" 41 43", fmt::format(FMT_COMPILE("{1:{2}} {0:4}"), 43, 41, 4));
EXPECT_EQ("42 1.2 ms ",
fmt::format(FMT_COMPILE("{0} {1:7.1%Q %q}"), 42,
std::chrono::duration<double, std::milli>(1.234)));
EXPECT_EQ(
"true 42 42 foo 0x1234 foo",
fmt::format(FMT_COMPILE("{0} {1} {2} {3} {4} {5}"), true, 42, 42.0f,
"foo", reinterpret_cast<void*>(0x1234), test_formattable()));
EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{0}"), 42));
}
TEST(compile_test, named) {
auto runtime_named_field_compiled =
fmt::detail::compile<decltype(fmt::arg("arg", 42))>(FMT_COMPILE("{arg}"));
static_assert(std::is_same_v<decltype(runtime_named_field_compiled),
fmt::detail::runtime_named_field<char>>);
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), fmt::arg("arg", 42)));
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{} {}"), fmt::arg("arg", 41),
fmt::arg("arg", 43)));
EXPECT_EQ("foobar",
fmt::format(FMT_COMPILE("{a0}{a1}"), fmt::arg("a0", "foo"),
fmt::arg("a1", "bar")));
EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{}{a1}"), fmt::arg("a0", "foo"),
fmt::arg("a1", "bar")));
EXPECT_EQ("foofoo", fmt::format(FMT_COMPILE("{a0}{}"), fmt::arg("a0", "foo"),
fmt::arg("a1", "bar")));
EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{0}{a1}"), fmt::arg("a0", "foo"),
fmt::arg("a1", "bar")));
EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{a0}{1}"), fmt::arg("a0", "foo"),
fmt::arg("a1", "bar")));
EXPECT_EQ("foobar",
fmt::format(FMT_COMPILE("{}{a1}"), "foo", fmt::arg("a1", "bar")));
EXPECT_EQ("foobar",
fmt::format(FMT_COMPILE("{a0}{a1}"), fmt::arg("a1", "bar"),
fmt::arg("a2", "baz"), fmt::arg("a0", "foo")));
EXPECT_EQ(" bar foo ",
fmt::format(FMT_COMPILE(" {foo} {bar} "), fmt::arg("foo", "bar"),
fmt::arg("bar", "foo")));
EXPECT_THROW(fmt::format(FMT_COMPILE("{invalid}"), fmt::arg("valid", 42)),
fmt::format_error);
# if FMT_USE_NONTYPE_TEMPLATE_ARGS
using namespace fmt::literals;
auto statically_named_field_compiled =
fmt::detail::compile<decltype("arg"_a = 42)>(FMT_COMPILE("{arg}"));
static_assert(std::is_same_v<decltype(statically_named_field_compiled),
fmt::detail::field<char, int, 0>>);
EXPECT_EQ("41 43",
fmt::format(FMT_COMPILE("{a0} {a1}"), "a0"_a = 41, "a1"_a = 43));
EXPECT_EQ("41 43",
fmt::format(FMT_COMPILE("{a1} {a0}"), "a0"_a = 43, "a1"_a = 41));
# endif
}
TEST(compile_test, join) {
unsigned char data[] = {0x1, 0x2, 0xaf};
EXPECT_EQ("0102af", fmt::format(FMT_COMPILE("{:02x}"), fmt::join(data, "")));
}
TEST(compile_test, format_to) {
char buf[8];
auto end = fmt::format_to(buf, FMT_COMPILE("{}"), 42);
*end = '\0';
EXPECT_STREQ("42", buf);
end = fmt::format_to(buf, FMT_COMPILE("{:x}"), 42);
*end = '\0';
EXPECT_STREQ("2a", buf);
}
TEST(compile_test, format_to_n) {
constexpr auto buffer_size = 8;
char buffer[buffer_size];
auto res = fmt::format_to_n(buffer, buffer_size, FMT_COMPILE("{}"), 42);
*res.out = '\0';
EXPECT_STREQ("42", buffer);
res = fmt::format_to_n(buffer, buffer_size, FMT_COMPILE("{:x}"), 42);
*res.out = '\0';
EXPECT_STREQ("2a", buffer);
}
TEST(compile_test, formatted_size) {
EXPECT_EQ(2, fmt::formatted_size(FMT_COMPILE("{0}"), 42));
EXPECT_EQ(5, fmt::formatted_size(FMT_COMPILE("{0:<4.2f}"), 42.0));
}
TEST(compile_test, text_and_arg) {
EXPECT_EQ(">>>42<<<", fmt::format(FMT_COMPILE(">>>{}<<<"), 42));
EXPECT_EQ("42!", fmt::format(FMT_COMPILE("{}!"), 42));
}
TEST(compile_test, unknown_format_fallback) {
EXPECT_EQ(" 42 ",
fmt::format(FMT_COMPILE("{name:^4}"), fmt::arg("name", 42)));
std::vector<char> v;
fmt::format_to(std::back_inserter(v), FMT_COMPILE("{name:^4}"),
fmt::arg("name", 42));
EXPECT_EQ(" 42 ", fmt::string_view(v.data(), v.size()));
char buffer[4];
auto result = fmt::format_to_n(buffer, 4, FMT_COMPILE("{name:^5}"),
fmt::arg("name", 42));
EXPECT_EQ(5u, result.size);
EXPECT_EQ(buffer + 4, result.out);
EXPECT_EQ(" 42 ", fmt::string_view(buffer, 4));
}
TEST(compile_test, empty) { EXPECT_EQ("", fmt::format(FMT_COMPILE(""))); }
struct to_stringable {
friend fmt::string_view to_string_view(to_stringable) { return {}; }
};
FMT_BEGIN_NAMESPACE
template <> struct formatter<to_stringable> {
auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const to_stringable&, FormatContext& ctx) -> decltype(ctx.out()) {
return ctx.out();
}
};
FMT_END_NAMESPACE
TEST(compile_test, to_string_and_formatter) {
fmt::format(FMT_COMPILE("{}"), to_stringable());
}
TEST(compile_test, print) {
EXPECT_WRITE(stdout, fmt::print(FMT_COMPILE("Don't {}!"), "panic"),
"Don't panic!");
EXPECT_WRITE(stderr, fmt::print(stderr, FMT_COMPILE("Don't {}!"), "panic"),
"Don't panic!");
}
#endif
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
TEST(compile_test, compile_format_string_literal) {
using namespace fmt::literals;
EXPECT_EQ("", fmt::format(""_cf));
EXPECT_EQ("42", fmt::format("{}"_cf, 42));
EXPECT_EQ(L"42", fmt::format(L"{}"_cf, 42));
}
#endif
// MSVS 2019 19.29.30145.0 - Support C++20 and OK.
// MSVS 2022 19.32.31332.0 - compile-test.cc(362,3): fatal error C1001: Internal
// compiler error.
// (compiler file
// 'D:\a\_work\1\s\src\vctools\Compiler\CxxFE\sl\p1\c\constexpr\constexpr.cpp',
// line 8635)
#if ((FMT_CPLUSPLUS >= 202002L) && \
(!FMT_MSC_VERSION || FMT_MSC_VERSION < 1930)) || \
(FMT_CPLUSPLUS >= 201709L && FMT_GCC_VERSION >= 1002)
template <size_t max_string_length, typename Char = char> struct test_string {
template <typename T> constexpr bool operator==(const T& rhs) const noexcept {
return fmt::basic_string_view<Char>(rhs).compare(buffer) == 0;
}
Char buffer[max_string_length]{};
};
template <size_t max_string_length, typename Char = char, typename... Args>
consteval auto test_format(auto format, const Args&... args) {
test_string<max_string_length, Char> string{};
fmt::format_to(string.buffer, format, args...);
return string;
}
TEST(compile_time_formatting_test, bool) {
EXPECT_EQ("true", test_format<5>(FMT_COMPILE("{}"), true));
EXPECT_EQ("false", test_format<6>(FMT_COMPILE("{}"), false));
EXPECT_EQ("true ", test_format<6>(FMT_COMPILE("{:5}"), true));
EXPECT_EQ("1", test_format<2>(FMT_COMPILE("{:d}"), true));
}
TEST(compile_time_formatting_test, integer) {
EXPECT_EQ("42", test_format<3>(FMT_COMPILE("{}"), 42));
EXPECT_EQ("420", test_format<4>(FMT_COMPILE("{}"), 420));
EXPECT_EQ("42 42", test_format<6>(FMT_COMPILE("{} {}"), 42, 42));
EXPECT_EQ("42 42",
test_format<6>(FMT_COMPILE("{} {}"), uint32_t{42}, uint64_t{42}));
EXPECT_EQ("+42", test_format<4>(FMT_COMPILE("{:+}"), 42));
EXPECT_EQ("42", test_format<3>(FMT_COMPILE("{:-}"), 42));
EXPECT_EQ(" 42", test_format<4>(FMT_COMPILE("{: }"), 42));
EXPECT_EQ("-0042", test_format<6>(FMT_COMPILE("{:05}"), -42));
EXPECT_EQ("101010", test_format<7>(FMT_COMPILE("{:b}"), 42));
EXPECT_EQ("0b101010", test_format<9>(FMT_COMPILE("{:#b}"), 42));
EXPECT_EQ("0B101010", test_format<9>(FMT_COMPILE("{:#B}"), 42));
EXPECT_EQ("042", test_format<4>(FMT_COMPILE("{:#o}"), 042));
EXPECT_EQ("0x4a", test_format<5>(FMT_COMPILE("{:#x}"), 0x4a));
EXPECT_EQ("0X4A", test_format<5>(FMT_COMPILE("{:#X}"), 0x4a));
EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42));
EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42ll));
EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42ull));
EXPECT_EQ("42 ", test_format<5>(FMT_COMPILE("{:<4}"), 42));
EXPECT_EQ(" 42", test_format<5>(FMT_COMPILE("{:>4}"), 42));
EXPECT_EQ(" 42 ", test_format<5>(FMT_COMPILE("{:^4}"), 42));
EXPECT_EQ("**-42", test_format<6>(FMT_COMPILE("{:*>5}"), -42));
}
TEST(compile_time_formatting_test, char) {
EXPECT_EQ("c", test_format<2>(FMT_COMPILE("{}"), 'c'));
EXPECT_EQ("c ", test_format<4>(FMT_COMPILE("{:3}"), 'c'));
EXPECT_EQ("99", test_format<3>(FMT_COMPILE("{:d}"), 'c'));
}
TEST(compile_time_formatting_test, string) {
EXPECT_EQ("42", test_format<3>(FMT_COMPILE("{}"), "42"));
EXPECT_EQ("The answer is 42",
test_format<17>(FMT_COMPILE("{} is {}"), "The answer", "42"));
EXPECT_EQ("abc**", test_format<6>(FMT_COMPILE("{:*<5}"), "abc"));
EXPECT_EQ("**🤡**", test_format<9>(FMT_COMPILE("{:*^6}"), "🤡"));
}
TEST(compile_time_formatting_test, combination) {
EXPECT_EQ("420, true, answer",
test_format<18>(FMT_COMPILE("{}, {}, {}"), 420, true, "answer"));
EXPECT_EQ(" -42", test_format<5>(FMT_COMPILE("{:{}}"), -42, 4));
}
TEST(compile_time_formatting_test, custom_type) {
EXPECT_EQ("foo", test_format<4>(FMT_COMPILE("{}"), test_formattable()));
EXPECT_EQ("bar", test_format<4>(FMT_COMPILE("{:b}"), test_formattable()));
}
TEST(compile_time_formatting_test, multibyte_fill) {
EXPECT_EQ("жж42", test_format<8>(FMT_COMPILE("{:ж>4}"), 42));
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,56 +0,0 @@
// Formatting library for C++ - custom argument formatter tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "fmt/format.h"
#include "gtest-extra.h"
// MSVC 2013 is known to be broken.
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
// A custom argument formatter that doesn't print `-` for floating-point values
// rounded to 0.
class custom_arg_formatter
: public fmt::arg_formatter<fmt::buffer_range<char>> {
public:
using range = fmt::buffer_range<char>;
typedef fmt::arg_formatter<range> base;
custom_arg_formatter(fmt::format_context& ctx,
fmt::format_parse_context* parse_ctx,
fmt::format_specs* s = nullptr)
: base(ctx, parse_ctx, s) {}
using base::operator();
iterator operator()(double value) {
// Comparing a float to 0.0 is safe.
if (round(value * pow(10, specs()->precision)) == 0.0) value = 0;
return base::operator()(value);
}
};
std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) {
fmt::memory_buffer buffer;
// Pass custom argument formatter as a template arg to vwrite.
fmt::vformat_to<custom_arg_formatter>(buffer, format_str, args);
return std::string(buffer.data(), buffer.size());
}
template <typename... Args>
std::string custom_format(const char* format_str, const Args&... args) {
auto va = fmt::make_format_args(args...);
return custom_vformat(format_str, va);
}
TEST(CustomFormatterTest, Format) {
EXPECT_EQ("0.00", custom_format("{:.2f}", -.00001));
}
#endif

18
externals/fmt/test/detect-stdfs.cc vendored Normal file
View File

@ -0,0 +1,18 @@
// Formatting library for C++ - tests of formatters for standard library types
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include <exception> // _GLIBCXX_RELEASE & _LIBCPP_VERSION
#if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8
# error libfound "stdc++fs"
#elif !defined(__apple_build_version__) && defined(_LIBCPP_VERSION) && \
_LIBCPP_VERSION >= 7000 && _LIBCPP_VERSION < 9000
# error libfound "c++fs"
#else
// none if std::filesystem does not require additional libraries
# error libfound ""
#endif

View File

@ -0,0 +1,63 @@
// Formatting library for C++ - formatting library tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include <iterator>
#include <vector>
#include "fmt/chrono.h"
#include "fmt/color.h"
#include "fmt/format.h"
#include "fmt/ostream.h"
#include "fmt/ranges.h"
#include "fmt/xchar.h"
// Exercise the API to verify that everything we expect to can compile.
void test_format_api() {
(void)fmt::format(FMT_STRING("{}"), 42);
(void)fmt::format(FMT_STRING(L"{}"), 42);
(void)fmt::format(FMT_STRING("noop"));
(void)fmt::to_string(42);
(void)fmt::to_wstring(42);
std::vector<char> out;
fmt::format_to(std::back_inserter(out), FMT_STRING("{}"), 42);
char buffer[4];
fmt::format_to_n(buffer, 3, FMT_STRING("{}"), 12345);
wchar_t wbuffer[4];
fmt::format_to_n(wbuffer, 3, FMT_STRING(L"{}"), 12345);
}
void test_chrono() {
(void)fmt::format(FMT_STRING("{}"), std::chrono::seconds(42));
(void)fmt::format(FMT_STRING(L"{}"), std::chrono::seconds(42));
}
void test_text_style() {
fmt::print(fg(fmt::rgb(255, 20, 30)), FMT_STRING("{}"), "rgb(255,20,30)");
(void)fmt::format(fg(fmt::rgb(255, 20, 30)), FMT_STRING("{}"),
"rgb(255,20,30)");
fmt::text_style ts = fg(fmt::rgb(255, 20, 30));
std::string out;
fmt::format_to(std::back_inserter(out), ts,
FMT_STRING("rgb(255,20,30){}{}{}"), 1, 2, 3);
}
void test_range() {
std::vector<char> hello = {'h', 'e', 'l', 'l', 'o'};
(void)fmt::format(FMT_STRING("{}"), hello);
}
int main() {
test_format_api();
test_chrono();
test_text_style();
test_range();
}

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.1.0)
cmake_minimum_required(VERSION 3.1...3.18)
project(fmt-test)

View File

@ -1,6 +1,5 @@
#include "fmt/format.h"
int main(int argc, char** argv) {
for(int i = 0; i < argc; ++i)
fmt::print("{}: {}\n", i, argv[i]);
for (int i = 0; i < argc; ++i) fmt::print("{}: {}\n", i, argv[i]);
}

View File

@ -1,861 +0,0 @@
// Formatting library for C++ - the standard API implementation
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_FORMAT_
#define FMT_FORMAT_
#include <cassert>
#include <variant>
#include "fmt/format.h"
// This implementation verifies the correctness of the standard API proposed in
// P0645 Text Formatting and is optimized for copy-pasting from the paper, not
// for efficiency or readability. An efficient implementation should not use
// std::variant and should store packed argument type tags separately from
// values in basic_format_args for small number of arguments.
namespace std {
template<class T>
constexpr bool Integral = is_integral_v<T>;
template <class O>
using iter_difference_t = ptrdiff_t;
}
// https://fmt.dev/Text%20Formatting.html#format.syn
namespace std {
// [format.error], class format_error
class format_error;
// [format.formatter], formatter
template<class charT> class basic_format_parse_context;
using format_parse_context = basic_format_parse_context<char>;
using wformat_parse_context = basic_format_parse_context<wchar_t>;
template<class Out, class charT> class basic_format_context;
using format_context = basic_format_context<
/* unspecified */ std::back_insert_iterator<fmt::internal::buffer<char>>, char>;
using wformat_context = basic_format_context<
/* unspecified */ std::back_insert_iterator<fmt::internal::buffer<wchar_t>>, wchar_t>;
template<class T, class charT = char> struct formatter {
formatter() = delete;
};
// [format.arguments], arguments
template<class Context> class basic_format_arg;
template<class Visitor, class Context>
/* see below */ auto visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);
template<class Context, class... Args> struct format_arg_store; // exposition only
template<class Context> class basic_format_args;
using format_args = basic_format_args<format_context>;
using wformat_args = basic_format_args<wformat_context>;
template<class Out, class charT>
using format_args_t = basic_format_args<basic_format_context<Out, charT>>;
template<class Context = format_context, class... Args>
format_arg_store<Context, Args...>
make_format_args(const Args&... args);
template<class... Args>
format_arg_store<wformat_context, Args...>
make_wformat_args(const Args&... args);
// [format.functions], formatting functions
template<class... Args>
string format(string_view fmt, const Args&... args);
template<class... Args>
wstring format(wstring_view fmt, const Args&... args);
string vformat(string_view fmt, format_args args);
wstring vformat(wstring_view fmt, wformat_args args);
template<class Out, class... Args>
Out format_to(Out out, string_view fmt, const Args&... args);
template<class Out, class... Args>
Out format_to(Out out, wstring_view fmt, const Args&... args);
template<class Out>
Out vformat_to(Out out, string_view fmt, format_args_t<fmt::type_identity_t<Out>, char> args);
template<class Out>
Out vformat_to(Out out, wstring_view fmt, format_args_t<fmt::type_identity_t<Out>, wchar_t> args);
template<class Out>
struct format_to_n_result {
Out out;
iter_difference_t<Out> size;
};
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
string_view fmt, const Args&... args);
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
wstring_view fmt, const Args&... args);
template<class... Args>
size_t formatted_size(string_view fmt, const Args&... args);
template<class... Args>
size_t formatted_size(wstring_view fmt, const Args&... args);
}
// https://fmt.dev/Text%20Formatting.html#format.error
namespace std {
class format_error : public runtime_error {
public:
explicit format_error(const string& what_arg) : runtime_error(what_arg) {}
explicit format_error(const char* what_arg) : runtime_error(what_arg) {}
};
}
namespace std {
namespace detail {
struct error_handler {
// This function is intentionally not constexpr to give a compile-time error.
void on_error(const char* message) {
throw std::format_error(message);
}
};
}
}
// https://fmt.dev/Text%20Formatting.html#format.parse_context
namespace std {
template<class charT>
class basic_format_parse_context {
public:
using char_type = charT;
using const_iterator = typename basic_string_view<charT>::const_iterator;
using iterator = const_iterator;
private:
iterator begin_; // exposition only
iterator end_; // exposition only
enum indexing { unknown, manual, automatic }; // exposition only
indexing indexing_; // exposition only
size_t next_arg_id_; // exposition only
size_t num_args_; // exposition only
public:
explicit constexpr basic_format_parse_context(basic_string_view<charT> fmt,
size_t num_args = 0) noexcept;
basic_format_parse_context(const basic_format_parse_context&) = delete;
basic_format_parse_context& operator=(const basic_format_parse_context&) = delete;
constexpr const_iterator begin() const noexcept;
constexpr const_iterator end() const noexcept;
constexpr void advance_to(const_iterator it);
constexpr size_t next_arg_id();
constexpr void check_arg_id(size_t id);
// Implementation detail:
constexpr void check_arg_id(fmt::string_view) {}
detail::error_handler error_handler() const { return {}; }
void on_error(const char* msg) { error_handler().on_error(msg); }
};
}
namespace std {
template<class charT>
/* explicit */ constexpr basic_format_parse_context<charT>::
basic_format_parse_context(basic_string_view<charT> fmt,
size_t num_args) noexcept
: begin_(fmt.begin()), end_(fmt.end()), indexing_(unknown), next_arg_id_(0), num_args_(num_args) {}
template<class charT>
constexpr typename basic_format_parse_context<charT>::const_iterator basic_format_parse_context<charT>::begin() const noexcept { return begin_; }
template<class charT>
constexpr typename basic_format_parse_context<charT>::const_iterator basic_format_parse_context<charT>::end() const noexcept { return end_; }
template<class charT>
constexpr void basic_format_parse_context<charT>::advance_to(typename basic_format_parse_context<charT>::iterator it) { begin_ = it; }
template<class charT>
constexpr size_t basic_format_parse_context<charT>::next_arg_id() {
if (indexing_ == manual)
throw format_error("manual to automatic indexing");
if (indexing_ == unknown)
indexing_ = automatic;
return next_arg_id_++;
}
template<class charT>
constexpr void basic_format_parse_context<charT>::check_arg_id(size_t id) {
// clang doesn't support __builtin_is_constant_evaluated yet
//if (!(!__builtin_is_constant_evaluated() || id < num_args_))
// throw format_error(invalid index is out of range");
if (indexing_ == automatic)
throw format_error("automatic to manual indexing");
if (indexing_ == unknown)
indexing_ = manual;
}
}
// https://fmt.dev/Text%20Formatting.html#format.context
namespace std {
template<class Out, class charT>
class basic_format_context {
basic_format_args<basic_format_context> args_; // exposition only
Out out_; // exposition only
public:
using iterator = Out;
using char_type = charT;
template<class T> using formatter_type = formatter<T, charT>;
basic_format_arg<basic_format_context> arg(size_t id) const;
iterator out();
void advance_to(iterator it);
// Implementation details:
using format_arg = basic_format_arg<basic_format_context>;
basic_format_context(Out out, basic_format_args<basic_format_context> args, fmt::internal::locale_ref)
: args_(args), out_(out) {}
detail::error_handler error_handler() const { return {}; }
basic_format_arg<basic_format_context> arg(fmt::basic_string_view<charT>) const {
return {}; // unused: named arguments are not supported yet
}
void on_error(const char* msg) { error_handler().on_error(msg); }
};
}
namespace std {
template<class O, class charT>
basic_format_arg<basic_format_context<O, charT>> basic_format_context<O, charT>::arg(size_t id) const { return args_.get(id); }
template<class O, class charT>
typename basic_format_context<O, charT>::iterator basic_format_context<O, charT>::out() { return out_; }
template<class O, class charT>
void basic_format_context<O, charT>::advance_to(typename basic_format_context<O, charT>::iterator it) { out_ = it; }
}
namespace std {
namespace detail {
template <typename T>
constexpr bool is_standard_integer_v =
std::is_same_v<T, signed char> ||
std::is_same_v<T, short int> ||
std::is_same_v<T, int> ||
std::is_same_v<T, long int> ||
std::is_same_v<T, long long int>;
template <typename T>
constexpr bool is_standard_unsigned_integer_v =
std::is_same_v<T, unsigned char> ||
std::is_same_v<T, unsigned short int> ||
std::is_same_v<T, unsigned int> ||
std::is_same_v<T, unsigned long int> ||
std::is_same_v<T, unsigned long long int>;
template <typename T, typename Char> struct formatter;
}
}
// https://fmt.dev/Text%20Formatting.html#format.arg
namespace std {
template<class Context>
class basic_format_arg {
public:
class handle;
private:
using char_type = typename Context::char_type; // exposition only
variant<monostate, bool, char_type,
int, unsigned int, long long int, unsigned long long int,
double, long double,
const char_type*, basic_string_view<char_type>,
const void*, handle> value; // exposition only
template<typename T,
typename = enable_if_t<
std::is_same_v<T, bool> ||
std::is_same_v<T, char_type> ||
(std::is_same_v<T, char> && std::is_same_v<char_type, wchar_t>) ||
detail::is_standard_integer_v<T> ||
detail::is_standard_unsigned_integer_v<T> ||
sizeof(typename Context::template formatter_type<T>().format(declval<const T&>(), declval<Context&>())) != 0
>> explicit basic_format_arg(const T& v) noexcept; // exposition only
explicit basic_format_arg(float n) noexcept; // exposition only
explicit basic_format_arg(double n) noexcept; // exposition only
explicit basic_format_arg(long double n) noexcept; // exposition only
explicit basic_format_arg(const char_type* s); // exposition only
template<class traits>
explicit basic_format_arg(
basic_string_view<char_type, traits> s) noexcept; // exposition only
template<class traits, class Allocator>
explicit basic_format_arg(
const basic_string<char_type, traits, Allocator>& s) noexcept; // exposition only
explicit basic_format_arg(nullptr_t) noexcept; // exposition only
template<class T, typename = enable_if_t<is_void_v<T>>>
explicit basic_format_arg(const T* p) noexcept; // exposition only
// Fails due to a bug in clang
//template<class Visitor, class Ctx>
// friend auto visit_format_arg(Visitor&& vis,
// basic_format_arg<Ctx> arg); // exposition only
friend auto get_value(basic_format_arg arg) {
return arg.value;
}
template <typename T, typename Char> friend struct detail::formatter;
template<class Ctx, class... Args>
friend format_arg_store<Ctx, Args...>
make_format_args(const Args&... args); // exposition only
public:
basic_format_arg() noexcept;
explicit operator bool() const noexcept;
};
}
namespace std {
template<class Context>
basic_format_arg<Context>::basic_format_arg() noexcept {}
template<class Context>
template<class T, typename> /* explicit */ basic_format_arg<Context>::basic_format_arg(const T& v) noexcept {
if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, char_type>)
value = v;
else if constexpr (std::is_same_v<T, char> && std::is_same_v<char_type, wchar_t>)
value = static_cast<wchar_t>(v);
else if constexpr (detail::is_standard_integer_v<T> && sizeof(T) <= sizeof(int))
value = static_cast<int>(v);
else if constexpr (detail::is_standard_unsigned_integer_v<T> && sizeof(T) <= sizeof(unsigned))
value = static_cast<unsigned>(v);
else if constexpr (detail::is_standard_integer_v<T>)
value = static_cast<long long int>(v);
else if constexpr (detail::is_standard_unsigned_integer_v<T>)
value = static_cast<unsigned long long int>(v);
else if constexpr (sizeof(typename Context::template formatter_type<T>().format(declval<const T&>(), declval<Context&>())) != 0)
value = handle(v);
}
template<class Context>
/* explicit */ basic_format_arg<Context>::basic_format_arg(float n) noexcept
: value(static_cast<double>(n)) {}
template<class Context>
/* explicit */ basic_format_arg<Context>::basic_format_arg(double n) noexcept
: value(n) {}
template<class Context>
/* explicit */ basic_format_arg<Context>::basic_format_arg(long double n) noexcept
: value(n) {}
template<class Context>
/* explicit */ basic_format_arg<Context>::basic_format_arg(const typename basic_format_arg<Context>::char_type* s)
: value(s) {
assert(s != nullptr);
}
template<class Context>
template<class traits>
/* explicit */ basic_format_arg<Context>::basic_format_arg(basic_string_view<char_type, traits> s) noexcept
: value(s) {}
template<class Context>
template<class traits, class Allocator>
/* explicit */ basic_format_arg<Context>::basic_format_arg(
const basic_string<char_type, traits, Allocator>& s) noexcept
: value(basic_string_view<char_type>(s.data(), s.size())) {}
template<class Context>
/* explicit */ basic_format_arg<Context>::basic_format_arg(nullptr_t) noexcept
: value(static_cast<const void*>(nullptr)) {}
template<class Context>
template<class T, typename> /* explicit */ basic_format_arg<Context>::basic_format_arg(const T* p) noexcept
: value(p) {}
template<class Context>
/* explicit */ basic_format_arg<Context>::operator bool() const noexcept {
return !holds_alternative<monostate>(value);
}
}
namespace std {
template<class Context>
class basic_format_arg<Context>::handle {
const void* ptr_; // exposition only
void (*format_)(basic_format_parse_context<char_type>&,
Context&, const void*); // exposition only
template<class T> explicit handle(const T& val) noexcept; // exposition only
friend class basic_format_arg<Context>; // exposition only
public:
void format(basic_format_parse_context<char_type>&, Context& ctx) const;
};
}
namespace std {
template<class Context>
template<class T> /* explicit */ basic_format_arg<Context>::handle::handle(const T& val) noexcept
: ptr_(&val), format_([](basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx, const void* ptr) {
typename Context::template formatter_type<T> f;
parse_ctx.advance_to(f.parse(parse_ctx));
format_ctx.advance_to(f.format(*static_cast<const T*>(ptr), format_ctx));
}) {}
template<class Context>
void basic_format_arg<Context>::handle::format(basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx) const {
format_(parse_ctx, format_ctx, ptr_);
}
// https://fmt.dev/Text%20Formatting.html#format.visit
template<class Visitor, class Context>
auto visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg) {
return visit(vis, get_value(arg));
}
}
// https://fmt.dev/Text%20Formatting.html#format.store
namespace std {
template<class Context, class... Args>
struct format_arg_store { // exposition only
array<basic_format_arg<Context>, sizeof...(Args)> args;
};
}
// https://fmt.dev/Text%20Formatting.html#format.basic_args
namespace std {
template<class Context>
class basic_format_args {
size_t size_; // exposition only
const basic_format_arg<Context>* data_; // exposition only
public:
basic_format_args() noexcept;
template<class... Args>
basic_format_args(const format_arg_store<Context, Args...>& store) noexcept;
basic_format_arg<Context> get(size_t i) const noexcept;
};
}
namespace std {
template<class Context>
basic_format_args<Context>::basic_format_args() noexcept : size_(0) {}
template<class Context>
template<class... Args>
basic_format_args<Context>::basic_format_args(const format_arg_store<Context, Args...>& store) noexcept
: size_(sizeof...(Args)), data_(store.args.data()) {}
template<class Context>
basic_format_arg<Context> basic_format_args<Context>::get(size_t i) const noexcept {
return i < size_ ? data_[i] : basic_format_arg<Context>();
}
}
namespace std {
// https://fmt.dev/Text%20Formatting.html#format.make_args
template<class Context /*= format_context*/, class... Args>
format_arg_store<Context, Args...> make_format_args(const Args&... args) {
return {basic_format_arg<Context>(args)...};
}
// https://fmt.dev/Text%20Formatting.html#format.make_wargs
template<class... Args>
format_arg_store<wformat_context, Args...> make_wformat_args(const Args&... args) {
return make_format_args<wformat_context>(args...);
}
}
namespace std {
namespace detail {
template <typename Range>
class arg_formatter
: public fmt::internal::arg_formatter_base<Range, error_handler> {
private:
using char_type = typename Range::value_type;
using base = fmt::internal::arg_formatter_base<Range, error_handler>;
using format_context = std::basic_format_context<typename base::iterator, char_type>;
using parse_context = basic_format_parse_context<char_type>;
parse_context* parse_ctx_;
format_context& ctx_;
public:
typedef Range range;
typedef typename base::iterator iterator;
typedef typename base::format_specs format_specs;
/**
\rst
Constructs an argument formatter object.
*ctx* is a reference to the formatting context,
*spec* contains format specifier information for standard argument types.
\endrst
*/
arg_formatter(format_context& ctx, parse_context* parse_ctx = nullptr, fmt::format_specs* spec = nullptr)
: base(Range(ctx.out()), spec, {}), parse_ctx_(parse_ctx), ctx_(ctx) {}
using base::operator();
/** Formats an argument of a user-defined type. */
iterator operator()(typename std::basic_format_arg<format_context>::handle handle) {
handle.format(*parse_ctx_, ctx_);
return this->out();
}
iterator operator()(monostate) {
throw format_error("");
}
};
template <typename Context>
inline fmt::internal::type get_type(basic_format_arg<Context> arg) {
return visit_format_arg([&] (auto val) {
using char_type = typename Context::char_type;
using T = decltype(val);
if (std::is_same_v<T, monostate>)
return fmt::internal::type::none_type;
if (std::is_same_v<T, bool>)
return fmt::internal::type::bool_type;
if (std::is_same_v<T, char_type>)
return fmt::internal::type::char_type;
if (std::is_same_v<T, int>)
return fmt::internal::type::int_type;
if (std::is_same_v<T, unsigned int>)
return fmt::internal::type::uint_type;
if (std::is_same_v<T, long long int>)
return fmt::internal::type::long_long_type;
if (std::is_same_v<T, unsigned long long int>)
return fmt::internal::type::ulong_long_type;
if (std::is_same_v<T, double>)
return fmt::internal::type::double_type;
if (std::is_same_v<T, long double>)
return fmt::internal::type::long_double_type;
if (std::is_same_v<T, const char_type*>)
return fmt::internal::type::cstring_type;
if (std::is_same_v<T, basic_string_view<char_type>>)
return fmt::internal::type::string_type;
if (std::is_same_v<T, const void*>)
return fmt::internal::type::pointer_type;
assert(get_value(arg).index() == 12);
return fmt::internal::type::custom_type;
}, arg);
}
template <typename Context>
class custom_formatter {
private:
using parse_context = basic_format_parse_context<typename Context::char_type>;
parse_context& parse_ctx_;
Context& format_ctx_;
public:
custom_formatter(parse_context& parse_ctx, Context& ctx) : parse_ctx_(parse_ctx), format_ctx_(ctx) {}
bool operator()(typename basic_format_arg<Context>::handle h) const {
h.format(parse_ctx_, format_ctx_);
return true;
}
template <typename T> bool operator()(T) const { return false; }
};
template <typename ArgFormatter, typename Char, typename Context>
struct format_handler : detail::error_handler {
typedef typename ArgFormatter::range range;
format_handler(range r, basic_string_view<Char> str,
basic_format_args<Context> format_args,
fmt::internal::locale_ref loc)
: parse_ctx(str), context(r.begin(), format_args, loc) {}
void on_text(const Char* begin, const Char* end) {
auto size = fmt::internal::to_unsigned(end - begin);
auto out = context.out();
auto&& it = fmt::internal::reserve(out, size);
it = std::copy_n(begin, size, it);
context.advance_to(out);
}
void on_arg_id() {
arg = context.arg(parse_ctx.next_arg_id());
}
void on_arg_id(unsigned id) {
parse_ctx.check_arg_id(id);
arg = context.arg(id);
}
void on_arg_id(fmt::basic_string_view<Char>) {}
void on_replacement_field(const Char* p) {
parse_ctx.advance_to(parse_ctx.begin() + (p - &*parse_ctx.begin()));
custom_formatter<Context> f(parse_ctx, context);
if (!visit_format_arg(f, arg))
context.advance_to(visit_format_arg(ArgFormatter(context, &parse_ctx), arg));
}
const Char* on_format_specs(const Char* begin, const Char* end) {
parse_ctx.advance_to(parse_ctx.begin() + (begin - &*parse_ctx.begin()));
custom_formatter<Context> f(parse_ctx, context);
if (visit_format_arg(f, arg)) return &*parse_ctx.begin();
fmt::basic_format_specs<Char> specs;
using fmt::internal::specs_handler;
using parse_context = basic_format_parse_context<Char>;
fmt::internal::specs_checker<specs_handler<parse_context, Context>> handler(
specs_handler<parse_context, Context>(specs, parse_ctx, context), get_type(arg));
begin = parse_format_specs(begin, end, handler);
if (begin == end || *begin != '}') on_error("missing '}' in format string");
parse_ctx.advance_to(parse_ctx.begin() + (begin - &*parse_ctx.begin()));
context.advance_to(visit_format_arg(ArgFormatter(context, &parse_ctx, &specs), arg));
return begin;
}
basic_format_parse_context<Char> parse_ctx;
Context context;
basic_format_arg<Context> arg;
};
template <typename T, typename Char>
struct formatter {
// Parses format specifiers stopping either at the end of the range or at the
// terminating '}'.
template <typename ParseContext>
FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext& ctx) {
namespace internal = fmt::internal;
typedef internal::dynamic_specs_handler<ParseContext> handler_type;
auto type = internal::mapped_type_constant<T, fmt::buffer_context<Char>>::value;
internal::specs_checker<handler_type> handler(handler_type(specs_, ctx),
type);
auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
auto type_spec = specs_.type;
auto eh = ctx.error_handler();
switch (type) {
case internal::type::none_type:
case internal::type::named_arg_type:
FMT_ASSERT(false, "invalid argument type");
break;
case internal::type::int_type:
case internal::type::uint_type:
case internal::type::long_long_type:
case internal::type::ulong_long_type:
case internal::type::bool_type:
handle_int_type_spec(type_spec,
internal::int_type_checker<decltype(eh)>(eh));
break;
case internal::type::char_type:
handle_char_specs(
&specs_, internal::char_specs_checker<decltype(eh)>(type_spec, eh));
break;
case internal::type::double_type:
case internal::type::long_double_type:
internal::parse_float_type_spec(specs_, eh);
break;
case internal::type::cstring_type:
internal::handle_cstring_type_spec(
type_spec, internal::cstring_type_checker<decltype(eh)>(eh));
break;
case internal::type::string_type:
internal::check_string_type_spec(type_spec, eh);
break;
case internal::type::pointer_type:
internal::check_pointer_type_spec(type_spec, eh);
break;
case internal::type::custom_type:
// Custom format specifiers should be checked in parse functions of
// formatter specializations.
break;
}
return it;
}
template <typename FormatContext>
auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) {
fmt::internal::handle_dynamic_spec<fmt::internal::width_checker>(
specs_.width, specs_.width_ref, ctx);
fmt::internal::handle_dynamic_spec<fmt::internal::precision_checker>(
specs_.precision, specs_.precision_ref, ctx);
using range_type = fmt::internal::output_range<typename FormatContext::iterator,
typename FormatContext::char_type>;
return visit_format_arg(arg_formatter<range_type>(ctx, nullptr, &specs_),
basic_format_arg<FormatContext>(val));
}
private:
fmt::internal::dynamic_format_specs<Char> specs_;
};
} // namespace detail
// https://fmt.dev/Text%20Formatting.html#format.functions
template<class... Args>
string format(string_view fmt, const Args&... args) {
return vformat(fmt, make_format_args(args...));
}
template<class... Args>
wstring format(wstring_view fmt, const Args&... args) {
return vformat(fmt, make_wformat_args(args...));
}
string vformat(string_view fmt, format_args args) {
fmt::memory_buffer mbuf;
fmt::internal::buffer<char>& buf = mbuf;
using range = fmt::buffer_range<char>;
detail::format_handler<detail::arg_formatter<range>, char, format_context>
h(range(std::back_inserter(buf)), fmt, args, {});
fmt::internal::parse_format_string<false>(fmt::to_string_view(fmt), h);
return to_string(mbuf);
}
wstring vformat(wstring_view fmt, wformat_args args);
template<class Out, class... Args>
Out format_to(Out out, string_view fmt, const Args&... args) {
using context = basic_format_context<Out, decltype(fmt)::value_type>;
return vformat_to(out, fmt, make_format_args<context>(args...));
}
template<class Out, class... Args>
Out format_to(Out out, wstring_view fmt, const Args&... args) {
using context = basic_format_context<Out, decltype(fmt)::value_type>;
return vformat_to(out, fmt, make_format_args<context>(args...));
}
template<class Out>
Out vformat_to(Out out, string_view fmt, format_args_t<fmt::type_identity_t<Out>, char> args) {
using range = fmt::internal::output_range<Out, char>;
detail::format_handler<detail::arg_formatter<range>, char, basic_format_context<Out, char>>
h(range(out), fmt, args, {});
fmt::internal::parse_format_string<false>(fmt::to_string_view(fmt), h);
return h.context.out();
}
template<class Out>
Out vformat_to(Out out, wstring_view fmt, format_args_t<fmt::type_identity_t<Out>, wchar_t> args);
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
string_view fmt, const Args&... args);
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
wstring_view fmt, const Args&... args);
template<class... Args>
size_t formatted_size(string_view fmt, const Args&... args);
template<class... Args>
size_t formatted_size(wstring_view fmt, const Args&... args);
#define charT char
template<> struct formatter<charT, charT> : detail::formatter<charT, charT> {};
template<> struct formatter<char, wchar_t>;
template<> struct formatter<charT*, charT> : detail::formatter<const charT*, charT> {};
template<> struct formatter<const charT*, charT> : detail::formatter<const charT*, charT> {};
template<size_t N> struct formatter<const charT[N], charT>
: detail::formatter<std::basic_string_view<charT>, charT> {};
template<class traits, class Allocator>
struct formatter<basic_string<charT, traits, Allocator>, charT>
: detail::formatter<std::basic_string_view<charT>, charT> {};
template<class traits>
struct formatter<basic_string_view<charT, traits>, charT>
: detail::formatter<std::basic_string_view<charT>, charT> {};
template <> struct formatter<nullptr_t, charT> : detail::formatter<const void*, charT> {};
template <> struct formatter<void*, charT> : detail::formatter<const void*, charT> {};
template <> struct formatter<const void*, charT> : detail::formatter<const void*, charT> {};
template <> struct formatter<bool, charT> : detail::formatter<bool, charT> {};
template <> struct formatter<signed char, charT> : detail::formatter<int, charT> {};
template <> struct formatter<short, charT> : detail::formatter<int, charT> {};
template <> struct formatter<int, charT> : detail::formatter<int, charT> {};
template <> struct formatter<long, charT>
: detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), int, long long>, charT> {};
template <> struct formatter<long long, charT> : detail::formatter<long long, charT> {};
template <> struct formatter<unsigned char, charT> : detail::formatter<unsigned int, charT> {};
template <> struct formatter<unsigned short, charT> : detail::formatter<unsigned int, charT> {};
template <> struct formatter<unsigned int, charT> : detail::formatter<unsigned int, charT> {};
template <> struct formatter<unsigned long, charT>
: detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), unsigned, unsigned long long>, charT> {};
template <> struct formatter<unsigned long long, charT> : detail::formatter<unsigned long long, charT> {};
template <> struct formatter<float, charT> : detail::formatter<double, charT> {};
template <> struct formatter<double, charT> : detail::formatter<double, charT> {};
template <> struct formatter<long double, charT> : detail::formatter<long double, charT> {};
#undef charT
#define charT wchar_t
template<> struct formatter<charT, charT> : detail::formatter<charT, charT> {};
template<> struct formatter<char, wchar_t> : detail::formatter<charT, charT> {};
template<> struct formatter<charT*, charT> : detail::formatter<const charT*, charT> {};
template<> struct formatter<const charT*, charT> : detail::formatter<const charT*, charT> {};
template<size_t N> struct formatter<const charT[N], charT>
: detail::formatter<std::basic_string_view<charT>, charT> {};
template<class traits, class Allocator>
struct formatter<std::basic_string<charT, traits, Allocator>, charT>
: detail::formatter<std::basic_string_view<charT>, charT> {};
template<class traits>
struct formatter<std::basic_string_view<charT, traits>, charT>
: detail::formatter<std::basic_string_view<charT>, charT> {};
template <> struct formatter<nullptr_t, charT> : detail::formatter<const void*, charT> {};
template <> struct formatter<void*, charT> : detail::formatter<const void*, charT> {};
template <> struct formatter<const void*, charT> : detail::formatter<const void*, charT> {};
template <> struct formatter<bool, charT> : detail::formatter<bool, charT> {};
template <> struct formatter<signed char, charT> : detail::formatter<int, charT> {};
template <> struct formatter<short, charT> : detail::formatter<int, charT> {};
template <> struct formatter<int, charT> : detail::formatter<int, charT> {};
template <> struct formatter<long, charT>
: detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), int, long long>, charT> {};
template <> struct formatter<long long, charT> : detail::formatter<long long, charT> {};
template <> struct formatter<unsigned char, charT> : detail::formatter<unsigned int, charT> {};
template <> struct formatter<unsigned short, charT> : detail::formatter<unsigned int, charT> {};
template <> struct formatter<unsigned int, charT> : detail::formatter<unsigned int, charT> {};
template <> struct formatter<unsigned long, charT>
: detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), unsigned, unsigned long long>, charT> {};
template <> struct formatter<unsigned long long, charT> : detail::formatter<unsigned long long, charT> {};
template <> struct formatter<float, charT> : detail::formatter<double, charT> {};
template <> struct formatter<double, charT> : detail::formatter<double, charT> {};
template <> struct formatter<long double, charT> : detail::formatter<long double, charT> {};
#undef charT
template<> struct formatter<const wchar_t, char> {
formatter() = delete;
};
}
#endif // FMT_FORMAT_

Some files were not shown because too many files have changed in this diff Show More