Compare commits

..

1630 Commits

Author SHA1 Message Date
SachinVin
b80bde7c0d frontend/A32: remove decoder hack vfp instructions 2020-04-25 19:15:22 +05:30
SachinVin
880c31a858 a64_emiter: CountLeadingZeros intrinsic shortcuts 2020-04-24 21:23:38 +05:30
BreadFish64
bcc14dcb0e emit_a64: get rid of useless NOP generation
We don't actually patch anything in those locations beside a jump.
2020-04-20 15:11:25 -05:00
SachinVin
894c6c4016 emit_a64: Do not clear fast_dispatch_table unnecessarily
port 4305c74 - emit_x64: Do not clear fast_dispatch_table unnecessarily
2020-04-18 14:28:21 +05:30
SachinVin
7ecd068069 backend/A64/block_of_code.cpp: Clean up C style casts 2020-04-18 14:19:01 +05:30
SachinVin
083d354ac2 backend/A64/a32_emit_a64.cpp: EmitA32{Get,Set}Fpscr, set the guest_fpcr to host fpcr 2020-04-14 21:49:29 +05:30
SachinVin
c7957fe153 backend/A64: Add Step 2020-04-11 10:39:41 +05:30
SachinVin
7c8f7381b7 backend/A64/block_of_code: Always specify codeptr to run from 2020-04-11 10:39:33 +05:30
BreadFish64
1832425c4a backend/A64: fix mp 2020-04-07 23:22:59 -05:00
SachinVin
8682440145 backend/A64: Move SP to FP in GenMemoryAccessors + Minor cleanup and 2020-04-07 23:22:31 -05:00
SachinVin
c3ee450aeb backend/A64: Use X26 for storing remaining cycles. 2020-04-07 23:22:31 -05:00
BreadFish64
af4c225f9f backend/A64: add fastmem support
fix crash on game close

fix generic exception handler

reorder hostloc gpr list

use temp register instead of X0 for writes

go back to regular std::partition
2020-04-07 23:22:31 -05:00
BreadFish64
892c7904ca merge fastmem 2020-04-07 23:22:31 -05:00
SachinVin
b8bac24fd4 backend\A64\constant_pool.cpp: Correct offset calculation 2020-04-07 23:07:24 -05:00
SachinVin
a79bd7e8c8 backend/A64/a32_jitstate: Upstream changes from x64 backend 2020-04-07 23:07:24 -05:00
SachinVin
ef898c6181 backend/A64: Add test for q flag being incorrectly set 2020-04-07 23:07:24 -05:00
SachinVin
9f07aa0b7d backend/A64/a32_emit_a64.cpp: Use unused HostCall registers 2020-04-07 23:07:24 -05:00
SachinVin
ff5c3d5ab5 backend/A64/a32_emit_a64.cpp: Use MOVP2R instead of MOVI2R. 2020-04-07 23:07:24 -05:00
SachinVin
3972263e73 backend/A64/abi: Fix FP caller and callee save registers 2020-04-07 23:07:24 -05:00
SachinVin
c3bc26b6f5 a64/block_of_code: use GetWritableCodePtr() instead of const_cast<...>(GetCodePtr()) 2020-04-07 23:07:24 -05:00
SachinVin
b7b65f10e6 backend/A64/constant_pool: Clean up unused stuff 2020-04-07 23:07:24 -05:00
SachinVin
aa95927614 emit_a64_data_processing.cpp: remove pointless DoNZCV. 2020-04-07 23:07:24 -05:00
SachinVin
8cd195beaf IR + backend/*: add SetCpsrNZCVRaw and change arg1 type of SetCpsrNZCV to IR::NZCV 2020-04-07 23:07:24 -05:00
SachinVin
5246568d10 backend/A64: Fix ASR impl 2020-04-07 23:07:24 -05:00
SachinVin
103ab07fa4 a64_emitter: Use Correct alias for ZR and WZR in CMP 2020-04-07 23:07:24 -05:00
SachinVin
1e37ecaa25 backend/A64: Use CSLE instead of branches for LSL LSR and ASR + minor cleanup 2020-04-07 23:07:24 -05:00
SachinVin
6ab3c04037 backend/A64: Use correct register size for EmitNot64 2020-04-07 23:07:24 -05:00
SachinVin
ea2c5e6dce tests/A32: Check if Q flag is cleared properly 2020-04-07 23:07:24 -05:00
SachinVin
fcfd3f3183 backend/A64: SignedSaturatedSub and SignedSaturatedAdd 2020-04-07 23:07:24 -05:00
SachinVin
1b6d9e417f backend/A64/emit_a64_saturation.cpp: Implement EmitSignedSaturation and EmitUnsignedSaturation
Implements SSAT SSAT16 USAT USAT16 QASX QSAX UQASX UQSAX
2020-04-07 23:07:24 -05:00
SachinVin
82488c7feb backend/A64: add emit_a64_saturation.cpp 2020-04-07 23:07:24 -05:00
SachinVin
8eea0660ce backend/A64: Fix EmitA32SetCpsr 2020-04-07 23:07:24 -05:00
SachinVin
cc1caa5007 backend/A64/devirtualize: remove unused DevirtualizeItanium 2020-04-07 23:07:24 -05:00
SachinVin
4cdb8ec142 backend/A64: refactor to fpscr from mxcsr 2020-04-07 23:07:24 -05:00
SachinVin
f671e1ef4d backend/A64: Use ScratchGpr() instead of ABI_SCRATCH1 where possible 2020-04-07 23:07:24 -05:00
SachinVin
743aa2385e backend/A64: support for always_little_endian 2020-04-07 23:07:24 -05:00
SachinVin
a11111bcde backend/a64: Add hook_hint_instructions option
534eb0f
2020-04-07 23:07:24 -05:00
SachinVin
2d5b21ecc2 backend /A64: cleanup 2020-04-07 23:07:24 -05:00
SachinVin
23d30423d7 gitignore: add .vs dir 2020-04-07 23:07:24 -05:00
SachinVin
962a359ec4 Minor style fix 2020-04-07 23:07:24 -05:00
SachinVin
b883dbe240 backend\A64\emit_a64_packed.cpp: Implement AddSub halving and non halving 2020-04-07 23:07:24 -05:00
SachinVin
6adc894ffd backend\A64: Instructions that got implemented on the way 2020-04-07 23:07:24 -05:00
SachinVin
93a183de02 backend\A64\emit_a64_packed.cpp: Implement Unsigned Sum of Absolute Differences 2020-04-07 23:07:24 -05:00
SachinVin
e3b8eb1735 a64 emitter: Absolute Difference and add across vector instructions 2020-04-07 23:07:24 -05:00
SachinVin
664914d141 backend\A64\emit_a64_packed.cpp: Implement Packed Select 2020-04-07 23:07:24 -05:00
SachinVin
a4ca210798 Backend/a64: Fix asset when falling back to interpreter 2020-04-07 23:07:24 -05:00
SachinVin
ea2c98a7c3 backend\A64\emit_a64_packed.cpp: Implement Packed Halving Add/Sub instructions 2020-04-07 23:07:24 -05:00
SachinVin
93c946dfb3 backend\A64\emit_a64_packed.cpp: Implement Packed Saturating instructions 2020-04-07 23:07:24 -05:00
SachinVin
d3c4ffbdc8 backend\A64\emit_a64_packed.cpp: Implement SignedPacked*- ADD and SUB 2020-04-07 23:07:24 -05:00
SachinVin
0f00a1a00b a64 emitter: Vector Halving and Saturation instructions 2020-04-07 23:07:24 -05:00
SachinVin
d2847a202e backend\A64\emit_a64_packed.cpp: Implement UnsignedPacked*- ADD and SUB...
with few other in the emitter
2020-04-07 23:07:24 -05:00
SachinVin
5550e6f157 a64 emitter: fix Scalar Saturating Instructions 2020-04-07 23:07:24 -05:00
SachinVin
5d6242ac46 A64 Emitter: Implement Saturating Add and Sub 2020-04-07 23:07:24 -05:00
SachinVin
5e55e8297f backend\A64\emit_a64_data_processing.cpp: Implement Division 2020-04-07 23:07:24 -05:00
SachinVin
d6f0b3532f backend\A64\emit_a64_data_processing.cpp: Implement 64bit CLZ 2020-04-07 23:07:24 -05:00
SachinVin
b9c6a99cf5 backend\A64\emit_a64_data_processing.cpp: Implement 64bit LSL and ROR Instructions
Also EmitTestBit
2020-04-07 23:07:24 -05:00
SachinVin
2ff25d4fbb backend\A64\emit_a64_data_processing.cpp: Implement 64bit Logical Instructions 2020-04-07 23:07:24 -05:00
SachinVin
f33a51cb09 backend/a64: implememnt CheckBit 2020-04-07 23:07:23 -05:00
SachinVin
2dc985237b backend/a64: Redesign Const Pool 2020-04-07 23:07:23 -05:00
SachinVin
66978a9fb7 backend\A64\emit_a64_floating_point.cpp: Fix include paths 2020-04-07 23:07:23 -05:00
SachinVin
5af7146374 backend\A64\a32_emit_a64.cpp: Fix Coproc* after rebase 2020-04-07 23:07:23 -05:00
SachinVin
0fbb8a5a73 backend/a64/opcodes.inc: Coproc instructions 2020-04-07 23:07:23 -05:00
SachinVin
49dce5c8fa a64 emitter: Fix LDR literal 2020-04-07 23:07:23 -05:00
SachinVin
ec41144951 a64 emitter: Move IsInRange* and MaskImm* into anon namespace 2020-04-07 23:07:23 -05:00
SachinVin
d309b0a917 backend\A64\emit_a64_floating_point.cpp: Implement VADD VSUB VMUL and other stuff 2020-04-07 23:07:23 -05:00
SachinVin
ee981d64ea backend\A64\emit_a64_floating_point.cpp: Implement VABS VNEG VCMP and a few others 2020-04-07 23:07:23 -05:00
SachinVin
a44e2cbdd0 frontend/A32/Decoder : (backend/a64)VMOV 2020-04-07 23:07:23 -05:00
SachinVin
f9696def84 backend\A64\emit_a64_floating_point.cpp: Implement VCVT instructions 2020-04-07 23:07:23 -05:00
SachinVin
b947f47c3f backend\A64\emit_a64_floating_point.cpp: part 1 2020-04-07 23:07:23 -05:00
SachinVin
e761af6a6c backend/a64/reg_alloc: Fix EmitMove for FPRs 2020-04-07 23:07:23 -05:00
SachinVin
49407c1b0b A64 emitter: Support for 64bit FMOV 2020-04-07 23:07:23 -05:00
SachinVin
1025f8b24c a64 backend: Load "guest_FPSR" 2020-04-07 23:07:23 -05:00
SachinVin
701b851964 A64 backend: Add Get/SetExtendedRegister and Get/SetGEFlags 2020-04-07 23:07:23 -05:00
SachinVin
3ad30f2de3 tests: Dont compile A64 tests for non x64 backend 2020-04-07 23:07:23 -05:00
SachinVin
f22f1a8a92 travis a64: unicorn 2020-04-07 23:07:03 -05:00
SachinVin
4ebf381ece travis a64 backend 2020-04-07 23:07:03 -05:00
SachinVin
0d2213bb41 Frontend/A32: a64 backend; Interpret SEL 2020-04-07 23:07:03 -05:00
SachinVin
c2a47d98b8 frontend/A32: A64 Backend implemented instructions 2020-04-07 23:07:03 -05:00
SachinVin
944b31a2fd backend\A64\emit_a64_data_processing.cpp: Implement REV and CLZ ops 2020-04-07 23:07:03 -05:00
SachinVin
fa1dca005f backend\A64\emit_a64_data_processing.cpp: Implement Sext an Zext ops 2020-04-07 23:07:03 -05:00
SachinVin
5ef6c28cb5 backend\A64\emit_a64_data_processing.cpp: Implement Logical ops 2020-04-07 23:07:03 -05:00
SachinVin
6008e63a4b backend\A64\emit_a64_data_processing.cpp: Implement Arithmetic ops 2020-04-07 23:07:03 -05:00
SachinVin
41ca83102e backend\A64\emit_a64_data_processing.cpp: Implement Shift and Rotate ops 2020-04-07 23:07:03 -05:00
SachinVin
5af0945b6d backend\A64\emit_a64_data_processing.cpp:Implement ops 2020-04-07 23:07:03 -05:00
SachinVin
157fce5ab9 backend\A64\emit_a64_data_processing.cpp: Mostly empty file 2020-04-07 23:07:03 -05:00
SachinVin
b06f3e0f2f backend/a64: Add a32_interface 2020-04-07 23:07:03 -05:00
SachinVin
1a184e0cb6 backend/a64: Port a32_emit_a64 2020-04-07 23:07:03 -05:00
SachinVin
10e0f70aa9 backend/a64: Port block_of_code and emit_a64 2020-04-07 23:07:03 -05:00
SachinVin
01b2ea1ca3 backend/a64: Port callback functions 2020-04-07 23:07:03 -05:00
SachinVin
36e22a6ebf backend/a64: Port exception handler 2020-04-07 23:07:03 -05:00
SachinVin
ac1b058650 backend/a64: Port const pool 2020-04-07 23:07:03 -05:00
SachinVin
d34ce15d01 backend/a64: Port reg_alloc 2020-04-07 23:07:03 -05:00
SachinVin
30a67b6f9b backend/a64: Port ABI functions 2020-04-07 23:07:03 -05:00
SachinVin
43ad1ab4a4 backend/a64: Port perfmap 2020-04-07 23:07:03 -05:00
SachinVin
53c0761748 backend/a64: Port hostloc 2020-04-07 23:07:03 -05:00
SachinVin
a7c08a6240 backend/a64: Devirtualize functions for a64 2020-04-07 23:07:03 -05:00
SachinVin
2d9d104719 backend/a64: Port block_range_info 2020-04-07 23:07:03 -05:00
SachinVin
01a943c3d3 CMakeModules\DetectArchitecture.cmake: Refactor ARCHITECTURE to DYNARMIC_ARCHITECTURE
Don't rely on super-project's definition of ARCHITECTURE
2020-04-07 23:07:03 -05:00
SachinVin
3eced9ffc3 [HACK] A32/exception_generating: Interpret undefined instructions 2020-04-07 23:07:03 -05:00
SachinVin
0a945f8c0b [HACK] CMakeLists: Do not build A64 tests on AArch64 2020-04-07 23:07:03 -05:00
MerryMage
c0993253e5 fuzz_thumb: Add [JitA64] tag to supported instructions 2020-04-07 23:07:03 -05:00
SachinVin
8c5b94bae0 backend/A64: Port a32_jitstate 2020-04-07 23:07:03 -05:00
MerryMage
4f416ca0ee code_block: Support Windows and fix munmap check 2020-04-07 23:07:03 -05:00
SachinVin
67f3a1aef9 ir_opt: Port a32_merge_interpreter_blocks 2020-04-07 23:07:03 -05:00
SachinVin
3c3c0dd8b0 assert: Use __android_log_print on Android 2020-04-07 23:07:03 -05:00
SachinVin
42c187c179 CMakeLists: xbyak should only be linked on x64 2020-04-07 23:06:46 -05:00
SachinVin
f35bd519b3 a64_emitter: Fix ABI push and pop 2020-04-07 23:05:41 -05:00
SachinVin
0ca5a5cc1a a64_emitter: More style cleanup 2020-04-07 23:05:41 -05:00
SachinVin
8581a98e4f a64_emitter: Style cleanup 2020-04-07 23:05:41 -05:00
BreadFish64
b5c3b6302f Backend/A64: add jitstate_info.h 2020-04-07 23:05:41 -05:00
BreadFish64
3848532de2 Backend/A64: Add Dolphin's ARM emitter 2020-04-07 23:05:41 -05:00
BreadFish64
59ed378522 Add aarch64 CI 2020-04-07 23:05:41 -05:00
MerryMage
0973ec8640 block_of_code: Reduce jmps in dispatcher loop 2020-04-07 19:35:36 +01:00
MerryMage
b58048a5a8 block_of_code: Always specify codeptr to run from 2020-04-06 15:55:25 +01:00
MerryMage
c24b15be64 A32: Add Step 2020-04-06 15:55:24 +01:00
MerryMage
8cbba8adf9 A64: Add Step
Allow for stepping instruction-by-instruction
2020-04-06 15:33:49 +01:00
MerryMage
58be30f06d appveyor: Remove DYNARMIC_USE_SYSTEM_BOOST option
We no longer use this as a cmake option.
2020-04-05 23:42:47 +01:00
MerryMage
3415f47579 IR: Add masked shift IR instructions
Also use these in the A64 frontend to avoid the need to mask the shift amount.
2020-04-05 23:42:47 +01:00
MerryMage
42722392de cast_util: Add FptrCast
Reduce unnecessary type duplication when casting a lambda to a function pointer.
2020-04-04 10:57:41 +01:00
MerryMage
254f4e3659 lut_from_list: Reduce number of required template arguments 2020-04-04 10:06:55 +01:00
MerryMage
ea0cb8ca4c travis: Temporarily disable unicorn-related tests 2020-04-04 09:01:11 +01:00
MerryMage
6a014e3569 mp: Migrate to shared version of mp library 2020-04-04 01:30:36 +01:00
MerryMage
b6476285a6 externals: Add mp
Merge commit '01586664ad6a11977026a59b6a656588bd4bea16' as 'externals/mp'
2020-04-04 00:33:33 +01:00
MerryMage
01586664ad Squashed 'externals/mp/' content from commit 29cb5588
git-subtree-dir: externals/mp
git-subtree-split: 29cb5588da3a18ed571a0e41622900a01b9f01eb
2020-04-04 00:32:25 +01:00
MerryMage
607dd2c95e mp/function_info: Add parameter_count_v 2020-04-02 13:33:53 +01:00
MerryMage
3315faf592 bit_util: Add CountLeadingZeros 2020-04-02 13:33:53 +01:00
MerryMage
be2f78bb60 print_info: Add -exec parameter to test execution 2020-04-02 13:33:53 +01:00
MerryMage
de63384ad4 a64_emit_x64: Reduce patchpoint sizes 2020-03-31 19:14:02 +01:00
MerryMage
a84a746831 A64: Add options for detecting misaligned loads and stores 2020-03-31 14:45:04 +01:00
Marshall Mohror
f1bfa5b5c0
A32/x64: Create a global_offset optimization for the page table (#507)
Instead of looking up the page table like:
  table[addr >> 12][addr & 0xFFF]
We can use a global offset on the table to query the memory like:
  table[addr >> 12][addr]

This saves two instructions on *every* memory access within the recompiler.

Original change by degasus in A64 emitter
2020-03-22 17:55:07 +00:00
MerryMage
525cac401e ir/basic_block: Add FastDispatchHint to TerminalToString
Use a boost::static_visitor to ensure this is caught at compile-time in the future.
2020-03-21 13:20:46 +00:00
Lioncash
0046466107 A64/impl: Move AccType and MemOp enum into general IR emitter header
These will be used by both frontends in the future, so this performs the
migratory changes separate from the changes that will make use of them.
2020-03-15 22:19:16 +00:00
Lioncash
206bb7074a externals: Update catch to 2.11.1
Updates our unit testing library from 2.9.1 to 2.11.1.

Keeps it up to date.
2020-01-27 14:10:20 +00:00
Merry
f6ae9e1c33
Merge pull request #505 from degasus/page_table
A64/x64: Create a global_offset optimization for the page table.
2019-12-31 18:52:10 +00:00
Markus Wick
f2c7c6a0d0 A64/x64: Create a global_offset optimization for the page table.
Instead of looking up the page table like:
  table[addr >> 12][addr & 0xFFF]
We can use a global offset on the table to query the memory like:
  table[addr >> 12][addr]

This saves two instructions on *every* memory access within the recompiler.

Thanks at skmp for the idea.
2019-12-31 00:08:35 +01:00
MerryMage
087a74417a Reduce requirements to macOS 10.12 2019-08-14 21:14:23 +01:00
MerryMage
79db0c7c40 a32_emit_x64: Use std::get_if in EmitA32Coproc* 2019-08-14 21:14:21 +01:00
MerryMage
8c6cab482f CMakeLists: Put -Wfatal-errors behind a CMake flag 2019-08-14 20:50:36 +01:00
MerryMage
af8e6c4127 test_arm_instruction: Revive some old tests 2019-07-28 21:31:05 +01:00
MerryMage
156cfa97db constant_propagation_pass: Handle GetCarryFromOp for MostSignificantWord 2019-07-28 21:28:02 +01:00
MerryMage
6921ef5632 a32_interface: Remove unused TransferJitState function 2019-07-28 21:23:16 +01:00
MerryMage
3aecba9833 a32_jitstate: Only transfer required state
Importantly, reset exclusive state upon transfer.
2019-07-28 18:59:44 +01:00
MerryMage
0e7b6b1a60 A32/Thumb: Correct behaviour for UDF and Unpredictable instructions
Raise an exception instead of calling the interpreter and ASSERT-ing respectively.
2019-07-27 19:56:18 +01:00
MerryMage
1b17d1e7bd fuzz_arm: Test MSR and MRS instructions against unicorn
* Add always_little_endian option to mach unicorn behavior.
* Correct CPSR.Mode = Usermode
2019-07-27 19:54:57 +01:00
MerryMage
993784faa3 print_info: Add support for printing A32 instructions 2019-07-27 16:33:19 +01:00
MerryMage
e656eb0b82 a32_emit_x64: EmitA32SetCpsr: BUGFIX: Actually set CPSR.GE
Was unintentionally masking the writing of CPSR.GE due to 32-bit immediate sign extension.
2019-07-27 08:29:32 +01:00
MerryMage
6049e3ef91 a32_emit_x64: GenTerminalHandlers: Remove unnecessary mov 2019-07-27 08:28:39 +01:00
MerryMage
e814b47812 A64: Add hook_hint_instructions option 2019-07-25 12:15:54 +01:00
MerryMage
534eb0fe1d A32: Add hook_hint_instructions option 2019-07-25 12:11:39 +01:00
MerryMage
254ab9355e a32_jitstate: Consolidate upper bits of location descriptor into upper_location_descriptor
Also solves a performance regression initially introduced by b6e8297e369f2dc4758bafe944e51efb8d1a2552,
primarily due to excessively mismatched load/store sizes causing less than optimal load-to-store forwarding.
2019-07-25 11:40:40 +01:00
MerryMage
dc8e6ccf74 CMakeLists: Temporarily remove export
Unable to export fmt in projects that have DYNARMIC_NO_BUNDLED_FMT enabled
2019-07-23 21:42:14 +01:00
Lioncash
e1709546f9
externals: Update catch to 2.9.1
Keeps the unit-testing library up to date.
2019-06-17 06:36:01 -04:00
Merry
313622a53a
Merge pull request #503 from lioncash/cmp
A64: Implement half-precision variants of FCMEQ
2019-05-30 00:58:57 +01:00
Merry
f67690157a
Merge pull request #502 from lioncash/header
General: Remove unnecessary includes
2019-05-27 13:45:05 +01:00
Lioncash
4715b11216
A64: Implement all half-precision variants of FCMEQ 2019-05-25 23:51:39 -04:00
Lioncash
a3f211847c
frontend/ir_emitter: Add half-precision opcode for FPVectorEquals 2019-05-25 23:51:39 -04:00
Lioncash
6d8c9a7dd9
common/fp/op: Add soft-float implementation of FPCompareEQ
This will be used to implement the half-precision floating-point
variants of FCMEQ in following changes.
2019-05-25 23:51:35 -04:00
Lioncash
a9e12969c0
backend/x64/reg_alloc: Apply const where applicable
Also tidies up bracing where applicable along the way.
2019-05-25 17:41:24 -04:00
Lioncash
0a5a34bda4
backend/x64/emit_*: Apply const where applicable 2019-05-25 17:35:05 -04:00
Lioncash
81a3c1c477
A64/translate/*: Apply const where applicable
Just some tidying up for consistency
2019-05-25 17:27:01 -04:00
Lioncash
dfca10ed73
disassembler_arm: Apply const where applicable 2019-05-25 17:15:00 -04:00
Lioncash
8a4439808d
a64_emit_x64: Apply [[maybe_unused]] to unused lambda parameter
This can result in an unused variable warning on Windows otherwise.
2019-05-25 17:07:23 -04:00
Lioncash
d079a4812c
A64/translate/impl: Mark DecodeBitMasks and AdvSIMDExpandImm as static
These don't rely on instance state to perform their behavior. They're
just helper functions.
2019-05-24 02:29:41 -04:00
Lioncash
4dc39252fd
x64/exception_handler_windows: Join namespace declaration
Uses a nested namespace declaration like the rest of the codebase.
2019-05-24 02:18:36 -04:00
Lioncash
2f09577dbf
a32_interface: Remove duplicated documentation comments
These already exist in the header, so these ones can be removed.
2019-05-24 02:15:51 -04:00
Lioncash
d01ec837d2
frontend/A32/types: Remove redundant std::string initializer
std::string initializes to empty by default. While we're at it, brace a
lone unbraced if statement.
2019-05-24 02:05:19 -04:00
Lioncash
31754c6918
ir_opt/a64_get_set_elimination_pass: Remove redundant return
This lambda function has a void return type, so we don't need to
explicitly return at the end of it.
2019-05-24 02:03:28 -04:00
Lioncash
76ca184afc
General: Make parameter names from declarations and implementations consistent
Most of the time when this occurs, it's a bug. Thankfully this isn't the
case. However, we can resolve these cases to make the codebase more
consistent.
2019-05-24 01:59:08 -04:00
Lioncash
c6b321d31c
A32/translate/translate: Add missing doxygen parameter string 2019-05-24 01:48:00 -04:00
Lioncash
2bc8a095dd
General: Correct typos is code comments 2019-05-24 01:37:03 -04:00
Lioncash
268d08511e
a32_interface: std::move UserConfig where applicable
UserConfig instances contain up to 16 std::shared_ptr<Coprocessor>
instances. We can std::move here to avoid performing 16 redundant atomic
reference increment and decrement operations.

Mostly inconsequential on x64, but we may as well signify intent.
2019-05-23 22:09:16 -04:00
Lioncash
9100696696
ir/basic_block: std::move Terminal within SetTerminal and ReplaceTerminal
A terminal isn't a trivial type (and boost::variant is allowed to heap
allocate), so we can std::move it here to avoid a redundant copy.
2019-05-23 22:05:45 -04:00
Lioncash
72f863a223
ir/terminal: std::move constructor parameters where applicable
Allows the compiler to choose the most suitable code in this scenario,
given a Terminal isn't a trivial type.
2019-05-23 22:02:32 -04:00
Lioncash
1d65e3a521
a32_interface: Default destructor in the cpp file
Makes it more consistent with code throughout the codebase.
2019-05-23 21:56:24 -04:00
Lioncash
a178031d6c
General: Remove unnecessary includes
Removes unnecessary header dependencies that have accumulated over time
as changes have been made. Lessens the amount of files that need to be
rebuilt when the headers change.
2019-05-23 21:43:10 -04:00
Lioncash
884d759eba
A32/coprocessor: Remove lingering boost mention in documentation comment
This should have been changed to mention std::monostate, but was
overlooked during the transition to standardized facilities.
2019-05-18 15:10:42 -04:00
Lioncash
7fe1a40bf4
common/cast_util: Declare BitCast and BitCastPointee with the noexcept specifier
std::bit_cast is also defined with the noexcept specifier, so we can do
the same here to match up with it and stay similar with the standard
library.
2019-05-18 15:06:27 -04:00
Lioncash
0765f0ce27
frontend/A32/ir_emitter: Remove unnecessary includes
std::initializer_list isn't used anywhere in here, and we can just
forward declare the CoprocReg enum to avoid needing to include the
header.
2019-05-18 14:31:31 -04:00
Lioncash
07e29a9f82
A32/A64: Make public header inclusions consistent
For all public header inclusions, we use the <> form of including them
as opposed to "", which we typically use for internal headers.
2019-05-18 14:10:39 -04:00
Lioncash
6caeadbe42
A32: Make includes consistent
Normalizes includes to be relative to the project root, like the rest of
the includes in the project.
2019-05-18 14:06:38 -04:00
Lioncash
5e6568dffa
A64/fuzz_with_unicorn: Avoid repeated unnecessary library calls in RunTestInstance()
Repeatedly retrieving the vectors and registers from unicorn involves
copying the entire set of registers and vectors by value instead of
simply retrieving a reference to them. Instead, we can just do the work
once and print out the values.

While we're at it, also make our bracing consistent.
2019-05-17 14:08:26 -04:00
MerryMage
3d2c511928 travis: Test on GCC 8 2019-05-08 22:41:01 +01:00
MerryMage
9f1233a236 CMakeLists: Define FMT_USE_USER_DEFINED_LITERALS=0
This disable a fmtlib feature that depends on a non-standard feature
for its implementation.
2019-05-08 22:18:56 +01:00
Lioncash
2683a9a3e3
Revert "CMakeLists: Handle DYNARMIC_NO_BUNDLED_FMT in relation to export()"
I was being silly. This isn't required.

This reverts commit 00b79cbb72c61744470e0aa1a96b673702b33931.
2019-05-07 03:17:43 -04:00
Lioncash
00b79cbb72
CMakeLists: Handle DYNARMIC_NO_BUNDLED_FMT in relation to export()
This is pretty gross, but until DYNARMIC_NO_BUNDLED_FMT is eliminated,
this fixes the use of it in existing libraries or applications making
use of dynarmic.
2019-05-06 14:29:36 -04:00
MerryMage
11fab29834 A32/translate_thumb: Split off implementation into thumb16 and thumb32 2019-05-06 17:48:27 +01:00
MerryMage
8434f748e4 A32/translate: Rename translate_arm directory to impl
Mirror what the A64 frontend does.
2019-05-06 17:31:00 +01:00
MerryMage
3af0bdc381 Add .gitignore 2019-05-06 12:10:25 +01:00
MerryMage
69c7e77953 travis: Rename test-a64 to test-with-unicorn
Also remove [a64] filter so that the A32 frontend is exercised as well.
2019-05-06 00:49:01 +01:00
MerryMage
291b237f96 A32/location_descriptor: Add CPSR.IT to A32::LocationDescriptor 2019-05-06 00:28:45 +01:00
MerryMage
bacabcd39c PSR: Use Common::ModifyBit{,s} 2019-05-05 23:50:34 +01:00
MerryMage
94632525e0 A32: Add ITState 2019-05-05 23:50:31 +01:00
MerryMage
b6e8297e36 a32_jitstate: Optimize runtime location descriptor calculation
Calculation is now one unaligned 64-bit load.
2019-05-05 23:24:57 +01:00
MerryMage
205e60273c a32_jitstate: Remove fpsr_idc
We do not really have accurate FPSR state in any case.
2019-05-05 23:19:08 +01:00
MerryMage
e5e8036917 {a32,a64}_jitstate: Rename CPSR_* to cpsr_* 2019-05-05 19:49:54 +01:00
MerryMage
ddd5699a83 a32_jitstate: Remove old_FPSCR 2019-05-05 19:47:38 +01:00
MerryMage
0aae9ea07c a32_jitstate: Rename FPSCR_nzcv to fpsr_nzcv 2019-05-05 19:46:57 +01:00
MerryMage
8dc9aec9db a32_jitstate: Rename FPSCR_mode to fpcr_mode 2019-05-05 19:45:45 +01:00
MerryMage
0fb12df549 {a32,a64}_jitstate: Rename FPSCR_IDC to fpsr_idc 2019-05-05 19:44:12 +01:00
MerryMage
33715d2a97 {a32,a64}_jitstate: Remove FPSCR_UFC 2019-05-05 19:42:17 +01:00
MerryMage
0f20a56fe9 a32_jitstate: Enable SSE FTZ and DAZ 2019-05-05 19:40:14 +01:00
MerryMage
852591ff37 a32_jitstate: Remove exception trap enables from FPSCR_MODE_MASK
We don't currently use this for anything (we do not currently trap
floating point exceptions).

This frees these bits up for other purposes.
2019-05-05 19:38:55 +01:00
Merry
c3d20e4ebf
Merge pull request #500 from lioncash/cbz
A32: Implement Thumb-1's CBZ/CBNZ instructions
2019-05-05 18:48:13 +01:00
MerryMage
0cca95d9eb tests: Fix Windows build when DYNARMIC_TESTS_USE_UNICORN is enabled 2019-05-05 18:43:58 +01:00
Merry
766f368f7b
Merge pull request #498 from lioncash/ahp
A32/location_descriptor: Add AHP bit to the FPSCR mask
2019-05-05 11:50:37 +01:00
Lioncash
4a7d62d528
common/fp/info: Make formatting of FPInfo struct member functions consistent
Orgranizes the functions to all be consistent with the half-precision
specialization.
2019-05-04 21:24:18 -04:00
Lioncash
3991361352
common/fp/util: Make ProcessNaN utility functions constexpr
Nothing in particular prevents these from being constexpr. Do so to make
them consistent with the bulk of other functions in this header that are
constexpr.
2019-05-04 21:20:43 -04:00
Lioncash
4cfd1f28cc
common/fp/op/FPNeg: Make FPNeg constexpr
Negation in (standard IEEE) floating-point is simply flipping the sign-bit, so this
operation will never be more complex than what is presented here, making
constexpr a reasonable allowance.
2019-05-04 21:07:49 -04:00
Lioncash
75fd25b2ec
CMakeLists: Add FPNeg.h to the library target sources
Ensures that the header shows up in IDE generated projects.
2019-05-04 21:05:51 -04:00
Lioncash
94717dc11a
general: Remove trailing spaces
General code-related cleanup. Gets rid of trailing spaces in the
codebase.
2019-05-04 21:03:34 -04:00
Lioncash
0085c21321
x64/reg_alloc: Remove reference qualifier to variable in GetArgumentInfo()
The result of GetArg() is returned by value, so this is essentially
still a copy. While the previous code *is* valid, this communicates what
is actually happening a little more explicitly.
2019-05-04 19:15:19 -04:00
Lioncash
f8814e7e05
ir_opt/verification_pass: Add include for std::puts
Ensures that the header dependency is always satisfied directly, and not
through other project headers. While we're at it, we can qualify the
call with the std:: namespace.
2019-05-04 19:10:05 -04:00
Lioncash
bd0ed7ee79
ir_opt/verification_pass: Eliminate redundant GetArg()
Given the same argument is used inside the condition's body if it's
true, we can just utilize the local to cut out a GetArg() operation.
Avoids redundant internal assertion checking.
2019-05-04 19:07:45 -04:00
Merry
161f0ba2fa
Merge pull request #499 from lioncash/movw
A32: Implement ARM-mode MOVW
2019-05-04 16:53:01 +01:00
Merry
ff75a409b6
Merge pull request #497 from lioncash/boost
A32/coprocessor: Remove boost from public interface
2019-05-04 16:52:24 +01:00
Lioncash
f0f9fd1065
CMakeLists: Specify the /volatile flag with standard-conforming semantics
Makes Windows builds more standard-compliant. Given we currently make no
use of volatile, and the libraries we currently use don't use it any
meaningful way, this is safe to specify without worrying.
2019-05-04 00:46:25 -04:00
Lioncash
6f7fbb31a1
CMakeLists: Add /Zc:externConstexpr compilation flag
Improves standard conformance on Windows builds.
2019-05-04 00:40:12 -04:00
Lioncash
c65ea6a92d
CMakeLists: Remove setting of CMAKE_WARN_DEPRECATED
CMake documentation states:
    "If this variable is not set, CMake behaves as if it were set to TRUE."

So this isn't needed, as it's the default behavior.
2019-05-04 00:17:29 -04:00
Lioncash
d56ed7e513
CMakeLists: Turn generic target path into an error
There's currently no way this path can occur and result in any
functioning executable. The recompiler backends are platform-specific.
If those platforms aren't available, then it's quite literally
impossible to use this library for anything meaningful. Instead of
defining a generic architecture and continuing on, notify the developer
that their platform is not currently supported.
2019-05-04 00:10:46 -04:00
Lioncash
13c3f25ac5
CMakeLists: Remove detection of 32-bit platforms
We currently have no plans to add 32-bit host architecture support, so
we don't even need to check for these platforms.
2019-05-04 00:04:15 -04:00
Lioncash
2f8167a3e0
block_of_code: Use variable template variants of type traits
Now all type traits are using the variable template variants where
applicable.
2019-05-03 22:55:50 -04:00
Lioncash
9d9ba745db
dynarmic_tests: Use variable template equivalents of type traits where applicable
Same thing, same readability, less writing.
2019-05-03 22:44:38 -04:00
Lioncash
835f490765
frontend/decoder/decoder_detail: Replace std::is_same, with std::is_same_v
Same thing, same readability, less characters.
2019-05-03 22:41:53 -04:00
Lioncash
fb95482a85
A32: Implement Thumb-1's CBZ/CBNZ instructions
Introduced in ARMv6T2, this allows for short forward branches.
2019-05-03 19:29:08 -04:00
Lioncash
80320bfed0
frontend/ir/ir_emitter: Add A32 equivalent to A64's SetCheckBit
This will be used in a subsequent change to implement ARMv6T2's CBZ/CBNZ
Thumb-1 instructions.
2019-05-03 19:13:21 -04:00
Lioncash
17f6494432
A32: Implement ARM-mode MOVW
Introduced to the ISA in ARMv6T2
2019-05-03 18:00:54 -04:00
Lioncash
19f21d0be2
travis: Bump macOS deployment version to 10.14
Some of std::variant's functions are only available in 10.14 and later.
2019-05-03 16:36:58 -04:00
Merry
c3b92ed7ee
Merge pull request #496 from lioncash/thumb-hint
A32: Implement Thumb-1 hint instructions
2019-05-03 21:22:37 +01:00
Lioncash
64ffdb6d14
A32: Implement Thumb-1 variant of SEVL
While we're at it, also add the Thumb-2 encoding to the encoding table
to make sure it isn't forgotten about in the future.
2019-05-03 16:16:07 -04:00
Lioncash
ae7aa581b8
A32: Implement the ARM-mode variant of SEVL 2019-05-03 16:16:07 -04:00
Lioncash
245d41ac93
A32: Implement Thumb-1 variant of YIELD 2019-05-03 16:15:11 -04:00
Lioncash
293d5355b6
A32: Implement Thumb-1 variant of WFI 2019-05-03 16:15:11 -04:00
Lioncash
b6a6a23f8d
A32: Implement Thumb-1 variant of WFE 2019-05-03 16:15:11 -04:00
Lioncash
2396d6ace9
A32: Implement Thumb-1 variant of SEV 2019-05-03 16:15:11 -04:00
Lioncash
489083438b
A32/translate_thumb: Add helper function for raising exceptions
Similar to the variant within the ARM-mode translator visitor. This will
be used in subsequent changes to implement the hint instructions
introduced in ARMv7.
2019-05-03 16:15:11 -04:00
Lioncash
4e21593a8b
A32: Implement Thumb-1 variant of NOP 2019-05-03 16:15:07 -04:00
Merry
a3456b39ac
Merge pull request #495 from lioncash/bkpt
A32: Implement Thumb-16's variant of BKPT
2019-05-03 21:10:24 +01:00
Merry
2debd4dc5a
Merge pull request #494 from lioncash/pldw
A32: Handle PLDW
2019-05-03 21:09:13 +01:00
Lioncash
44de480aea
A32/location_descriptor: Add AHP bit to the FPSCR mask
Ensures the alternate half-precision state is preserved within the
location descriptors, which will be necessary when implementing the
half-precision extensions for VFP and NEON.
2019-05-03 15:59:31 -04:00
Lioncash
41c1aa61df
A32/coprocessor: Remove boost from public interface
Removes a boost header from the public includes in favor of using the
standard-provided std::variant.

The use of boost in public interfaces is often a dealbreaker for some
people. Given we use std::optional in the header already, we can
transition over to std::variant from boost::variant.

With this removal, this makes all of our dependencies internal to the
library itself.
2019-05-03 12:43:57 -04:00
Lioncash
ae4d168c76
a64_emit_x64: Use const on locals where applicable
Normalizes the use of const in the source file.
2019-05-03 12:27:27 -04:00
Lioncash
7ab5b65706
a32_emit_x64: Use const on locals where applicable
Normalizes the use of const in the source file.
2019-05-03 12:15:30 -04:00
Lioncash
2d9a155de2
emit_x64: Use const on locals where applicable 2019-05-03 11:54:44 -04:00
Lioncash
c8860a0742
emit_x64: Remove unnecessary typename in GetBasicBlock()
This can be deduced from the name alone.
2019-05-03 11:51:46 -04:00
Lioncash
eb8bf6630a
A32: Implement Thumb-16's variant of BKPT 2019-05-02 22:40:07 -04:00
Lioncash
b8bfe3ac51
A32/disassembler_arm: Remove <unimplemented> from hint instruction output
Given we now support hooking these hint instructions, we can consider
them implemented.
2019-05-02 22:09:03 -04:00
Lioncash
c93451823f
A32: Handle different variants of PLD 2019-05-02 20:48:15 -04:00
Lioncash
3a29baabc0
emit_x64_vector: Use const on locals where applicable
Normalizes the use of const in the source file.
2019-05-02 19:22:49 -04:00
Lioncash
9f86639b46
emit_x64_saturation: Use const on locals where applicable
Normalizes the use of const in the source file.
2019-05-02 19:22:49 -04:00
Lioncash
0b2ba9410e
emit_x64_packed: Use const on locals where applicable
Normalizes the use of const across the source file.
2019-05-02 19:22:49 -04:00
Lioncash
d1bb04b035
emit_x64_data_processing: Use const on locals where applicable
Normalizes the use of const across the source file.
2019-05-02 19:22:49 -04:00
MerryMage
244222bed5 fuzz_thumb: Disable fuzzing longer blocks 2019-05-03 00:17:48 +01:00
Merry
120d264bc9
Merge pull request #493 from lioncash/ir
frontend/ir/ir_emitter: Remove unnecessary logical shift overloads
2019-05-02 23:47:16 +01:00
Merry
9a9906bc1b
Merge pull request #492 from lioncash/vfp
A32: Rename vfp2-related files to vfp
2019-05-02 23:46:53 +01:00
Merry
f2fa3853b7
Merge pull request #491 from lioncash/hint
A32: Allow hooking of hint instructions in ARM mode.
2019-05-02 23:45:59 +01:00
Merry
7fb72ddf93
Merge pull request #490 from lioncash/crc32
A32: Implement ARM-mode CRC32 instructions
2019-05-02 23:45:09 +01:00
Lioncash
ee174e60aa
frontend/ir/ir_emitter: Remove unnecessary logical shift overloads
These aren't necessary anymore, now that the U32U64 overload already
exists.
2019-05-02 18:06:30 -04:00
Lioncash
78a93b0540
A64/translate/impl/impl: Mark locals const where applicable in DecodeBitMasks()
Follows the convention of making immutable state explicit.
2019-05-02 17:46:37 -04:00
MerryMage
71a448c66f block_of_code: Explicitly delete copy constructor 2019-05-02 21:41:49 +01:00
MerryMage
6bf0470e09 Suppress MSVC warning C4702: unreachable code 2019-05-02 21:41:22 +01:00
Lioncash
e5d77334f0
A32: Implement ARM-mode CRC32 instructions
Implements the ARM-mode variants of the CRC32 instructions introduced
within ARMv8. This is also one of the instruction cases where there is
UNPREDICTABLE behavior that is constrained (we must do one of the
options indicated by the reference manual).

In both documented cases of constrained unpredictable behavior, we treat
the instructions as unpredictable in order to allow library users to
hook the unpredictable exception to provide the intended behavior they
desire.
2019-05-02 16:22:10 -04:00
Lioncash
fc0ecdf3b1
travis: Make macOS builder use Xcode 10.2
Keeps it targeting the latest Xcode revision.
2019-05-02 11:40:54 -04:00
Lioncash
16a9e3c4d3
dynarmic_tests: Resolve CPSR discrepancies in tests
Unicorn internally checks if the LSB is set in order to determine
whether or not it should assume thumb mode internally. Clearing this
ourselves will always result in the incorrect PSR between runs.
2019-05-02 11:12:36 -04:00
Lioncash
469b6ad90e
A32: Rename vfp2-related files to vfp
Now that we fuzz against Unicorn, we aren't just restricted to VFPv2.
VFPv3 and VFPv4 facilities can now be implemented. This renames
constructs mentioning VFPv2 to just refer to VFP.
2019-05-02 10:25:43 -04:00
Lioncash
74cf752b2c
frontend/ir/ir_emitter: Amend arguments to conversion opcodes
Accidentally caused within 967d1fcc8d6f60749a162a96b997439450fed687.
That one's on me. My bad.
2019-05-02 10:24:26 -04:00
Lioncash
1634059618
{A32, A64}/types: Use std::array deduction guides where applicable
We also make the arrays static here, as MSVC tends to load the whole
array every time the function is called, instead of storing the data
within rodata.

This also line breaks the elements a little earlier for readability.
2019-05-02 09:28:31 -04:00
Lioncash
13e9d48720
frontend/ir/type: Generify std::array declaration
With deduction guides, we can eliminate the need to explicitly size the
array. Also newlines the elements based off their relation, making it
slightly nicer to read.
2019-05-02 09:08:43 -04:00
Lioncash
994f3cfa33
CMakeLists: Add a namespace to the export
Avoids potentially dumping boost, fmt, and xbyak targets into a
top-level namespace without any qualification, which can lead to build
errors in projects that already make use of them.
2019-05-02 08:39:11 -04:00
Lioncash
362dc5e350
frontend/A32/ir_emitter: Mark locals as const where applicable
Makes const usage consistent within the source file.
2019-05-02 00:07:13 -04:00
Lioncash
9b7a8547b9
frontend/A32/types: Use helper function in operator+ overload
Allows deduplicating an assert and a cast.
2019-05-02 00:03:13 -04:00
Lioncash
28eedda6ff
frontend/A64/types: Make RegNumber() and VecNumber() constexpr
Given they simply perform casting, they can be safely made constexpr.
2019-05-02 00:00:15 -04:00
Lioncash
455a7a0359
frontend/A64/types: Use helper functions in operator+ overloads
Allows us to get rid of another explicit cast.
2019-05-01 23:59:20 -04:00
Lioncash
08cd3f0385
frontend/ir/ir_emitter: Apply const to locals where applicable
Makes const usage consistent with all other functions in the source
file.
2019-05-01 23:54:22 -04:00
Lioncash
967d1fcc8d
frontend/ir/ir_emitter: Use switch constructs in floating point opcodes where applicable
This'll reduce the amount of noise necessary in changes implementing
half-precision instructions, as the type can just be prepended to the
switch cases, instead of rewriting the whole if/else branch.
2019-05-01 23:45:01 -04:00
Lioncash
63c22e9fcb
A32: Allow hooking of hint instructions in ARM mode.
Mirrors the hooking functionality from the AArch64 frontend to make the
behavior of both consistent.
2019-05-01 22:15:49 -04:00
Merry
98c01b0e1a
Merge pull request #489 from lioncash/imm
A32: Replace immediate type aliases with the Imm template
2019-05-01 16:02:44 +01:00
Lioncash
2bd54d6485
A32: Resolve parameter discrepancies discovered via use of the Imm template 2019-04-30 23:58:39 -04:00
Lioncash
17815bdda3
A32: Replace immediate type aliases with the Imm template
Replaces type aliases of raw integral types with the more type-safe Imm
template, like how the AArch64 frontend has been using it.

This makes the two frontends more consistent with one another.
2019-04-28 07:31:00 -04:00
Lioncash
f6a4aaef6e
externals: Update Catch to 2.7.2
Updates Catch from 2.7.0 to 2.7.2. Keeps the unit-testing library up to
date.
2019-04-27 17:36:14 -04:00
Lioncash
f17bf4a352
A32/barrier: Correct PC assignment within ISB
The SetRegister() IR function doesn't allow specifying the PC as a
register. This is a discrepancy that slipped through (my bad). Instead,
we can use BranchWritePC(), like how the other similar PC modifying
locations do it.
2019-04-27 17:22:32 -04:00
Mat M
055fab687d
Merge pull request #488 from lioncash/imm
frontend: Move imm.h to the top-level directory of the frontends
2019-04-27 15:01:12 -04:00
Lioncash
4ed37614c6
frontend: Move imm.h to the top-level directory of the frontends
Preparation to utilize the immediate type within the A32 backend as
well, which will allow eliminating numerous type aliases like Imm4,
Imm5, etc.
2019-04-27 14:53:33 -04:00
Lioncash
6201b0e32d
A32/disassembler_arm: Mark utility functions as static where applicable
These don't depend on class state and can be marked static to make that
explicit.
2019-04-27 09:45:15 -04:00
Mat M
d88e1d027d
Merge pull request #487 from lioncash/fuzz2
a32/fuzz_arm: Use same fuzzing mechanism as AArch64
2019-04-27 09:42:46 -04:00
Merry
19c59bbf26
Merge pull request #486 from lioncash/barrier
A32: Implement barrier instructions introduced in ARMv7
2019-04-27 14:40:06 +01:00
Lioncash
f3679e6278
A32: Implement barrier instructions introduced in ARMv7
Provides basic implementations of the barrier instruction introduced
within ARMv7. Currently these simply mirror the behavior of the AArch64
equivalents.
2019-04-27 08:29:49 -04:00
Lioncash
c32a10ca7e
a32/fuzz_arm: Use same fuzzing mechanism as AArch64
Introduces the same fuzzing mechanism used by the AArch64 code for
fuzzing instruction implementations, getting rid of the need to
manually specify the instruction generator sequences--replacing it with
an instruction blacklist instead.

Much of this change originates from a previous patch made by Mary. This
just makes it interact nicely with the alterations made to get Unicorn
to cooperate properly.
2019-04-27 06:11:55 -04:00
Mat M
b27fe43120
Merge pull request #485 from lioncash/a32
A32: Handle all ARM-mode arithmetic and data processing instructions added in ARMv6T2 and ARMv7
2019-04-26 06:51:24 -04:00
Lioncash
23571f99c5
A32: Implement ARM-mode MLS 2019-04-26 06:50:03 -04:00
Lioncash
adf04f6f9a
A32: Implement ARM-mode MOVT 2019-04-26 06:50:03 -04:00
Lioncash
b4429e7f55
A32: Implement ARM-mode SBFX 2019-04-26 06:50:03 -04:00
Lioncash
42964964ce
A32: Implement ARM-mode UBFX 2019-04-26 06:50:03 -04:00
Lioncash
745dfd5046
A32: Implement ARM-mode BFI 2019-04-26 06:50:02 -04:00
Lioncash
20e499d8d6
A32: Implement ARM-mode BFC 2019-04-26 06:50:02 -04:00
Lioncash
3b7b50b0c0
A32: Implement ARM-mode RBIT 2019-04-26 06:49:56 -04:00
Lioncash
c62b822937
A32: Implement ARM-mode SDIV/UDIV
Now that we have Unicorn in place, we can freely implement instructions
introduced in newer versions of the ARM architecture.
2019-04-21 21:30:29 -04:00
Lioncash
9110e70bd3
travis: Re-enable A32 tests 2019-04-20 06:02:32 -04:00
Lioncash
79af6c118c
a32_unicorn: Silence PC value assertions
Ensure the PC is properly masked off after a run.
2019-04-20 06:02:29 -04:00
Lioncash
43422bc106
travis: Amend build parameters
Currently just run the 64-bit tests.
2019-04-20 05:22:54 -04:00
Lioncash
0d3764569d
fuzz_arm: Tidy up existing tests
Now that we utilize C++17, we can use std::array's deduction guides to
avoid the need to explicitly specify the template arguments.

While we're at it, also use const where applicable.
2019-04-20 05:00:15 -04:00
Lioncash
27e8a41b7f
Merge branch 'fuzz' 2019-04-20 04:19:37 -04:00
Lioncash
bce91ff07b
dynarmic_tests: Remove skyeye interpreter
This is quite a messy interpreter and would require a large amount of
work to bring it up to speed to begin implementing newer portions of the
AArch32 instruction set into Dynarmic.

Given we already have fuzzing with Unicorn set up for
AArch64/AArch32, we can get rid of this and unify our testing
infrastructure.

This will also make building the tests much faster, given a whole
interpreter doesn't need to be built anymore as part of the project.
2019-04-20 04:19:22 -04:00
Lioncash
ad7d439ef5
A32: Fuzz instructions using unicorn
While skyeye was OK previously, now that we have an AArch64 backend,
this also means that we eventually have to support the AArch32
counterpart to it. Unfortunately, SkyEye is only compatible up to
ARMv6K, so we woud need to do a lot of work to bring the interpreter up
to speed with things to even begin testing new instruction
implementations.

For the AArch64 side of things, we already use Unicorn, so we can toss
out SkyEye in favor of it instead.
2019-04-20 04:17:18 -04:00
Lioncash
127efc592d
A32/translate_thumb: Clean up formatting
Performs a similar tidying up of the Thumb translator, like what was
done with the regular ARM translator to make it consistent with the rest
of the codebase.

The A32 backend (both Thumb and ARM), will likely see more changes to it
in the near future, so this just acts as a "dusting off".
2019-04-20 00:32:25 -04:00
Merry
7316ab18f6
Merge pull request #483 from lioncash/invert
frontend/ir/cond: Remove unused invert() function
2019-04-17 10:45:34 +01:00
Lioncash
66e3b1c1eb
common/fp/op/FPConvert: Remove unnecessary casts in FPConvert()
These were made unnecessary in 2c2fdb435cf8e358a0c5b907ce8131e434df3f22,
but were missed during the initial removal.
2019-04-16 21:53:22 -04:00
Lioncash
fe7c21b687
frontend/ir/cond: Remove unused invert() function
This is no longer used by anything in the codebase, so it can be
removed.
2019-04-16 21:37:12 -04:00
Merry
6377fd9866
Merge pull request #482 from lioncash/fixedfp
A64: Handle half-precision variants of FP->Fixed instructions
2019-04-15 20:08:01 +01:00
MerryMage
732215d68d emit_x64_data_processing: Remove INVALID_REG
INVALID_REG.cvt8() now throws
2019-04-15 16:59:39 +01:00
MerryMage
731aa2df8d externals: Update xbyak to 73ac586
Merge commit 'b0bc810667409c2fddd4e8c7a28ea4b1ffa76a03'
2019-04-15 16:18:43 +01:00
MerryMage
b0bc810667 Squashed 'externals/xbyak/' changes from 4a6fac8a..73ac5866
73ac5866 fix Reg::changeBit

git-subtree-dir: externals/xbyak
git-subtree-split: 73ac5866099b19bd8063f06434e19b9d7bbc9b8d
2019-04-15 16:18:43 +01:00
Lioncash
105d4ed9e5
A64: Handle half-precision variants of FP->Fixed-point instructions 2019-04-15 08:50:00 -04:00
Merry
d32f648578
Merge pull request #481 from lioncash/alloc
ir/basic_block: Forward declare headers where applicable
2019-04-15 13:04:02 +01:00
Merry
c8446bda2b
Merge pull request #480 from lioncash/info
common/fp/info: Make half-precision info struct functions return correctly sized types
2019-04-15 12:14:30 +01:00
Lioncash
f4d0a09bf4
ir/basic_block: Forward declare headers where applicable
Now that the constructor and destructors have been placed within the cpp
file, we can forward declare the memory pool data structures. Now, a
change to the memory pool code won't ripple across the entirety of the
IR emitter.
2019-04-15 06:00:35 -04:00
Lioncash
db78e2f32c
ir/block: Default ctor and dtor in the cpp file
Prevents potentially inlining allocation code everywhere. While we're at
it, also explicitly delete/default the copy/move constructor/assignment
operators to be explicit about them.
2019-04-15 05:58:36 -04:00
Lioncash
2c2fdb435c
common/fp/info: Make half-precision info struct functions return correctly sized types
While initially done to potentially prevent creating bugs due to C++
having a silly type-promotion mechanism involving types < sizeof(int)
and unsignedness, given that the bulk of these functions' usages
are on exit paths, these can return the correct type to avoid the need
to cast at every usage point.
2019-04-15 04:55:00 -04:00
Merry
973c87445e
Merge pull request #479 from lioncash/rsqrts
A64: Handle half-precision variants of FRSQRTS
2019-04-15 08:28:30 +01:00
Lioncash
189692246d
frontend/ir/microinstruction: Add missing fixed-point opcodes to ReadsFromAndWritesToFPSRCumulativeExceptionBits() 2019-04-15 00:55:49 -04:00
Lioncash
1d3fc42bfe
frontend/ir_emitter: Add half-precision->fixed-point opcodes 2019-04-15 00:55:46 -04:00
Lioncash
6c7de6c9c4
common/fp/op/FPToFixed: Add half-precision specialization of FPToFixed 2019-04-15 00:17:44 -04:00
Lioncash
28e0f4fe59
A64: Implement FRSQRTS' half-precision vector variant 2019-04-14 21:12:54 -04:00
Lioncash
6f7a370cfb
A64: Implement FRSQRTS' half-precision scalar variant
With the necessary machinery in place, we can now handle the
half-precision variant.
2019-04-14 21:12:54 -04:00
Lioncash
793b3b38d4
frontend/ir_emitter: Add half-precision opcode variant of FPVectorRSqrtStepFused 2019-04-14 21:12:54 -04:00
Lioncash
db4d134726
frontend/ir_emitter: Add half-precision opcode variant of FPRSqrtStepFused 2019-04-14 21:12:49 -04:00
Lioncash
cff4394717
common/fp/op/FPRSqrtStepFused: Add half-precision specialization for FPRSqrtStepFused 2019-04-14 20:51:58 -04:00
Merry
eea732febf
Merge pull request #478 from lioncash/stepfused
A64: Handle half-precision variants of FRECPE and FRECPS
2019-04-14 12:40:18 +01:00
Merry
0c62dba214
Merge pull request #477 from lioncash/rsqrt
A64: Handle half-precision variants of FRSQRTE
2019-04-14 11:21:05 +01:00
Lioncash
b67cc72213
A64: Implement half-precision vector variant of FRECPE 2019-04-14 06:14:20 -04:00
Lioncash
4b3f5b8a30
A64: Implement half-precision scalar variant of FRECPE 2019-04-14 06:14:20 -04:00
Lioncash
4519e4641c
A64: Implement half-precision vector variant of FRECPS 2019-04-14 06:14:19 -04:00
Lioncash
abcf1a6e09
A64: Implement half-precision scalar variant of FRECPS 2019-04-14 06:14:19 -04:00
Lioncash
c55db96819
frontend/ir_emitter: Add half-precision opcode for FPVectorRecipEstimate 2019-04-14 06:14:19 -04:00
Lioncash
1615ba0adc
frontend/ir_emitter: Add half-precision opcode for FPRecipEstimate 2019-04-14 06:14:19 -04:00
Lioncash
e93161e25b
common/fp/op: Add half-precision specialization for FPRecipEstimate 2019-04-14 06:14:19 -04:00
Lioncash
4ae0a27ea4
frontend/ir_emitter: Add half-precision opcode for FPVectorRecipStepFused 2019-04-14 06:14:19 -04:00
Lioncash
065143b395
frontend/ir_emitter: Add half-precision opcode for FPRecipStepFused 2019-04-14 06:14:18 -04:00
Lioncash
408bbfb766
common/fp/op: Add half-precision specialization for FPRecipStepFused 2019-04-14 06:13:43 -04:00
Lioncash
e35352b69e
A64: Implement half-precision variant of FRSQRTE's vector variant 2019-04-14 06:12:20 -04:00
Lioncash
0f677744bb
A64: Implement half-precision variant of FRSQRTE's scalar variant 2019-04-14 06:12:20 -04:00
Lioncash
5edbb415c5
frontend/ir_emitter: Add half-precision opcode variant for FPVectorRSqrtEstimate 2019-04-14 06:12:20 -04:00
Lioncash
f1e556632c
frontend/ir_emitter: Add half-precision opcode variant for FPRSqrtEstimate 2019-04-14 06:11:45 -04:00
Lioncash
9c9087ea47
common/fp/op/FPRSqrtEstimate: Add half-precision specialization for FPRSqrtEstimate 2019-04-14 06:10:27 -04:00
Merry
5ae8e4e043
Merge pull request #476 from lioncash/frint
A64: Handle half-precision variants of FRINT* instructions
2019-04-14 10:57:09 +01:00
Lioncash
f8fb10289a
A64: Enable half-precision vector FRINT* variants 2019-04-13 18:05:00 -04:00
Lioncash
7c5cc15f4e
A64: Enable half-precision variants of floating-point FRINT* variants
With all the backing machinery in place, we can remove the fallback
check for half-precision.
2019-04-13 17:54:36 -04:00
Lioncash
95a96b32c5
frontend/microinstruction: Add FPVectorRoundInt types to ReadsFromAndWritesToFPSRCumulativeExceptionBits()
All variants were previously missing from this.
2019-04-13 17:51:13 -04:00
Lioncash
722daae0d4
frontend/ir_emitter: Add half-precision variant of FPVectorRoundInt 2019-04-13 17:49:04 -04:00
Lioncash
8243705134
frontend/ir_emitter: Add half-precision variant of FPRoundInt 2019-04-13 17:44:37 -04:00
Lioncash
590388b9ec
fp/op/FPRoundInt: Add half-precision specialization of FPRoundInt 2019-04-13 17:37:45 -04:00
Merry
b34f42575d
Merge pull request #475 from lioncash/muladd
A64: Enable half-precision variants of floating-point multiply-add instructions
2019-04-13 14:30:03 +01:00
Merry
2218912292
A64/location_descriptor: Ensure FZ16 is included in the FPCR mask 2019-04-13 08:05:04 -04:00
Merry
9faf1bdfd4
Merge pull request #474 from lioncash/bracing
load_store_*: Make bracing consistent and variables const where applicable
2019-04-13 10:53:21 +01:00
Merry
5f351a669c
Merge pull request #473 from lioncash/sqshlu
A64: Implement SQSHLU
2019-04-13 08:31:17 +01:00
Lioncash
a935f35553
A64: Implement FMLA/FMLS' half-precision vector indexed variants 2019-04-13 02:19:06 -04:00
Lioncash
caaa04cba1
A64: Implement FMLA/FMLS' half-precision scalar indexed variants 2019-04-13 02:11:44 -04:00
Lioncash
894169dc7a
A64: Implement half-precision vector variants of FMLA/FMLS 2019-04-13 01:48:22 -04:00
Lioncash
278c7ae744
ir/frontend: Add half-precision opcode for FPVectorMulAdd 2019-04-13 01:42:35 -04:00
Lioncash
0eb6412c4d
A64: Enable half-precision floating point variants of FP data-processing three register instructions
This handles half-precision floating point for:

- FMADD
- FMSUB
- FNMADD
- FNMSUB
2019-04-13 01:35:32 -04:00
Lioncash
13b41525cb
frontend/ir_emitter: Add half-precision opcode for FPMulAdd 2019-04-13 00:18:09 -04:00
Lioncash
2ae0c4807a
fp/op/FPMulAdd: Add half-precision floating-point specialization 2019-04-13 00:07:34 -04:00
Lioncash
94ac9becda
load_store_*: Make bracing consistent and variables const where applicable
Makes bracing consistent, and variables const where applicable to be
consistent with the rest of the codebase.

In most bracing cases, they'd need to be added to conditionals that
would involve checking stack pointer alignment in the future anyways.
2019-04-12 23:51:36 -04:00
Lioncash
be3fc0f9ff
A64: Implement SQSHLU's scalar variant 2019-04-12 19:49:33 -04:00
Lioncash
508c77c3ee
A64: Implement SQSHLU's vector variant
The vector shift by immediate category is now fully implemented.
2019-04-12 19:45:20 -04:00
Lioncash
31867874de
frontend/ir_emitter: Add opcodes for signed saturated left shifts with unsigned saturation 2019-04-12 19:44:23 -04:00
Merry
5e77d110cc
Merge pull request #472 from lioncash/exception
general: Mark hash functions as noexcept
2019-04-12 21:33:47 +01:00
Merry
ed8c218076
Merge pull request #471 from lioncash/sqrdmulh
A64: Implement SQRDMULH's scalar vector variant
2019-04-12 20:29:22 +01:00
Lioncash
57629276c1
general: Mark hash functions as noexcept
Generally hash functions shouldn't throw exceptions. It's also a
requirement for the standard library-provided hash functions to not
throw exceptions.

An exception to this rule is made for user-defined specializations,
however we can just be consistent with the standard library on this to
allow it to play nicer with it.

While we're at it, we can also make the std::less specializations
noexcpet as well, since they also can't throw.
2019-04-12 15:27:28 -04:00
Merry
c963996e0b
Merge pull request #470 from lioncash/assert
general: Replace unreachable-imitating assertions with UNREACHABLE()
2019-04-12 20:14:18 +01:00
Merry
8ac3fb8df3
Merge pull request #469 from lioncash/void
A64/impl: Reorganize peculiar void use in V_scalar
2019-04-12 20:13:57 +01:00
Lioncash
f58406333a
A64: Implement SQRDMULH's scalar vector variant
Implements the scalar variant in terms of the vector variant for the
time being.
2019-04-12 15:05:53 -04:00
Lioncash
a5ca872208
general: Replace unreachable-imitating assertions with UNREACHABLE()
We can just use the self-documenting assertion for indicating
unreachable paths, instead of manually passing false and providing a
message.
2019-04-12 14:51:43 -04:00
Lioncash
d75af9d0e1
A64/impl: Reorganize peculiar void use in V_scalar
To a reader this might look particularly strange, given the function
itself has a void return value, but this is actually valid, given the
function in the return statement also has a void return value.

This instead alters it to be a little easier to parse and potentially be
a little less confusing at a glance.
2019-04-12 14:44:16 -04:00
Merry
4ed7009f24
Merge pull request #468 from lioncash/const
ir_opt: Mark locals as const where applicable
2019-04-12 19:15:32 +01:00
Merry
25039d02ff
Merge pull request #467 from lioncash/reserved
A64: Handle reserved instruction cases more specifically where applicable
2019-04-12 19:13:08 +01:00
Merry
5fdbb46008
Merge pull request #466 from lioncash/fcmla
A64: Implement FCMLA's indexed element variant
2019-04-12 08:15:05 +01:00
Lioncash
e244bf4f68
ir_opt/verification_pass: Mark locals as const where applicable
Makes our immutable state a little more explicit.
2019-04-11 18:30:30 -04:00
Lioncash
d02eef2fac
ir_opt/a64_callback_config_pass: Mark locals as const where applicable
Makes our immutable state a little more explicit.
2019-04-11 18:28:11 -04:00
Lioncash
38977fac33
ir_opt/a32_get_set_elimination_pass: Mark local variables as const where applicable
Makes our intended immutable state slightly more explicit.
2019-04-11 18:26:13 -04:00
Lioncash
e299e92698
ir_opt/a32_constant_memory_reads_pass: Apply const where applicable to locals
Makes immutable state just slightly more explicit.
2019-04-11 18:18:32 -04:00
Lioncash
0dca81d20f
A64: Handle reserved instruction cases more specifically where applicable
These are cases that are defined as reserved within the ARMv8 reference
manual, so we can handle them as such instead of as unallocated
encodings.

While this doesn't actually change emulated behavior, it does at least
allow the JIT to generate the more appropriate exception.
2019-04-11 17:47:28 -04:00
Lioncash
06e7e9fbef
A64: Implement FCMLA's indexed element variant
With this, all of the instructions introduced with ARMv8.3-CompNum have
an implementation.
2019-04-11 17:20:06 -04:00
Merry
c635591355
Merge pull request #465 from neobrain/master
CMakeLists: Allow importing dynarmic build trees into other CMake projects
2019-04-11 22:00:46 +01:00
Merry
3a2fc56e81
Merge pull request #464 from lioncash/uqshl
A64: Implement UQSHL (immediate)'s scalar variant
2019-04-11 21:29:03 +01:00
Tony Wasserka
fd4fa20834 CMakeLists: Allow importing dynarmic build trees into other CMake projects 2019-04-11 18:04:57 +02:00
Lioncash
b7a76d6967
simd_scalar_shift_by_immediate: Change UnallocatedEncoding() path in SaturatingShiftLeft to ReservedValue()
Strictly speaking, immh being zero is defined as reserved in the ARMv8
reference manual. This was just an error on my part when introducing the
SQSHL immediate scalar variant.
2019-04-10 15:20:11 -04:00
Lioncash
2769572231
A64: Implement UQSHL (immediate)'s scalar variant
Like SQSHL's immediate scalar variant, we can also implement UQSHL's
immediate scalar variant in terms of the vector variant for the time
being.
2019-04-10 15:12:57 -04:00
Lioncash
24479ecbe5
simd_scalar_shift_by_immediate: Migrate SQSHL implementation to file-scope function
This will allow it to be reused for the implementation of UQSHL.
2019-04-10 15:10:32 -04:00
Merry
2483b6b0dc
Merge pull request #463 from lioncash/sqshl
A64: Implement scalar variant of SQSHL (immediate)
2019-04-10 14:12:52 +01:00
Lioncash
fc729bee8c
A64: Implement scalar variant of SQSHL (immediate)
This can be handled in terms of the vector variant for the time being.
2019-04-09 10:13:14 -04:00
MerryMage
0bcc47a71c README: Update README 2019-04-06 10:56:21 +01:00
Merry
cbeb5c9929
Merge pull request #462 from lioncash/undef
{common/fp, backend/x64}: Prevent undefined left shifts where applicable
2019-04-02 17:22:35 +01:00
Lioncash
06ac561e1c
backend/x64/emit_x64_vector: Prevent undefined behavior within VectorSignedSaturatedShiftLeft
Avoids undefined behavior by potentially left-shifting a signed negative
value.
2019-04-01 19:53:48 -04:00
Lioncash
f4d63ff07d
common/fp/op/FPRecipExponent: Prevent undefined behavior from shifting a negative value
Due to promotion rules (types < int, even if unsigned, get promoted to
int when arithmetic is performed on them), this is a potential spot for
undefined behavior.
2019-04-01 19:51:52 -04:00
Lioncash
89581c0c8c externals/fmt: Update fmt to 5.3.0 2019-03-29 16:34:24 +00:00
Lioncash
8f92310698 externals/xbyak: Update xbyak to 5.77
Keeps the external library up to date.
2019-03-29 16:24:22 +00:00
Merry
b52a9da924
Merge pull request #459 from lioncash/catch
externals: Update catch to 2.7.0
2019-03-28 14:42:02 +00:00
Lioncash
64bbe05fa6 Squashed 'externals/fmt/' changes from 3e75ad98..9e554999
9e554999 Update version
b34d92b0 Bump version
d39ece18 Make rst2md runnable and update changelog
fe2d715f Update changelog
27b30670 Update changelog
68837079 Update changelog
c98b202e Update changelog
587a7f66 Update changelog and docs
84e5170c Update changelog and deprecate visit
130e412b Update changelog and docs
0bbdca5b Fix conversion warnings (#989)
77a72448 Implement fill/align/width for strftime-like formatting
3e01376e Implement fill/align/width parsing in chrono formatter
1f92f8a9 Remove noexcept
8668639a Get rid of null_terminating_iterator in format
93fd473b Add support for builtin terminal colors. (#974)
61ad543c Windows .sln filename changed from FORMAT to FMT
7f7504b3 Clean up docs
37f599b1 Fix docs
8c2e15ae Make printf work in search (#164)
de71db6d Fix asan error (#977)
b180b391 Fix default formatting
24594c74 Disable printing the reset escape code when no style modifiers where applied. (#973)
b0f22247 Implement default chrono formatting
74927607 Add file stream support for stylized text printing. (#967)
f54f3d0f Move chrono-specific code to a separate header
bf1f1c73 Fix time test
b6bc6ec2 Add default ctor and fix use of constexpr macros in text_style
acfa95d4 Workaround a bug in MSVC's strftime (#965)
628f8305 More chrono formatting
aa3b5aba Implement locale-specific minute formatting
639de217 Workaround more MSVC bugs
3242ddf7 Fix warnings
bd110404 Workaround a bug in MSVC
81b5c4a5 Add experimental emphasis support (#961)
7c4eb0fb Fix warnings in time.h
2d624218 Fix another warning
b3168099 Fix a warning
b10ccb83 Add rpclib to projects
0497875f Stop the orgy of casts
37dc495b Simplify MSVC workaround
2ff4996d Fix ambiguous complier error C2666 in vs2017.The '+' opeator may cause ambiguity.Avoid implicit conversion.
77656c67 Fix sign-conversion warnings reported by Clang7
ea5e4790 Fix formatting
86681c4b Update README.rst
e867768e Do not override user provided compile flag
0c7f5c3c Update README.rst
e7e2ab10 Make return type of basic_format_args::max_size() consistent.
29352af3 Update README.rst
68214bd9 More time formatting
bcf3fcd6 Clean up bit fiddling for argument packing
9dcf127f Workaround a bogus MSVC warning
b8b06e3e Fix conversion warnings in Grisu
322b2594 Implement more time specifiers
0835f1ba Use full paths for fmt.pc.in
a084495d Add Ceph to projects
fa1d4dbc Fix warnings
2b2cfdac Update docs
99744f8f Suppress unfixable warning
f5fe8492 Specialize formatter for chrono durations
a5a9805a First stub at the datetime format parser
645c76a9 Fix dummy warnings
fecb2d6f Eliminate msvc compiler warnings (#931)
64690d3a Add context_base::arg()
01640f44 Fully qualify dummy_int (#941)
e37d6a98 add make_printf_args and make_wprintf_args functions (#934)
982ee5c6 parse_context -> format_parse_context
b7b85485 thousands_sep -> thousands_sep_impl (#939)
00a8cc83 Fix formatting
33fbb3a7 Fix remaining linker errors.
bd612159 Disable fmt-impl-test in windows + shared lib.
702b3d16 Fix link error in windows with shared library.
9d4ef943 Install pdb files.
6c95fb35 Default Context to format_context
16b78ee6 fix incompatibilities with c++2a mode in clang
19e00887 More locale support
f2ee9881 Improve locale support
1385050e More formatter tests
03c1b110 Fix gcc 4.4 build
cc805c61 Test enabled formatters
e0157923 Disallow leading zeros in arg-id
34030dec Cleanup warning flags
6b26e3f2 Manifest & Gradle comment
d286c977 Update for Gradle build
d951f6df Get latest Gradle (ver. 4.10.2)
a23d5924 Fix check_format_string (#925)
36161284 Update docs
38f355d8 Revert "find sphinx-build before calling build.py"
324eac1a Make locales work with any character type
bdda4d60 Simplify compile-time strings
5ee1a4bc check for property 'mutable iterator' and SFINAE on it
2dea780f change type naming and fix sfinae bug
b98e8301 add non-char support for compile-time format check
ccd3e8bb Make is_constructible public (#918)
43731538 Update usage.rst
73cfd8f3 Fix colored print
ec384302 additional test for print with background color
0a96c032 Parameterize v*printf on string type (#920)
61e6d2e3 Fix core version of vformat_to
ea4010d7 Merge has_to_string_view into is_string
486fff59 Add sprintf_format instantiations and remove syntactic noise
1e3dcbba fix: 'format_to_n' compiles 'std::back_inserter' arguments
f0328f8e Use char_traits::length in string_view ctor (#914)
895fb984 Disallow gcc 4.4 failures
20c708bf Fix build on gcc 4.4
9d0c9c4b cmake: output share/fmt.pc
2d2326a7 Fix compilation with older gcc
1ec02723 Get rid of FMT_UNION
2c81c851 Adapt any string-like type to be used by {fmt} just like the standard string types already supported. The adaption is totally non-intrusive.
846c644e Workeround broken sprintf in MSVC
13d472bd Compute output size for grisu
b71d3fe7 Remove use_grisu
847abb6f Fix test
dda47c94 Merge min_digits and max_digits
29246221 Fix naming of basic_format_specs members
bda5f9a5 Replace grisu2_specs with core_format_specs
b1ca608b Remove unused empty_spec
e8efdef8 Avoid extra copy
98f1c1fe Remove unused code
50b18a3c Integrate Grisu
69929752 Implement Grisu rounding
4bb76ef0 Remove redundant definition of print
ddd7caf3 Fix locale-dependent formatting (#905)
10e03e69 use found python executable for launching sphinx-build
07200f44 find sphinx-build before calling build.py
08a65c22 Workaround broken constexpr in MSVC2017
167f8fe3 Fix a typo in api.rst
57983423 Remove signbit workaround
7bebb3e1 Clarify overload resolution in docs
939fbe55 Remove basic_fixed_buffer.
61f81a07 minor documentation corrections
f27defc6 Parameterize printf functions on the type of the format string.
6a685571 Make 'std::*::basic_string_view' a valid argument type for 'format_str' parameters.
87a0408c Fix ostream.h build
2b5acad4 Remove redundant size argument to write_padded
655ce533 is_format_string -> is_string
fea712ab Parameterize ostream functions on the type of the format string.
f16a118e Fix non-matching char types.
041bf83d Improve fmt::format readability
22990323 Document how to write a formatter for a type hierarchy
f5480635 visit -> visit_format_arg
cdf3fa08 Put related code together in fmt/core.h
38325248 Count width in code points (#628)
deb901b9 Parameterize core functions on the type of the format string.
0f98de30 Update docs
c797708f Workaround strlen being non-constexpr in ARM toolchain
49b4c1e9 Update docs
63a87beb Add to_string_view
4e0c3146 checked_format_args -> checked_args
c3538a1e Simplify variadic functions further
2d7d0835 Simplify variadic functions
3f4cfa6c Implement UTF-8 string support
f8027414 Impelement char8_t support
76a47d41 Cleanup the use of FMT_CHAR
267fdc7a Parameterize core functions on the type of the format string.
5bced124 Parameterize more functions on string type
674999c5 fix vs2017 warning fmt::v5::localtime 'not all control paths return a value'.
e4fea22d Make char8_t a strongly-typed enum
66992e90 Clarify that writing to memory_buffer appends (#877)
e864acfd Fix compilation with intel compilers (ICC/ICPC) v14.0
4cf21f58 constrain templated format_to on proper format string type.
d7f17613 Fix compilation on platforms with exotic double (#878)
e4ca37cc Parameterize format_to on string type (#880)
d66fa221 Reduce syntactic noise
48e6dcd0 Implement workarounds for gcc 4.4
0ea3221d Remove is_named_arg and add FMT_CHAR
73c53d78 Parameterize 'printf(rgb color, ...)' and 'vprint_rgb(rgb color, ...)' on the type of the format string.
d41be23a Simplify string_view detection
2def9e4c Remove FMT_DTOR_NOEXCEPT
ff6e46ed More cleanup
715f2b4c Remove require_wchar and internalize no_formatter_error
ec0cdc46 Workaround Windows slowness

git-subtree-dir: externals/fmt
git-subtree-split: 9e554999ce02cf86fcdfe74fe740c4fe3f5a56d5
2019-03-24 14:24:09 -04:00
Lioncash
1957180595 Squashed 'externals/xbyak/' changes from f72646a7..4a6fac8a
4a6fac8a update version to 5.77
801cf3fd cosmetic change of getNumCores
d397e824 fix number of cores that share LLC cache
a669e092 support non-intel-cpu visual studio
af5f422e Merge branch 'fenghaitao-guard_x86' into develop
9b98dc17 Guard x86 specific codes with "#if defined(__i386__) || defined(__x86_64__)"
dd4173e1 move some member variables input private

git-subtree-dir: externals/xbyak
git-subtree-split: 4a6fac8ade404f667b94170f713367fe7da2a852
2019-03-24 14:20:49 -04:00
Lioncash
12b783918b
externals: Update catch to 2.7.0
Keeps the unit testing library up to date.
2019-03-24 14:02:24 -04:00
MerryMage
a1f642f838 emit_x64_floating_point: F16C implementation of FPSingleToHalf 2019-03-24 15:42:14 +00:00
MerryMage
2a5b4f4933 emit_x64_floating_point: F16C implementation of FPHalfToSingle and FPHalfToDouble 2019-03-24 11:42:22 +00:00
MerryMage
59887e8b62 emit_x64_floating_point: Factor out ConvertRoundingModeToX64Immediate 2019-03-24 11:28:04 +00:00
MerryMage
16a40b3b9d backend/x64: Expose FPCR in EmitContext instead of its subcomponents 2019-03-24 11:28:04 +00:00
Merry
d5263c17cb
Merge pull request #458 from lioncash/float-op
A64: Handle half-precision floating point in FABS, FNEG, and scalar FMOV
2019-03-24 11:23:21 +00:00
Merry
42ae48e768
Merge pull request #457 from lioncash/fpconv
A64: Handle half-precision floating point in floating-point FCVT, FCVTL, and FCVTN
2019-03-23 20:59:20 +00:00
Lioncash
f12b0f926c
A64: Handle half-precision floating point in FCVTL
Like FCVTN, now that we have half-precision floating point conversion
functions available, we can go ahead and use those to eliminate the
interpreter fallback.
2019-03-23 14:16:44 -04:00
Lioncash
d4d642198c
A64: Handle half-precision floating point in FCVTN
Now that we have IR instructions for performing conversions with
half-precision floating point, we can also handle half-precision values
within FCVTN.
2019-03-23 14:16:44 -04:00
Lioncash
ede3d7284a
A64: Enable FCVT floating-point conversions for half-precision
With this, we no longer have to fall back to the interpreter in any of
the FCVT floating-point conversion instructions.
2019-03-23 14:16:44 -04:00
Lioncash
eb09ae27db
frontend/ir_emitter: Add half->{single, double} and {double, single}->half conversion opcodes 2019-03-23 14:16:44 -04:00
Lioncash
f74c9dad6f
common/fp/unpacked: Amend behavior of FPUnpackCV
This is supposed to call FPUnpackBase instead of FPUnpack. This would
result in alternate half-precision representations being misinterpreted
when it comes to dealing with NaNs.
2019-03-23 14:16:44 -04:00
Lioncash
36e739ba9b
common/fp/op/FPConvert: Amend off-by one in double NaN case in FPConvertNaN
Avoids potentially clobbering the intended sign bit value during
conversions to double-precision values. The other conversion types are
already properly handled, so those don't need to be addressed.
2019-03-23 14:16:44 -04:00
Lioncash
29e1a024c7
common/fp/op/FPConvert: Add half-precision instantiations to FPConvert 2019-03-23 14:16:37 -04:00
Lioncash
d59cff531c
A64: Handle half-precision floating point in scalar FMOV
This is simply performing a scalar value transfer between registers
without conversions, so this is trivial to handle as-is.
2019-03-23 13:46:47 -04:00
Lioncash
5196e94792
A64: Handle half-precision floating point in scalar FABS
Now that we have the half-precision variant of the opcode added, we can
simply handle the instruction instead of treating it as undefined.
2019-03-23 13:39:23 -04:00
Lioncash
c75f73785d
frontend/ir_emitter: Add half-precision variant of FPAbs 2019-03-23 13:38:09 -04:00
Lioncash
b772cb7c5a
A64: Handle half-precision floating point in scalar FNEG
With the half-precision variant of the FPNeg opcode added, we can
utilize it here to emulate the half-precision variant of FNEG.
2019-03-23 13:23:34 -04:00
Lioncash
fd71df5efd
frontend/ir_emitter: Add half-precision variant of FPNeg 2019-03-23 13:21:59 -04:00
Merry
0f2f6ef789
Merge pull request #456 from lioncash/mov
A64: Enable FMOV (general) for half-precision floating point
2019-03-22 22:27:48 +00:00
Lioncash
7627fa389b
A64: Enable FMOV (general) for half-precision floating point
This just transfers values between vector registers and general-purpose
registers with no conversions performed, so this is trivial to add
support for half-precision to.
2019-03-22 15:18:12 -04:00
Merry
004adfe844
Merge pull request #455 from lioncash/sqrdmulh-scalar
A64: Implement SQRDMULH and SQDMULL's scalar indexed variants
2019-03-22 12:43:53 +00:00
Merry
a3a41a91cd
Merge pull request #454 from lioncash/sqrdmulh
A64: Implement SQRDMULH and SQDMULL{2}'s vector indexed element variants
2019-03-21 19:14:30 +00:00
Lioncash
5c6becc402
A64: Implement SQRDMULH's scalar indexed element variant 2019-03-20 23:26:55 -04:00
Lioncash
2d78390d43
A64: Implement SQDMULL{2}'s scalar indexed element variant 2019-03-20 23:05:07 -04:00
Lioncash
3238864878
simd_scalar_x_indexed_element: Factor out index and Vm argument construction
This will be useful in the implementations of SQRDMULH and SQDMULL{2} as
well.
2019-03-20 22:28:46 -04:00
Lioncash
996a618643
simd_vector_x_indexed_element: Deduplicate index and Vm operand construction 2019-03-20 16:21:48 -04:00
Lioncash
328211b0c5
A64: Implement SQDMULL{2}'s by-element variant 2019-03-20 15:36:27 -04:00
Lioncash
b4ca6b67d1
A64: Implement SQRDMULH's by-index vector variant 2019-03-20 14:05:41 -04:00
Merry
6e8b7d27ec
Merge pull request #452 from lioncash/frecpx
A64: Implement FRECPX's half-precision floating-point variant
2019-03-10 20:43:55 +00:00
Lioncash
f8ad1819ab
A64: Implement FRECPX's half-precision floating point variant 2019-03-09 20:08:01 -05:00
Lioncash
db67a42244
frontend/ir/ir_emitter: Amend FPRecipExponent to handle half-precision floating point 2019-03-09 20:08:01 -05:00
Lioncash
8036a54a74
frontend/ir/value: Add U16U32U64 type to represent floating point types 2019-03-09 20:08:01 -05:00
Lioncash
1e0933907a
common/fp/op/FPRecipExponent: Add half-precision floating point specialization 2019-03-09 20:07:53 -05:00
Lioncash
5117997cde
common/fp/unpacked: Correct edge-cases within FPUnpack for half-precision floating point
This corrects one case where floating-point exceptions could be set when
they're not supposed to be.

This also corrects a case where values were being treated as NaNs when
they weren't supposed to be.
2019-03-09 19:21:16 -05:00
Merry
d3e242b4af
Merge pull request #451 from lioncash/unpck
common/fp: Minor adjustments for half-precision floating point support
2019-03-09 16:05:42 +00:00
Lioncash
1b66e43094
common/fp/process_nan: Add half-precision instantiations for NaN processing functions 2019-03-09 02:26:58 -05:00
Lioncash
2f7f75ff09
common/fp/unpacked: Add half-precision instantiation of FPRoundBase 2019-03-09 02:26:47 -05:00
Lioncash
74e230de9d
common/fp/unpacked: Handle half-precision unpacking in FPUnpackBase 2019-03-09 01:19:55 -05:00
Lioncash
9c96c4c9fc
common/fp/unpacked: Adjust FPUnpack to operate like ARM pseudocode
This function is defined as always disabling the AHP bit in the fpcr
before performing any operations.

At the same time, rename the original FPUnpack function to FPUnpackBase
to match the pseudocode in the ARM reference manual.
2019-03-09 00:08:12 -05:00
Merry
c535f4bf89
Merge pull request #448 from lioncash/saturate
A64: Implement SQSHRN, SQSHRUN, and UQSHRN's scalar variants
2019-03-08 18:50:18 +00:00
Merry
b3d6f40dbb
Merge pull request #449 from lioncash/hp
common/fp/info: Add specialization of FPInfo for half-precision floating point
2019-03-08 18:49:18 +00:00
Merry
d2fbcc6dde
Merge pull request #450 from lioncash/cv
common/fp/unpacked: Add FPRoundCV and FPUnpackCV
2019-03-08 12:05:52 +00:00
Lioncash
6dad779547
common/fp/unpacked: Add FPRoundCV
Corresponds to the equivalent pseudocode within the ARMv8 reference
manual. This will be necessary for supporting half-precision
floating-point.

This also makes use of it within FPConvert
2019-03-08 06:24:54 -05:00
Lioncash
deca5e5dae
common/fp/unpacked: Add FPUnpackCV
Adds a template function that performs the same behavior as in the ARM
pseudocode, and utilizes it in FPConvert, which will be necessary for
half-float support.
2019-03-08 06:20:54 -05:00
Lioncash
d1a1434af6
common/fp/info: Add specialization of FPInfo for half-precision floating point
Puts the necessary info struct in place for further use.
2019-03-08 03:50:48 -05:00
Lioncash
203678bd9e
A64: Implement SQSHRN, SQSHRUN, and UQSHRN's scalar variants
These can just be implemented in terms of the vector variants for the
time being.
2019-03-08 03:23:56 -05:00
Lioncash
fb3847b044
A64: Amend prototypes of some SIMD scalar shift by immediate opcodes
These take a vector for a destination.
2019-03-08 00:20:24 -05:00
Merry
40339b1278
Merge pull request #447 from lioncash/flag
A64: Implement CFINV, RMIF, AXFlag and XAFlag
2019-03-07 16:17:13 +00:00
Lioncash
8d115ae80d
ir_opt/a64_get_set_elimination_pass: Add handling for NZCV raw get and set operations 2019-03-07 03:57:18 -05:00
Lioncash
5b66ae2a5a
A64: Implement AXFlag and XAFlag 2019-03-06 18:39:19 -05:00
Lioncash
080d163d39
A64: Implement RMIF 2019-03-06 18:39:19 -05:00
Lioncash
9cd84c5149
A64: Implement CFINV 2019-03-06 18:39:12 -05:00
Merry
04f09eb644
Merge pull request #442 from lioncash/fcvtxn
A64: Implement scalar and vector variants of FCVTXN
2019-03-06 20:27:59 +00:00
Lioncash
27af30d7c3
ir: Add A64-specific opcodes for getting and setting raw NZCV values
This will be necessary to implement the flag manipulation and flag
format instructions.
2019-03-06 14:17:27 -05:00
Lioncash
cdfdd95e63
A64: Implement the vector version of FCVTXN 2019-03-06 12:05:24 -05:00
Lioncash
e3ba07971e
A64: Implement the scalar version of FCVTXN 2019-03-06 12:05:24 -05:00
Lioncash
f44cafe3ca
frontend/ir/ir_emitter: Alter parameters of FPDoubleToSingle() and FPSingleToDouble() to pass along desired rounding mode
This will be necessary to special-case the non-IEEE Von Neumann rounding
to odd rounding mode.
2019-03-06 12:05:20 -05:00
Merry
d0ae8dcf97
Merge pull request #446 from lioncash/sqshl
A64: Implement scalar variants of SQSHL (register) and UQSHL (register)
2019-03-06 14:14:41 +00:00
Merry
948984bc94
Merge pull request #445 from lioncash/sqrt
A64: Implement single and double-precision vector variant of FSQRT
2019-03-06 14:14:21 +00:00
Merry
768a2a6973
Merge pull request #443 from lioncash/flag
A64: Rearrange flag format/manipulation instructions
2019-03-06 14:13:59 +00:00
Merry
a5ce4c7831
Merge pull request #441 from lioncash/constexpr
common/bit_util: Mark a few functions as constexpr
2019-03-05 19:57:12 +00:00
Merry
fa1671b655
Merge pull request #440 from lioncash/include
common/fp: Remove unnecessary includes
2019-03-05 19:56:58 +00:00
Merry
ecd544098b
Merge pull request #444 from lioncash/interpret
A64: Fall back to interpreting for FCADD and FCMLA half-precision variants
2019-03-05 18:51:50 +00:00
Lioncash
4429a0c8e5
A64: Implement UQSHL (register)'s scalar variant
This can be implemented in terms of the vector variant.
2019-03-04 14:26:25 -05:00
Lioncash
a3eeb334fa
A64: Implement SQSHL (register)'s scalar variant
We can implement this in terms of the vector variant.
2019-03-04 14:26:20 -05:00
Lioncash
16e6a8f343
A64: Implement single and double-precision vector variant of FSQRT 2019-03-04 13:37:27 -05:00
Lioncash
3e5a52cc66
frontend/ir: Add opcodes for vector square roots 2019-03-04 13:24:36 -05:00
Lioncash
d365d4083a
A64: Fall back to interpreting for FCADD and FCMLA half-precision variants
Rather than straight-up treating them as undefined, we can fall back to an
interpreter in this case.
2019-03-04 12:23:57 -05:00
Lioncash
36eba63641
A64: Rearrange flag format/manipulation instructions
Gives these instructions better categorical labeling.
2019-03-04 12:08:49 -05:00
Lioncash
9426cc9795
common/fp/op: Add FP conversion functions 2019-03-04 11:57:41 -05:00
Lioncash
7ae37bcc64
frontend/ir/microinstruction: Add missing cases for FPRecipExponent{32,64} for ReadsFromAndWritesToFPSRCumulativeExceptionBits()
This was intended to be added within #437, but was missed
2019-03-04 09:43:48 -05:00
Lioncash
e042c63de6
common/bit_util: Make a few functions as constexpr
These four functions can be made constexpr with no issue.
2019-03-04 09:21:29 -05:00
Lioncash
f01fca3bc3
common/fp: Remove unnecessary includes 2019-03-04 08:25:48 -05:00
Merry
f2fb7db668
Merge pull request #439 from lioncash/fcmla
A64: Implement FCADD and FCMLA
2019-03-03 14:43:22 +00:00
Merry
73e230aa3f
Merge pull request #438 from lioncash/fmulx
A64: Implement scalar double/single precision FMULX (by element)
2019-03-03 14:42:45 +00:00
Merry
456f2ec49f
Merge pull request #437 from lioncash/frecpx
A64: Implement FRECPX (single, double precision)
2019-03-03 14:42:23 +00:00
Merry
8be7648e79
Merge pull request #436 from lioncash/no-alloc
A64: Implement LDNP/STNP
2019-03-03 14:40:57 +00:00
Merry
4f88bf352f
Merge pull request #435 from lioncash/a32
tests/a32/testenv: Make A32TestEnv's code_mem member a std::vector
2019-03-03 12:59:36 +00:00
Merry
36fbe8de86
Merge pull request #434 from lioncash/format
A32/translate_arm: Formatting/tidying up
2019-03-03 12:58:03 +00:00
Lioncash
dae46f0132
A64: Implement FRECPX (single, double precision) 2019-03-02 23:31:30 -05:00
Lioncash
7b004e7230
frontend/ir/ir_emitter: Add opcodes for floating point reciprocal exponents 2019-03-02 23:31:30 -05:00
Lioncash
78742a6aea
common/fp/op: Add operations for floating-point reciprocal exponents 2019-03-02 23:31:26 -05:00
Lioncash
9f556b8447
A64: Implement FCMLA 2019-03-02 22:50:17 -05:00
Lioncash
0d9cca04c0
A64: Implement FCADD 2019-03-02 22:49:57 -05:00
Lioncash
ccc3d5258e
A64: Implement scalar double/single precision FMULX (by element) 2019-03-02 21:12:09 -05:00
Lioncash
fc111fda0c
A64: Implement LDNP/STNP
LDNP and STNP indicate that a memory access is non-temporal/streaming
(i.e. unlikely to be repeated), allowing data caching to not be
performed. However, given this is only a hint, we can treat these two
instructions as regular LDP and STP instructions for the time being.
2019-03-02 17:41:09 -05:00
Lioncash
5c11851f33
tests/a32/testenv: Make A32TestEnv's code_mem member a std::vector
Makes the data member consistent with the A64 test environment.
2019-03-02 16:26:37 -05:00
Merry
48cc7274c1
Merge pull request #433 from lioncash/unicorn
tests/unicorn_emu: Add getters and setters for PC/SP
2019-03-01 22:03:20 +00:00
Merry
468aba4ccd
Merge pull request #432 from lioncash/catch
externals: Update Catch to 2.6.1
2019-03-01 21:58:06 +00:00
Merry
8f4ea28988
Merge pull request #431 from lioncash/noexcept
backend/x64/a32_interface: Mark Context move constructor and move assignment as noexcept
2019-03-01 21:57:48 +00:00
Lioncash
02a70f3be1
translate_arm/coprocessor: Minor tidying up 2019-03-01 03:15:43 -05:00
Lioncash
c1f4241ca8
translate_arm/vfp2: Invert conditionals where applicable 2019-03-01 03:10:18 -05:00
Lioncash
797fca0125
translate_arm/synchronization: Invert conditionals where applicable 2019-03-01 02:23:24 -05:00
Lioncash
6a851dc412
translate_arm/status_register_access: Invert conditionals where applicable 2019-03-01 02:11:05 -05:00
Lioncash
18276e7c66
translate_arm/saturated: Invert conditionals where applicable 2019-03-01 02:05:30 -05:00
Lioncash
55fff7b2f6
translate_arm/reversal: Invert conditionals where applicable 2019-03-01 01:51:47 -05:00
Lioncash
a6a9fbcc48
translate_arm/parallel: Invert conditionals where applicable 2019-03-01 01:49:30 -05:00
Lioncash
b970daf983
translate_arm/packing: Invert conditionals where applicable 2019-03-01 01:23:48 -05:00
Lioncash
3b1133ad13
translate_arm/multiply: Invert conditionals where applicable 2019-03-01 01:21:00 -05:00
Lioncash
e71e560673
translate_arm/misc: Invert conditionals where applicable 2019-03-01 00:58:47 -05:00
Lioncash
83daf1c50e
translate_arm/load_store: Invert conditionals where applicable 2019-03-01 00:56:52 -05:00
Lioncash
3706f58083
translate_arm/extension: Invert conditionals where applicable 2019-03-01 00:31:46 -05:00
Lioncash
ef37cebb71
translate_arm/exception_generating: Invert conditionals where applicable 2019-03-01 00:22:45 -05:00
Lioncash
b613045b38
translate_arm/data_processing: Invert conditionals where applicable 2019-03-01 00:20:08 -05:00
Lioncash
a71a2b3b89
translate_arm/branch: Invert conditionals where applicable
Allows unindenting code a bit.
2019-02-28 23:35:01 -05:00
Lioncash
c63dfa7409
tests/unicorn_emu: Add getters and setters for PC/SP
Makes the interface consistent with the A64Unicorn class.
2019-02-28 23:12:13 -05:00
Lioncash
22c946ebcc
externals: Update Catch to 2.6.1
Keeps the unit testing library up to date.
2019-02-28 22:57:18 -05:00
Lioncash
82be728033
backend/x64/a32_interface: Mark Context move constructor and move assignment as noexcept
Provides a more "correct" move constructor/assignment operator, since
these relevant functions shouldn't throw exceptions.

Has the benefit of playing nicely with std::move_if_noexcept and other
noexcept library facilities.
2019-02-27 10:47:47 -05:00
Merry
555ae3e809
Merge pull request #430 from lioncash/unused
block_of_code: Replace cast with [[maybe_unused]] in DoesCpuSupport()
2019-02-23 11:37:35 +00:00
Lioncash
0be97f3ecc
block_of_code: Replace cast with [[maybe_unused]] in DoesCpuSupport() 2019-02-22 22:46:06 -05:00
Merry
767665bcef
Merge pull request #428 from lioncash/unused
common: Remove address_range.h
2019-02-08 21:55:22 +00:00
Lioncash
ab4b82167f
externals/xbyak: Update xbyak to 5.76
Keeps the external library up to date.
2019-02-08 12:58:59 -05:00
Lioncash
cc67312fed Squashed 'externals/xbyak/' changes from 42462ef9..f72646a7
f72646a7 update version
4612528f format change
4b95e862 Merge branch 'shelleygoel-master'
4c262fa6 add functionality to get num of cores using x2APIC ID
bc70e7e1 recover Xbyak::CastTo
d09a230f unlink Label when LabelManager is destroyed
973e8597 update version
afdb9fe9 Xbyak::CastTo is removed
b011aca4 add RegRip +/- int
acae93cd increase max temp regs for StackFrame
ea4e3562 util::StackFrame uses push/pop instead of mov

git-subtree-dir: externals/xbyak
git-subtree-split: f72646a7c817885d7fd29abe6f1f5b50dd621ef6
2019-02-08 12:58:53 -05:00
Lioncash
18f5916e4d
common: Remove address_range.h
The AddressRange structure isn't used anywhere within the codebase, so
this can be removed. Particularly because there's no real appeal/heavy
potential use of it in the future that isn't trivial to add back if
needed.
2019-02-08 09:41:37 -05:00
Merry
5c57df39ad
Merge pull request #426 from lioncash/const
frontend/{A32, A64}/ir_emitter: Mark PC() and AlignPC() as const-qualified member functions
2019-02-07 20:03:30 +00:00
Merry
f624867d5a
Merge pull request #427 from lioncash/include
tests/A32/fuzz_arm: Remove unused Unix-specific include
2019-02-07 20:03:17 +00:00
Lioncash
7593eadc2e
tests/A32/fuzz_arm: Remove unused Unix-specific include
This was introduced within 6f6f60c61b2137780102c75841441f760d3cc3fc,
however, the relevant code that it was used with has since been removed,
making the include unnecessary.
2019-02-05 20:59:24 -05:00
Lioncash
67c39ec79b
frontend/A32/ir_emitter: Mark PC() and AlignPC() as const-qualified member functions
These don't modify instance state, so they can be const-qualified member
functions.
2019-02-05 20:21:48 -05:00
Lioncash
539fda5350
frontend/A64/ir_emitter: Mark PC() and AlignPC() as const qualified member functions
These don't actually alter any instance state.
2019-02-05 20:21:44 -05:00
Annomatg
735e6c58be Reduce Inst::NumArgs calls / opcodes: Prefer std::vector to std::map (#425)
* Don't call Inst::NumArgs in a loop conditional
* opcodes: Prefer a simple std::vector instead of a std::map
2019-02-03 20:21:14 +00:00
Merry
7957066968
Merge pull request #423 from lioncash/catch
externals: Update catch to v2.5.0
2019-02-02 22:59:54 +00:00
Merry
58bc4bcd3c
Merge pull request #422 from lioncash/truncate
a32_unicorn: Silence a truncation warning within UnmappedMemoryHook()
2019-02-02 22:59:41 +00:00
Merry
dced81eec0
Merge pull request #421 from lioncash/comma
tests/.../vfp_helper: Amend use of the comma operator
2019-02-02 22:59:27 +00:00
Mat M
6cdb4e3d8c
Merge pull request #424 from meme/readme
Correct README (`jit` to `cpu`)
2019-02-01 00:31:35 -05:00
meme
23eeb5ebae Correct README (jit to cpu) 2019-01-31 12:53:00 -05:00
Lioncash
69eec29993
externals: Update catch to v2.5.0
Keeps the unit testing library up to date.
2019-01-28 08:51:03 -05:00
Lioncash
6e54c8f8c8
tests/.../vfp_helper: Amend use of the comma operator
Makes the lines of code slightly nicer to read
2019-01-22 19:06:11 -05:00
Lioncash
91e82bb615
a32_unicorn: Silence a truncation warning within UnmappedMemoryHook()
MemoryRead8() takes a u32, but we were passing the result of a

u32 + size_t operation, which is 64-bit on 64-bit platforms. This
results in a truncation warning
2019-01-22 19:05:42 -05:00
Merry
6598d2147e
Merge pull request #419 from lioncash/fold-op
constant_propagation_pass: Fold byte reversal opcodes where applicable
2018-11-25 09:50:56 +00:00
Lioncash
70a392af9e
constant_propagation_pass: Fold byte reversal opcodes where applicable
These are reasonably trivial to fold away when applicable. We just
perform the swap and replace the instruction with the constant value.
2018-11-24 18:11:08 -05:00
Merry
79d51f8d4a
Merge pull request #418 from lioncash/fold-op
constant_propagation_pass: Handle folding for Least/MostSignificant{Bit, Byte, Half, Word} opcodes
2018-11-24 12:45:26 +00:00
Merry
607b2f98ee
Merge pull request #417 from lioncash/swap
common: Move byte swapping functions to bit_utils.h
2018-11-24 12:44:41 +00:00
Merry
230dcdab4b
Merge pull request #416 from lioncash/space
dynarmic_tests: Remove inconsistent spacing
2018-11-24 12:44:19 +00:00
Merry
bd8c467132
Merge pull request #415 from lioncash/alloc
a64_emit_x64: Convert std::vector instances in GenFastmemFallbacks() to std::array
2018-11-24 12:44:08 +00:00
Merry
6eeec2f9d0
Merge pull request #414 from lioncash/retval
fuzz_util: Simplify result return in InstructionGenerator's Generate() function
2018-11-24 12:43:40 +00:00
Lioncash
043cace402
constant_propagation_pass: Handle folding for Least/MostSignificant{Bit, Byte, Half, Word} opcodes
These are quite trivial to fold.
2018-11-23 23:11:00 -05:00
Lioncash
75b8308cef
common: Move byte swapping functions to bit_utils.h
These are quite general functions, so they can just be moved into common
instead of recreating a namespace here.
2018-11-23 22:50:41 -05:00
Lioncash
4e4e1d315c
dynarmic_tests: Remove inconsistent spacing
Makes the changed code more consistent with the surrounding code.
2018-11-23 21:49:57 -05:00
Lioncash
54aac80504
a64_emit_x64: Make constness of loop elements explicit within GenFastmemFallbacks() 2018-11-23 20:12:55 -05:00
Lioncash
4763bb706e
a64_emit_x64: Convert std::vector instances in GenFastmemFallbacks() to std::array
Given these are quite small, we can avoid the need to heap allocate
here.
2018-11-23 20:11:12 -05:00
Lioncash
d7af990350
fuzz_util: Simplify result return in InstructionGenerator's Generate() function
This can just be a simple direct return without a separated declaration
and assignment.
2018-11-23 19:55:32 -05:00
MerryMage
b781237151 emit_x64_vector_floating_point: AVX && DN implementation of EmitFPVectorMulX 2018-11-18 10:03:13 +00:00
MerryMage
e9acec2091 A64: Implement FMULX (by element), single and double precision variants 2018-11-17 21:51:39 +00:00
MerryMage
ea0c1919bb A64: Implement FMULX, vector single-precision and double-precision variant 2018-11-17 21:32:12 +00:00
MerryMage
333d3b734d IR: Implement FPVectorMulX 2018-11-17 21:31:22 +00:00
Michał Janiszewski
af96812b47 Provide justification for always-true condition (#412) 2018-11-02 19:36:30 +00:00
Michał Janiszewski
4295f727cd Enable ninja and ccache on travis (#413)
* Use ninja, the fast build system

Make is known to be rather slow, but it's possible to generate other
build system files with CMake, so use a faster one.

* Use ccache on Travis

* Dummy commit to test ccache
2018-11-01 12:33:45 +00:00
Merry
a5f35d45f0
Merge pull request #411 from janisozaur/include-guards
Add missing include guards
2018-11-01 12:33:09 +00:00
Michał Janiszewski
a695635efd Add missing include guards 2018-10-31 22:54:17 +01:00
Merry
52e646408f
Merge pull request #409 from VPeruS/switch-optional
Switch boost::optional to std::optional
2018-10-24 18:49:49 +01:00
V.Kalyuzhny
05a2dbfce0 Switch boost::optional to std::optional 2018-10-24 15:02:39 +00:00
Merry
409ff8d78e
Merge pull request #410 from lioncash/catch
externals: Update catch to v2.4.1
2018-10-24 07:32:38 +01:00
Lioncash
1c0bed959d
externals: Update catch to v2.4.1
Keeps the unit testing library up to date.
2018-10-23 18:10:58 -04:00
Merry
d0bcca81a8
Merge pull request #408 from lioncash/shift
constant_propagation_pass: Add 64-bit variants of shifts to the pass
2018-10-12 20:22:29 +01:00
Lioncash
2c8c83c2f1
constant_propagation_pass: Add 64-bit variants of shifts to the pass
These optimizations can also apply to the 64-bit variants of the shift
opcodes; we just need to check if the instruction has an associated
pseudo-op before performing the 32-bit variant's specifics.

While we're at it, we can also relocate the code to its own function
like the rest of the cases to keep organization consistent.
2018-10-12 14:50:21 -04:00
Merry
fc051d2c5c
Merge pull request #407 from lioncash/div
constant_propagation_pass: Fold division operations where applicable
2018-10-11 15:50:47 +01:00
Lioncash
b55b7a5c7f
constant_propagation_pass: Fold division operations where applicable
We can fold division operations if:

1. The divisor is zero, then we can replace the result with zero (as this is how
ARM platforms expect it).
2. Both values are known, in which case we can just do the operation and
store the result
3. The divisor is 1, in which case just return the other operand.
2018-10-09 16:03:47 -04:00
Merry
c3a1558dfc
Merge pull request #406 from lioncash/mul
constant_propagation_pass: Fold Mul32 and Mul64 cases where applicable
2018-10-09 15:11:36 +01:00
Merry
caea0460ca
Merge pull request #405 from lioncash/inst
a64: Add ARMv8.4+ instructions encodings to the encoding table
2018-10-08 08:35:04 +01:00
Lioncash
a5d1d27c8c
constant_propagation_pass: deduplicate common 32/64 bit checking for results in folding functions
It's common for an folding operation to apply to both the 32-bit and
64-bit variant of the same opcode, which leads to checking which kind of
result we need to store the value as. This moves it to its own function,
so that we don't need to duplicate it in various functions.
2018-10-07 22:16:40 -04:00
Lioncash
a0ea3a566a
constant_propagation_pass: Fold Mul32 and Mul64 cases where applicable
Multiplication operations can currently be folded if:

1. Both arguments are known constant values
2. Either operand is zero (in which case the result is also zero)
3. Either operand is one (in which case the result is the non-one
operand).
2018-10-07 22:16:01 -04:00
Merry
e6ccf2e79d
Merge pull request #404 from lioncash/fold
constant_propagation_pass: Extend folding of sign-extension/zero-extension opcodes
2018-10-07 16:40:11 +01:00
Lioncash
62a2ba7981
a64: Add ARMv8.4+ instructions encodings to the encoding table
Keeps the table up to date with the ARM specification.
2018-10-06 02:27:50 -04:00
Lioncash
f1d907c980
constant_propagation_pass: Fold SignExtend{Type}ToLong opcodes if possible 2018-10-05 21:06:57 -04:00
Lioncash
4f03ca65a0
constant_propagation_pass: Fold SignExtend{Type}ToWord opcodes if possible 2018-10-05 21:06:57 -04:00
Lioncash
f47c5e4ede
constant_propagation_pass: Fold ZeroExtend{Type}ToLong opcodes if possible
These are equivalent to the ZeroExtendXToWord variants, so we can
trivially do this as well.
2018-10-05 21:06:57 -04:00
Lioncash
e0eec323f2
constant_propagation_pass: Combine zero-extension folding code into its own function
Separates the behavior from the actual switch statement and gets rid of
duplication, now that we can use the general GetImmediateAsU64()
function.
2018-10-05 21:06:54 -04:00
Merry
86539d97d3
Merge pull request #403 from lioncash/zero
Add several convenience functions to the Value class
2018-10-04 17:57:11 +01:00
Lioncash
8f262d485a
ir/value: Add IsSignedImmediate() and IsUnsignedImmediate() functions to Value's interface
This allows testing against arbitrary values while also simultaneously
eliminating the need to check IsImmediate() all the time in expressions.
2018-10-04 12:33:23 -04:00
Lioncash
01aa5096bf
ir/value: Add a GetImmediateAsS64() function
Provides a signed analogue to GetImmediateAsU64() for consistency with
both integral classes when it comes to signed/unsigned..
2018-10-04 12:33:19 -04:00
Lioncash
d3263fd605
ir/value: Add an IsZero() member function to Value's interface
By far, one of the most common things to check for is whether or not a
value is zero, as it typically allows folding away unnecesary
operations (other close contenders that can help with eliding operations  are 1 and -1).

So instead of requiring a check for an immediate and then actually
retrieving the integral value and checking it, we can wrap it within a
function to make it more convenient.
2018-10-04 05:04:22 -04:00
MerryMage
49041cb451 Squashed 'externals/fmt/' changes from 135ab5cf..3e75ad98
3e75ad98 Update version
4f043f8e Bump version
cc02cbc4 Fix formatting
73c0238e Update changelog
cb122a4d Fix format_to formatting to wmemory_buffer
dc69cc45 Clean tests
9d8021f0 Add checks for NVIDIA's CUDA compiler
9d2221b9 Improve error message when formatting unknown types
70a6a4bb prevent ""fmt/range.h"" from specializing fmt::basic_string_view (#865)
e4fc856c Disable android build due to gradle issues
3f4984fb Clean core-test and fix linkage errors on older gcc
d4366505 Workaround visit lookup issues in printf.h on gcc
894b6fac Changed to use scoped enum
59f555ad Workaround more visit lookup issues on gcc
a7e356cc Update README.rst
e758bfba Merge branch 'release' of github.com:fmtlib/fmt
66381e30 Minor cleanup
295a0d84 Update version
1fb1c4c9 Update docs
465a5935 Add table support to rst2md
d62f4c3b Formatting
a243490a Add more methods to benchmark results
9e12ca60 Update changelog
fbca830d Update changelog, readme and improve compat
6146248c Update changelog
bc26fbf1 Move experimental color API to fmt/color.h
97cc8893 Workaround a visit lookup issue in gcc 8 (#851)
7110b460 Optimize default formatting
c8a8464f Optimize buffer construction
8cbfb6e7 Get rid of conversion warning in gcc-4.8 (#854)
6ffc828a Phasing out null_terminating_iterator
aeb6add3 Skip strchr for the common case
5614289d Optimize and simplify format string parsing
10c7f893 Optimize format string processing on dumb compilers
59c268a5 Use strlen when possible since it's constexpr on gcc
918bb1ce Optimize argument capture
a3ba6b4f Disable the fmt(...) macro by default (#853)
86716894 Update docs and formatting
cc10b460 Make format_to faster on older gcc
981797f0 Get rid of implicit-fallthrough warn. in GCC 7 and 8
21177757 Micro-optimize parsing
be0e2684 Optimize processing of trailing '}'
fbc38b90 Pass heavy arguments by ref
8dc69b9d Workaround a bug in Intellisense
1489d3b7 Implement exponential notation
dd8c5ce4 Implement more FP formatting options
46484da7 Fix a warning
802ff886 Fix compilation of time.h when localtime_t is a macro (#843)
95a71899 Remove conversion compiler warnings (#844)
e483a01a Implement some formatting options in Grisu
f5108091 Revert "Implement some formatting options in Grisu"
2a952dd0 Implement some formatting options in Grisu
0de44a46 Implement exponent formatting
f0d0a1eb Implement Grisu2 digit generation
569ac91e Implement Grisu boundary computation
a11eb3a0 Workaround various icc bugs (#822)
62010520 Disable gnu-string-literal-operator-template warning
98751476 Make convert_to_int public (#818)
ba95e36a Clarify that '\0' cannot be used as fill (#832)
abde38b4 Add compilation support with Newlib nano for embedded targets
18400503 Fix C4127 warning in basic_writer<Range>::write_double
9de31211 Reformat and add a comment
8bbb0b48 Update README.rst
5c0101ab Use the correct function signature in the docs
fbe6410e Fix docs
8b9fb9fb Fix ambiguous instantiation with formatter in fmt/ostream.h (#830)
0f04ec68 Fix package upload (#828)
80907385 Update changelog
5d02041c Update changelog
4b868b89 Re-enable compile-time format-string checking
4061a0d3 Parameterize vformat to support custom char types
c68bab70 Remove broken fmt::internal::format_enum (#818)
0c63d15e Improve wording
ce19309d Workaround a bug in icc 15
c6843491 Move contiguous version of format_to to fmt/core.h
8db14efa util-test -> core-test and minor cleanup
ffe414ca Add compile-time format string checks to format_to (#783)
c178ab44 Remove FMT_USE_RVALUE_REFERENCES
5befe658 Remove fmt/folly.h and clean up core API
35538ca6 Merge more format overloads
4f164097 Merge format overloads using SFINAE
2a4e9488 Add UTF-8 types
d778bded Make line in tests fit within 80chars
7b4f170c Fix warning about using old-style cast
b1d10a28 Add support for dynamic arg sets
cf2719bd Add support for types explicitly convertible to wstring_view
50584f42 Test formatting of an object with templated conversion to string-like
73bed45b Add support for types explicitly convertible to fmt::string_view
6eaa5074 Fix global initialization issue (#807)
48dff9f3 Update docs
a9e26159 Minor cleanup
efd8ee8a Reduce warnings, support #809
8615ff2a Micro-optimize argument retrieval
916ed99d Micro-optimize argument retrieval
e7e9578e Optimize format string parsing
c99a2597 Mark new functions with FMT_API (#808)
e0f6a2f8 Add a formatter for folly::StringPiece
ae4a3945 Revert "Better support for newer CMake's"
a317448b Keep noexcept specifier when exceptions are disabled.
0eb01b83 Better support for newer CMake's
2a4cd6d0 Fix the returned value of `format_to_n` with user-defined types having operator<<.
9c32e73a Fixing return unreachable warning on NVCC
e5c93108 Added clear() to basic_buffer
60c662b3 Add an example of reusing formatters
f66ba650 Optimize format string parsing
f21268aa Revert "Optimize format string parsing" because of a bug in MSVC
07b690a6 Update README.rst
f9e9bf02 Optimize format string parsing
c2ce7e4f Update version
434eb916 Update README.rst
09d94162 Update changelog
e6362642 Fix pedantic conversion warning
f0110e81 Update changelog and CI
479ee2a8 Fix MSVC build, take 2
e928b672 Fix MSVC 2013 build
ec218a3a Fix redefinition warning for RESET_COLOR
c04fb91b Fix handling of user-defined types in format_to (#793)
323b92bf Force linking of inline functions into the library (#795)
c6d9730d Fix sign conversion warnings (#790)
2e95823e Move new color support to format.h and mark old as deprecated
ab2d88ca Make format_to work with basic_memory_buffer (#776)
3abd036c Fix compilation on gcc 4
c2f38054 Add vformat_to_n (#769)
ce500635 Renamed enum color to colors. Added enum colors conversion to rgb struct. Added colors_test.cpp.
0508bbc7 Add wchar_t overload of format_to_n (#764)
c2fbadb9 Fixed issue #779
47268ecd Fixed GCC version test
9ff3b6af Fix handling of compile-time strings when including ostream.h (#768)
e3707ef1 Document that file should be in wide-oriented mode for wide print
45fa4ee9 Merge branch 'master' of github.com:fmtlib/fmt
9c07b37f Using enum class now. Renamed from hex to color. Changed colr names to snake case.
5b5886a9 Fixed line length.
d2bfee13 Added quotes for strings in ranges and tuple likes.
aff6e45e Added support for rgb color output.
1b8a7f8f Fix postincrement in truncating and counting iterators
4bc26f0a Merge branch 'master' of github.com:fmtlib/fmt
fc6e0fe9 Fix FP formatting to a non-back_insert_iterator with sign & numeric alignment (#756)
cd5b5670 Make is_range and is_tuple_like public API, fix #751
6322b47e Minor cleanup
691a7a91 Add more compilers to CI and increase FMT_PEDANTIC warning levels (#736)
dd1a5ef7 Let requests close the file
d5c46259 Fix formatting of more than 15 named arguments (#754)
47d147b6 Simplify the nvcc warning fix
911a7511 Fix nvcc warnings (#752)
94b47628 Fix docs
252f11f8 Fix a bogus MSVC warning about unreachable code, take 2
81d56638 Fix more bogus MSVC warnings about unreachable code (#748)
68f0ac82 Fix a bogus MSVC warning about unreachable code
b60a5c5d Improve floating-point formatting
8dc2360b Fix a comment
4e4b8570 Implement simple version of Grisu
40275579 Fix tests on 64-bit MSVC
5c32aa41 Workaround a bug in MSVC
468c243c Add a function to get cached power of 10
2f257b72 Implement normalization and simplify power table
6a5bb6e2 Move Android.mk to support and update
e282d963 Bump version
e2cd521b Fix incorrect call to on_align in '{:}=' (#750)
fba352a9 Don't use UDL templates on Intel C++ compiler (#742)
6dcc526d Update release script
5386f1df Update version
ba6640b2 Fix formatting
507a50c3 Fix changelog
147807c9 Detect integer_sequence support on MSVC
8b246531 Update changelog
5ad54256 Fix a conflict between fmt::join and fmt/ostream.h (#744)
6ebc1a96 Merge locale.h into format-inl.h
6966db1d Update docs
2196025d Fix a warning
589f5f37 Update changelog
edd5f144 Fix compilation errors on gcc 4.4
936aba5f Fix compilation errors on gcc 4.4
3e3a2774 Update changelog
b76bb796 Improve naming consistency
fbd51534 Update changelog
69823bf8 Improve naming consistency
d940fa67 Disable unsafe implicit conversion to std::string (#729)
d2bf93fe Update changelog
550ef1d2 MSVC improvements and data truncation cleanup.
728e4f5a Fix docs
8c255771 Update docs and changelog
a68fd44e Add ranges.h to FMT_HEADERS in CMakeLists.txt (#738)
e3f7f3a2 Add support for ranges, containers and tuple-like types in fmt/ranges.h
984232db Remove duplicate ChangeLog entries
78677e3f Update ChangeLog and docs
ad23270e Document to_wstring
3c0f8c26 Update ChangeLog
98937893 Detect inline namespaces on gcc
dfb65469 Fix docs
3aa29115 Update ChangeLog.rst
d3f6c841 Update ChangeLog.rst
c1441ae4 Update ChangeLog.rst
dece85b3 Fix docs, take 2
6a1df3bd Fix docs
838400d2 Add inline namespace fmt::v5
b64b24eb Update ChangeLog.rst
fc908711 Update ChangeLog.rst
46c374a8 Fix compilation with new gcc and -std=c++11 (#734)
f0ae7257 Clarify the use of allocators
d72d0462 Update paths in fmt.pro
edbbf7ce Fix FreeBSD 12
a4e4f745 Fix a -Wundef when FMT_GCC_VERSION < 600
7d3de497 Implement double to fp conversion
a4c7d99f Add bit_cast
0adccaef Fix a -Wundef of _LIBCPP_VERSION
2570f1af Provide more overloads for the wide string flavour
ca31ca13 Fixed arg_formatter_base::write_pointer to not mutate the format specs.
6cd66610 remove trailing spaces.
fe19c266 Move format_string to fmt namespace for ADL
2768af23 Add cached powers of 10
dd296e1d Add a script to compute powers of 10
0efc8a18 Fix compiler warning about narrowing
df1ba52b Update example
221b08fd Merge branch 'master' of github.com:fmtlib/fmt
fa9066fe context_base::begin -> out
90ff31b3 Fix a -Wundef warning on clang
b1f68c43 Merge branch 'master' of github.com:fmtlib/fmt
cd90097c Implement handmade FP
822eccc3 Sync API with standards proposal
2ae41242 allow time formatting with wchar_t contexts
a1579b0f Update key
ded921f0 Fix documentation build, take 2
3284751f Fix documentation build
bb738c4c Remove section on Write API since it's being superceeded by compile-time Format API
d180c25c Update godbolt link
1ed842a3 Update godbolt link
e80aba1c Remove format_float stub
7b8cb313 Make context_base::args() public
48ae0506 fixes MSVC compiler warning bloat (Visual Studio 2017, latest updates)
096c4051 Simplify char_traits
7610c536 Remove unused macro
111fa581 Update README.rst
52fcef1e Update docs
7d28674d make_args -> make_format_args
9382b76f context_t -> format_context_t
fd0b07a7 (w)context -> (w)format_context
26aa34f3 basic_context -> basic_format_context
44cc0346 Relax string_view requirements
0829cab8 Remove from_checked
cb7bbc62 Improve checked iterator support
5079f924 Fix a narrowing warning
5859e58b Fix msvc warnings
1e747f60 Fix msvc warnings
9d4efd7a Iterator Wars VI: Return of the checked iterator
9764f558 Update docs
4ef97b9b Add a missing comma
23759b26 basic_arg -> basic_format_arg, arg_store -> format_arg_store
4975297e Simplify counting iterators
e8e006f4 Fix compile checks for mixing narrow and wide strings (#690)
c5ebecf7 Document format_to_n
3cf05263 Return output iterator to the end from format_to_n
174087bf Implement format_to_n
050f3f1f Remove parts of obsolete write API
e90b1da3 Fix linker errors using fmt as shared library in MSVC
8e10d404 Fix compile tests
7a41d61d Add make_printf_args
4fea018b Fix string_view detection
6957d28c Detect string_view on libc++ (#686)
0ea70def Update readme
9ce5e30c Update readme
8c29459e Fix handling of empty string_view (#689)
a24005d5 Fix a narrowing warning
3651b7fc Fix a narrowing warning
b64486da Add format.cc
3da71d51 Move source files to the src directory
7971ed3d Update readme
f61ca2ec Update readme
84e520b7 Update readme
e8aa0f33 Update docs
17258e9c Update docs
6d339e32 Improve comment
c3d05245 Fix a shadowing warning
b58c8dde Update docs
505b3ae6 Workaround GCC bug 67371 (#682)
70dffc63 Remove unnecessary check
df828f88 Don't define FMT_GCC_VERSION on clang
42f70c8b Avoid narrowing casts
10b939b0 Remove unneeded usage of anonymous struct on clang
3adfaae2 Remove extra semicolon in format_args constructor
40066785 Fix warnings under MSVC (#679)
9c5f54a7 Add format example for padded hex byte
7bab90e5 Remove extra comma
2e21e7d1 Fix util-test
acb469ae Fixed UTF8/16 converters to support empty string input
c37c4c43 Fix find-package-test
6d21fc43 add alias targets with fmt namespace
e02aacc6 Add CMake namespace (#511)
aee4512c Gradle (#649)
7db0e94b Fix handling of numeric alignment with no width (#675)
9facc119 Update docs
a1d18711 Merge branch 'master' of github.com:fmtlib/fmt
daf650c4 Disallow formatting of multibyte strings into a wide buffer (#606)
8fd7e30f Update README.rst
ca93be13 Use fmt(s) as an alias for FMT_STRING(s)
80e57c7a Update to new naming conventions
ae3cc844 Check format string at compile time in print
585512fc Remove unnecessary instantiations
7755cdc1 Make symbols readable
f867d082 Update docs
a103b9bc Workaround missed optimization in gcc (#668)
bb47109a Cleanup
f1ede638 Make inline_buffer_size public and update docs
995b63ad Update copyright
40232917 Update docs
86a9bc82 Cleanup
b7632e96 Make format_to return iterator and update docs
5281ea6a do_vformat_to -> vformat_to and update docs
d07ba498 Fix docs
418659ad Fix compilation errors on gcc 4.4
1d2adef2 Fix compilation errors on gcc 4.4
45518c3f Fix compilation errors on gcc 4.4
698d9097 Workaround a bug in gcc 5.1
81074c70 Fix more compilation errors on gcc 4.6
1b452538 Fix more compilation errors on gcc 4.6
6090e51b Fix compilation errors on gcc 4.6
0827ec5a Fix compilation errors on gcc 4.6
4d35f941 Always use fallback string_view to pass format string (#664)
34cf54c2 Update README.rst
0565d654 Fix gcc 7.2 issue
f5dc0ed3 Break long lines
ea06f021 test: comment out one FormatStringErrors constexpr test
5b491773 test: Initialize some local variables
f45f70af Use trailing return type instead of deduction
db86e8d5 Remove a couple of unused argument names
55f5c9f2 Use FMT_NULL instead of 0 is a few more places.
e92ba107 Fix Python str.format link to point to Python 3 docs
a7ae5666 Enable join on msvc
24d249b0 Fix formatting of objects convertible to string_view
e508e308 Don't define FMT_LOCALE on OpenBSD
0ee4273b Put is_enum check first not to instantiate convert_to_int unnecessarily
8ca3ab2c Revert problematic pragma
18ac9870 Fix formatting of objects convertible to std::string
ce4a65ff Add pointer support to basic_writer
91721caa Add detection of wostream operator<< (#650)
1efc15c1 Fix MSVC build
8ed264fc Rename type enum constants to prevent collision with poorly written C libs (#644)
4ba3f7db Update docs
7d2723d5 posix.cc: Fix compilation with -fno-exceptions
24d66c5d compilation fix & warnings
229887bd Make constexpr remove_prefix gcc version check tighter (#648)
f3f19e76 Update docs
e9fa42ac Fix docs and build issues on gcc-4.6
affb35cf Replace using with typedef for compatibility with gcc-4.6
9710c058 Update documentation building script
1a4e8927 Move output_range to format.h
522de7b5 Replace using with typedef for compatibility with gcc-4.6
0b508fd2 Fix c++0x detection
1849735f Fallback to c++11 if c++14 not available
3239c518 Get rid of generic lambdas
78166ccd Get rid of generic lambdas
d8ef8a9e Cleanup
82222218 Update README.rst
b0005324 Merge the std branch
a502decd Added a fmt.pro to support build using qmake (#641)
61065e1a Fix unreachable code warning when signbit returns bool
403ae0a2 Add debug postfix for libfmt (#636)
5096c0fe Fix string_view detection
5b3f9eab Update syntax.rst
e802cf14 Add note about errno to the documentation
c96d6465 CMakeLists: Use GNUInstallDirs to set install location
dbd84697 Update usage.rst
5013c157 Silence MSVC 2017 constant if expression warning
cdfcee27 Use allocator_traits if available
66b25ef0 Add examples
6cb68f94 Fix warnings
0b635c9d Fix handling of fixed enums in clang (#580)
66afd9b3 Fix compilation on gcc 6
67e070fe Make format work with C++17 std::string_view (#571)
867b3309 Remove ANDROID macro check per comment in #458
64599973 Enable stream exceptions (#581)
35f8f036 Use less version 2.6.1 and sudo to fix npm install issues on travis
92a250fd Suppress Clang's warning on zero as a null pointer
2f13d41e Add to_wstring
1e19ae83 Workaround a bug in MSVC
3810d7e4 Workaround a bug in MSVC
5c7474e1 Relax constexpr requirements
1f57243b Relax constexpr requirements
dc540361 Conditionally compile constexpr
5d8ba816 Fix a segfault in test on glibc 2.26 #551
a9f810c1 Update README.rst
2582f41e Fix ifdefs
1a7d0ba2 Adding OpenSpace to the list of projects
8921f613 Update build script
f62e225e Automatically update version in release script (#431)
94806747 remove 'FMT_CPPFORMAT' CMake option
bfce29ff Improve conversion
8cf30aa2 Fix segfault on complex pointer formatting (#642)
f164e4c7 Remove old bcc-related comments
c57029c1 Add Drake & Lyft Envoy to the list of projects
8fa9acb8 Workaround broken __builtin_clz in clang with MS codegen (#519)
3dae2582 Describe cmake use of header-only target
1c7b751d Fix handling of implicit conversion to integral types larger than int
08dff377 Allow compiling and using as DLL in windows #502
c753a2af Don't include the world with WIN32_LEAN_AND_MEAN (#503)
a5185ec8 add SOURCELINK_SUFFIX for compatibility with Sphinx 1.5
768061c8 Fix FormatBuf implementation (#491)
0c136381 Move back_insert_range to format.h
5060568f %.f should have zero precision, not default precision
a09f7488 Add Kodi (xbmc) to the list of projects using fmt
f9fa7c40 Add FMT_API and FMT_OVERRIDE where needed
a980d3b4 Add fmt::join to format ranges (#466)
87eab90e Fix missing intrinsic when included from C++/CLI (#457)
75005bbc Don't export the -std=c++11 flag from the fmt target
19f990a9 Use https to fetch dependencies from github
bca9de9e Return iterator from format_to
0555cea5 Added a fmt.pro to support build using qmake (#641)
a93270fd Replace a bunch of craft with type_traits, take 2
21429c86 Revert "Replace a bunch of craft with type_traits"
0473c48f Add std::basic_string allocator support (#441)
72d9fffd Fix test compilation for FreeBSD (#433)
e79588d6 Replace a bunch of craft with type_traits
3a6c7d0c Fix signbit detection (#423)
5e4c34b2 Add version macro FMT_VERSION (#411)
bd8a7e7e More iteratification
f78c3e41 Fix unreachable code warning when signbit returns bool
0a402056 Add CONTRIBUTING.rst
e35d41ff Add extern templates for format_float (#413)
d8c25a17 Use nullptr if available
e95e4659 Add syntax.rst to build
e5111950 argument index -> argument id
229ee34e Fix compiler warnings
7fe0f3da Update ChangeLog
38b603a4 Update README.rst
a1e7e4a7 Fix compilation with -fno-exceptions (#402, #405)
3f24a388 Thread-safe time formatting (#396)
f853d94a Remove unnecessary fmt/ prefix (#397)
9649919d Document use of format_arg for user-defined type #393
c8efe145 Add api.rst to build
da80005f Fix compilation on Cygwin (#388)
8ed16353 Fix a typo
1760c31b Workaround Doxygen mess
72606f23 Add missing types to counting_iterator
c1571003 Add debug postfix for libfmt (#636)
6822466a Handle nested braces in join (#638)
64b349ae More iterator support & fmt::count
e3b69efb Suppress msvc warnings in gmock
322736d3 Add support for arbitrary output iterators
10291194 Cleanup
c1d137ed Add support for nonconiguous iterators
f6fd38bb More iterator support
c2fecb9b Clean API
9a53a706 Add support for back_insert_iterator
91ee9c9a Return iterator from the format method
67928eae Don't inherit context from parse_context
217e7c76 Pass ranges by value
22994c62 Decouple arg_formatter_base from buffer
00f1450d Update tesmplate parameter names
3a2e89e1 Reduce dependency on buffer
c719d944 Fix experimental/string_view detection
cea3c207 Give a better error message for function pointers (#633)
232ceabb Workaround an internal compiler error in MSVC
c0954453 Replace buffer with range
c3d6c5fc Replace buffer with range
0f987731 add transition helper to format.h
d165d9c4 Decouple locale and buffer
36634140 Parameterize basic_writer on buffer type
6f2769d0 Revert "Added support for format string containing '\0' in _format udl (#619) (#620)"
5f1c73db Shorten a comment in locale.h
31934602 Update version
51a16f8c Update ChangeLog.rst
a0087460 Merge release branch
941663d0 Merge ostream.cc into ostream.h
955062da Merge printf.cc into printf.h
5705bf1c Added support for pre-c++17 experimental string_view (#607)
cabce31f Update syntax.rst
ccaae0c0 Refer to jeaiii project
e3715102 Add a integer formatter based on jeaiii
b3495f2e Update README.rst
61f296e3 Move FMT_HAS_BUILTIN to format.h
ce801c90 Remove dependency on <vector> and <array>
41fc2990 Merge branch 'std' of github.com:fmtlib/fmt into std
971fb584 Allow mixing named and automatic arguments
af0f21da add missing inline in header-only mode (#626)
7cea1638 numeric -> arithmetic
5328907f Get rid of <limits> dependency
faaafc7e Remove <utility> dependency and replace typedefs with using
94edb1a7 Add a lightweight header for the core API
3aaa25fa Added support for format string containing '\0' in _format udl (#619) (#620)
84bd2f19 Merge include/fmt/CMakeLists.txt into the main CMake file
7f351dec Decouple <locale> for better compile times
81bd9e8e args -> format_args
10e70a06 Improve handling of custom arguments
e0243000 arg_index -> arg_id
ac5f9520 Automatically add package to release
0e914372 Avoid conflict with the macro CHAR_WIDTH
f03a35a6 Check string specs at compile time
e9da5741 Check char specs at compile time
b25a0292 Check pointer type specs are compile time
c8a9d902 Check floating-point type specifiers
6570dc31 Disallow formatting of multibyte strings into a wide buffer (#606)
3851994a Fix yet another internal compiler error in MSVC
44e18651 Refactor parse context and fix warnings
e7e270f5 Test error on invalid type spec and remove unused alias
692b82d3 UdlArg -> udl_arg
c523dd58 Use error handler to report errors
5a32e64b More tests
093e2a47 Improve error handling
dc104cba Workaround internal compiler errors in MSVC
39411504 More tests
e3eb5ea0 Add parse_context::error_handler()
734e722d Fix warnings
62af25dc Workaround yet another MSVC internal error
594bd8fe More tests
f2b52bba More tests
dfdb1ade More tests
7967c2f8 Disable test that triggers an MSVC bug
18a0b94b Fix overflow check
686ff942 Fix compile-time parsing and add more tests
5b95b5d7 Test compile-time errors
246bdafc Add FMT_STRING macro for compile-time strings
e8055433 Remove FMT_USE_VARIADIC_TEMPLATES
dba1ccc4 Update readme
e613b3c7 Update readme
9fda7a36 Check integral type specs at compile time
92847a0d Add integral type handler
a03842b0 More compile-time checks
1c855a47 Integrate constexpr format specs parsing
780b44bf Add compile-time format string check
8ca6e76d Detect user-defined literal templates
a7e98616 Workaround another MSVC madness
db9ffa14 Make parse_format_string constexpr
e926ae78 Add parse_format_string
57e266ab Rename handlers
d29c7c3a Workaround a bug in MSVC
aadb38a5 Make specs_checker constexpr
dd0b72e1 Remove refactoring artefacts
e52b10e3 Merge branch 'vitaut-patch-1' of github.com:fmtlib/fmt into std
529d88ce Make dynamic_format_specs construction constexpr
d2f2a8b0 constexpr support of dynamic width and precision
6b3840b7 Make format_specs construction constexpr
a38bd9ca Fix formatting and naming
91014f01 Naming conventions
932ab2bf Report error from parse_nonnegative_int via handler
0ebdf41e Fix compile-test
170f5c67 Move headers to include/fmt
3d11eac7 Workaround another MSVC constexpr bug
c69e3086 Update README.rst
25aac0be Fix travis build on macOS
b83241ff Make format spec parsing constexpr
bd5188c8 Remove MinGW because it's not on appveyor image
62616b88 Workaround a bug in MSVC's constexpr handling
b8f85f67 Use Visual Studio 2017 image on appveyor
7174de0d Fix contexpr-ness of pointer_from
3785afc5 Pass errors to handler instead of throwing (#566)
1b5ccf6c Make parse_arg_id constexpr
17f93fe0 Make basic_string_view ctors constexpr
d5e918b6 Detect C++14 compiler support
be5b4552 Make null_terminating_iterator more iteratory
643fb066 Check for argument indexing switch
d45544d1 Fix width handling in dynamic formatting
8cbf5447 Add parse context
ec4f5175 Replace Range with ParseContext in parse()
83dd2ab9 Simplify dynamic_specs_handler
5a8ae0bb Fix a warning
39bc319b Update test results
534bff7d Fix handling of max packed arguments
0cda806d Fix compile tests
a3191a99 Get rid of FMT_MAKE_WSTR_VALUE macro
fced79b0 Get rid of old compat macros
be887d92 Replace internal::get with std::declval
53cf0735 Get rid of FMT_MAKE_VALUE macro
2972de4b Char -> char_type
9ee7c216 Type -> type
1a09194a Cleanup type handling
c18a4041 Remove conditional and to_iterator
1cade7ef Remove FMT_USE_RVALUE_REFERENCES
7413239f Remove unnecessary qualification
af00e4f9 Remove printf_arg_formatter from format.h and cleanup
44a26e5e CharPtr -> pointer_type and move to writer
0fbd8465 Replace fmt::internal::make_unsigned with std::make_unsigned
8a2bc0ab Add nullptr support
80505995 Allow delayed type checking
b0867f3f AlignSpec -> align_spec and fix a warning
f194a418 Replace fmt::is_same with std::is_same
47c84d79 Move part of write API (spec factories) to a separate header
20168147 Add ptr, a helper function for pointer formatting
77c892c8 Fix more warnings
be7d72ba Fix expansion-to-defined warning
d4c504ae Fix a warning
27ad6cee Use standard enable_if
64681739 Fix a warning
38806167 Remove FMT_HAS_GXX_CXX11
a7320bdc Fix a warning
016acebb Remove legacy code
07f8ffc4 Suppress shadowing warnings
466386d5 Suppress a warning in gmock
70ef82a8 Workaround a bug in MSVC
5e0562ab Separate parsing and formatting
1102d465 Make format spec parsing context-independent
45911770 Separate parsing and formatting in extension API
7bd776e7 Explain why null_terminating_iterator is used
873c8451 Remove system_header pragma
9f7957c0 Separate argument parsing and formatting
da439f28 Suppress warning about missing noreturn attribute (#549)
eefdb379 Fix an unused argument warning
2f4f49fd Switch from cstring_view to string_view
a8d6f309 Minor optimizations
d16582a0 Move printf-related code to printf.cc
361911dd Use preinstalled version of cmake on travis
9ea183aa Fix MSVC build
8f4b918c Check argument index
4193485b Remove test files
07123e8f Use Ubuntu Trusty on Travis for a new CMake
586d6363 Implement more efficient handling of large number of format arguments
12252152 CStringRef -> cstring_view
5aa8d6ea Return locale by value
32ec13f1 Switch to C++ locale
b4f4b7e2 Clean the buffer API (#477)
f423e468 Replace clear() with resize(0) and data_ -> store_
23b8c24d Add noexcept
7175bd8a Fix error on MinGW
7258d1b8 Fix tests
3610f34c Fix windows build
572491ad Document which header defines formatting functions
c333dca0 Follow standard naming conventions
6a2ff287 Follow standard naming conventions
eedfd07f internal::MemoryBuffer -> basic_memory_buffer
4ec88607 ArgFormatter -> arg_formatter
50e71673 StringRef -> string_view, LongLong -> long_long
e022c21d Fix windows build
87b691d8 Merge StringWriter into StringBuffer
c2f02169 Merge ArrayWriter into FixedBuffer
fefaf07b Pass buffer instead of writer to format_value
6e568f3a buffer -> basic_buffer
bb1c82ef Fix build
a13b96ed Simplify API
624c5868 Simplify API
7ae8bd70 basic_format_arg -> basic_arg, Buffer -> buffer
bf0f1075 Parameterize format_specs on character type
296e9cad FrmatSpec -> format_spec
b5fb8dd1 stream -> buffer
984a1029 Remove IntFormatSpec and StrFormatSpec
4863730e Remove pad
aaa0fc39 Improve compatibility with old compilers and fix test
aea5d3ab Improve compatibility with older gcc and update tests
84850277 Use named argument emulation instead of nested functions
ec15ef7b Replace operator<< with write function
b77c8190 FPUtil -> fputil
8428621d BasicWriter -> basic_writer
939aff29 Remove unnecessary template arg from basic_format_args
f69786a7 Remove Not
b2a0d891 Merge value and MakeValue
acd1811c Value -> value
42a31907 Parameterize Value on context
a4d6cb32 Clean up basic_format_arg
d705d516 Parameterize basic_format_arg on context (#442)
422236af Don't erase writer type
abb6996f MakeArg -> make_arg
ee1651ce Handle empty format_arg state
3bbc5799 Fix MinGW build
63fcfc57 Fix build on older gcc
d86e51e9 Don't inherit basic_format_arg from internal::Value
f0588869 Fix handling of unpacked args (#437)
11836218 Add support for exotic character types
763ca978 Parameterize Value on character type
6cba8fe9 Move stuff out of internal::Value
e1ee5bf0 Replace StringValue with StringRef
0854f8c3 Parameterize formatting argument on char type.
9cf6c8fd Get rid of fmt::internal::Arg
5f022ae0 Remove FMT_DISPATCH
41d4bcf0 Ingore Xcode files
28429701 Merge BasicArgFormatter and ArgFormatter
d4084ac5 Get rid of ArgVisitor
d58cc8a4 Merge BasicPrintfArgFormatter and PrintfArgFormatter
e2dfd39c Update arg visitors
751ff64b Update ArgConverter to the new visitor API
c9dc41ab Replace ArgVisitor::visit with a free visit function
caa60b9c Update comment
95a53e1f Refactor argument visitor API (#422)
6d241167 Improve visitor API
a1dd524b format_arg -> do_format_arg
55a1ac50 Fix test
85793a18 Simplify API
9998f66f Replace formatter with context
2bba4203 Pass writer directly to format_value (#400)
b656a1c1 Make value the second argument to format_value
edf98792 Pass writer to format_value
64ca334a CharType -> Char
be613204 Char -> char_type
f85d5f4d BasicFormatter -> basic_formatter
18dfa257 Pass correct formatters to make_format_args
dafbec75 Fix type safety when using custom formatters (#394)
506435bf Fix formatting
f2879940 Fix formatting
48fe9783 Add format_arg::operator bool
119a63ab internal::Arg -> format_arg
65a8c2c3 format_arg -> format_value
13b04044 Add format_args::size_type
8a77e792 Enable C++11 in tests.
1e8553d6 Enable C++11 in tests.
06bab3ed Workaround mingw bug https://sourceforge.net/p/mingw/bugs/1531/
6fd6ecc1 Enable C++11 for no-windows-h-test
c4212f9e format -> vformat
21c6700b Don't build std branch with -std=c++0=98
209a1d58 Get rid of macros
9a079732 Test types
ea28a637 Get rid of FMT_VARIADIC_CTOR
0d8aca8d Get rid of FMT_VARIADIC_VOID
4ece95a7 Make make_format_args public
0028ce57 Get rid of FMT_VARIADIC
ece7ae5f Make format_arg_store convertible to format_args
621447fe Make initialization C++11-compatible
a0190e4b Add a missing include
b903f5c1 format -> vformat
43c0095a Refactor type mapping
4873685c ArgArray -> format_arg_store
fc73e106 ArgList -> format_args
92605eb4 Remove FMT_USE_VARIADIC_TEMPLATES
9bb213e9 FormatError -> format_error
REVERT: 135ab5cf Update version
REVERT: 93d95f17 Fix markup
REVERT: 4f15c72f Fix markup
REVERT: e9b19414 Automatically add package to release
REVERT: c3d1f604 Fix markup
REVERT: c96062bf Update changelog and version number

git-subtree-dir: externals/fmt
git-subtree-split: 3e75ad9822980e41bc591938f26548f24eb88907
2018-10-02 21:24:56 +01:00
MerryMage
bcb947eb6b externals: Update fmt to 5.2.1
Merge commit '49041cb4514956a8754df6f1845f5593037ac870' into HEAD
2018-10-02 21:24:56 +01:00
Merry
ba7a5b6c98
Merge pull request #401 from lioncash/folding
constant_propagation_pass: Fold &, |, ^, and ~ operations where applicable
2018-10-02 21:22:58 +01:00
Lioncash
7868411de5
constant_propagation_pass: Fold NOT operations 2018-10-01 18:53:54 -04:00
Lioncash
0d1f9841d1
constant_propagation_pass: Fold OR operations 2018-10-01 18:53:54 -04:00
Lioncash
142978041d
constant_propagation_pass: Fold AND operations 2018-10-01 18:53:54 -04:00
Lioncash
be3ba545e7
ir/value: Add member function to check whether or not all bits of a contained value are set
This is useful when we wish to know if a contained value is something
like 0xFFFFFFFF, as this helps perform constant folding. For example the
operation: x & 0xFFFFFFFF can be folded to just x in the 32-bit case.
2018-10-01 18:53:47 -04:00
MerryMage
4e6848d1c9 A32/ir_emitter: Bugfix: ExceptionRaised was producing incorrect PC
Use actual PC and not pipelined PC.
2018-09-30 19:39:52 +01:00
Lioncash
f5233bfc69
constant_propagation_pass: Fold EOR operations
It's possible to fold cases of exclusive OR operations if they can be
known to be an identity operation, or if both operands happen to be known
immediates, in which case we can just store the result of the
exclusive-OR directly.
2018-09-29 03:59:15 -04:00
Lioncash
41ba9fd7bc value: Move ImmediateToU64() to be a part of Value's interface
This'll make it slightly nicer to do basic constant folding for 32-bit
and 64-bit variants of the same IR opcode type. By that, I mean it's
possible to inspect immediate values without a bunch of conditional
checks beforehand to verify that it's possible to call GetU32() or
GetU64, etc.
2018-09-28 22:19:11 +01:00
MerryMage
c6a6271f86 reg_alloc: Emit AVX instructions where able
Smaller codesize.
2018-09-28 21:12:48 +01:00
MerryMage
aedd32aa20 abi: Emit AVX instructions where able
Smaller codesize.
2018-09-28 21:12:17 +01:00
MerryMage
f2d9337663 a64_exclusive_monitor: Loosen memory ordering requirements
It is not necessary to be as strict as it was.
2018-09-27 16:21:56 +01:00
Lioncash
7ca709de81 travis: Make macOS builds use Xcode 10
Keeps the toolchain up to date and allows the use of things like
<optional> and <variant> from the standard library.
2018-09-25 19:23:51 +01:00
MerryMage
14dd45eed9 Fix VShift terminology
An arithmetic shift is by definition a signed shift, and a logical shift is by definition an unsigned shift.

- Rename VectorLogicalVShiftS* -> VectorArithmeticVShift*
- Rename VectorLogicalVShiftU* -> VectorLogicalVShift*
2018-09-23 10:50:39 +01:00
MerryMage
88554c4f04 emit_x64_vector: AVX512 implementation of EmitVectorLogicalVShiftS16 2018-09-23 10:41:41 +01:00
MerryMage
ab4e316b24 emit_x64_vector: AVX512 implementation of EmitVectorLogicalVShiftS64 2018-09-23 10:41:30 +01:00
MerryMage
0ea84f34fe emit_x64_vector: AVX2 implementation of EmitVectorLogicalVShiftS32 2018-09-23 10:41:10 +01:00
MerryMage
c77a2c5bab emit_x64_vector: AVX512 implementation of EmitVectorLogicalVShiftU16() 2018-09-23 10:14:20 +01:00
MerryMage
e9441fd561 emit_x64_vector: AVX2 implementation of EmitVectorLogicalVShiftU64() 2018-09-23 10:14:20 +01:00
MerryMage
0e9c33cbf3 emit_x64_vector: AVX2 implementation of EmitVectorLogicalVShiftU32() 2018-09-23 10:14:20 +01:00
Lioncash
8f8527407c emit_x64_vector: SSSE3 variant of EmitVectorCountLeadingZeros8()
pshufb lyfe
2018-09-23 10:13:08 +01:00
Mat M
be05e75818
Merge pull request #397 from VelocityRa/dec-shift-fix
decoders: Cast to correctly-sized type before shifting
2018-09-22 19:17:36 -04:00
VelocityRa
bc328fc645 decoders: Cast to correctly-sized type before shifting
Fixes decoding for 64-bit instructions

Does not help/apply to any currently supported ARM versions (since
all are 32-bit length or below), it's for future-proofing should
such an arch be supported.
2018-09-22 22:10:29 +03:00
MerryMage
9c3d2d104d a64_emit_x64: Lowercase PAGE_SIZE
PAGE_SIZE is defined as a macro by musl.
2018-09-22 18:54:49 +01:00
MerryMage
f538d29be7 emit_x64_vector_floating_point: SSE4.1 implementation of EmitFPVectorToFixed 2018-09-22 18:47:15 +01:00
MerryMage
1603a6e9f8 emit_x64_vector_floating_point: EmitFPVectorRoundInt: Use FCODE 2018-09-22 16:19:54 +01:00
MerryMage
2e1ccaff53 emit_x64_vector: AVX implementation for EmitVectorCountLeadingZeros8 2018-09-22 16:08:23 +01:00
MerryMage
555bfdacf9 emit_x64_vector: SSE implementation of EmitVectorCountLeadingZeros16 2018-09-22 13:05:47 +01:00
Lioncash
71c2589662
externals: Update Xbyak to 5.73
Merge commit '1ec1b2febb1eac58cf98384dd8ba977a74be7054' into xbyak
2018-09-19 17:55:45 -04:00
Lioncash
1ec1b2febb Squashed 'externals/xbyak/' changes from 1de435ed..42462ef9
42462ef9 use evex encoding for vpslld/vpslldq/vpsraw/...(reg, mem, imm);
da9117a9 update version of readme.md
d35f4fb7 fix the encoding of vinsertps for disp8N

git-subtree-dir: externals/xbyak
git-subtree-split: 42462ef922893f0d3f2156d005fa27ba6898498b
2018-09-19 17:54:43 -04:00
MerryMage
171d11659d A64: Implement SCVTF, UCVTF (vector, fixed-point), scalar variant 2018-09-19 20:11:14 +01:00
MerryMage
f221bb0095 emit_x64_floating_point: Reduce fallback LUT code in EmitFPToFixed 2018-09-19 20:11:14 +01:00
MerryMage
eb123e2a74 A64: Implement FCVTZS, FCVTZU, UCVTF, SCVTF (vector, fixed-point), vector variant 2018-09-19 19:47:28 +01:00
Lioncash
487d37a4a1 A64: Implement UQSHL's vector immediate and register variants 2018-09-19 12:13:22 +01:00
Lioncash
f69893345f ir: Add opcodes for unsigned saturating left shifts 2018-09-19 12:13:22 +01:00
Lioncash
7148e661f6 A64/translate/impl: Make signatures consistent for unimplemented by-element SIMD variants
Makes them all consistent, so it isn't necessary to change the
prototypes over when implementing them.
2018-09-19 12:11:35 +01:00
Lioncash
fdde4ca363 A64: Implement BRK
Currently, we can just implement this as part of the exception
interface, similar to how it's done for the A32 interface with BKPT.
2018-09-19 07:09:27 +01:00
Lioncash
b1490db0e9 A64/imm: Add full range of comparison operators to Imm template
Makes the comparison interface consistent by providing all of the
relevant members. This also modifies the comparison operators to take
the Imm instance by value, as it's really only a u32 under the covers,
and it's cheaper to shuffle around a u32 than a 64-bit pointer address.
2018-09-19 07:09:00 +01:00
MerryMage
1ec40ef6ed IR: Add fbits argument to FPVectorFrom{Signed,Unsigned}Fixed 2018-09-18 21:46:17 +01:00
MerryMage
d6d5e986c2 A64: Implement SCVTF, UCVTF (scalar, fixed-point) 2018-09-18 21:08:06 +01:00
MerryMage
6513595c09 opcodes.inc: Align columns to a tabstop of 4 2018-09-18 20:37:03 +01:00
MerryMage
6b0d2b529e IR: Add fbits argument to FixedToFP-related opcodes 2018-09-18 20:36:37 +01:00
Lioncash
c4b383124f A64: Implement SQSHL's vector immediate variant 2018-09-18 18:22:03 +01:00
Lioncash
e0d8d2d855 A64: Implement SQSHL's vector register variant 2018-09-18 18:22:03 +01:00
Lioncash
532762582b ir: Add opcodes for left signed saturated shifts 2018-09-18 18:22:03 +01:00
Lioncash
9705252968 branch: Make variables const where applicable 2018-09-18 17:45:49 +01:00
Lioncash
650946e41c move_wide: Make variables const where applicable 2018-09-18 17:45:49 +01:00
Lioncash
62b3a6dcfb load_store_register_unprivileged: Make variables const where applicable 2018-09-18 17:45:49 +01:00
Lioncash
3add1c7b3f load_store_register_immediate: Place conditional bodies on their own line
Makes the conditionals visually consistent with the rest of the
codebase.
2018-09-18 17:45:49 +01:00
Lioncash
2fc4088a74 load_store_load_literal: Make variables const where applicable 2018-09-18 17:45:49 +01:00
Lioncash
b2c146259f data_processing_logical: Move datasize declarations after early-exit conditionals
While we're at it, make variables const where applicable.
2018-09-18 17:45:49 +01:00
Lioncash
028028f9eb data_processing_conditional_select: Make variables const where applicable
Makes CSEL's function consistent with all of the others.
2018-09-18 17:45:49 +01:00
Lioncash
c66042da57 data_processing_addsub: Move datasize declarations after early-exit conditionals
While we're at it, also make relevant variables const where applicable
2018-09-18 17:45:49 +01:00
Lioncash
6bc546e1f7 data_processing_bitfield: Move datasize variables after early-exit conditionals
Moves the declaration of datasize to the scope that it's used within.
This also takes the opportunity to apply const where applicable, and
make early-exits all vertically consistent with one another.
2018-09-17 18:14:16 +01:00
Lioncash
2aad5fa87f A64: Implement CLS's vector variant
Leverages CLZ like the integral variant does.
2018-09-17 18:14:00 +01:00
Lioncash
6c877ff8db emit_x64_vector: Make EmitVectorUnsignedSaturatedAccumulateSigned() internally linked
Given this is just an internal helper function, it can be marked static.
2018-09-16 08:16:54 +01:00
Lioncash
4b5926dcab perf_map: Use std::string_view instead of std::string for PerfMapRegister()
We can just use a non-owning view into a string in this case instead of
potentially allocating a std::string instance.
2018-09-16 08:16:43 +01:00
MerryMage
74459479b9 A64: Implement SQRDMULH (vector), vector variant 2018-09-15 14:04:42 +01:00
MerryMage
03b80f2ebe A64: Implement SQDMULL (vector), vector variant 2018-09-15 13:38:37 +01:00
MerryMage
4a2c5962c7 IR: Add VectorSignedSaturatedDoublingMultiplyLong 2018-09-15 13:38:17 +01:00
MerryMage
59dc33ef12 emit_x64_vector: Changes to VectorSignedSaturatedDoublingMultiply
* Return both the upper and lower parts of the multiply if required
* SSE2 does not support the pmuldq instruction, do sign correction to an unsigned result instead
* Improve port utilisation where possible (punpck instructions were a bottleneck)
2018-09-15 09:55:25 +01:00
MerryMage
bbaebeb217 IR: Implement Vector{Signed,Unsigned}Multiply{16,32} 2018-09-15 09:55:25 +01:00
Lioncash
baac5a8810 backend_x64/a64_interface: Re-enable the constant folding pass
This was disabled for debugging, but never re-enabled. Just to be sure,
testing was done downstream in yuzu to make sure this didn't happen to
break anything (which seems to be the case).
2018-09-14 12:14:19 +01:00
MerryMage
e78ca1947b emit_x64_vector_floating_point: Hardware FMA implementation for RSqrtStepFused 2018-09-12 21:01:06 +01:00
MerryMage
8a5ae9a366 emit_x64_vector_floating_point: Hardware FMA implementation of FPVectorRecipStepFused 2018-09-12 20:45:39 +01:00
MerryMage
39818f98e8 emit_x64_floating_point: Hardware FMA implementation of FPRSqrtStepFused 2018-09-12 16:10:18 +01:00
MerryMage
3d0a0b432b emit_x64_floating_point: Hardware FMA implementation of FPRecipStepFused{32,64} 2018-09-12 14:58:09 +01:00
MerryMage
2293dff6d8 emit_x64_vector: SSE implementation of VectorSignedSaturatedAccumulateUnsigned{8,16,32} 2018-09-11 19:57:31 +01:00
Lioncash
2047683777 emit_x64_vector: Correct static asserts for < 64-bit type checks in saturated accumulate fallbacks
I had initially meant to use BitSize() here, not sizeof()
2018-09-11 07:08:32 +01:00
MerryMage
55e9e401aa emit_x64_vector: EmitVectorSignedSaturatedAccumulateUnsigned64: SSE implementation 2018-09-10 22:39:30 +01:00
MerryMage
1076651426 emit_x64_vector: Simplify fpsr_qc related code
Move the bool conversion into A64JitState::GetFpsr so we don't have to continuously
pay the cost of conversion for every saturation instruction.
2018-09-10 21:24:07 +01:00
Lioncash
4039030234 A64: Implement CLZ's vector variant 2018-09-10 18:30:40 +01:00
Lioncash
0bb908fb53 ir: Add opcodes for vector CLZ operations
We can optimize these cases further for with the use of a fair bit of
shuffling via pshufb and the use of masks, but given the uncommon use of
this instruction, I wouldn't consider it to be beneficial in terms of
amount of code to be worth it over a simple manageable naive solution
like this.

If we ever do hit a case where vectorized CLZ happens to be a
bottleneck, then we can revisit this. At least with AVX-512CD, this can
be done with a single instruction for the 32-bit word case.
2018-09-10 18:30:40 +01:00
MerryMage
3b13259630 A64/translate: VectorZeroUpper for V(64) stores
Ensures correctness.
2018-09-09 19:59:02 +01:00
MerryMage
1931d44495 simd_two_register_misc: FNEG (vector) with Q == 0 had dirty upper 2018-09-09 19:55:37 +01:00
Lioncash
a0790f02d0 emit_x64_vector: Remove unnecessary [[maybe_unused]] attributes
These were unintentionally left in when introducing SUQADD and USQADD
2018-09-09 19:30:14 +01:00
Lioncash
b0e1eb5a15 A64: Implement USQADD's scalar and vector variants 2018-09-09 17:06:03 +01:00
Lioncash
28424c7ad1 ir: Add opcodes form unsigned saturated accumulations of signed values 2018-09-09 17:06:03 +01:00
Lioncash
9923ea0b71 A64: Implement SUQADD's scalar and vector variants 2018-09-09 17:06:03 +01:00
Lioncash
4c0adbb7f1 ir: Add opcodes for signed saturated accumulations of unsigned values 2018-09-09 17:06:03 +01:00
Lioncash
799bfed2df A64: Implement SMLAL{2}, SMLSL{2}, UMLAL{2}, and UMLSL{2}'s vector by-element variants
We can simply modify the general function made for SMULL{2} and
UMULL{2}'s by-element variants to also handle the other multiply-based
by-element variants.
2018-09-09 13:55:40 +01:00
Lioncash
94451ec321 A64: Implement UMULL{2}'s vector by-element variant 2018-09-09 13:55:40 +01:00
Lioncash
45867deac9 A64: Implement SMULL{2}'s vector by-element variant 2018-09-09 13:55:40 +01:00
Lioncash
02357939ac ir/value: Replace includes with forward declarations
enum classes are still considered complete types when forward declared
(as the compiler knows the exact size of the type from the declaration
alone). The only difference in this case being that the members of the
enum class aren't visible. Given we don't use the members within this
header in any way, we can simply forward declare them here and remove
the inclusions.
2018-09-09 09:04:22 +01:00
Lioncash
450f721df5 ir/cond: Migrate to C++17 nested namespace specifiers 2018-09-09 09:03:42 +01:00
Lioncash
e649988cd6 CMakeLists: Add missing cond.h header to file listing
Allows the file to show up within IDEs more easily.
2018-09-09 09:03:42 +01:00
Lioncash
d20e7694dd A64: Implement URSQRTE 2018-09-09 00:37:28 +01:00
Lioncash
4f3bde5f12 ir: Add opcodes for performing unsigned reciprocal square root estimates 2018-09-09 00:37:28 +01:00
Lioncash
cfeeaec1c6 A64: Implement URECPE 2018-09-09 00:37:28 +01:00
Lioncash
622b60efd6 ir: Add opcodes for unsigned reciprocal estimate 2018-09-09 00:37:28 +01:00
Lioncash
d17599af40
Update Xbyak to 5.71
Merge commit 'f7c26e9f7ace572f440b80b0e71625295755c38b'
2018-09-08 17:09:25 -04:00
Lioncash
f7c26e9f7a Squashed 'externals/xbyak/' changes from 671fc805..1de435ed
1de435ed bf uses Label class
613922bd add Label L() for convenience
43e15583 fix typo
93579ee6 add protect-re.cpp
60004b5c fix url of protect-re.cpp
348b2709 fix typo of doc
f34f6ed5 update manual
232110be update test
82b78bf0 add setProtectMode
dd8b290f put warning message if pageSize != 4096
64775ca2 a little refactoring
7c3e7b85 fix wrong VSIB encoding with idx >= 16

git-subtree-dir: externals/xbyak
git-subtree-split: 1de435ed04c8e74775804da944d176baf0ce56e2
2018-09-08 16:52:55 -04:00
Lioncash
8782b69c93 travis: Make macOS build with Xcode 9.4.1
Builds against the latest release version of the Xcode toolchain
2018-09-08 13:21:58 +01:00
Lioncash
b575b23ea9 A64: Implement SQNEG's scalar and vector variant 2018-09-08 11:23:32 +01:00
Lioncash
06062a91c5 A64: Add opcodes for signed saturating negations 2018-09-08 11:23:32 +01:00
Lioncash
1c40579de5 emit_x64_vector: Simplify "position == 0" case for EmitVectorExtract()
In the event position is zero, we can just treat it as a NOP, given
there's no need to move the data.
2018-09-08 11:23:32 +01:00
Lioncash
e335050886 emit_x64_vector: Simplify "position == 0" case for EmitVectorExtractLower()
In the event position == 0, we can just treat it as a simple movq,
clearing the upper half of the XMM register. This also makes that case
use only one register.
2018-09-08 11:23:32 +01:00
Lioncash
8b13421bac A64: Implement SQDMULH's by-element scalar variant 2018-09-08 11:23:32 +01:00
Lioncash
9122a6e19e A64: Implement SQDMULH's by-element vector variant 2018-09-08 11:23:32 +01:00
MerryMage
176e60ebb1 backend/x64: Do not clear fast_dispatch_table if not enabled
There is no need to pay for the cost of setting a large block of memory if we're not using it.
2018-09-08 11:23:32 +01:00
MerryMage
959446573f A64: Implement FastDispatchHint 2018-09-07 22:07:44 +01:00
MerryMage
2be95f2b3b A32: Implement FastDispatchHint 2018-09-07 22:07:44 +01:00
MerryMage
96f23acd00 ir/terminal: Add FastDispatchHint 2018-09-07 21:29:47 +01:00
Lioncash
f5ca9e9e4a A64: Implement SQDMULH's scalar variant 2018-09-06 20:35:43 +01:00
Lioncash
af8bea59d5 ir: Add opcodes for scalar signed saturated doubling multiplies 2018-09-06 20:35:43 +01:00
Lioncash
fed4220dc0 A64: Implement SQDMULH's vector variant 2018-09-06 20:35:43 +01:00
Lioncash
72eb6ad362 ir: Add opcodes for signed saturated doubling multiplies 2018-09-06 20:35:43 +01:00
Lioncash
0f8ae84c80 externals: Update catch to 2.4.0
Keeps the unit testing library up to date.
2018-09-06 20:33:10 +01:00
Lioncash
235165ba70 A64: Implement SQABS' scalar variant 2018-09-06 15:49:25 +01:00
Lioncash
1adca93d4a A64: Implement SQABS' vector variant. 2018-09-06 15:49:25 +01:00
Lioncash
f978c445fa ir: Add opcodes for signed saturated absolute values 2018-09-06 15:49:25 +01:00
MerryMage
d895a84e72 emit_x64_floating_point: EmitFPToFixed: maxsd optimization
maxsd is not required when doing a signed conversion, because x64
produces a 0x80...00 value for out of range values.
2018-09-06 15:44:09 +01:00
MerryMage
c624fe3ff3 emit_x64_floating_point: ZeroIfNaN: pxor -> xorps
xorps is shorter and more appropriate here.
2018-09-05 22:00:36 +01:00
MerryMage
e987a84062 IR: Simplify FP{Single,Double}ToFixed{U,S}{32,64} 2018-09-05 21:04:40 +01:00
Lioncash
f1babc8924 externals: Update catch to 2.3.0
Keeps the unit-testing library up to date.
2018-09-03 17:56:02 +01:00
Lioncash
a0c587ac1a A32/decoder: Add missing <algorithm> includes
These includes should be present, as we use std::find_if() within these headers.
2018-09-03 13:53:26 +01:00
Lioncash
0435ac2d80 emit_x64_vector: Provide AVX path for EmitVectorMinU64() 2018-08-31 21:15:48 +01:00
Lioncash
5e40b8fcf8 emit_x64_vector: Provide AVX path for EmitVectorMinS64() 2018-08-31 21:15:48 +01:00
Lioncash
26bc231b47 emit_x64_vector: Provide AVX path for EmitVectorMaxU64() 2018-08-31 21:15:48 +01:00
Lioncash
ae734a7a8e emit_x64_vector: Provide AVX path for EmitVectorMaxS64() 2018-08-31 21:15:48 +01:00
Lioncash
1d0334c8cb emit_x64_vector: Simplify EmitVectorLogicalLeftShift8()
Similar to EmitVectorLogicalRightShift8(), we can determine a mask ahead
of time and just and the results of a halfword left shift.
2018-08-31 19:44:54 +01:00
Lioncash
f4a1196e60 emit_x64_vector: Simplify EmitVectorLogicalShiftRight8()
We can generate the mask and AND it against the result of a halfword
shift instead of looping.
2018-08-31 19:44:54 +01:00
Lioncash
4fc51f41b1 emit_x64_vector: Amend value definition in SSE 4.1 path for EmitVectorSignExtend16()
We should be defining the value after the results have been calculated
to be consistent with the rest of the code.
2018-08-31 13:48:32 +01:00
Lioncash
e50adae441 emit_x64_vector: Remove fallback in EmitVectorSignExtend64()
This is fairly trivial to do manually.
2018-08-31 13:48:14 +01:00
Lioncash
0a364f385d emit_x64_vector: Remove fallback for EmitVectorSignExtend32()
We can just do the extension manually, which gets rid of the need to
fall back here.
2018-08-31 13:48:14 +01:00
Lioncash
799e519707 ir_emitter: Rename fpscr_controlled parameters to fpcr_controlled
Part of addressing #333
2018-08-28 18:43:01 +01:00
MerryMage
68ca03e8d4 a32/exception_generating: BPKT: Define unpredictable behaviour
Define unpredictable behaviour to be BKPT executes conditionally
2018-08-26 00:48:29 +01:00
MerryMage
42c0589881 A32: Add define_unpredictable_behaviour option 2018-08-26 00:48:27 +01:00
MerryMage
3262736fb6 A32/location_descriptor: Change formatting to use hex 2018-08-26 00:33:44 +01:00
MerryMage
f3bb54e042 microinstruction: A32ExceptionRaised causes CPU exception 2018-08-26 00:33:43 +01:00
MerryMage
2b4224bcb4 A32/types: CondToString: Add nv 2018-08-25 23:02:58 +01:00
MerryMage
0d17b076bd block_of_code: Hide NX support behind compiler flag
Systems that require W^X can use the DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT cmake option.
2018-08-23 20:56:05 +01:00
MerryMage
1ee3f3d9e6 Implement perfmap 2018-08-23 15:09:19 +01:00
MerryMage
72ed55f143 a32_emit_x64: Fix incorrect BMI2 implementation for SetCpsr
* The MSB for each byte in cpsr_ge were not being appropriately set.
* We also expand test coverage to test this case.
* We fix the disassembly of the MSR (imm) and MSR (reg) instructions as well.
2018-08-23 14:48:23 +01:00
MerryMage
2a705d0393 backend/x64: Support W^X systems
Closes #176.
2018-08-22 13:21:23 +01:00
BreadFish64
c95f023403 Backend: Create "backend" folder
similar to the "frontend" folder
2018-08-22 13:13:46 +01:00
MerryMage
deb1ab62d4 A64/translate: Standardize arguments of helper functions
Don't pass in IREmitter when TranslatorVisitor is already available.
2018-08-21 12:26:46 +01:00
MerryMage
30b6a5ffca A64/translate: Standardize TranslatorVisitor abbreviation
Prefer v to tv.
2018-08-21 12:16:32 +01:00
MerryMage
f9cd96bb1a emit_x64_vector: Avoid recalculating addresses in EmitVectorTableLookup 2018-08-21 12:16:32 +01:00
Lioncash
a42f301c28 A64: Implement SQXTN, SQXTUN, and UQXTN's scalar variants
We can implement these in terms of the vector variants
2018-08-20 08:08:57 +01:00
Lioncash
8a822def14 A64: Implement SDOT and UDOT's (by element) variants
Gets all of the dot product instructions out of the way.
2018-08-20 08:06:59 +01:00
MerryMage
b604f0d237 emit_x64_vector: Don't load zero constant from memory in EmitVectorTableLookup 2018-08-19 21:33:33 +01:00
MerryMage
8ac462fca9 emit_x64_vector: Special-case is_defaults_zero && table_size == 2 in EmitVectorTableLookup 2018-08-19 21:32:54 +01:00
MerryMage
08fae72a57 emit_x64_vector: Release registers when possible in EmitVectorTableLookup 2018-08-19 21:08:00 +01:00
MerryMage
c7d264bbe2 reg_alloc: Add the ability to Release an allocation early 2018-08-19 21:07:37 +01:00
MerryMage
3172a4b066 emit_x64_vector: Special-case table_size == 1 in EmitVectorTableLookup 2018-08-19 09:29:41 +01:00
MerryMage
50c589b2b5 emit_x64_vector: SSE4.1 implementation of EmitVectorTableLookup 2018-08-18 22:07:58 +01:00
MerryMage
bc6cf3021f A64: Implement TBL and TBX 2018-08-18 22:00:03 +01:00
MerryMage
8067ab9553 IR: Add VectorTable and VectorTableLookup IR instructions 2018-08-18 21:59:44 +01:00
MerryMage
0e0e839ba0 opcodes: Cleanup opcodes table
* Remove T:: prefix from types.
* Add another column for a 4th argument.
2018-08-18 19:39:59 +01:00
Lioncash
8e47d44c4d A64: Implement SDOT and UDOT's vector variant 2018-08-18 15:19:39 +01:00
Lioncash
3a367f341f A64: Implement SADALP and UADALP
While we're at it we can join the code for SADDLP and UADDLP with these
instructions, since the only difference is we do an accumulate at the
end of the operation.
2018-08-18 14:24:43 +01:00
Lioncash
5f322a160f A64: Implement SRSHL and URSHL
Implements both scalar and vector variants.
2018-08-18 14:23:29 +01:00
Lioncash
a278775c43 ir: Add opcodes for performing rounding left shifts 2018-08-18 14:23:29 +01:00
MerryMage
720efe337e emit_x64_floating_point: Fix smallest normal check in EmitFPMulAdd 2018-08-18 13:49:19 +01:00
Lioncash
fc96d512c9 A64: Implement ISB
Given we want to ensure that all instructions are fetched again, we can
treat an ISB instruction as a code cache flush.
2018-08-18 13:30:54 +01:00
Lioncash
2a0317198f A64: Implement FCVTN{2} 2018-08-16 23:01:38 +01:00
Lioncash
f9e084283b A64: Implement FCVTL{2} 2018-08-16 23:01:38 +01:00
Lioncash
9f873410c8 A64: Implement FMAXNM and FMINNM vector variants.
Currently we can implement these in terms of the scalar IR variants.
2018-08-16 23:00:42 +01:00
Lioncash
d5d2c36221 A64: Implement FMAXP, FMAXNMP, FMINP, and FMINNMP's vector variants
We can just implement these in terms of scalars for the time being.
2018-08-16 15:12:43 +01:00
MerryMage
1474f09d1c emit_x64_vector_floating_point: Correct value of smallest_normal_number 2018-08-16 10:55:02 +01:00
MerryMage
821cabac1b fp/info: Incorrect point_position in FPValue 2018-08-16 10:50:28 +01:00
MerryMage
550d662f0e load_store_exclusive: Define s == t state to be Constraint_NONE
Downstream (yuzu) mentioned that the instruction:

STXR W9, W9, [X0]

was executed in the program "Crash N-Sane Trilogy".
2018-08-16 10:04:54 +01:00
MerryMage
0b69381ff4 A64/translate: Allow for unpredictable behaviour to be defined 2018-08-16 09:59:06 +01:00
MerryMage
6d236d459f system: Implement MRS CNTFRQ_EL0 2018-08-16 09:58:34 +01:00
MerryMage
6cbb6fb190 A32/testenv: Add missing headers 2018-08-15 13:48:50 +01:00
MerryMage
67293289bf externals: Update xbyak to v5.67
Merge commit '1812bd20d08020bfff2ca15e23c0377a21e3cee0'
2018-08-15 13:31:03 +01:00
MerryMage
1812bd20d0 Squashed 'externals/xbyak/' changes from 2794cde7..671fc805
671fc805 update test/cybozu
8ca86231 remove mutable in Address
8b93498f add cmpsb/scasb/...
7eb62750 avoid core_sharing_data_cache = 0 for some cloud envrionment
85767e95 support mingw64
59573e6e add PROTECT_RE mode for protect()
71b75f65 fix push(qword[mem])
811f4959 Merge branch 'rsdubtso-master'
8e3cb711 Account for potentially zero 0xb leaf when parsing cache/topology via cpuid
a816249f update version
fe083912 fix to avoid zero division for some virtual machine
f0a8f7fa update version
cac09b7a Merge pull request #62 from mgouicem/master
1f96b5e0 Fixes an error raised by clang < 3.9
c0f885ac Merge pull request #61 from mgouicem/master
bfe2d201 Change default value for n_cores in setCacheHierarchy.
fd587b55 change format and add getter for data_cache_size
80b3c7b9 remove macro
88189609 Merge branch 'mgouicem-master'
e6b79723 Adding queries to get the cpu topology on Intel architectures.
221384f0 vmov* supports [mem]|k|z
c04141ef define XBYAK_NO_OP_NAMES for test
af7f05ee add const for Label

git-subtree-dir: externals/xbyak
git-subtree-split: 671fc805d09d075f48d4625f183ef2e1ef725106
2018-08-15 13:28:55 +01:00
MerryMage
9a9580290b externals: Document subtrees 2018-08-15 13:28:13 +01:00
Lioncash
714a8405bc A64: Implement SQ{ADD, SUB}, and UQ{ADD, SUB}'s vector variants
Currently we implement these in terms of the scalar variants. Falling
back to the interpreter is slow enough to make it more effective than
doing that.
2018-08-14 08:48:06 +01:00
Lioncash
8cab459661 A64: Implement UQADD/UQSUB's scalar variants 2018-08-14 08:48:06 +01:00
Lioncash
18a8151684 ir: Add opcodes for unsigned saturating add and subtract 2018-08-14 08:48:06 +01:00
Lioncash
a5660eec11 x64/reg_alloc: Use type alias for array returned by GetArgumentInfo()
This way if the number ever changes, we don't need to change the type in
other places.
2018-08-13 21:55:40 +01:00
Lioncash
29489b598e ir/value: Use type alias CoprocessorInfo for std::array<u8, 8>
Provides a more descriptive label for the interface, and avoids the need
to hardcode the array size in multiple places.
2018-08-13 21:55:14 +01:00
MerryMage
e23ba26d88 status_register_access: Add support for bits 0 and 1 of mask to MSR 2018-08-11 21:26:15 +01:00
MerryMage
55190bd792 fuzz_with_unicorn: Split utility functions into fuzz_util 2018-08-11 20:51:30 +01:00
MerryMage
23b049d2fe A32/translate/load_store: Correct detection of writeback 2018-08-11 20:51:30 +01:00
MerryMage
7ec9f15636 A32/translate: Add TranslateSingleInstruction 2018-08-11 20:51:30 +01:00
MerryMage
efeecb46ff A32/ir_emitter: Bug fix: IREmitter::ExceptionRaised using incorrect opcode 2018-08-11 18:18:29 +01:00
MerryMage
08d1d19805 A32/decoders: Split instruction list into include file 2018-08-11 18:18:29 +01:00
MerryMage
2d929cc3b3 tests: Refactor unicorn_emu to allow for A32 unicorn 2018-08-11 18:18:29 +01:00
MerryMage
f672368ac3 microinstruction: Improve assert messages 2018-08-11 10:43:40 +01:00
MerryMage
7ebff50d46 emit_x64_vector: EmitVectorNarrow16: AVX512 implementation 2018-08-10 21:57:58 +01:00
MerryMage
edce230ebe emit_x64_vector: EmitVectorNarrow32: prefer pblendw to loading constant 2018-08-10 21:57:37 +01:00
MerryMage
0118ee04f9 emit_x64_vector: packusdw is SSE4.1 2018-08-10 11:09:49 +01:00
MerryMage
4f96c63025 emit_x64_vector_floating_point: Simplify FPVector{Min,Max} 2018-08-03 11:48:17 +01:00
MerryMage
e15fdfe696 emit_x64_vector_floating_point: Simplify Get*Vector functions 2018-08-03 11:48:17 +01:00
MerryMage
734a00b608 emit_x64_floating_point: Remove EmitProcessNaNs 2018-08-03 11:48:17 +01:00
MerryMage
fd45191e44 devirtualize: Replace DEVIRT macro with function template 2018-08-03 09:09:29 +01:00
MerryMage
67ba5d0072 fuzz_with_unicorn: Remove FCVT_float from ignore list 2018-08-03 08:18:40 +01:00
Lioncash
66e6dd1cab a32_emit_x64: std::move A32::UserConfig in the constructor
This avoids a few redundant atomic increments and decrements,
considering the UserConfig instance contains a std::array of
std::shared_ptr<Coprocessor> instances.
2018-08-03 08:12:36 +01:00
MerryMage
b4890b6f32 emit_x64_floating_point: Use EmitPostProcessNaNs in EmitFPMulX 2018-08-03 07:31:51 +01:00
MerryMage
18b29435f7 emit_x64_floating_point: Remove unnecessary DenormalsAreZero from EmitFPSingleToDouble and EmitFPDoubleToSingle 2018-08-02 21:12:24 +01:00
MerryMage
df1f81f998 emit_x64_floating_point: Simplify EmitFP{Min,Max}{,Numeric}{32,64} 2018-08-02 21:09:35 +01:00
MerryMage
21fb1c3a7f emit_x64_floating_point: Reduce NaN processing overhead 2018-08-02 17:17:23 +01:00
MerryMage
f5c9f0fa5f A64: Implement FMULX, scalar single/double variant 2018-08-02 14:11:30 +01:00
MerryMage
8f4777338e IR: Implement FPMulX IR instruction 2018-08-02 14:11:14 +01:00
MerryMage
79e6440ea0 fuzz_with_unicorn: Randomize SP 2018-08-01 15:30:59 +01:00
MerryMage
33c80e3181 fuzz_with_unicorn: Randomize PC 2018-08-01 15:30:59 +01:00
MerryMage
8d41024661 testenv: Make code_mem mobile 2018-08-01 15:30:59 +01:00
Lioncash
a9fae0e610 emit_x64_vector: Vectorize 32-bit variants of paired min/max
Gets rid of the fallbacks for these cases.
2018-08-01 12:20:01 +01:00
MerryMage
8926a92a03 emit_x64_vector: Improve code emission of VectorGetElement* for index == 0 2018-07-31 22:04:11 +01:00
MerryMage
e20bd387e9 reg_alloc: Do a UseScratch if a Use destination is too small 2018-07-31 21:55:14 +01:00
MerryMage
a19fa0e294 fuzz_with_unicorn: Randomize FPCR.AHP and FPCR.FZ16 2018-07-31 21:27:24 +01:00
MerryMage
775f368205 emit_x64_floating_point: AVX implementation of ForceToDefaultNaN 2018-07-31 21:22:01 +01:00
MerryMage
71018a1faa emit_x64_vector_floating_point: Prefer blendvp{s,d} to vblendvp{s,d} where possible
It's a cheaper instruction.
2018-07-31 21:13:16 +01:00
MerryMage
137f4b3b01 backend_x64: Remove all use of xmm0 2018-07-31 20:54:16 +01:00
MerryMage
e73d67a841 emit_x64_vector_floating_point: AVX implementation of ForceToDefaultNaN 2018-07-31 20:33:50 +01:00
MerryMage
43cca54dd3 emit_x64_vector_floating_point: Reduce codesize of ForceToDefaultNaN 2018-07-31 20:25:56 +01:00
MerryMage
5dc40f49f8 emit_x64_vector_floating_point: Reduce codesize of EmitTwoOpVectorOperation 2018-07-31 20:25:03 +01:00
MerryMage
07622eedf0 emit_x64_vector_floating_point: Correct FMA in FTZ mode
x64 rounds before flushing to zero
AArch64 rounds after flushing to zero

This difference of behaviour is noticable if something would round to a smallest normalized number
2018-07-31 18:12:39 +01:00
MerryMage
621c85b90c emit_x64_floating_point: DenormalsAreZero is redundant as hardware already does DAZ
Exceptions: F{MIN,MAX}{,NM}
2018-07-31 18:05:13 +01:00
MerryMage
3d0ebaa6d6 emit_x64_floating_point: FlushToZero is redundant as hardware already does FTZ 2018-07-31 16:08:13 +01:00
MerryMage
f626ff82d0 backend_x64: Fix FPVectorMulAdd and FPMulAdd NaN handling with denormals
Denormals should be treated as zero in NaN handler
2018-07-31 16:07:46 +01:00
MerryMage
adeb9d9ba0 a32/fuzz_arm: Disable vfp tests 2018-07-31 16:01:28 +01:00
MerryMage
19ea70d3a0 fuzz_with_unicorn: Randomize FPCR.FZ 2018-07-31 15:39:39 +01:00
MerryMage
895db36543 backend_x64: Fix bugs when FPCR.FZ=1
Bugs:
* DenormalsAreZero flushed to positive zero instead of preserving sign.
* FMAXNM/FMINNM (scalar) should perform DAZ *before* special zero handling.
* FMAX/FMIN/FMAXNM/FMINNM (vector) did not DAZ.
2018-07-31 15:39:33 +01:00
MerryMage
d7e2de2659 fuzz_with_unicorn: Extract RandomFpcr function
Deduplicate randomization of fpcr and make use of FP::FPCR
2018-07-31 12:35:04 +01:00
MerryMage
c858d6c7b4 fp/info: Deduplicate functions 2018-07-30 20:25:29 +01:00
MerryMage
5b88ec252c emit_x64_floating_point: Deduplicate EmitFPMulAdd implementation 2018-07-30 20:16:45 +01:00
MerryMage
73d3efc3e0 emit_x64_floating_point: Deduplicate code 2018-07-30 15:13:43 +01:00
MerryMage
c9508c3d13 fuzz_with_unicorn: Randomize FPCR.DN 2018-07-30 14:52:22 +01:00
MerryMage
29708331bb emit_x64_vector_floating_point: Fix FPVector{Max,Min} when FPCR.DN = 1 2018-07-30 14:52:22 +01:00
MerryMage
150764f718 emit_x64_floating_point: Fix FP{Max,Min} when FPCR.DN = 1 2018-07-30 14:52:22 +01:00
MerryMage
b7d209cfa4 IR: SSE4.1 implementation of FPVectorRoundInt 2018-07-30 14:52:22 +01:00
MerryMage
8cf8270139 A64: Implement FRINT{N,M,P,Z,A,X,I} (vector), single/double variant 2018-07-30 13:32:20 +01:00
MerryMage
8f46c26d26 IR: Initial implementation of FPVectorRoundInt 2018-07-30 13:31:51 +01:00
MerryMage
97017bbdf7 A64: Implement SQADD and SQSUB, scalar variant 2018-07-30 11:01:38 +01:00
MerryMage
ce58863903 IR: Generalise SignedSaturated{Add,Sub} to support more bitwidths 2018-07-30 11:01:36 +01:00
MerryMage
e80f8ff244 a64_emit_x64: Bugfix EmitA64OrQC - Incorrect argument 2018-07-30 11:00:37 +01:00
Lioncash
1e4ec7e1f0 simd_three_same: Extract non-paired SMAX, SMIN, UMAX, UMIN code to a common function
Deduplicates a bit of code and makes its layout consistent with the
paired variants
2018-07-30 08:40:32 +01:00
Lioncash
6f9dc9b143 A64: Implement SMAXP, SMINP, UMAXP, UMINP 2018-07-30 08:40:32 +01:00
Lioncash
1dfb29fc14 ir: Add opcodes for vector paired maximum and minimums
For the time being, we can just do a naive implementation which avoids
falling back to the interpreter a bit. Horizontal operations aren't
necessarily x86 SIMD's forte anyways.
2018-07-30 08:40:32 +01:00
Lioncash
017b51095f A64: Implement SMAXV, SMINV, UMAXV, and UMINV 2018-07-30 08:39:33 +01:00
Lioncash
aae22eec26 ir: Add opcodes for performing scalar integral min/max 2018-07-30 08:39:33 +01:00
Lioncash
6ef3af3bc9 A64: Implement PMULL{2} 2018-07-29 10:04:58 +01:00
Lioncash
2a4ce19af3 translate: Deduplicate GetDataSize() functions
Avoids defining the same function multiple times in different files.
2018-07-29 10:00:34 +01:00
Lioncash
0e015008af floating_point_{conditional}_compare: Deduplicate code
Deduplicates the implementation code of instructions by extracting the
code to a common function.
2018-07-29 10:00:34 +01:00
MerryMage
259237ce58 common: Move all cryptographic function to common/crypto 2018-07-29 08:49:12 +01:00
MerryMage
c5f1080b40 a32_emit_x64: BMI2 implementation of A32SetCpsr 2018-07-27 11:41:31 +01:00
MerryMage
a23304a16c a32_emit_x64: Shorten EmitA32GetCpsr 2018-07-27 11:24:06 +01:00
MerryMage
57604d2ea8 a32_emit_x64: Assert that memory layout assumption in EmitA32GetCpsr is valid 2018-07-26 19:26:01 +01:00
Lioncash
945fa48667 A64: Implement PMUL 2018-07-26 16:16:30 +01:00
Lioncash
656a4042a2 ir: Add opcode for performing polynomial multiplication 2018-07-26 16:16:30 +01:00
MerryMage
05143df9d8 A64: Implement FCVT{N,M,A,P}{U,S} (vector), FCVTZU (vector, integer), single/double variant 2018-07-26 12:48:36 +01:00
MerryMage
34ce767a00 A64: Implement FCVTZS (vector, integer), single/double variant 2018-07-26 12:48:36 +01:00
MerryMage
0f9bc2d391 IR: Implement FPVectorTo{Signed,Unsigned}Fixed 2018-07-26 12:48:36 +01:00
MerryMage
0189e4454a fp/info: Replace constant value generators with FPValue
Instead of having multiple different functions we can just have one.
2018-07-26 11:35:35 +01:00
MerryMage
db165684c0 emit_x64_vector_floating_point: AVX implementation of FPVector{Max,Min} 2018-07-26 10:10:47 +01:00
MerryMage
31148bdb42 emit_x64_vector_floating_point: Remove unnecessary double jump in HandleNaNs 2018-07-26 09:42:34 +01:00
Lioncash
4c3ca51e86 A64: Implement FMAX's vector single and double precision variants 2018-07-26 09:32:02 +01:00
Lioncash
bf0f21cc12 A64: Implement FMIN's vector single and double precision variants 2018-07-26 09:32:02 +01:00
MerryMage
76f0ca04d6 IR: Implement FPVector{Max,Min} 2018-07-26 09:31:56 +01:00
MerryMage
6c37c311de FPRecipEstimate: Move offset out of function
MSVC has weird lambda capturing rules.
2018-07-25 19:22:35 +01:00
MerryMage
59546f3c60 microinstruction: Update ReadsFromAndWritesToFPSRCumulativeExceptionBits 2018-07-25 19:17:07 +01:00
MerryMage
3f6b03a06b A64: Implement FRECPS, vector/scalar single/double variants 2018-07-25 19:14:23 +01:00
MerryMage
2d2ca5ebc1 IR: Implement FPRecipStepFused, FPVectorRecipStepFused 2018-07-25 19:14:23 +01:00
MerryMage
5cb9f1dab2 A64: Implement FRECPE, vector single/double variant 2018-07-25 18:55:58 +01:00
MerryMage
c5a14ab21b IR: Implement FPVectorRecipEstimate 2018-07-25 18:55:40 +01:00
MerryMage
56f8a0b172 A64: Implement FRECPE, scalar single/double variant 2018-07-25 18:47:45 +01:00
MerryMage
fde69b4d36 IR: Implement FPRecipEstimate 2018-07-25 18:47:22 +01:00
MerryMage
186e52ca50 IR: Implement FPRecipEstimate 2018-07-25 18:36:40 +01:00
MerryMage
cf2e1aed96 fp: Change FPUnpacked to a normalized representation
Having a known position for the highest set bit makes writing algorithms easier
2018-07-25 17:42:36 +01:00
MerryMage
98e2380129 fuzz_with_unicorn: Disable testing of FDIV 2018-07-25 14:05:13 +01:00
MerryMage
041b7d5e17 block_of_code: Add ABI_PARAMS array 2018-07-25 13:59:14 +01:00
MerryMage
2a2371c7a5 A64: Implement MLA, MLS (by element), vector single/double variant 2018-07-25 13:58:34 +01:00
MerryMage
78c640ad9e A64: Implement FMLS (vector), single/double variant 2018-07-25 13:45:02 +01:00
MerryMage
b6b6993884 emit_x64_vector_floating_point: Specify NanHandler::function_type explicitly
MSVC doesn't like dealing with auto return types
2018-07-25 13:38:32 +01:00
MerryMage
4b9d12a585 emit_x64_vector_floating_point: ChooseOnFsize arguments maybe_unused 2018-07-25 13:27:31 +01:00
MerryMage
b1e3616de2 IR: Implement FPVectorNeg 2018-07-25 13:25:35 +01:00
MerryMage
4343612ec4 A64: Implement FMLA (vector), single/double variant 2018-07-25 13:20:07 +01:00
MerryMage
93eeb25fac IR: Implement FPVectorMulAdd 2018-07-25 13:19:48 +01:00
MerryMage
57e5c7e7a5 emit_x64_vector_floating_point: Standardize naming scheme 2018-07-25 12:08:00 +01:00
MerryMage
bcb9e4106d emit_x64_floating_point: Simplify indexers 2018-07-25 12:05:41 +01:00
MerryMage
83aa5854b6 emit_x64_vector_floating_point: Simplify EmitVectorOperation* 2018-07-25 11:34:22 +01:00
MerryMage
f4087c81e5 mp: rename mp.h to mp/function_info.h 2018-07-25 11:28:36 +01:00
MerryMage
18640903ac emit_x64_vector: Slightly improve ArithmeticShiftRightByte 2018-07-25 09:33:02 +01:00
MerryMage
e048441d44 emit_x64_vector: Simplify VectorShuffleImpl 2018-07-24 22:46:45 +01:00
MerryMage
ff025e88d0 IR: Implement A64OrQC 2018-07-24 19:04:40 +01:00
MerryMage
6fac68dd1d A64: Implement UQSHRN, UQRSHRN (vector) 2018-07-24 18:54:28 +01:00
MerryMage
5a8d9c3487 emit_x64_vector: -0x80000000 isn't -0x80000000 2018-07-24 18:45:45 +01:00
MerryMage
759289ec5c A64: Implement UQXTN (vector) 2018-07-24 18:31:32 +01:00
MerryMage
2a96281587 emit_x64_vector: Fix non-SSE4.1 saturated narrowing reconstruction comparison
Allows non-SSE4.1 to produce the correct FPSR.QC flag
2018-07-24 18:17:14 +01:00
MerryMage
0682353626 A64: Implement SQXTN (vector) 2018-07-24 17:59:14 +01:00
MerryMage
6c5229ed47 emit_x64_vector: packusdw reqiures SSE4.1
In EmitVectorSignedSaturatedNarrowToUnsigned32.
2018-07-24 17:32:00 +01:00
MerryMage
158d9b16f0 A64: Implement SQSHRUN, SQRSHRUN (vector) 2018-07-24 17:20:49 +01:00
MerryMage
f886013526 simd_shift_by_immediate: Simplify ShiftRight 2018-07-24 16:38:51 +01:00
MerryMage
d9b59c69de A64: Implement SQXTUN 2018-07-24 16:32:10 +01:00
MerryMage
50fe28b976 microinstruction: Reorganize FPSCR related instruction queries 2018-07-24 12:13:18 +01:00
Lioncash
d9d036acc9 microinstruction: Add missing FP scalar opcodes to ReadsFromFPSCR() and WritesToFPSCR()
These were forgotten when the opcodes were added.
2018-07-24 11:55:15 +01:00
Lioncash
db96163637 u128: Make Bit() a const-qualified member function
This function doesn't modify the struct members, so it can be made
const.
2018-07-24 09:15:44 +01:00
MerryMage
f7052ae04d A64: Implement FRSQRTS (vector), single/double variant 2018-07-23 22:58:52 +01:00
MerryMage
0925ef6248 A64: Implement FRSQRTE (vector), single/double variant 2018-07-23 22:46:12 +01:00
MerryMage
f4cbbe3218 A64: Implement FRSQRTS (scalar), single/double variant 2018-07-23 22:05:17 +01:00
MerryMage
4ef864e81c IR: Implement FPRSqrtStepFused 2018-07-23 22:05:17 +01:00
MerryMage
9dffeebc44 fp: Implement FPRSqrtStepFused 2018-07-23 22:05:17 +01:00
MerryMage
aa0455667e fp: Implement FPNeg 2018-07-23 22:03:07 +01:00
MerryMage
cbde1c5a15 process_nan: Add two operand variant 2018-07-23 22:03:07 +01:00
Lioncash
1ec2663de3 A64: Implement FMAXP, FMINP, FMAXNMP and FMINNMP's scalar double/single-precision variant 2018-07-23 21:22:32 +01:00
MerryMage
027ddf9e2c emit_x64_floating_point: Fixup special NaN case in FMA FPMulAdd implementation 2018-07-23 21:10:52 +01:00
Lioncash
75a9f7799a fp: Use a forward declaration in fused.h
It's permissible to forward declare here, so we can do so and eliminate
a direct header dependency
2018-07-23 20:46:34 +01:00
Lioncash
1ee16303bd u128: Implement comparison operators in terms of one another
We can just implement the comparisons in terms of operator< and
implement inequality with the negation of operator==.
2018-07-23 20:23:10 +01:00
MerryMage
3b77f48a76 tests: Print cpu info 2018-07-23 20:22:38 +01:00
MerryMage
bed3cc03f9 u128: StickyLogicalShiftRight requires special-casing for amount == 64
In this case (128 - amount) == 64, and this invokes undefined behaviour
2018-07-23 20:22:01 +01:00
Lioncash
15d04f489b A64: Implement FMLA and FMLS (by element)'s double/single-precision scalar variant 2018-07-23 19:13:39 +01:00
Lioncash
7cfccdfa29 A64: Implement FMUL (by element)'s scalar double/single-precision variant 2018-07-23 19:13:39 +01:00
MerryMage
7d2d62ece7 emit_x64_floating_point: Implement accurate fallback for FPMulAdd{32,64} 2018-07-23 18:52:09 +01:00
MerryMage
a599eacebf fp: Implement FPMulAdd 2018-07-23 18:52:07 +01:00
MerryMage
d70b90ed5d process_nan: Add FPProcessNaNs3 2018-07-23 18:51:36 +01:00
MerryMage
38ef0e04cb block_of_code: Add SysV ABI fifth and sixth parameters 2018-07-23 18:51:36 +01:00
MerryMage
8e2ff56569 u128: Add StickyLogicalShiftRight 2018-07-23 18:51:36 +01:00
MerryMage
3b337df076 u128: Add Multiply64To128 2018-07-23 18:51:36 +01:00
MerryMage
8219075ea3 u128: Add u128::Bit 2018-07-23 18:51:11 +01:00
MerryMage
a574dcb2ae u128: Add comparison operators 2018-07-23 18:51:11 +01:00
MerryMage
391d6d46a4 unpacked: Use ResidualErrorOnRightShift in FPRoundBase
Fixes a bug relating to exponents that are severely out of range.
2018-07-23 18:29:44 +01:00
MerryMage
5e0cf9c83e fp: Remove MantissaT 2018-07-23 14:23:47 +01:00
MerryMage
8c0a84cbd3 FPRSqrtEstimate: Improve documentation of RecipSqrtEstimate 2018-07-23 11:26:51 +01:00
Lioncash
c41d8552a7 FPRSqrtEstimate: Deduplicate array bounds
Dehardcodes a few constants in the loops.
2018-07-23 10:56:46 +01:00
Lioncash
4cf055ba47 A64: Implement FMAXV, FMINV, FMAXNMV, and FMINNMV 2018-07-23 10:45:12 +01:00
Lioncash
bf24f0febf FPRSqrtEstimate: Use forward declarations where applicable 2018-07-23 10:36:49 +01:00
Lioncash
206230e9c4 translate: Return by bool in helpers where applicable
Gets rid of a bit of duplication regarding the early-out cases and makes
all helpers functions consistent (previously some had a return type of
bool, while others had a return type of void).
2018-07-23 10:36:28 +01:00
Lioncash
346b725878 Simplify fallback case for EmitVectorSetElement64() 2018-07-23 10:34:44 +01:00
MerryMage
2c34e1d964 emit_x64_floating_point: s/Esimate/Estimate/ 2018-07-22 21:49:08 +01:00
MerryMage
5213fb670d simd_scalar_two_register_misc: Implement FRSQRTE, scalar variant 2018-07-22 18:35:43 +01:00
MerryMage
7ed089fd8e IR: Implement FPRSqrtEstimate 2018-07-22 18:35:43 +01:00
MerryMage
cd2e286313 simd_vector_x_indexed_element: Implement FMUL (by element), vector variant 2018-07-22 17:43:08 +01:00
MerryMage
fc6b73bd85 a64_emit_x64: Ensure host has updated ticks in EmitA64GetCNTPCT
Discovered by @Subv.
Fixes incomplete fix begun in 5a91c94dca47c9702dee20fbd5ae1f4c07eef9df.
That fix fails to take into account that LinkBlock doesn't update ticks until there
are no remaining ticks to be executed.

Test added to confirm fix.
2018-07-22 16:16:26 +01:00
MerryMage
888c6783a1 a64_emit_x64: Fix stack misalignment on Windows for 128-bit exclusive writes
Discovered by @Subv.
Includes a test to ensure this codepath is exercised on Windows.
2018-07-22 15:26:25 +01:00
Lioncash
352d53908a emit_x64_aes: Eliminate extraneous usage of a scratch register in EmitAESInverseMixColumns()
We can just use the same register the data is in as the result register,
eliminating the need to use a completely separate register to store the
result.
2018-07-22 07:06:09 +01:00
Lioncash
ab7fe77799 A64: Implement SADDLV 2018-07-22 07:05:36 +01:00
Lioncash
09bd2b2c6e A64: Implement UADDLV 2018-07-22 07:05:36 +01:00
Lioncash
62e86d7287 fp: Use forward declarations where applicable
Minimizes the amount of files that need to be rebuilt if the headers
ever change.
2018-07-22 07:04:47 +01:00
Lioncash
b3edb7a956 emit_x64_vector: Append 'v' prefix onto movq in AVX path
This is something I missed when adding in the AVX broadcast code.
2018-07-22 07:04:35 +01:00
Subv
7ea1241953 A64: The A64SetTPIDR IR instruction writes to a system register and should not be eliminated by the dead code elimination pass.
Previously this instruction was alway eliminated, resulting in incorrect values for TPIDR_EL0.
2018-07-21 09:34:23 +01:00
MerryMage
853bdd6b98 fp: A64::FPCR -> FP::FPCR 2018-07-20 11:39:39 +01:00
MerryMage
faa3ea2f2a bit_util: Implement ClearBits and ModifyBits 2018-07-20 11:39:30 +01:00
MerryMage
f659f0fb5c system: Simplify static_cast 2018-07-19 12:03:23 +01:00
Lioncash
9db6794f59 externals: Update Xbyak to 5.65 2018-07-19 10:43:26 +01:00
MerryMage
5a91c94dca system: Ensure value of CNTPCT_EL0 is accurate
Since we currently only update the host's tick count at the end of a
block, we force an end-of-block before executing a MRS %, CNTPCT_ELO
instruction.
2018-07-19 02:37:28 +01:00
Lioncash
1e303aa1f3 safe_ops: Avoid cases where shift bases are invalid with signed values
For example, say the converted signed type is s64, shifting left  by 63
bits would be undefined behavior.

However, given an ASL is essentially the same behavior as an LSL
we can just use an unsigned type instead of converting to a signed type.
2018-07-17 21:24:34 +01:00
Lioncash
e3d533d954 safe_ops: Avoid signed overflow in Negate()
Negation of values such as -9223372036854775808 can't be represented in
signed equivalents (such as long long), leading to signed overflow.
Therefore, we can just invert bits and add 1 to perform this behavior
with unsigned arithmetic.
2018-07-17 21:24:34 +01:00
Lioncash
6bf7280179 simd_scalar_shift_by_immediate: Implement FCVT{ZS, ZU} (vector, fixed-point)'s scalar double/single-precision variant 2018-07-17 19:45:58 +01:00
Lioncash
be860cf7e1 simd_scalar_two_register_misc: Implement FCVT{AS, AU, MS, MU, NS, NU, PS, PU, ZS, ZU} (vector)'s scalar double/single-precision variants
We can simply implement this in terms of the fixed-point IR opcodes.
2018-07-17 19:45:58 +01:00
Lioncash
cae96d1da5 tests: Silence warnings in skyeye code
Gets rid of warning noise when compiling the tests.
2018-07-17 19:44:10 +01:00
Lioncash
adbb8964c6 emit_x64: Remove FPSCR_RoundTowardsZero() virtual function from EmitContext struct
This code was bugged in that we were comparing if the rounding mode was
not equal to rounding towards zero. Fortunately, however, nothing uses
this function anymore, and there's already the more general
FPSCR_RMode() available, so this can be removed entirely.
2018-07-17 19:27:33 +01:00
Lioncash
6bcc766729 emit_x64: Add missing <array> include
Commit 755adef62e504a8d616de9dda8937d2428a9471b introduced a helper
alias for std::array, eliminating the need to manually type out sizes
for them, however I forgot to add the include for <array>
2018-07-17 19:00:00 +01:00
Lioncash
755adef62e emit_x64_vector{_floating_point}: Add helper alias for sizing arrays relative to vector width
Avoids needing to remember to specify the proper size of the arrays, all
that's needed is to specify the type of the array and the size will
automatically be deduced from it. This helps prevent potential oversized
or undersized arrays from being specified.
2018-07-17 17:54:22 +01:00
MerryMage
0c3b6bd11f A64/PopRSBHint: Prevent RETing to a guest PC of ~0ull from crashing the jit 2018-07-16 18:29:25 +01:00
MerryMage
5ae55914e2 tests: Add FABD test 2018-07-16 16:55:26 +01:00
MerryMage
39958434b6 A64: Implement FABD in terms of existing IR instructions
Fixes NaN issue. Closes #306.
2018-07-16 16:51:16 +01:00
MerryMage
4a3453179b FPRoundInt: Final FPRound based on new sign
While this shouldn't change any of the results in theory, it's just logically more consistent
2018-07-16 15:07:26 +01:00
MerryMage
5879b5f73f emit_x64_floating_point: SSE4.1 implementation of EmitFPRound 2018-07-16 14:22:29 +01:00
MerryMage
a981d3ffb1 A64: Implement FRINTX, FRINTI (scalar) 2018-07-16 14:10:53 +01:00
MerryMage
aa315c97b9 A64: Implement FRINTP, FRINTM, FRINTZ (scalar) 2018-07-16 14:10:53 +01:00
MerryMage
80aa4f49e6 A64: Implement FRINTN (scalar) 2018-07-16 14:10:53 +01:00
MerryMage
eaf4106620 A64: Implement FRINTA (scalar) 2018-07-16 14:10:53 +01:00
MerryMage
48166d80cd IR: Implement FPRoundInt 2018-07-16 14:10:53 +01:00
MerryMage
f600f48bdd fp: Implement FPRoundInt 2018-07-16 13:50:37 +01:00
MerryMage
a8952a521b fp: Implement FPProcessNaN 2018-07-16 13:50:37 +01:00
MerryMage
4ba4ed2dca fp/info: Add DefaultNaN 2018-07-16 13:50:37 +01:00
MerryMage
b08e49d337 fp: Move FPToFixed to its own file 2018-07-16 13:50:37 +01:00
MerryMage
814092c5be a64_jit_state: Add FPSR.QC flag 2018-07-16 13:50:37 +01:00
Lioncash
54c6d119ba emit_x64_vector: Use non-scratch Use* variants of registers within EmitVectorUnsignedAbsoluteDifference()
In some cases, a register isn't modified, depending on the branch taken,
so we can signify this by using the non-scratch variants in certain
cases.
2018-07-16 10:35:51 +01:00
Lioncash
ca579d2603 simd_scalar_two_register_misc: Implement scalar double/single-precision variants of FCM{EQ, GE, GT, LE, LT} (zero) 2018-07-16 10:35:26 +01:00
Lioncash
3b3e1c0991 translate_arm: Remove unnecessary rotr() function
We already have RotateRight() in our common code, so we can remove this
function and replace it with it. We can also implement ArmExpandImm_C()
in terms of ArmExpandImm().
2018-07-16 10:32:46 +01:00
Merry
dda07710e1
Merge pull request #309 from lioncash/typename
cast_util: Remove unnecessary typename
2018-07-16 10:18:03 +01:00
Lioncash
13df147ffb
cast_util: Remove unnecessary typename
Given we use std::aligned_storage_t, we don't need to specify
typename here. If we used std::aligned_storage, then we would need to.
2018-07-15 19:38:02 -04:00
MerryMage
41074a2547 A64: Implement FADDP (scalar) 2018-07-15 22:49:58 +01:00
MerryMage
59e78dc57e A64: Implement FADDP (vector) 2018-07-15 22:49:58 +01:00
MerryMage
dfdec797e3 A64: Implement SADDLP 2018-07-15 18:50:09 +01:00
MerryMage
3bb6a432d8 A64: Implement UADDLP 2018-07-15 18:26:54 +01:00
MerryMage
c103a28386 A64: Implement EXT 2018-07-15 17:47:32 +01:00
Merry
f23475764f
Merge pull request #289 from MerryMage/fptofixed
Implement most of the scalar fp -> integer instructions
2018-07-15 17:12:52 +01:00
MerryMage
d870a75417 emit_x64_floating_point: SSE4.1 implementation for FP{Double,Single}ToFixed{S,U}{32,64} 2018-07-15 17:03:40 +01:00
MerryMage
f0910c357a A64: Implement FCVTMU (scalar) 2018-07-15 15:37:29 +01:00
MerryMage
dd6772786e A64: Implement FCVTMS (scalar) 2018-07-15 15:37:29 +01:00
MerryMage
5b82fa8018 A64: Implement FCVTPU (scalar) 2018-07-15 15:37:29 +01:00
MerryMage
79c4e922db A64: Implement FCVTPS (scalar) 2018-07-15 15:37:29 +01:00
MerryMage
128db2f62a A64: Implement FCVTAU (scalar) 2018-07-15 15:37:29 +01:00
MerryMage
bb92f95b9d A64: Implement FCVTAS (scalar) 2018-07-15 15:37:29 +01:00
MerryMage
8cad14eee6 A64: Implement FCVTNU (scalar) 2018-07-15 15:37:29 +01:00
MerryMage
d3e8cf3e15 A64: Implement FCVTNS (scalar) 2018-07-15 15:37:29 +01:00
MerryMage
ec0c7e1acd floating_point_conversion_integer: Refactor implementation of FCVTZS_float_int and FCVTZU_float_int 2018-07-15 15:37:29 +01:00
MerryMage
2f567fe003 IR: Initial implementation of FP{Double,Single}ToFixed{S,U}{32,64}
This implementation just falls-back to the software floating point implementation.
2018-07-15 15:37:29 +01:00
MerryMage
564c1b091f EmitContext: Expose FPCR 2018-07-15 15:37:29 +01:00
MerryMage
5e16785b3a fp/op: Implement FPToFixed 2018-07-15 15:37:29 +01:00
MerryMage
b5658dc310 mantissa_util: Implement ResidualErrorOnRightShift
Accurately calculate residual error that is shifted out
2018-07-15 15:37:29 +01:00
MerryMage
4425da9684 tests/fp: Add FPRound tests 2018-07-15 15:37:28 +01:00
MerryMage
cbedf2d498 fp/unpacked: Implement FPRound 2018-07-15 15:37:28 +01:00
MerryMage
b4cf436bfa FPCR: Add AHP setter and FZ16 getter 2018-07-15 15:37:28 +01:00
MerryMage
50ec57e372 mp: Implement metaprogramming library 2018-07-15 15:37:28 +01:00
MerryMage
64f4d14b39 fp: Implement FPUnpack 2018-07-15 14:32:06 +01:00
MerryMage
909e9aae2e fp: Implement FPProcessException 2018-07-15 14:32:06 +01:00
MerryMage
f6cdd58976 fp: Move fp_util to fp/util 2018-07-15 14:32:06 +01:00
MerryMage
60f5ef3a11 fp: Add FPSR 2018-07-15 14:32:06 +01:00
MerryMage
2384b7e6a0 fp: Add FPInfo
Provides information about floating-point format for various bit sizes
2018-07-15 14:32:06 +01:00
MerryMage
af82bc4871 safe_ops: Implement safe shifting operations
Implement shifiting operations that perform consistently across architectures
without running into undefined or implemented-defined behaviour.
2018-07-15 14:32:06 +01:00
MerryMage
a3a8efb018 bit_util: Implement MostSignificantBit 2018-07-15 14:32:06 +01:00
MerryMage
3f2194dcba bit_util: Use Ones to implement Bits 2018-07-15 14:32:06 +01:00
MerryMage
c319c4a193 bit_util: Add ClearBit and ModifyBit 2018-07-15 14:32:06 +01:00
MerryMage
639b0bb493 u128: Implement u128
For when we need a 128-bit integer
2018-07-15 14:32:06 +01:00
Lioncash
6c6cdcec10 A64: Implement UCVTF (vector, integer)'s double/single-precision variant 2018-07-15 12:46:35 +01:00
Lioncash
d921423160 ir: Add opcodes for vector conversion of u32/u64 to floating-point 2018-07-15 12:46:35 +01:00
Lioncash
8754289927 simd_three_different: Deduplicate common implementations
Generally, the only difference between the signed variants and the
unsigned variants is whether or not we use a sign-extension or
zero-extension, so we can simply use common functions to implement both
cases without totally duplicating code twice here.
2018-07-15 12:44:49 +01:00
Lioncash
c396261092 floating_point_conversion_integer: Handle S64/U64 -> F32 conversions in SCVTF_float_int and UCVTF_float_int 2018-07-15 12:29:26 +01:00
Lioncash
0b2c6c4eb8 ir: Add opcodes for converting S64 and U64 to single-precision floating-point values 2018-07-15 12:29:26 +01:00
Lioncash
1dc24b6d2e constant_pool: Remove unnecessary std::memset from constructor
AllocateFromCodeSpace() already zeroes out the allocated memory.
2018-07-15 12:12:28 +01:00
MerryMage
9dd908de1d fuzz_with_unicorn: Avoid self-modifying code
* Don't immediately terminate when unicorn raises an interrupt
* Detect self-modifying code
2018-07-15 12:07:52 +01:00
MerryMage
b81a9a52e1 fuzz_with_unicorn: Configure as per qemu max configuration 2018-07-14 08:51:08 +01:00
Lioncash
751bc31b60 tests/A32/testenv: Add type aliases for register arrays
Allows avoiding duplicating std::array instance sizes and types.
2018-07-14 08:22:18 +01:00
Lioncash
badc29f2ea tests/unicorn: Add type aliases to the Unicorn class
Centralizes all register and vector array definitions to a single set of
aliases, so if these are ever changed, then the rest of the testing code
will follow suit without the need to manually change them.
2018-07-14 08:22:18 +01:00
Lioncash
ca7a35f55f A64: Implement ADDV 2018-07-14 08:18:51 +01:00
Lioncash
5b5d79144e emit_x64_vector: Vectorize fallback path for EmitVectorMaxU32() 2018-07-14 08:17:46 +01:00
Lioncash
563959908b simd_three_same: Join FPAbsoluteComparison() into FPCompareRegister()
These are part of the same comparison family, so there's no real point
in keeping them separate.
2018-07-14 07:50:37 +01:00
Lioncash
7391f70318 A64: Implement scalar double/single-precision variants of FACGE, FACGT, FCMEQ, FCMGE, FCMGT 2018-07-14 07:50:37 +01:00
MerryMage
dbfdb2506a emit_x64_floating_point: Fix EmitFPU64ToDouble for TowardsMinusInfinity rounding mode 2018-07-14 07:11:32 +01:00
MerryMage
e292ac2e7b backend_x86: Add FPSCR_RMode to EmitContext 2018-07-14 07:11:32 +01:00
MerryMage
22cd3bac86 tests/A64: Randomize FPCR.RMode for single random instruction 2018-07-14 07:11:32 +01:00
MerryMage
c277e6f988 fp: Extract common RoundingMode enum 2018-07-14 07:11:32 +01:00
Lioncash
1bfac4aed0 inst_gen: Compress loop into std::any_of in IsInvalidInstruction()
Same behavior, but using a more self-documenting function.
2018-07-13 18:28:38 +01:00
Lioncash
a665470545 fuzz_with_unicorn: Move std::vector outside loop in small random block test case
Avoids constructing and destructing the vector repeatedly, we can just
alter the contents of the vector on each iteration instead. Also move
out the std::array instances as well, like with the floating-point test
case and the single random instruction test case.

We can also use the regular form of std::generate and avoid hardcoding
size values twice.
2018-07-13 14:48:09 +01:00
MerryMage
537df2e0b8 fuzz_with_unicorn: Temporarily disable FDIV 2018-07-12 22:34:58 +01:00
MerryMage
28786e6ee2 tests/A64: Test small blocks 2018-07-12 22:34:58 +01:00
MerryMage
fc5870d592 fuzz_with_unicorn: Randomize FPCR.RMode 2018-07-12 13:52:29 +01:00
Lioncash
d2406bf42b floating_point_conversion_integer: Use FPS64ToDouble and FPU64ToDouble in SCVTF_float_int and UCVTF_float_int
The opcodes introduced in 979b6f39f1621b80bd463645ec5b08661cb6b1bf can
also be used here, avoiding more falling back to the interpreter.
2018-07-10 00:27:10 +01:00
Lioncash
6fc9e127fe simd_scalar_two_register_misc: Handle 64-bit case in SCVTF and UCVTF's scalar double/single-precision variant
Avoids falling back to the interpreter in the 64-bit case.
2018-07-10 00:15:19 +01:00
Lioncash
08572fa670 emit_x64_floating_point: Correct use of UseGpr() in EmitFPU32ToDouble() and EmitFPU32ToSingle()
In the non-AVX512 path, the following code is present:

code.mov(from.cvt32(), from.cvt32());

since this potentially modifies 'from', we should be using
UseScratchGpr() instead.
2018-07-10 00:15:19 +01:00
Lioncash
c121a7c611 emit_x64_floating_point: Add AVX512F conversion operations to EmitFPU32ToSingle() and EmitFPU32ToDouble()
AVX-512F provides convenient instructions for these kinds of conversions
directly
2018-07-10 00:15:19 +01:00
Lioncash
979b6f39f1 ir: Add opcodes for converting S64 and U64 to double-precision values 2018-07-10 00:15:19 +01:00
MerryMage
5573953428 Merge branch 'global_monitor' 2018-07-07 22:52:50 +01:00
Lioncash
0ae8540234 simd_two_register_misc: Utilize FPVectorAbs in FABS implementations
Since we already have opcodes introduced to implement FACGE and FACGT,
we can reutilize it for the FABS implementations.
2018-07-07 21:42:42 +01:00
Lioncash
c566307b87 ir: Extend FPVectorAbs opcode to also handle 16-bit elements for FP16 2018-07-07 21:42:42 +01:00
Lioncash
9760ea1f93 A64: Implement FACGE's vector single/double precision variants 2018-07-07 14:49:47 +01:00
Lioncash
488ebdb793 A64: Implement FACGT's vector single/double precision variants 2018-07-07 14:49:47 +01:00
Lioncash
f769be89dc ir: Add opcodes for performing vector absolute floating-point values
This will be usable for implementing FACGE and FACGT
2018-07-07 14:49:47 +01:00
Lioncash
402032d107 emit_x64_vector: Deduplicate a bit of code in EmitVectorSetElement{8, 32, 64} functions
Given both branches are the same, we can hoist out the common code.
2018-07-07 14:49:14 +01:00
Lioncash
f7d11baa1c A64: Implement load/store single structure instructions
Implements LD{1, 2, 3, 4}, LD{1, 2, 3, 4}R, and ST{1, 2, 3, 4} single
structure variants.
2018-07-06 23:01:35 +01:00
Lioncash
c4be14d5bf emit_x64_vector: Deduplicate a bit of code within EmitVectorGetElement8()
Given both branches use the same destination register size, we can hoist
the common code out.
2018-07-06 23:00:58 +01:00
MerryMage
a6432b7e5b A64: Add ClearExclusiveState method 2018-07-04 00:05:14 +01:00
MerryMage
86cd8c9a69 tests: Add print_info program
Eases debugging by printing out dynarmic IR for a given A64 instruction, along with
information about what instruction dynarmic thinks it is.

Also prints an LLVM disassembly of the instruction.
2018-06-27 21:23:14 +01:00
MerryMage
f4e824d396 ir/basic_block: Add missing U16 immediate type to DumpBlock 2018-06-27 21:23:05 +01:00
MerryMage
89a2b80c1f llvm_disassemble: Allow disassembly of invalid AArch64 instructions 2018-06-27 21:22:53 +01:00
Lioncash
11941f70e1 externals: Update catch to v2.2.3
Keeps the unit-testing library up to date.
2018-06-09 22:33:57 +01:00
Lioncash
96c4b1e793 A64: Implement FABD's scalar single/double precision variant 2018-06-09 10:28:45 +01:00
Lioncash
2b0df59e7b A64: Implement FABD's vector single/double precision variant 2018-06-09 10:28:45 +01:00
Lioncash
cfeda05286 ir: Add opcode for performing FP vector absolute differences 2018-06-09 10:28:45 +01:00
MerryMage
c15c9e7049 A64: Implement FNMSUB 2018-06-08 15:23:44 +01:00
MerryMage
6ad682c1c4 A64: Implement FNMADD 2018-06-08 15:23:42 +01:00
MerryMage
a0093c031f A64: Implement FMSUB 2018-06-08 15:23:40 +01:00
MerryMage
4a2c374500 A64: Implement FMADD 2018-06-08 15:23:37 +01:00
MerryMage
f05cb06244 IR: Implement FPMulAdd 2018-06-08 15:23:35 +01:00
Lioncash
0299f05698 A64: Implement FCMGT, FCMGE (register) vector double and single precision variants 2018-06-05 17:21:35 +01:00
Lioncash
7454c8a93a A64: Implement FCMGT, FCMGE, FCMLE, FCMLT (zero) vector double and single precision variants. 2018-06-05 17:21:35 +01:00
Lioncash
21a38854e5 ir: Add opcode for floating-point GE and GT comparisons
The rest of the comparisons can be implemented in terms of these two
2018-06-05 17:21:35 +01:00
MerryMage
614840940e a64_emit_x64: Clear exclusive state in EmitA64CallSupervisor
The kernel would have to execute an ERET instruction to return to
userland; this clears exclusive state.
2018-06-05 13:05:41 +01:00
MerryMage
f915f0860c Implement global exclusive monitor 2018-06-05 12:27:37 +01:00
MerryMage
169c1a07ca a64_emit_x64: Simplify EmitExclusiveWrite 2018-06-05 12:26:05 +01:00
MerryMage
7e31103cf8 CMakeLists: Add missing files 2018-06-05 12:25:16 +01:00
Lioncash
9d27e78989 A64: Implement FCMEQ (zero)'s vector single and double precision variant 2018-06-03 21:49:06 +01:00
Lioncash
0ca366b94e A64: Implement FCMEQ (register)'s vector single and double precision variant 2018-06-03 21:49:06 +01:00
Lioncash
239d2243c0 ir: Add opcodes for floating-point vector equalities 2018-06-03 21:49:06 +01:00
Lioncash
7dc6b5abb3 fuzz_with_unicorn: Make float_numbers in floating-point tests constexpr
Given this is just a lookup table, this can be made immutable.
2018-06-02 16:47:13 +01:00
Lioncash
06c1cf6721 emit_x64_vector: Vectorize fallback case in EmitVectorMultiply64()
Gets rid of the need to perform a fallback.
2018-05-26 21:33:46 +01:00
Lioncash
b747b67354 emit_x64_vector: Add break to final case in EmitVectorRoundingHalvingAddUnsigned()
This doesn't alter behavior but does make the code better if anything
else is ever added to this function in the future.
2018-05-26 21:25:14 +01:00
Lioncash
c623a94a4d A64: Implement SRHADD and URHADD 2018-05-26 11:48:56 +01:00
Lioncash
2652e92928 ir: Add opcodes for performing rounding halving adds 2018-05-26 11:48:56 +01:00
Lioncash
990a569b7a emit_x64_vector: Simplify AVX-512 codepath in EmitVectorMultiply64
I realized I introduced a helper for simple AVX operation emitting, so
use that instead of writing it all out long-form.
2018-05-23 08:02:12 +01:00
Lioncash
66c5d8fb06 A64: Implement UMLAL{2}, UMLSL{2}, and UMULL{2}
Now that we have the helper function set up for the signed variants, we
can also modify it to be used with the unigned ones by performing a zero
extension instead of a sign extension.
2018-05-23 07:58:41 +01:00
Lioncash
5f53fd2be8 A64: Implement SMLSL{2} 2018-05-23 07:58:41 +01:00
Lioncash
b6ed3f9c66 A64: Implement SMLAL{2} 2018-05-23 07:58:41 +01:00
Lioncash
2bfe1ce838 A64: Implement SMULL{2} 2018-05-23 07:58:41 +01:00
Lioncash
be453b0e1c fuzz_with_unicorn: Remove exclusion of FMOV (imm) for FP-16 floats
Qemu, or rather, Unicorn now supports FP-16, since I backported support
for the recent changes to mainline Qemu relating to FP-16 support.
2018-05-19 12:25:43 +01:00
Lioncash
1f00e53b54 A64: Implement SABAL/SABAL2 and SABDL/SABDL2
Now that we have a helper function for the unsigned variants, we can
modify it to also be usable with the signed variants.
2018-05-14 23:10:01 +01:00
Lioncash
de3b545e57 A64: Implement UABAL/UABAL2 2018-05-14 23:10:01 +01:00
Lioncash
e1ab52c057 A64: Implement UABDL/UABDL2 2018-05-14 23:10:01 +01:00
Lioncash
7cd0ff18bf emit_x64_vector: Emit VPMULLQ in EmitVectorMultiply64 on AVX-512{DQ, VL} capable CPUs
Shortens code-gen down to a single instruction in the 64-bit path.
2018-05-14 23:09:31 +01:00
Lioncash
f8f4f9abb4 A64: Implement LDR (literal, SIMD&FP) 2018-05-14 23:09:15 +01:00
Lioncash
b00f6d1044 Correct typo in DataCacheOperation enum
Fixes a typo for the InvalidateByVAToPoC enum entry. Given yuzu is the
only known user of 64-bit mode and it doesn't use this value, we can get
away with changing this.
2018-05-14 15:39:08 +01:00
Lioncash
ced64f7dda A64: Implement FABS' half-precision variant 2018-05-12 11:17:46 +01:00
Lioncash
672641de2c A64: Implement FABS' single and double precision variant 2018-05-12 11:17:46 +01:00
Lioncash
34e1b030dd A64: Implement URSHR (scalar) and URSRA (scalar)
Now that the utility function is all set up from implementing SRSRA, the
unsigned variants can now be trivially implemented by modifying the
utility function to perform a logical shift right instead of an
arithmetical shift right for the unsigned case.
2018-05-12 11:17:19 +01:00
Lioncash
e662942ee3 A64: Implement SRSRA (scalar) 2018-05-12 11:17:19 +01:00
Lioncash
4a81075641 A64: Implement SRSHR (scalar) 2018-05-12 11:17:19 +01:00
Lioncash
ae666903c4 A64: Implement SABA 2018-05-12 11:16:42 +01:00
Lioncash
1629beed25 A64: Implement SABD 2018-05-12 11:16:42 +01:00
Lioncash
d7951233bd ir: Add opcodes for signed absolute differences 2018-05-12 11:16:42 +01:00
Tillmann Karras
0718ee4482 decoder_detail: use structured bindings 2018-05-12 11:15:39 +01:00
Lioncash
cee8bfa797 CMakeLists: Add detection for Aarch64 compiler environments
Just closes a small hole in architecture detection for the ARM family.
2018-05-10 00:35:50 +01:00
Lioncash
e0faf3277e simd_two_register_misc: Handle 64-bit case for SCVTF_int_4 2018-05-08 18:14:50 +01:00
Lioncash
b166981ff5 ir: Add opcode to perform the vector conversion S64->F64
Unfortunately x86 prior to AVX-512 doesn't really give us any convenient instruction to do the work for us
2018-05-08 18:14:50 +01:00
Lioncash
4d2c5184ff A64: Implement SHLL/SHLL2 2018-05-08 17:57:55 +01:00
Lioncash
ae57f6eb58 A64: Add missing decoding for PRFM (unscaled offset) 2018-05-08 15:01:53 +01:00
Lioncash
3e0861d013 A64: Implement UHSUB 2018-05-07 19:04:10 +01:00
Lioncash
93255e6dbd A64: Implement SHSUB 2018-05-07 19:04:10 +01:00
Lioncash
a0e3943ade ir: Add opcodes for performing vector halving subtracts 2018-05-07 19:04:10 +01:00
Lioncash
b4a2d497f9 A64: Implement SM4EKEY 2018-05-07 19:01:22 +01:00
Lioncash
4372700ec9 A64: Implement SM4E 2018-05-07 19:01:22 +01:00
Lioncash
284afd18cb ir: Add an opcode for doing an SM4 lookup table query 2018-05-07 19:01:22 +01:00
Lioncash
97a9fce094 emit_x64_vector: Use VPOPCNTB in EmitVectorPopulationCount() if AVX-512 BITALG is available 2018-05-07 16:40:28 +01:00
Lioncash
f5fe2af89c fuzz_with_unicorn: Silence unused variable warning
Currently, structured bindings don't provide a way to ignore unused variables.
2018-05-07 16:39:42 +01:00
Lioncash
a86f56eb43 externals: Update Catch to v2.2.2
Keeps the unit-testing library up to date.
2018-05-07 16:39:42 +01:00
Lioncash
6d0b58039e A64: Implement UHADD 2018-05-07 16:39:17 +01:00
Lioncash
e4efd365fb A64: Implement SHADD 2018-05-07 16:39:17 +01:00
Lioncash
1da4671b53 ir: Add opcodes for performing halving adds 2018-05-07 16:39:17 +01:00
Lioncash
fae2d940f2 emit_x64_vector: Emit VPMINSQ and VPMINUQ for 64-bit vector min operations if AVX-512VL is available 2018-05-04 07:52:22 +01:00
Lioncash
ec66d94121 emit_x64_vector: Emit VPMAXSQ and VPMAXUQ for 64-bit vector max operations if AVX-512VL is available 2018-05-04 07:52:22 +01:00
Lioncash
69ac6dfca6 emit_x64_vector_floating_point: Deduplicate accurate NaN handling code
Allows the code to both be used from the 32 bit and 64 bit operations without duplicating code.
2018-05-03 23:22:50 +01:00
Lioncash
4ca546ce4d emit_x64_vector: Emit VPABSQ in EmitVectorAbs() for the 64-bit case if AVX-512VL is available 2018-05-03 23:22:18 +01:00
Lioncash
c9a6d6264e emit_x64_vector: Use VPSRAQ in EmitVectorArithmeticShiftRight64() if AVX-512VL is available 2018-05-03 16:13:11 +01:00
Lioncash
7a066fb011 disassembler_arm: Remove rotation helper function in favor of Common::RotateRight
Mildly reduces the amount of duplicated behavior
2018-05-02 17:14:13 +01:00
Lioncash
75d0b1ebd8 emit_x64_vector: Vectorize fallback path of EmitVectorMaxS32() 2018-05-02 17:14:07 +01:00
Lioncash
7f3cfff647 emit_x64_vector: Vectorize fallback path of EmitVectorMaxS8() 2018-05-02 17:14:07 +01:00
Lioncash
9607376f2f emit_x64_vector: Vectorize fallback path in EmitVectorMinU32() 2018-05-02 17:13:41 +01:00
Lioncash
1162be609d emit_x64_vector: Vectorize fallback path in EmitVectorMinU16() 2018-05-02 17:13:41 +01:00
Lioncash
7cab5c2e03 emit_x64_vector: Vectorize fallback path in EmitVectorMinS32() 2018-05-02 17:13:41 +01:00
Lioncash
7fa0d2765a emit_x64_vector: Vectorize fallback path in EmitVectorMinS8() 2018-05-02 17:13:41 +01:00
Lioncash
73477f04dd emit_x64_vector: Remove unnecessary if constexpr expression in LogicalVShift
This can simply be merged with the previous one.
2018-05-01 19:31:48 +01:00
Lioncash
f90a476546 emit_x64_vector: Avoid left shift of negative value in LogicalVShift
Now that we handle the signed variants, we also have to be careful about left shifts with negative values,
as this is considered undefined behavior.
2018-05-01 19:31:48 +01:00
Lioncash
e08c1bdae1 a64_jitstate: Zero SP and PC on construction of A64JitState
Given we zero out/reset everything else in the struct, do the same for these members to keep initialization consistent
2018-05-01 19:31:05 +01:00
Lioncash
e33ba25d8a backend_x64/callback: Default virtual destructor in the cpp file
Prevents the vtable being generated in each translation unit that includes the header (and silences -Wweak-vtables warnings)
2018-05-01 19:30:56 +01:00
Lioncash
83e20fc690 a32_interface/a64_interface: Change reinterpret_casts to static_casts in GetCurrentBlock thunks
It's well-defined to static_cast a void* to its proper type.
2018-05-01 19:30:25 +01:00
Lioncash
8aa9a47a6a A64: Implement SSHL (scalar) 2018-04-30 22:41:17 +01:00
Lioncash
8818d76212 A64: Implement SSHL (vector) 2018-04-30 22:41:17 +01:00
Lioncash
3e3ce37eb8 backend_x64/ir: Amend generic LogicalVShift() template to also handle signed variants
Also adds IR opcodes to dispatch said variants
2018-04-30 22:41:17 +01:00
Lioncash
4cb09c827d emit_x64_vector_floating_point: Use arrays for retrieving size instead of hardcoding the size
Similar changes were done in emit_x64_vector, but these were missed.
2018-04-30 22:40:25 +01:00
Lioncash
5e20e5a44a emit_x64_vector: Vectorize fallback path in EmitVectorMaxU16() 2018-04-28 19:19:06 +01:00
Lioncash
fea1e6ca1f A64: Implement CMTST's scalar variant 2018-04-28 19:17:38 +01:00
Lioncash
f8a96dbe5f emit_x64_vector: Vectorize non-SSE4.1 fallback path for VectorMultiply32() 2018-04-28 19:17:18 +01:00
Lioncash
43a3873dd2 emit_x64_vector: Use VBPROADCAST where applicable and available
Uses the instruction that does what it says in its name if available. Allows avoiding the use
of a scratch register in EmitVectorBroadcast8() and EmitVectorBroadcastLower8()'s SSSE3 path.
2018-04-26 22:28:09 +01:00
Lioncash
2a35b2a46a A64: Implement UZP1 and UZP2 2018-04-26 08:49:51 +01:00
Lioncash
9c2550ac72 ir: Add opcodes for performing vector deinterleaving 2018-04-26 08:49:51 +01:00
Lioncash
4765503fc6 A64: Implement FNEG (half-precision) 2018-04-26 08:49:03 +01:00
MerryMage
a00a605a4b README: Add usage example 2018-04-25 22:25:39 +01:00
Lioncash
96be76296e A64: Implement USHL (scalar) 2018-04-24 08:15:00 +01:00
Lioncash
8261911bd8 A64: Implement FNEG (vector) 2018-04-24 08:14:31 +01:00
Lioncash
633e8e3ecd A64: Implement RSUBHN/RSUBHN2 2018-04-23 21:08:43 +01:00
Lioncash
4dec013b09 A64: Implement RADDHN/RADDHN2 2018-04-23 21:08:43 +01:00
Lioncash
7fb04ccb36 A64: Implement XAR 2018-04-23 16:05:40 +01:00
Lioncash
db29d68a2d simd_two_register_misc: Factor out common comparison code
Gets rid of a tiny bit of duplicated code.
2018-04-23 16:04:58 +01:00
Lioncash
1692e26c2e A64: Implement CMLE (zero)'s vector variant 2018-04-23 16:04:58 +01:00
Lioncash
21936a82aa A64: Implement CMTST (vector) 2018-04-23 16:04:40 +01:00
Lioncash
4f27764191 A64: Implement ADDHN{2} and SUBHN{2} 2018-04-21 08:58:16 +01:00
Lioncash
1791114ab1 translate: zero extend result in Vpart when storing to lower part of vector 2018-04-21 08:58:16 +01:00
Lioncash
e96bfd1133 emit_x64_vector: Emit PMAXUD in EmitVectorMaxU32 on SSE4.1-capable CPUs 2018-04-20 23:34:32 +01:00
Lioncash
f85e2681fc emit_x64_vector: Emit PMINUD in EmitVectorMinU32 on SSE4.1-capable CPUs 2018-04-20 23:34:32 +01:00
Lioncash
2fb3ddd2cd emit_x64_vector: Emit PMINSD in EmitVectorMinS32 on SSE4.1-capable CPUs
Provides a better alternative to a fallback operation.
2018-04-20 23:34:32 +01:00
Lioncash
be48d44132 emit_x64_vector: Get rid of some magic numbers in loop bounds 2018-04-20 18:54:29 +01:00
Lioncash
a3c8ab61ea emit_x64_vector: Generify variable shift functions 2018-04-20 18:54:14 +01:00
Lioncash
f6e624e9ea A64: Implement CMLE (zero)'s scalar variant 2018-04-20 17:31:07 +01:00
Lioncash
41a3e87c15 A64: Implement CMLT (zero)'s scalar single/double-precision variant 2018-04-20 15:48:50 +01:00
Lioncash
51912ca6ab A64: Implement SHA512H2 2018-04-20 07:29:26 +01:00
Lioncash
4655f78ec2 A64: Implement SHA512H 2018-04-20 07:29:26 +01:00
Lioncash
3a52275611 A64: Handle S32->F32 case for SCVTF (vector) 2018-04-19 21:09:42 +01:00
Lioncash
230e954e5c IR: Add opcode for packed word->f32 conversions 2018-04-19 21:09:42 +01:00
Lioncash
f24cfba5c2 A64: Implement SHA512SU1 2018-04-19 19:51:31 +01:00
Lioncash
e3412d9779 A64: Implement SHA512SU0 2018-04-19 19:51:31 +01:00
Lioncash
cc76802990 A64: Implement SHA256H and SHA256H2 2018-04-19 19:50:17 +01:00
MerryMage
b5585baefb A64: Implement SCVTF (vector, integer), scalar varaint 2018-04-19 19:48:45 +01:00
MerryMage
badc7ac467 impl: Reorganize scalar two-register misc instructions 2018-04-19 19:48:45 +01:00
Lioncash
d53decf9e1 A64: Implement SHA256SU1 2018-04-19 08:40:55 +01:00
Lioncash
62be988507 simd_two_register_misc: Add missing zeroing of the vector for CMGT and CMLT 2018-04-19 08:39:56 +01:00
Lioncash
cd5fee6746 A64: Implement CMGE (zero)'s vector variant 2018-04-19 08:39:56 +01:00
Lioncash
da99e1fdaa A64: Implement MLS (by element) 2018-04-19 08:39:25 +01:00
Lioncash
8920238d59 A64: Implement MUL (by element) 2018-04-19 08:39:25 +01:00
MerryMage
68d6a1276b A64: Implement MLA (by element) 2018-04-19 00:04:52 +01:00
Lioncash
7340c36ae0 A64: Implement ABS (scalar) 2018-04-19 00:03:08 +01:00
Lioncash
c196c73e17 A64: Implement SHA256SU0 2018-04-19 00:00:39 +01:00
Lioncash
21790dcf98 CMake: Make FindUnicorn introduce a unicorn target
Makes the find module do all the work of properly setting up the target instead of needing to do it in the main CMakeLists file.
2018-04-18 23:59:54 +01:00
Lioncash
cb3b885025 A64: Implement SHA1M 2018-04-16 07:47:22 +01:00
Lioncash
4381ded969 A64: Implement SHA1P 2018-04-16 07:47:22 +01:00
Lioncash
dc5c2508a5 A64: Implement scalar variants of CMEQ, CMGT, and CMGE zero comparison instructions
These can trivially use the ScalarCompare helper function.
2018-04-15 13:38:42 +01:00
Lioncash
3a71801f10 A64: Implement scalar variant of NEG 2018-04-15 13:37:07 +01:00
Lioncash
f8e387f13f simd: Relocate REV16, REV32 and REV64 vector variants to the proper file
These aren't scalar instruction variants.
2018-04-15 13:37:07 +01:00
Lioncash
e23f6b666e A64: Implement CMEQ (register, scalar) 2018-04-15 11:31:20 +01:00
Lioncash
5f879af788 A64: Implement CMHS (register, scalar) 2018-04-15 11:31:20 +01:00
Lioncash
41e4b3e286 A64: Implement CMHI (register, scalar) 2018-04-15 11:31:20 +01:00
Lioncash
03f6247239 A64: Implement CMGE (register, scalar) 2018-04-15 11:31:20 +01:00
Lioncash
62ddc0631e A64: Implement CMGT (register, scalar) 2018-04-15 11:31:20 +01:00
Lioncash
cd1f7894b3 A64: Implement SHA1C 2018-04-15 10:32:03 +01:00
Lioncash
5315e63a2e A64: Implement SLI (scalar) 2018-04-15 08:56:09 +01:00
Lioncash
37051e9cb6 A64: Implement SRI (scalar) 2018-04-15 08:56:09 +01:00
Lioncash
1336e1a4ec unicorn: Be explicit about casting away const to const-incorrect APIs
Uses C++ casts which silence relevant warnings in Xcode 9.3

Also migrates relevant Read function equivalents over for consistency.
2018-04-15 08:54:36 +01:00
Lioncash
f9fbeb40bc general: Remove unused lambda captures
Resolves warnings that occur in Xcode 9.3
2018-04-15 08:53:23 +01:00
Lioncash
ea0435eee6 A64: Implement SHA1SU1 2018-04-14 08:06:15 +01:00
Lioncash
83e20f24f7 A64: Implement SHA1SU0 2018-04-14 08:06:15 +01:00
Lioncash
a48ff2b9e2 A64: Implement TRN2 2018-04-14 08:01:52 +01:00
Lioncash
9442cc8afa A64: Implement TRN1 2018-04-14 08:01:52 +01:00
Lioncash
d9ff5b1a9a A64: Implement SSRA (scalar) 2018-04-13 16:05:18 +01:00
Lioncash
fb5d5f8881 A64: Implement SSHR (scalar) 2018-04-13 16:05:18 +01:00
Lioncash
f0ecc27f2f A64: Implement USRA (scalar) 2018-04-13 16:05:18 +01:00
Lioncash
1e71835cb1 A64: Implement USHR (scalar) 2018-04-13 16:05:18 +01:00
Lioncash
746969bbe6 A64: Implement SHL (scalar) 2018-04-13 16:05:18 +01:00
Lioncash
a90cddaa05 A64: Implement SM3PARTW1 2018-04-13 15:22:10 +01:00
Lioncash
7570ea1a33 simd_sha512: Simplify RAX1
Now that the vector rotation helpers are in, replace the explicit
shifting with the relevant helper function that does the same thing.

Simply tidies up code; no behavioral changes are made.
2018-04-13 06:31:09 +01:00
Lioncash
c7c2fa2b66 A64: Implement SM3PARTW2 2018-04-12 09:21:51 +01:00
Lioncash
987ca9566b ir: Add helper functions for vector rotation 2018-04-12 09:21:51 +01:00
Lioncash
066cf3e7a7 A64: Implement SM3TT2B 2018-04-10 22:22:56 +01:00
Lioncash
bb7c0ab1ba A64: Implement SM3TT2A 2018-04-10 22:22:56 +01:00
Lioncash
3f81c90013 A64: Implement SM3TT1B 2018-04-10 18:30:33 +01:00
Lioncash
3e7483e1db A64: Implement SM3TT1A 2018-04-10 16:56:17 +01:00
Lioncash
8e739a73dc simd_shift_by_immediate: Merge signed/unsigned helper functions
Gets rid of a little more code duplication.
2018-04-10 16:43:59 +01:00
Lioncash
5f8f4d106a A64: Implement SM3SS1 2018-04-08 11:02:54 +01:00
Lioncash
c9c6ae101e A64: Implement SRI (vector) 2018-04-08 11:01:08 +01:00
Lioncash
4b9bdb2270 A64: Implement SLI (vector) 2018-04-08 11:01:08 +01:00
Lioncash
4e8fd68308 A64: Implement SRSRA (vector) 2018-04-08 10:55:27 +01:00
Lioncash
b3834adc2e A64: Implement SRSHR (vector) 2018-04-08 10:55:27 +01:00
MerryMage
6febae5f8e imm: Add additional bit position checks to Imm::Bits 2018-04-08 10:42:23 +01:00
MerryMage
5bc164adb9 math_util: rvalue references for std::forward 2018-04-08 10:37:11 +01:00
Lioncash
3fdaf77c7a A64: Implement SSUBL/SSUBL2 2018-04-07 15:20:58 +01:00
Lioncash
c669f091e6 A64: Implement SADDL/SADDL2 2018-04-07 15:20:58 +01:00
Lioncash
c144cb39c9 A64: Implement USUBL/USUBL2 2018-04-07 15:20:58 +01:00
Lioncash
14bc8bce7f A64: Implement UADDL/UADDL2 2018-04-07 15:20:58 +01:00
Lioncash
a000cb6e36 simd_shift_by_immediate: Factor out common code in shift instructions
Gets rid of partial duplication of the same code for instructions that only have a small behavior difference to them.

e.g. The only difference between SSHR and SSRA is that SSRA adds an accumulator before storing the result.
2018-04-07 15:20:28 +01:00
Lioncash
436eddcfa1 A64: Implement URSRA (vector) 2018-04-04 14:17:43 +01:00
Lioncash
c72c8bff0d A64: Implement URSHR (vector) 2018-04-04 14:17:43 +01:00
Lioncash
4f705d840f A64: Implement RSHRN/RSHRN2 2018-04-04 11:43:02 +01:00
Lioncash
6e3e03a48b A64: Implement SHRN/SHRN2 2018-04-04 11:43:02 +01:00
Lioncash
523c0fd0e0 A64/translate: Amend I() to also handle u8 and u16 immediates
This is necessary for instructions like SRSHR, and other related instructions.
2018-04-04 11:43:02 +01:00
MerryMage
f0ba929fc3 fuzz_with_unicorn: Correct GenRandomInst
UnallocatedEncoding is now handled in ShouldTestInst
2018-04-04 11:15:56 +01:00
MerryMage
3c3767e073 A64: Implement FMOV (vector, immediate) and mark other SIMD modified immediate instructions as unallocated 2018-04-04 10:36:27 +01:00
MerryMage
92e416a9b8 A64: Implement ZIP2 2018-04-04 10:23:04 +01:00
MerryMage
9891fb3b2c travis: Enable DYNARMIC_USE_LLVM
Provides disassembly, which is useful for debugging failing tests
on CI.
2018-04-04 09:17:38 +01:00
MerryMage
6968880eb6 decoder/a64: Tweak ordering algorithm
Ensuring only instruction families are sorted with each other in
the fashion previously devised does not admit a total ordering.
2018-04-04 09:14:41 +01:00
MerryMage
3a5b6ba709 ir_emitter: Remove overloads
Having overloads made explicit casting necesssary for these functions when
using types like UAny.
2018-04-03 23:13:52 +01:00
Lioncash
61fd0d4fdb A64: Implement RBIT (vector) 2018-04-03 21:18:03 +01:00
Lioncash
f921005a70 ir: Add opcode for reversing bits in a vector 2018-04-03 21:18:03 +01:00
Lioncash
4fc8daa103 A64/translate: Amend instruction prototypes erroneously marked as taking Reg
Makes the prototypes consistent
2018-04-03 18:05:01 +01:00
Lioncash
b4e944cd51 A64: Implement RAX1 2018-04-03 14:28:41 +01:00
Lioncash
d56bed53e6 a64_get_set_elimination_pass: Make TrackingType enum an enum class
Prevents placing single letter enum members into the surrounding scope.
2018-04-03 07:49:33 +01:00
Lioncash
748f624fe8 A64: Implement ABS (vector) 2018-04-03 07:49:08 +01:00
Lioncash
032b09cbdf ir: Add opcodes for performing vector absolute values 2018-04-03 07:49:08 +01:00
Lioncash
8cb52b48e6 A64: Implement USUBW/USUBW2 2018-04-03 07:48:26 +01:00
Lioncash
958e30a87a A64: Implement SSUBW/SSUBW2 2018-04-03 07:48:03 +01:00
Lioncash
8b3ff327bb A64: Implement SADDW/SADDW2 2018-04-03 07:48:03 +01:00
MerryMage
cfbe7cfd83 A64: Implement EXT 2018-04-02 22:10:28 +01:00
MerryMage
14d3d72aac IR: Implement VectorExtract, VectorExtractLower IR instructions 2018-04-02 21:52:46 +01:00
MerryMage
9d471a6899 A64: Implement UADDW 2018-04-02 21:51:40 +01:00
MerryMage
c56b6d0981 A64: Implement FMUL (vector) 2018-04-02 21:02:57 +01:00
Lioncash
19068dea1f A64: Implement UABA
Now that we have unsigned absolute difference capabilities, we can just use this to
append onto the result via a vector add.
2018-04-02 19:08:20 +01:00
Lioncash
62d49b32c2 A64: Implement UABD 2018-04-02 19:08:20 +01:00
Lioncash
734447ef3d ir: Add opcodes for performing vector unsigned absolute differences 2018-04-02 19:08:20 +01:00
Lioncash
5baa22b26b ir_emitter: Make immediate member functions const qualified
These don't modify class state
2018-04-02 19:07:26 +01:00
Lioncash
1e8fe95cc4 IR: Add opcodes for interleaving upper-order bytes/halfwords/words/doublewords
I should have added this when I introduced the functions for interleaving
low-order equivalents for consistency in the interface.
2018-03-31 11:01:38 +01:00
Lioncash
3970a8856d A64: Implement SHA1H
This is a fairly trivial instruction it's essentially:

result = ROL(data, 30);
2018-03-31 10:59:49 +01:00
Lioncash
cad9d31b83 emit_x64_data_processing: Deduplicate some code in zero-extension functions
EmitZeroExtendByteToLong() can be implemented in terms of EmitZeroExtendByteToWord() and
EmitZeroExtendHalfToLong() can be implemented in terms of EmitZeroExtendHalfToWord().
2018-03-29 20:59:50 +01:00
Lioncash
a94f321f69 A64: NOP immediate variant of PRFM
Makes behavior identical to the literal variant of PRFM. Given this is simply a hint instruction,
this is valid behavior. The upside is that we don't fall back to Unicorn unnecessarily whenever
the instruction is encountered.
2018-03-29 20:59:43 +01:00
MerryMage
9cc12d80b9 abi: Missing includes' 2018-03-29 12:46:29 +01:00
MerryMage
ac35ad5838 emit_x64_floating_point: Near jump instead of short jump in FPMinNumberic{32,64} 2018-03-29 12:45:33 +01:00
Lioncash
6f03fddee5 A64: system: Use an enum class for MRS/MSR register encodings
Reduces the need to manually write out the register bit encodings repeatedly.
2018-03-29 12:44:37 +01:00
MerryMage
12a102046c emit_X64_floating_point: Near jmp to end instead of short jmp
Jump destination can be further than what can be reached in a short
jump under some FPCR options.
2018-03-27 08:21:21 +01:00
Lioncash
6278f83560 emit_x64_vector: Fix typo in VectorShuffleImpl
This is supposed to be pshufd, not pshufw (which only allows a 64-bit operand)
2018-03-23 19:51:09 +00:00
Lioncash
25a0204203 A64: Implement REV64 2018-03-23 17:34:59 +00:00
Lioncash
aa92e33194 bit_util: Do nothing in RotateRight if the rotation amount is zero
Without this sanitizing it's possible to perform a shift with a shift
amount that's the same size as the type being shifted. This actually
occurs when decoding ORR variants.

We could get fancier here and make this branchless, but we don't
really use RotateRight in any performance intensive areas.
2018-03-21 19:30:02 +00:00
Lioncash
e537985584 A64: Implement REV32 (vector) 2018-03-21 15:40:03 +00:00
Lioncash
f62a258945 ir: Add IR opcodes for emitting vector shuffles
This uses the ARM terminology for sizes (Halfword -> 2 bytes, Word -> 4 bytes)
as opposed to the x86 terminology of (Word -> 2 bytes, Double word -> 4 bytes)
2018-03-21 15:40:03 +00:00
Lioncash
36ac6ec102 emit_x64_vector_floating_point: Fix out of bounds array access in EmitVectorOperation64 2018-03-21 15:39:44 +00:00
Lioncash
20a59a9721 A64: Implement REV16 (vector) 2018-03-16 18:01:33 +00:00
Lioncash
b2f7bb0263 CMakeLists: Add fp_util, macro_util and math_util headers
Allows the headers to show up within IDEs
2018-03-13 23:21:20 +00:00
Lioncash
fd21b58c3d A64: Implement EOR3 and BCAX 2018-03-13 23:20:58 +00:00
Lioncash
a48c0bbf9c travis: Use yuzu's unicorn fork 2018-03-13 23:20:58 +00:00
Lioncash
59e62e089e externals: Update catch to v2.2.1
Keeps the testing library up to date
2018-03-12 18:03:45 +00:00
MerryMage
6b4c6b06a9 impl: Update PC when raising exception 2018-02-21 21:02:42 +00:00
MerryMage
7a1313aa24 A64: Implement FDIV (vector) 2018-02-21 15:03:36 +00:00
MerryMage
b2d781da3a system: Raise exception for YIELD, WFE, WFI, SEV, SEVL 2018-02-20 20:31:56 +00:00
MerryMage
b277bf5061 Correct FPSR and FPCR 2018-02-20 20:31:17 +00:00
MerryMage
7673933a9b A64: Implement USHL 2018-02-20 19:48:15 +00:00
MerryMage
8d0e558271 A64: Implement UCVTF (vector, integer), scalar variant 2018-02-20 19:11:35 +00:00
MerryMage
da9a4f8877 A64: Partially implement FCVTZU (scalar, fixed-point) and FCVTZS (scalar, fixed-point) 2018-02-20 18:45:28 +00:00
MerryMage
747968416f A64: Implement system register TPIDR_EL0 2018-02-20 17:56:20 +00:00
MerryMage
0fd75fd9cb A64: Implement system registers FPCR and FPSR 2018-02-20 17:38:29 +00:00
MerryMage
31e370cdf4 A64: Implement system register CNTPCT_EL0 2018-02-20 16:56:05 +00:00
MerryMage
9a88fd3340 A64: Implement system register CTR_EL0 2018-02-20 16:44:13 +00:00
MerryMage
1d16896d25 A64: Implement NEG (vector) 2018-02-20 15:41:07 +00:00
MerryMage
3184edf4a9 IR: Add IR instruction ZeroVector 2018-02-20 15:41:07 +00:00
MerryMage
31f8fbc5b8 emit_x64_floating_point: Add maybe_unused to preprocess parameter 2018-02-20 15:41:07 +00:00
MerryMage
567eb1a2f1 A64: Implement FMINNM (scalar) 2018-02-20 14:14:40 +00:00
MerryMage
c6d8fa1d36 A64: Implement FMAXNM (scalar) 2018-02-20 14:05:14 +00:00
MerryMage
616056d9a3 constant_pool: Add frame parameter 2018-02-20 14:04:48 +00:00
MerryMage
a3747cb01c A64: Implement ADDP (scalar) 2018-02-18 23:55:38 +00:00
MerryMage
5cd5d9f5f8 reg_alloc: Only exchange GPRs 2018-02-18 23:24:15 +00:00
MerryMage
dd0452a435 A64: Implement DUP (element), scalar variant 2018-02-18 18:58:01 +00:00
MerryMage
e5732ea66f emit_x64_floating_point: Correct FP{Max,Min}{32,64} implementations for -0/+0 2018-02-18 15:19:10 +00:00
MerryMage
40eb9c3253 A64: Implement FMAX (scalar), FMIN (scalar) 2018-02-18 13:49:23 +00:00
MerryMage
7cef39bdb4 fuzz_with_unicorn: QEMU's implementation of FCVT is incorrect 2018-02-18 13:47:41 +00:00
MerryMage
826dce212e travis: Switch unicorn repository 2018-02-18 13:21:29 +00:00
MerryMage
9605f28792 a64/config: Allow NaN emulation accuracy to be set 2018-02-18 13:18:22 +00:00
MerryMage
e9435bc191 a64_emit_x64: Add conf to A64EmitContext 2018-02-18 13:18:22 +00:00
MerryMage
30b596df19 fuzz_with_unicorn: Explicitly test floating point instructions 2018-02-18 13:18:22 +00:00
MerryMage
be292a819c A64: Implement FSQRT (scalar) 2018-02-18 13:18:22 +00:00
MerryMage
3c42d48a3f backend_x64: Accurately handle NaNs 2018-02-18 13:18:22 +00:00
MerryMage
4aefed05d5 fuzz_with_unicorn: Print AArch64 disassembly 2018-02-18 13:18:22 +00:00
MerryMage
e585e1d49e T32: Add initial decoder list 2018-02-14 19:29:19 +00:00
MerryMage
1598af4f12 simd_three_same: Add VectorZeroUpper to CMGE (vector) and CMHS (vector) 2018-02-13 19:01:47 +00:00
MerryMage
029ae11040 A64: Implement CMGT (zero), CMEQ (zero), CMLT (zero) 2018-02-13 19:01:21 +00:00
MerryMage
91483ab975 decoder/a64: Rearrange SIMD two-register misc decoders 2018-02-13 18:51:43 +00:00
MerryMage
9158534048 A64: Implement CMGE (register) 2018-02-13 18:29:54 +00:00
MerryMage
41e421bf0b A64: Implement CMHI, CMHS 2018-02-13 18:20:18 +00:00
MerryMage
324810cfad IR: Implement Vector{Less,Greater}{,Equal}{Signed,Unsigned} 2018-02-13 18:20:00 +00:00
MerryMage
89007194a7 A64: Implement SMAX, SMIN, UMAX, UMIN 2018-02-13 17:57:07 +00:00
MerryMage
2880eb3da1 IR: Implement Vector{Max,Min}{Signed,Unsigned} 2018-02-13 17:56:46 +00:00
MerryMage
7d8543b70e A64: Implement CMGT (register) 2018-02-13 15:47:52 +00:00
MerryMage
6d4f14e876 IR: Implement VectorGreaterSigned 2018-02-13 15:47:52 +00:00
MerryMage
9527d52c49 Exclusive fixups
* Incorrect size of exclusive_address
* Disable tests on exclusive memory instructions for now
2018-02-13 15:47:52 +00:00
MerryMage
182c776d7e a64_emit_x64: EmitExclusiveWrite: Make MSVC happy (narrowing conversion warning) 2018-02-13 13:39:14 +00:00
MerryMage
229ff47738 Merge branch 'feature/exclusive-mem' 2018-02-13 12:53:29 +00:00
MerryMage
43f27b3e15 A64: Implement STXP, STLXP, LDXP, LDAXP 2018-02-13 12:50:50 +00:00
MerryMage
11eb8c2bea A64: Implement CLREX 2018-02-13 12:31:16 +00:00
MerryMage
22285842af A64: Implement STXRB, STXRH, STXR, STLXRB, STLXRH, STLXR, LDXRB, LDXRH, LDXR, LDAXRB, LDAXRH, LDAXR 2018-02-13 12:30:58 +00:00
MerryMage
d7323d6799 fuzz_with_unicorn: Speed up tests by not initializing/tearing down constantly 2018-02-12 21:48:29 +00:00
MerryMage
eac0933738 Merge branch 'feature/direct-page-table-access' 2018-02-12 21:47:43 +00:00
MerryMage
49f1de3188 Direct Page Table Access: Handle address spaces less than the full 64-bit in size 2018-02-12 21:26:23 +00:00
MerryMage
406725e533 Implement direct page table access 2018-02-12 20:51:03 +00:00
MerryMage
adc2d5a3cc fuzz_with_unicorn: Fix read-past-end access via jit_iter 2018-02-12 20:51:03 +00:00
MerryMage
885e092f99 callbacks: Member functions should be const 2018-02-12 20:51:03 +00:00
MerryMage
9598bd45ef a64_emit_x64: Implement {Read,Write}Memory128 in terms of a function call 2018-02-12 18:26:08 +00:00
MerryMage
276326e0e8 abi: Add RAX to ABI_ALL_CALLER_SAVE 2018-02-12 18:17:39 +00:00
MerryMage
7a161ed35c A64: Partially implement MRS 2018-02-12 00:06:44 +00:00
MerryMage
b733479b5e A64: Implement DSB, DMB 2018-02-11 23:27:28 +00:00
MerryMage
1ba2642742 Implement DC instructions 2018-02-11 23:12:28 +00:00
Lioncash
e12fa19142 A64: Implement NOT (vector) 2018-02-11 20:14:03 +00:00
MerryMage
1b836b6deb IR: Implement FPMax, FPMin 2018-02-11 16:43:47 +00:00
MerryMage
94115d1775 A64: Implement FADD (vector), vector variant 2018-02-11 16:30:03 +00:00
MerryMage
24def19cd7 IR: Implement FPVectorAdd 2018-02-11 16:29:48 +00:00
MerryMage
9379d54a44 A64: Implement SSHLL, SSHLL2 2018-02-11 16:24:55 +00:00
MerryMage
a7e4202828 IR: Implement VectorSignExtend 2018-02-11 16:24:33 +00:00
MerryMage
01760f1a21 CMakeLists: Ignore warnings within xbyak 2018-02-11 14:57:35 +00:00
MerryMage
ae7d118f22 A64: Implement DUP (element), vector variant 2018-02-11 14:34:13 +00:00
MerryMage
b87814ce88 load_store_multiple_structures: Improve IR codegen for selem == 1 case 2018-02-11 12:48:49 +00:00
MerryMage
6113346a5b A64: Implement FSUB (vector) 2018-02-11 12:18:05 +00:00
MerryMage
8c6fce20d2 IR: Implement FPVectorSub 2018-02-11 12:17:53 +00:00
MerryMage
3fffeadf0d emit_x64_vector: EmitOneArgumentFallback 2018-02-11 11:59:43 +00:00
MerryMage
4df6c424df Forward declare IR::Opcode and IR::Type where possible 2018-02-11 11:52:44 +00:00
MerryMage
09632954d7 A64: Implement CNT 2018-02-11 11:52:44 +00:00
MerryMage
c2c9ea85a5 IR: Implement VectorPopulationCount 2018-02-11 11:52:44 +00:00
MerryMage
0996d4fd2e A64: Implement MLS (vector) 2018-02-11 11:04:46 +00:00
MerryMage
5319f6af95 A64: Implement MLA (vector) 2018-02-11 11:00:16 +00:00
MerryMage
17519df3e8 emit_x64_vector: Add SSE4.1 implementation for EmitVectorMultiply64 2018-02-11 10:47:22 +00:00
MerryMage
eac6a56a4b emit_x64_vector: More explicit lambda decay 2018-02-11 10:47:00 +00:00
MerryMage
727b1b0b51 A64: Implement MUL (vector) 2018-02-11 10:18:47 +00:00
MerryMage
80fce9c4b9 IR: Implement VectorMultiply 2018-02-11 10:18:29 +00:00
MerryMage
cb65a26da2 emit_x64_vector: Order alphabetically 2018-02-11 09:41:37 +00:00
MerryMage
2b968981a1 A64: Implement STR (register, SIMD&FP), LDR (register, SIMD&FP) 2018-02-11 01:06:26 +00:00
MerryMage
7681159811 decoder/a64: Don't rearrange unrelated decoders 2018-02-11 00:43:33 +00:00
MerryMage
56fe848e4e A64: Implement SUB (vector) 2018-02-10 23:58:33 +00:00
MerryMage
b429efa081 A64: Implement SIMD instruction SSRA, vector variant 2018-02-10 23:30:00 +00:00
MerryMage
0a96a437cb A64: Implement SIMD instruction SSHR, vector variant 2018-02-10 23:28:05 +00:00
MerryMage
a5299d0be5 IR: Implement VectorArithmeticShiftRight 2018-02-10 23:27:46 +00:00
MerryMage
8e8068cfaf impl: Improve Vpart setter 2018-02-10 17:05:52 +00:00
MerryMage
5ffa84f41d A64: Implement SIMD instructions XTN, XTN2 2018-02-10 17:01:33 +00:00
MerryMage
dc9785bdcd IR: Implement VectorNarrow 2018-02-10 17:01:33 +00:00
MerryMage
ebc594385c constant_pool: Allow for 128-bit constants 2018-02-10 16:36:00 +00:00
MerryMage
8e23683b63 emit_x64_vector: Add SSE4.1 implementations for VectorZeroExtend 2018-02-10 16:24:43 +00:00
MerryMage
d9f803924e IR: Implement VectorSub 2018-02-10 11:25:50 +00:00
MerryMage
c01bbbd09d A64: Implement SIMD instruction USRA, vector variant 2018-02-10 11:12:54 +00:00
MerryMage
9e80f94b5f A64: Implement SIMD instruction USHR, vector variant 2018-02-10 11:05:58 +00:00
MerryMage
e6a0a4d8ce IR: Implement VectorLogicalShiftRight 2018-02-10 11:05:22 +00:00
MerryMage
60ddaa8f38 A64: Implement SIMD instructions USHLL, USHLL2 2018-02-10 10:35:14 +00:00
MerryMage
670b47149e IR: Implement VectorZeroExtend 2018-02-10 10:35:14 +00:00
MerryMage
7ec12cbade IR: Vector instructions now take esize argument in emitter 2018-02-10 10:18:10 +00:00
MerryMage
b219105b75 A64: Implement SIMD instruction SHL 2018-02-10 09:49:55 +00:00
MerryMage
570911e693 IR: Implement VectorLogicalShiftLeft{8,16,32,64} 2018-02-10 09:31:54 +00:00
MerryMage
e03a9fed98 opcodes: Sort vector IR opcodes alphabetically 2018-02-10 09:15:01 +00:00
MerryMage
406c071008 block_of_code: Increase constant pool size 2018-02-09 16:04:56 +00:00
MerryMage
9be412bbc2 devirtualize: MinGW uses Intanium MFP ABI 2018-02-09 16:04:48 +00:00
MerryMage
7a0fdf01bb callback: Properly handle calls with return pointers and simplify interface 2018-02-09 16:02:57 +00:00
FernandoS27
dee211c4df Implemented BSL, BIC, BIT and BIF vector instructions 2018-02-09 13:28:16 +00:00
MerryMage
15da38d3aa devirtualize: Handle Windows ABI 2018-02-09 11:19:40 +00:00
MerryMage
41ae12263d travis: Switch to yuzu-emu's unicorn repository 2018-02-08 19:48:04 +00:00
MerryMage
83a762eee7 fuzz_arm: Use SCOPE_FAIL 2018-02-08 02:14:42 +00:00
MerryMage
b0991ee46f A32/decoder/arm: bug: Correct bitstring for SRS 2018-02-08 02:05:49 +00:00
MerryMage
43035fd064 devirtualize: Devirtualize Itanium ABI MFPs at runtime 2018-02-07 12:25:45 +00:00
MerryMage
36ec1d09cf cast_util: Add BitCast and BitCastPointee 2018-02-07 12:25:45 +00:00
Lioncash
1ee5b2e352 A64: Move SDIV and UDIV out of data_processing_multiply.cpp 2018-02-07 12:07:09 +00:00
Lioncash
25e7c94995 A64: Implement ZIP1 2018-02-07 12:06:49 +00:00
FernandoS27
c882e6819d Implemented UMULH and SMULH instructions 2018-02-06 23:59:24 +00:00
MerryMage
32be42c68e A64: Implement MOVI, MVNI, ORR (vector, immediate), BIC (vector, immediate)
There wasn't a clean way to seperate these instructions out.
2018-02-06 23:29:18 +00:00
MerryMage
b6775f1282 impl: Add AdvSIMDExpandImm 2018-02-06 23:04:23 +00:00
MerryMage
023c2c9818 A64: Implement SUB (vector), scalar variant 2018-02-06 22:12:39 +00:00
MerryMage
b544b8f4b1 A64: Implement ADD (vector), scalar variant 2018-02-06 22:09:39 +00:00
MerryMage
63d3a1cc1c A64: Reorganize decoder tables (some vector entries were grouped with scalar entries) 2018-02-06 18:30:36 +00:00
MerryMage
59a84ed966 A64: Implement BIC (vector, register) 2018-02-06 17:57:50 +00:00
MerryMage
41bbb56cff docs: Update documentation (2018-02-05) 2018-02-05 22:36:03 +00:00
MerryMage
8530f52729 A64: Implement FMOV (general) 2018-02-05 21:44:20 +00:00
MerryMage
ef9057555b translate/impl: Add Vpart 2018-02-05 21:43:58 +00:00
MerryMage
37b4840c6f A64: Implement STLLRB, STLLRH, STLLR, LDLARB, LDLARH, LDLAR 2018-02-05 15:41:41 +00:00
MerryMage
a785d4fa66 A64: Implement FCCMPE 2018-02-05 12:26:19 +00:00
MerryMage
d2a2562a25 A64: Implement FCCMP 2018-02-05 12:26:19 +00:00
MerryMage
24178131a6 a64_jitstate: Remove unnecessary FPSCR_nzcv member 2018-02-05 12:26:19 +00:00
MerryMage
37a9472f81 IR: FPCompare{32,64} now return NZCV flags instead of implicitly setting them 2018-02-05 12:26:19 +00:00
Lioncash
d86b8fc40d A64: Implement FMOV (register) 2018-02-05 09:34:47 +00:00
MerryMage
97a742a7c0 A64: Implement STLRB, STLRH, STLR, LDARB, LDARH, LDAR 2018-02-05 01:12:19 +00:00
Lioncash
e619902ee5 A64: Implement CCMP (immediate) 2018-02-05 00:45:39 +00:00
Lioncash
d91989a014 A64: Implement CCMN (immediate) 2018-02-05 00:45:39 +00:00
Lioncash
d5e58ac771 A64: Implement CCMP (register) 2018-02-05 00:45:39 +00:00
Lioncash
cd3113c208 microinstruction: Add ConditionalSelectNZCV opcode to ReadsFromCPSR()'s switch statement 2018-02-05 00:45:11 +00:00
MerryMage
10594c7adb A64: Implement CCMN (register) 2018-02-04 23:11:07 +00:00
MerryMage
ee8726a8ba IR: Add ConditionalSelectNZCV instruction 2018-02-04 23:08:43 +00:00
Lioncash
1621741fc6 inst_gen: Make invalid_instructions a static inline variable 2018-02-04 19:44:29 +00:00
Lioncash
73ad0b0b00 fuzz_with_unicorn: Move instruction generator vector into GenRandomInst
Keeps scope localized and prevents potential static initialization issues.
2018-02-04 19:44:29 +00:00
MerryMage
c3d2edf8ee A64: Implement FNEG 2018-02-04 13:44:33 +00:00
MerryMage
ad5fe6dc43 A64: Implement FABS 2018-02-04 13:43:47 +00:00
MerryMage
107bd14a43 A64: Implement FCSEL 2018-02-04 13:40:37 +00:00
MerryMage
9db02bb4db A64: Implement SCVTF (scalar, integer), UCVTF (scalar, integer) 2018-02-04 13:21:31 +00:00
MerryMage
f87ecad5a4 A64: Implement FCVTZS (scalar, integer), FCVTZU (scalar, integer) 2018-02-04 13:09:57 +00:00
MerryMage
cc7b315268 backend_x64: Simplify FPDoubleToU32 and FPSingleToU32
They're inaccurate in terms of FPSR at the moment anyway.
2018-02-04 13:07:19 +00:00
MerryMage
e5ce22aabc A64: Implement STR{,B,H} (register), LDR{,B,H,SB,SH,SW} (register), PFRM (register) 2018-02-04 12:49:40 +00:00
Lioncash
dc9317f714 Common: Put AES code within its own nested namespace
Prevents the functions from potentially clashing with other stuff in Common in the future
2018-02-03 23:11:46 +00:00
Lioncash
ccf9493653 A64: Implement AESD 2018-02-03 23:11:46 +00:00
Lioncash
33bc59c55a A64: Implement AESE 2018-02-03 23:11:46 +00:00
MerryMage
db6999fc38 backend_x64: Use a reference to BlockOfCode instead of a pointer 2018-02-03 14:28:57 +00:00
MerryMage
a7209dc2f7 IR: Add IR instruction NZCVFromPackedFlags
This instruction expects NZCV to be in the high bits.
i.e.: The positions they were in PSTATE.
2018-02-03 13:41:36 +00:00
MerryMage
2262b08a04 A64: Implement INS (general) 2018-02-03 13:07:00 +00:00
MerryMage
3c140141db A64: Implement INS (element) 2018-02-03 13:03:50 +00:00
MerryMage
af5fb0a1a0 A64: Implement SMOV 2018-02-03 12:58:19 +00:00
MerryMage
818b9a4673 A64: Implement UMOV 2018-02-03 12:55:53 +00:00
MerryMage
9ea219e010 basic_block: Fix bogus GCC maybe-uninitialized warning 2018-02-03 03:04:44 +00:00
MerryMage
64e37de179 A64: Implement FCVT 2018-02-03 01:23:11 +00:00
MerryMage
f1d2cdde34 fuzz_with_unicorn: Skip instructions that need to be interpreted 2018-02-03 01:22:40 +00:00
MerryMage
2fd70e56ce A64: Implement FMOV (scalar, immediate) 2018-02-03 00:52:48 +00:00
MerryMage
567c1b57fc A64: Implement STUR (SIMD&FP), LDUR (SIMD&FP) 2018-02-02 22:39:24 +00:00
MerryMage
c42ca435ba A64: Implement FCMP, FCMPE 2018-02-02 22:25:51 +00:00
MerryMage
0131a87c43 a64_jitstate: A64 does not have a seperate FPSCR.NZCV 2018-02-02 22:25:18 +00:00
MerryMage
4728257d4e A64: Implement FMUL (scalar), FDIV (scalar), FADD (scalar), FSUB (scalar), FNMUL (scalar) 2018-02-02 22:04:09 +00:00
MerryMage
fcabd95ad0 IR: Merge U32 and U64 variants of FP instructions 2018-02-02 21:55:23 +00:00
MerryMage
6d9adb668e A64: Implement {ST,LD}{1,2,3,4} (multiple structures) 2018-02-02 21:10:30 +00:00
MerryMage
bfeb9ff617 emit_x64_vector: bug: VectorGetElement8 returning incorrect values for non-SSE4.1
This bug wasn't discovered earlier because we previously only used index == 0.
2018-02-02 21:07:00 +00:00
MerryMage
cc40b83ed0 IR: Implement VectorSetElement{8,16,32,64} 2018-02-02 21:00:12 +00:00
Lioncash
b608979be9 A64: Implement AESIMC and AESMC 2018-02-02 17:35:16 +00:00
Lioncash
58598e2e15 iterator_util: Make Reverse constexpr
C++17 makes non-member rbegin(), rend(), crbegin(), and crend() constexpr, allowing this to also be constexpr.
2018-01-31 18:09:15 +00:00
Lioncash
c9da41884c Common: Relocate common bits of CRC32
Allows the algorithm to be used in any other potential backend.
2018-01-30 07:57:29 +00:00
Lioncash
7fb386aa1c A64: Implement CRC32 2018-01-29 17:06:17 +00:00
MerryMage
64157d34cf travis: Bump MACOSX_DEPLOYMENT_TARGET 2018-01-29 17:05:50 +00:00
MerryMage
65078d5b18 fuzz_with_unicorn: Print information on test failure 2018-01-28 22:33:34 +00:00
MerryMage
4cc2cecaff scope_exit: Add SCOPE_SUCCESS and SCOPE_EXIT 2018-01-28 18:03:58 +00:00
MerryMage
607b9c8c62 A64: Add Disassemble method 2018-01-28 18:03:57 +00:00
MerryMage
e0ab098473 A32: data_processing: Remove !S assertions 2018-01-28 12:59:52 +00:00
MerryMage
b96014b3b2 A32: Implement BKPT 2018-01-28 12:59:52 +00:00
MerryMage
14910e53d3 A32: Add ExceptionRaised IR instruction and use it 2018-01-28 12:59:52 +00:00
Lioncash
0216cbd2a5 A64: Implement CRC32C 2018-01-28 12:20:56 +00:00
MerryMage
2e14326fd5 assert: Use fmt in ASSERT_MSG 2018-01-28 00:00:58 +00:00
Lioncash
7a96daa715 externals: Update catch to v2.1.1
Brings in a few minor improvements like proper stringification of static arrays.
2018-01-27 22:54:22 +00:00
Lioncash
7f31a9b5ab fuzz_with_unicorn: Move data outside loop
Given we know we're only ever going to use one instruction, we can just presize the vector and reassign to it
instead of potentially reallocating the same memory 100000 times
2018-01-27 22:54:01 +00:00
Lioncash
763a4783f9 fuzz_with_unicorn: Dehardcode some constants 2018-01-27 22:54:01 +00:00
MerryMage
1f06ca80d4 a64_emit_x64: Perform RSB predictions 2018-01-27 22:48:08 +00:00
MerryMage
3f6889f700 A32: Change UserCallbacks to be similar to A64's interface 2018-01-27 22:45:48 +00:00
Lioncash
4798a40908 reg_alloc: std::move RegAlloc's function argument 2018-01-27 02:52:59 +00:00
Lioncash
c40e7acc8e General: Add missing override specifiers 2018-01-27 02:46:04 +00:00
MerryMage
e111309aba EmitZeroExtendLongToQuad: Do not rely on register allocator to zero extend 64->128 2018-01-27 02:00:49 +00:00
MerryMage
a1018a4eea a64_get_set_elimination_pass: Simplify algorithm 2018-01-27 02:00:49 +00:00
MerryMage
ac1f4d3d5d a64_emit_x64: bug: x64 sign-extends 32-bit immediates 2018-01-27 00:38:43 +00:00
MerryMage
9232be5553 ir_opt: Add A64 Get/Set Elimination Pass 2018-01-27 00:38:43 +00:00
MerryMage
39b7625e9d ir_emitter: Allow the insertion point for new instructions to be set 2018-01-27 00:38:43 +00:00
MerryMage
68c5399607 {a32,a64}_interface: Predict entrypoint 2018-01-27 00:38:42 +00:00
Lioncash
dbddb4858a A64: Implement EXTR 2018-01-26 22:07:48 +00:00
MerryMage
43330ec3ba Squashed 'externals/xbyak/' changes from d512551e..2794cde7
2794cde7 add xword, yword, etc. in Xbyak::util
fb9c04e4 fix document for vfpclassps
a51be78b fix test dependency
04fdfb1e update version
e6354f8b add vgf2p8mulb
09a12642 add gf2p8affineqb
d171ba0e add gf2p8affineinvqb
457f4fd0 add vpshufbitqmb
5af0ba39 add vpexpand{b,w}
e450f965 vpopcnt{d,q} supports ptr_b
48499eb1 add vpdpbusd(s), vpdpwssd(s)
9c745109 add vpdpbusd, vpdpbusds
0e1a11b4 add vpopcnt{b,w,d,q}
9acfc132 add vpshrd(v){w,d,q}
ac8de850 add vpshld(v){w,d,q}
f181c259 add vcompressb, vcompressw
5a402477 vpclmulqdq supports AVX-512
9e16b40b vaes* supports AVX-512
7fde08e0 add flags for intel's manual 319433-030.pdf
c5da3778 add test of v4fmaddps, vp4dpwssd, etc.
e4fc9d8a fix mpx encoding
d0b2fb62 add bnd(0xf2) prefix for MPX
f12b5678 use db for array
cd74ab44 remove bat file

git-subtree-dir: externals/xbyak
git-subtree-split: 2794cde79eb71e86490061cac9622ad0067b8d15
2018-01-26 18:39:45 +00:00
MerryMage
0dc584a62d externals: Update xbyak to v5.601
Merge commit '43330ec3ba6dae3829675874258bdd717d0f3f19'
2018-01-26 18:39:45 +00:00
MerryMage
bda9148e71 A64: Implement LDP (SIMD&FP) and STP (SIMD&FP) 2018-01-26 18:39:19 +00:00
MerryMage
e789d8ff53 a64_jitstate: Have 128-bit wide spills 2018-01-26 18:38:31 +00:00
MerryMage
0c1c82a937 IR: Implement IR instructions A64{Get,Set}S 2018-01-26 18:38:30 +00:00
MerryMage
ef6b4f20ca a64_emit_x64: Use xword from Xbyak::util 2018-01-26 18:38:30 +00:00
Lioncash
8c013e7928 General: Convert multiple namespace specifiers to nested namespace specifiers where applicable
Makes namespacing a little less noisy
2018-01-26 17:06:48 +00:00
Lioncash
792cb91753 A64: Zero upper 64 bits in ORN if using the 64-bit variant
Resolves a TODO
2018-01-26 17:06:26 +00:00
Lioncash
07930f0253 unicorn: Display EC and ISS separately beside the full ESR value
Makes it a little nicer to pick out the exception class details at a glance
2018-01-26 12:31:43 +00:00
Lioncash
e99cbcf4e3 unicorn: Use static_cast instead of reinterpret_cast
It's well-defined to cast from void* back to the original pointer type.
2018-01-26 12:31:33 +00:00
MerryMage
a3af4dd218 load_store_register_unprivileged: bug: LDTRSW 2018-01-26 02:03:16 +00:00
MerryMage
06bea0ceaa A64: Implement CMEQ (register, vector) 2018-01-26 01:52:42 +00:00
MerryMage
f7e8a2259a IR: Implement IR instructions VectorEqual{8,16,32,64,128} 2018-01-26 01:52:06 +00:00
MerryMage
f833a17906 reg_alloc: Use std::exchange 2018-01-26 01:51:04 +00:00
Fernando Sahmkow
5ffd11d140 A64: Implemented EOR (vector), ORR (vector, register) and ORN (vector) Instructions (#142) 2018-01-26 00:57:56 +00:00
Lioncash
fc82109071 unicorn_load: Minor Windows-related changes
- Add missing include
- Fix a potential compilation issue where the constructor wouldn't be able to execute, as it would be private.
2018-01-26 00:52:46 +00:00
MerryMage
d08b738662 tests/A64: Test memory writes 2018-01-25 23:56:57 +00:00
MerryMage
d99c99aabb microinstruction: Missed A64{Read,Write}Memory128 from opcode information 2018-01-25 23:56:14 +00:00
MerryMage
85034beaac emit_x64_packed: EmitPackedSubU16 modified xmm_b wasn't writeable
For CPUs that didn't support SSE4.1, this was a bug.
2018-01-25 18:41:53 +00:00
Lioncash
1ffe4e03d9 tests: Fix truncation in GetFpcr() 2018-01-25 18:26:32 +00:00
James Rowe
0cc1bce1a8 Fixup: Xn|SP are 64 bit addresses encoded in the Rn field 2018-01-25 17:46:14 +00:00
James Rowe
76aaa84687 A64: Fix bugs and address review comments 2018-01-25 17:46:14 +00:00
James Rowe
7825ae3a4f Add missing returns 2018-01-25 17:46:14 +00:00
James Rowe
ddb5b3469d A64: Implement Load/Store register (unprivileged) 2018-01-25 17:46:14 +00:00
MerryMage
7f3a790de5 fixup: travis: Test with disabled CPU feature detection 2018-01-24 19:42:54 +00:00
Lioncash
850337e434 CMakeLists: Add opcodes.inc to the source file list
Allows the file to show up nicely within IDEs
2018-01-24 19:42:02 +00:00
MerryMage
7d389fb5f8 travis: Test with disabled CPU feature detection
Ensure that fallbacks are working correctly.
2018-01-24 19:22:45 +00:00
MerryMage
314e020992 IR: Add IR instruction VectorZeroUpper 2018-01-24 17:11:13 +00:00
MerryMage
8ce3e0518a a64_emit_x64: bug: EmitA64WriteMemory128 should write not read 2018-01-24 17:10:44 +00:00
FernandoS27
d1664096f5 Implemented SDIV and UDIV instructions 2018-01-24 17:09:00 +00:00
MerryMage
8873d17db2 A64: Implement LDR/STR (immediate, SIMD&FP) 2018-01-24 16:28:18 +00:00
MerryMage
7f5ce36368 IR: Add IR instructions A64Memory{Read,Write}128
Add the Windows ABI implementation
2018-01-24 16:28:18 +00:00
MerryMage
d6589fe3ee IR: Add IR instructions A64Memory{Read,Write}128
This implementation only works on macOS and Linux.
2018-01-24 16:18:58 +00:00
MerryMage
5421c90216 IR: Add IR instruction VectorGetElement{8,16,32,64} 2018-01-24 16:18:58 +00:00
MerryMage
3932d6d695 IR: Add IR instruction ZeroExtendToQuad 2018-01-24 16:18:58 +00:00
MerryMage
264c446e54 block_of_code: Add ABI_RETURN2 2018-01-24 16:18:58 +00:00
MerryMage
ed63cc7ae9 interface: Move Vector typedef to config.h 2018-01-24 16:18:58 +00:00
MerryMage
ef81c2bcfc bit_util: bug: Infinite loop in HighestSetBit 2018-01-24 16:18:58 +00:00
MerryMage
1db423b2ad A64: Implement DUP (general) 2018-01-24 12:01:26 +00:00
MerryMage
6f1c44e311 IR: Implement Vector{Lower,}Broadcast{8,16,32,64} 2018-01-24 12:01:26 +00:00
Lioncash
cdb588dab5 General: Default constructors and destructors where applicable 2018-01-24 09:07:22 +00:00
Lioncash
e300f1de46 ir_emitter: Remove unused includes 2018-01-24 01:50:10 +00:00
Lioncash
0e5988258d A64: Implement RBIT 2018-01-24 01:49:58 +00:00
MerryMage
ae603909d6 ir_emitted: Remove unimplemented IR instruction Unimplemented 2018-01-23 22:16:15 +00:00
MerryMage
f014a5bec7 emit_x64: Extract BlockRangeInformation, remove template parameter 2018-01-23 19:44:35 +00:00
MerryMage
5f5e664a66 emit_x64: Use JitStateInfo 2018-01-23 19:44:35 +00:00
MerryMage
d52cb2d0de A64: Implement CLS
This is not the cleanest implementation.
2018-01-23 19:44:35 +00:00
MerryMage
24383e543b A64: Implement ADDP (vector) 2018-01-23 17:46:28 +00:00
MerryMage
dfcbe5bd2f IR: Implement Vector{Lower,}PairedAdd{8,16,32,64} 2018-01-23 17:46:28 +00:00
MerryMage
961e64dfaf backend_x64: Split emit_x64 2018-01-23 17:46:28 +00:00
MerryMage
41d9a6421d fuzz_with_unicorn: Compare vectors 2018-01-23 17:46:28 +00:00
MerryMage
2b59e2ba0b microinstruction: bug: Add missing opcodes 2018-01-23 17:46:28 +00:00
Lioncash
bd00d9bc80 A64: Implement SMADDL, SMSUBL, UMADDL, and UMSUBL 2018-01-23 16:08:05 +00:00
Lioncash
768e5bcf9c A64: Implement MADD and MSUB 2018-01-23 16:08:05 +00:00
Lioncash
ffaf837e58 A64: Implement CLZ 2018-01-23 11:55:09 +00:00
Lioncash
585e77d20e opcodes: Add 64-bit CountLeadingZeroes opcode 2018-01-23 11:55:09 +00:00
MerryMage
f2dc9c7727 data_processing_register: Clean-up 2018-01-22 22:47:01 +00:00
Lioncash
efa67caf5f A64: Implement HINT, NOP, YIELD, WFE, WFI, SEV, and SEVL
Truly the most difficult A64 instructions to implement.
2018-01-22 11:54:12 +00:00
Lioncash
692cd6f27b A64: Implement ASRV, LSLV, LSRV, and RORV 2018-01-22 11:51:46 +00:00
Lioncash
a5978a01ca data_processsing_conditional_select: Implement CSINC, CSINV and CSNEG 2018-01-21 23:33:18 +00:00
Lioncash
48e4e021f7 a32/a64_emit_x64: Remove unused includes 2018-01-21 20:09:23 +00:00
MerryMage
a6d17e6bb0 A64: Implement AND (vector) 2018-01-21 18:27:06 +00:00
MerryMage
9634532822 tests/A64: Randomize vectors 2018-01-21 17:56:27 +00:00
MerryMage
adcd34fac7 tests/A64/unicorn: Print interrupt number when InterruptHook is hit 2018-01-21 17:56:27 +00:00
MerryMage
304c91abd3 tests/A64: Allow RunTestInstance to start from an arbitrary offset 2018-01-21 17:56:27 +00:00
MerryMage
d333b5dcee A64: Implement ADD (vector, vector) 2018-01-21 17:56:27 +00:00
Thomas Guillemard
1cf87a24b2 A64: Implement REV, REV32, and REV16 (#126) 2018-01-21 12:17:47 +00:00
MerryMage
9fc1570788 IR: Simplify types. F32 -> U32, F64 -> U64, F128 -> U128
ARM's Architecture Specification Language doesn't distinguish between floats and integers
as much as we do. This makes some things difficult to implement. Since our register
allocator is now capable of allocating values to XMMs and GPRs as necessary, the
Transfer IR instructions are no longer necessary as they used to be and they can be
removed.
2018-01-19 01:09:46 +00:00
MerryMage
50c18181aa reg_alloc: GetBitWidth: Add UNREACHABLE 2018-01-18 23:46:01 +00:00
MerryMage
adccbf3c6b reg_alloc: Consider bitwidth of data and registers when emitting instructions 2018-01-18 13:00:16 +00:00
MerryMage
7b7f239831 A64: Implement CSEL 2018-01-18 11:41:27 +00:00
MerryMage
2f84137f5b IR: Implement Conditional Select 2018-01-18 11:36:52 +00:00
MerryMage
ebb3e80129 A64/tests: Split unicorn sanity checking from other tests 2018-01-17 20:00:42 +00:00
MerryMage
5740a0272c tests/A64: Single random instruction: Test branch instructions as well 2018-01-17 00:35:01 +00:00
MerryMage
0892b487b7 A64/translate/branch: bug: Read-after-write error in BLR 2018-01-17 00:34:33 +00:00
MerryMage
e77bc26945 A64: Implement SBFM, BFM, UBFM 2018-01-17 00:15:44 +00:00
MerryMage
0c37ca71c6 A64: Implement MOVN, MOVZ, MOVK 2018-01-15 21:47:28 +00:00
MerryMage
b6bb592d9a travis: Print current test information 2018-01-14 20:38:50 +00:00
MerryMage
e772072679 fuzz_thumb: Off by one error 2018-01-14 20:37:08 +00:00
MerryMage
a04ca20a89 ir/location_descriptor: Add missing <functional> header for std::hash 2018-01-14 20:23:24 +00:00
MerryMage
1e0f5cd9b9 travis: Run A64 tests 2018-01-14 20:23:24 +00:00
MerryMage
bc73004dd5 a64_merge_interpret_blocks: Remove debug output 2018-01-13 22:05:05 +00:00
MerryMage
4e656ede94 tests/A64: Randomize PSTATE.<NZCV> 2018-01-13 21:57:18 +00:00
MerryMage
fd9530be25 A64: Optimization: Merge interpret blocks 2018-01-13 21:57:18 +00:00
MerryMage
3c9eb04812 testenv: Use format constants 2018-01-13 18:31:39 +00:00
MerryMage
324f3fc2b3 tests/A64: Unicorn interface fixes
- Use a std::unique_ptr instead of new/delete.
- UnmappedMemoryHook: Correct range when wraparound of the address space occurs
- UnmappedMemoryHook: Handle case when we attempt to map the same page twice
2018-01-13 18:30:02 +00:00
MerryMage
98ecbe75ca tests/A64: Fuzz against unicorn 2018-01-13 18:06:06 +00:00
MerryMage
b1d38e7a46 tests/A64: Move TestEnvironment to own header 2018-01-13 18:06:06 +00:00
MerryMage
5218ad97e2 A64/data_processing_pcrel: bug: ADR{,P} instructions sign extend their immediate 2018-01-13 18:06:06 +00:00
MerryMage
b1a8c39c19 A64/data_processing_addsub: bug: {ADD,SUB}S (extended register) instructions write to ZR when d = 31 2018-01-13 18:06:06 +00:00
MerryMage
64827fbe8e a64_emit_x64: bug: A64CallSupervisor trampled callee-save registers 2018-01-13 18:06:06 +00:00
MerryMage
1bfa04d7ac emit_x64: bug: OP m/r64, imm32 form instructions sign-extend their immediate on x64 2018-01-13 18:06:06 +00:00
MerryMage
edadeeabda A64 inferface: Use two argument static_assert
Don't require C++17 in the interface to the library
2018-01-13 18:06:06 +00:00
MerryMage
9ab130490b A64: Add ExceptionRaised IR instruction
The purpose of this instruction is to raise exceptions when certain decode-time
issues happen, instead of asserting at translate time. This allows us to
use the translator for code analysis without worrying about unnecessary asserts,
but also provides flexibility for the library user to perform custom behaviour
when one of these states are raised.
2018-01-13 18:06:06 +00:00
MerryMage
6843eed8de Update readme 2018-01-12 20:05:17 +00:00
MerryMage
7438d07f2b A64/translate: Add TranslateSingleInstruction function 2018-01-12 19:34:25 +00:00
MerryMage
83afe4353c Misc. fixups of MSVC build 2018-01-12 18:13:53 +00:00
MerryMage
ad95a75047 imm: Suppress MSVC warning C4244: value will never be truncated 2018-01-12 17:18:07 +00:00
MerryMage
f8178054d9 Merge remote-tracking branch 'origin/master' into a64 2018-01-12 17:12:18 +00:00
MerryMage
ebaeceec37 fixup! imm: compiler bug: MSVC 19.12 2018-01-12 17:11:42 +00:00
MerryMage
0d65c187a3 tests/a64: Use format constants 2018-01-12 17:02:26 +00:00
MerryMage
3a0b7d59f0 imm: compiler bug: MSVC 19.12 with /permissive- flag doesn't support fold expressions 2018-01-12 17:01:21 +00:00
MerryMage
dd285abec5 A64/decoder: Split decoder data from header 2018-01-11 13:03:56 +00:00
MerryMage
30af089e49 ir_opt: Split off A32 specific passes 2018-01-11 13:03:56 +00:00
MerryMage
648212995c A64: Implement LDP, STP 2018-01-11 13:03:54 +00:00
MerryMage
192e7a73ea A64/location_descriptor: Fix -fpermissive warning on GCC 2018-01-10 18:56:12 +00:00
MerryMage
3721098000 A32/location_descriptor: Disambiguate identifiers
Otherwise produces an -fpermissive error
2018-01-10 18:40:31 +00:00
MerryMage
7c4b318423 externals: Update catch to v2.1.0
This version of catch incorporates a fix for the std::uncaught_exception deprecation warning
2018-01-10 18:32:00 +00:00
MerryMage
a296373f0f Squashed 'externals/fmt/' changes from 39834389..135ab5cf
135ab5cf Update version
93d95f17 Fix markup
4f15c72f Fix markup
e9b19414 Automatically add package to release
c3d1f604 Fix markup
c96062bf Update changelog and version number
f9c97de4 Add note about errno to the documentation
62df6f27 CMakeLists: Use GNUInstallDirs to set install location
493586cb Fix overflow check
1d751bc6 fix warning in header: signed/unsigned comparison
11415bce Update usage.rst
9982dd01 Fix for warning C5030 in VS2015
42e88c4f Silenced MSVC 2017 constant if expression warning
7a9c1ba1 FMT_VARIADIC_CONST - Support for const variadic methods (#591)
324415c0 Use allocator_traits if available.
5f39721c Fix a warning
ca96acbe Add examples
708d9509 fix(Clang CodeGen): remove warnings
9328a074 Fix handling of fixed enums in clang (#580)
2c077dd4 Enable stream exceptions (#581)
933a33a7 Added MSVC checking for support for string_view.
bef89db6 Fix a bogus -Wduplicated-branches gcc warning (#573)
2a619d96 Make format work with C++17 std::string_view (#571)
e051de37 Use less version 2.6.1 and sudo to fix npm install issues on travis
5de459bf Suppress Clang's warning on zero as a null pointer
16589534 Make ArgMap::init not explicitly instantiated (#563)
3e75d3e0 Fix handling of types convertible to int
89654cd1 to_wstring added
37eb419a Fix noreturn attribute detection (#555)
14d85349 Explicitly cast range length to std::size_t to prevent conversion warnings
c2201ce0 Accept wide chars as integers to prevent conversion warning
6efbccb3 Add one more CMake warning fix
032c8380 Fix a segfault in test on glibc 2.26 #551, take 2
6655e804 Fix a segfault in test on glibc 2.26 #551
d16c4d20 Suppress warning about missing noreturn attribute (#549)
9c56a8ce Make format_arg() accept class hierarchies
ca0e3830 Update README.rst
81790d72 Update format.h to remove C4574 error on MSVC 14.2
30283443 Fix undefined behavior in UDL macro
4045d7fe Fix warning about missing ' character
89c3bc58 Remove warning C4668 in MSVC for FMT_GCC_VERSION and FMT_HAS_GXX_CXX11
4af9421f Adding OpenSpace to the list of projects
1a398b54 Fixed CMake CMP0048 warning.
589ccc16 Bump version
c3817046 Add an error on broken includes
16bdd842 Update scripts
b492316d Update version list
91f4ce02 Automatically update version in release script (#431)

git-subtree-dir: externals/fmt
git-subtree-split: 135ab5cf71ed731fc9fa0653051e7d4884a3652f
2018-01-10 18:23:25 +00:00
MerryMage
8cede8126d externals: Update fmt subtree to 4.10
Merge commit 'a296373f0fd1b44a73c9509d0e3c1f2f078ddd42'
2018-01-10 18:23:25 +00:00
MerryMage
89bdade0a0 A64: Implement LDP, STP 2018-01-10 02:05:08 +00:00
MerryMage
16e50ca0db A32: Implement load stores (immediate) 2018-01-10 01:30:30 +00:00
MerryMage
a5caa7cd8d A64: Implement SVC 2018-01-09 21:30:13 +00:00
MerryMage
79091043f0 imm: bug: SignExtend wasn't working for T with bit size > 32 2018-01-09 21:22:17 +00:00
MerryMage
78ffd3da90 a64_emit_x64: Don't use far code for now 2018-01-09 21:21:50 +00:00
MerryMage
347a5c7171 EmitA64SetW: bug: should zero extend to entire 64-bit register 2018-01-09 21:21:15 +00:00
MerryMage
cc647ce869 EmitA64SetNZCV: bug: to_store is scratch 2018-01-09 21:20:55 +00:00
MerryMage
81d9a62345 appveyor: Use a more recent version of boost 2018-01-09 19:12:20 +00:00
MerryMage
c029aef4da emit_x86: Fix nzcv for EmitSub 2018-01-09 18:57:07 +00:00
MerryMage
f19f014a42 A64: Implement SVC 2018-01-09 18:57:07 +00:00
MerryMage
1aa4afaa22 a64_emit_x64: Call interpreter 2018-01-09 18:57:07 +00:00
MerryMage
6633a19d65 A64: Add batch register retrieval to interface 2018-01-09 18:57:06 +00:00
MerryMage
305456b407 A64: Implement compare and branch 2018-01-09 18:57:06 +00:00
MerryMage
08c25c9ae7 A64: PSTATE access and tests 2018-01-09 18:57:06 +00:00
MerryMage
c4abd1fda1 A64: Implement branch (register) 2018-01-09 18:57:06 +00:00
MerryMage
5497fe9056 A64: Implement branch 2018-01-09 18:57:06 +00:00
MerryMage
f3e763a667 A64: Implement logical 2018-01-09 18:57:06 +00:00
MerryMage
f0c29feddb A64: Implement pcrel 2018-01-09 18:57:06 +00:00
MerryMage
8a8dcad250 A64: Implement addsub instructions 2018-01-09 18:57:06 +00:00
MerryMage
1431cedcaa A64: Implement ADD_shifted 2018-01-09 18:57:06 +00:00
MerryMage
ef6fd92fed A64: Backend framework 2018-01-09 18:57:06 +00:00
MerryMage
557fe60164 A64: Initial framework 2018-01-09 18:57:06 +00:00
MerryMage
cc0c084224 CMakeLists: CMAKE_CXX_STANDARD as no effect on MSVC until CMake 3.10
We add the /std:c++latest flag to DYNARMIC_CXX_FLAGS to fix this.
2018-01-09 18:41:22 +00:00
MerryMage
512dae0361 IR: Compile-time type-checking of IR 2018-01-09 18:20:57 +00:00
MerryMage
b88b7ecbbf IR/Value: Rename RegRef and ExtRegRef to A32Reg and A32ExtReg 2018-01-09 18:20:57 +00:00
MerryMage
dbbbf4c331 Make IR->A32 LocationDescriptor conversion explicit 2018-01-09 18:20:57 +00:00
MerryMage
be094ff150 Final A32 refactor 2018-01-09 18:20:57 +00:00
MerryMage
faf64f4a5f EmitX64: JitState type as template parameter 2018-01-09 18:20:57 +00:00
MerryMage
d95a01bcb3 Package up emit context 2018-01-09 18:20:57 +00:00
MerryMage
d67332e333 Rename JitState to A32JitState 2018-01-09 18:20:57 +00:00
MerryMage
053c58f48f backend_x64: Split A32 specific emission into separate class 2018-01-09 18:20:57 +00:00
MerryMage
42c83fadce IR: Split off A32 specific opcodes 2018-01-09 18:20:57 +00:00
MerryMage
f5402c8d82 A32: Split off A32 specific IREmitter 2018-01-09 18:20:57 +00:00
MerryMage
3e569047a5 Label A32 specific code appropriately 2018-01-09 18:20:57 +00:00
MerryMage
305fba50ba Bump requirements to C++17 2018-01-01 20:33:44 +00:00
Phanto-m
672069608f emit_x64: InvalidateCacheRanges: erase blocks after iterating through the map (#124) 2017-12-18 15:13:40 +00:00
MerryMage
ce9c265df0 EmitPackedHalvingSub{U,S}16: SSE2 implementation 2017-12-14 15:08:18 +00:00
MerryMage
13fa10e743 Merge branch 'misc'
These commits introduce context save and restore, and a small number of
optimizations that depend on their use for performance.
2017-12-12 22:07:39 +00:00
MerryMage
a7d2fac2d3 EmitPackedHalvingAddU8: Add SSE2 implementation 2017-12-12 16:11:22 +00:00
MerryMage
16ed4bd511 EmitPackedHalvingAdd{U,S}16: Add SSE2 implementation 2017-12-12 15:57:26 +00:00
MerryMage
afc47e1733 emit_x64: EmitSet{Register,ExtendedRegister32,ExtendedRegister64}: Store from current source 2017-12-12 15:28:37 +00:00
MerryMage
d1d4705364 Add re-entry prediction to avoid std::unordered_map lookups 2017-12-12 15:22:23 +00:00
MerryMage
dd07033dce emit_x64: Optimize code emitted by EmitGetCpsr 2017-12-12 14:25:22 +00:00
MerryMage
c823ecf524 interface: Allow saving and storing of contexts 2017-12-12 14:24:07 +00:00
MerryMage
976a098bf6 jit_state: Split off CPSR.NZCV 2017-12-12 14:24:07 +00:00
MerryMage
cfdc8d882f jit_state: Split off CPSR.Q 2017-12-12 14:23:34 +00:00
MerryMage
2e6eda226c jit_state: Split off CPSR.{E,T}
This allows us to improve code-emission for PopRSBHint. We also improve
code emission other terminals at the same time.
2017-12-12 14:23:34 +00:00
MerryMage
809ca5fcc2 jit_state: Split off CPSR.GE 2017-12-12 14:23:34 +00:00
MerryMage
e1daadff81 jit_state: Hide cpsr implementation 2017-12-12 14:23:34 +00:00
MerryMage
5b23e5b52e emit_x64: Make RSB a stack 2017-12-12 14:23:32 +00:00
MerryMage
2577803203 emit_x64: Arguments to MostSignificantBit and IsZero are 32-bit 2017-12-09 16:26:11 +00:00
MerryMage
199e79cead block_of_code: Remove vzeroupper 2017-12-09 16:26:03 +00:00
MerryMage
a2bd9a0e12 emit_x64: Reduce mxscr operations in EmitGetFpscr and EmitSetFpscr 2017-12-09 16:25:58 +00:00
MerryMage
96ad17ffc2 CMakeLists: Fixup boost
* boost is part of the public interface.
* Consider boost a system library so warnings from boost do not cause a build failure.
* If the parent project defines boost, use that.
2017-12-08 15:15:52 +00:00
MerryMage
5863ea7291 interface_x64: Fix MSVC cast warning 2017-12-07 20:26:46 +00:00
MerryMage
4110494ac4 emit_x64: Use boost::icl::interval_map to speed up ranged invalidation 2017-12-06 20:55:29 +00:00
MerryMage
b6b061f244 emit_x64: Remove unnecessary ABI overhead in ReadMemory, WriteMemory 2017-12-03 19:46:26 +00:00
MerryMage
f343c56268 block_of_code: Move MXCSR switching out of dispatch loop
Also clarify MXCSR entry/exit terminology
2017-12-03 15:39:47 +00:00
MerryMage
651460f941 Merge branch 'timing'
We do this to improve timing information before entering a supervior
function. We also do this to try and stay within JITted code as much
as possible, by updating the cycles we have remaining.
2017-12-03 15:20:43 +00:00
MerryMage
024fa2461c Add AddTicks and GetTicksRemaining callbacks 2017-12-03 15:18:08 +00:00
MerryMage
6131d0e053 BlockOfCode: Detect space remaining
We also clear the code cache when we run out of space.

This closes #111.
2017-12-03 14:32:30 +00:00
MerryMage
bb87d2540c Remove unnecessary use of boost::make_optional
Closes #119.
2017-11-28 20:56:54 +00:00
MerryMage
355d65ec0d CMakeLists: Default to a Release build 2017-11-28 20:08:45 +00:00
MerryMage
5f64bf9cfa decoder_detail: Lambda captures may be unused if iota is an empty sequence
Closes #120
2017-11-28 19:48:32 +00:00
MerryMage
1d75664afd Remove UNUSED macro 2017-11-28 19:44:33 +00:00
MerryMage
67c8e6e695 microinstruction: Remove DecrementRemainingUses 2017-11-27 20:10:23 +00:00
MerryMage
44e6ce33d4 reg_alloc: Add IsLastUse optimization for UseScratch 2017-11-27 19:51:54 +00:00
MerryMage
8e45418630 reg_alloc: Remove reliance on IR::Inst::DecrementRemainingUses 2017-11-27 19:51:54 +00:00
MerryMage
92ae4c783b emit_x86: Standardize time of DefineValue call 2017-11-27 19:51:54 +00:00
MerryMage
6776f83a0c basic_block: Add inst address and use count to DumpBlock
This additional output assists with debugging.
2017-11-27 19:51:54 +00:00
MerryMage
e53d00905f Revert "reg_alloc: Improve performance of HostLocInfo (#112)"
This reverts commit ed4964e8924abfec65d429edcdbb89eb83a17016.

While this may arguably provide a JIT-time benefit, this cannot
possibly provide a runtime benefit.
2017-11-27 19:51:54 +00:00
Mat M
87c9b0affe CMakeLists: Derive the source file listings from targets directly (#118)
This gets rid of the need to store to individual variables before creating
the target itself, cleaning up the variables in the surrounding scope a little bit.
2017-11-26 11:39:27 +00:00
MerryMage
993946fad8 emit_x64: Perform mask creation for packed instructions in SSE 2017-11-25 19:34:30 +00:00
MerryMage
6f4affd67f emit_x64: Eliminate conversion of GE flags
* We do this so that we can simplify PackedSelect.
* We also try to minimise xmm-gpr/gpr-xmm transfers in PackedSelect.
2017-11-25 17:34:39 +00:00
MerryMage
c1dd87aeeb fuzz_arm: Test SEL alongside packed instructions 2017-11-25 17:28:51 +00:00
MerryMage
311b6609aa Implement IR instruction PackedSelect, reimplement SEL 2017-11-25 16:33:48 +00:00
MerryMage
81c5322f40 emit_x64: Remove SSSE3 implementation of PackedHalvingAddU8
It is much slower than the SSE2 implementation, so there's no point keeping it around.
2017-11-25 15:39:06 +00:00
MerryMage
f050825d4d emit_x64: Improve code emission of FPCompare{32,64}
Replace if-chain with table lookup
2017-11-22 17:46:46 +00:00
MerryMage
c421a137c0 VCMP and VCMPE were the other way around
- This was due to a misunderstanding of what the E in VCMPE means.
- The E refers to an exception being raised when a QNaN is encountered.
- Added unit tests for VCMP{E}
2017-11-22 17:45:37 +00:00
MerryMage
3e4b02dd40 skyeye: Correct assumption that VFP_REG_ZERO will always be zero 2017-11-22 17:32:05 +00:00
MerryMage
dfbd3912a4 emit_x64: pmaxuw and pminuw require SSE 4.1
This commit is intended to close citra-emu/citra#3137.

pmaxuw and pminuw were used to perform unsigned comparisons; we emulate
these using a signed comparison by offsetting the inputs by 0x8000 for
CPUs that do not support SSE 4.1.
2017-11-19 23:14:56 +00:00
MerryMage
20b1ac49b1 Merge branch 'subtree'
Remove submodules and use subtrees instead.

The advantage of subtrees is that they would not decay due to link rot
like submodules might.
2017-11-17 11:43:25 +00:00
MerryMage
cc53307857 externals: Add xbyak subtree
Merge commit 'dc792fdb55013abf9ab3913608fe1a7c1c3fe5f3' as 'externals/xbyak'
2017-11-15 20:53:46 +00:00
MerryMage
dc792fdb55 Squashed 'externals/xbyak/' content from commit d512551e
git-subtree-dir: externals/xbyak
git-subtree-split: d512551e914737300ba35f3c049d1b40effbe76d
2017-11-15 20:53:40 +00:00
MerryMage
4b31cb4968 externals: Removed xbyak submodule 2017-11-15 20:51:52 +00:00
MerryMage
f1fe85702d externals: Add fmt subtree
Merge commit '15a8975273ff2ef472939aab4a39a6c4bdc1898d' as 'externals/fmt'
2017-11-15 20:50:35 +00:00
MerryMage
15a8975273 Squashed 'externals/fmt/' content from commit 3983438
git-subtree-dir: externals/fmt
git-subtree-split: 398343897f98b88ade80bbebdcbe82a36c65a980
2017-11-15 20:49:14 +00:00
MerryMage
417dbe1248 externals: Removed fmt submodule 2017-11-15 20:47:41 +00:00
Mat M
185f233bf8 Common: Delete Pool's copy constructor and copy/move assignment operators (#117)
The language defines a copy constructor as:

TypeName(const TypeName&)

so this was just deleting a constructor variant that would catch most cases of attempted copies.
2017-11-12 08:52:34 +00:00
Mat M
c53e0a8768 emit_x64: Amend doxygen parameters for InvalidateCacheRange() (#116) 2017-11-12 08:08:23 +00:00
Mat M
c03aee63e1 externals: Update catch to 2.0.1 (#115)
Keeps the unit testing library up to date.
2017-11-11 05:55:07 +00:00
MerryMage
d3fb603287 block_of_code: Add vzeroupper instructions where AVX-SSE transitions may occur 2017-11-02 20:08:26 +00:00
MerryMage
7b232ea845 block_of_code: BlockOfCode should provide cpu info 2017-11-02 20:06:36 +00:00
yesfish
ed4964e892 reg_alloc: Improve performance of HostLocInfo (#112)
This commit changes the type of HostLocInfo::values from std::vector<Inst*> to std::forward_list<Inst*>.
2017-10-19 02:41:49 +01:00
429 changed files with 12425 additions and 24086 deletions

2
.gitignore vendored
View File

@ -2,5 +2,3 @@
build/
docs/Doxygen/
.vs/
# Generated files
src/backend/x64/mig/

View File

@ -32,49 +32,45 @@ matrix:
script: ./.travis/build-x86_64-linux/build.sh
- env: NAME="Linux aarch64 Build"
os: linux
dist: bionic
dist: trusty
sudo: required
services: docker
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-8-aarch64-linux-gnu
- g++-8-aarch64-linux-gnu
- ninja-build
- qemu-user
install: ./.travis/build-aarch64-linux/deps.sh
script: ./.travis/build-aarch64-linux/build.sh
script: ./.travis/build-aarch64-linux/run.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
# - env: NAME="Test - Fuzz against Unicorn"
# os: linux
# dist: trusty
# 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: trusty
# 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

@ -3,11 +3,12 @@
set -e
set -x
export CC=aarch64-linux-gnu-gcc-8
export CXX=aarch64-linux-gnu-g++-8
export PKG_CONFIG_PATH=$HOME/.local/lib/pkgconfig:$PKG_CONFIG_PATH
export UNICORNDIR=$(pwd)/dynarmic/externals/unicorn
cd dynarmic
mkdir build && cd build
cmake .. -DBoost_INCLUDE_DIRS=${PWD}/../externals/ext-boost -DCMAKE_BUILD_TYPE=Release -G Ninja
cmake .. -DBoost_INCLUDE_DIRS=${PWD}/../externals/ext-boost -DCMAKE_BUILD_TYPE=Release -DDYNARMIC_TESTS_USE_UNICORN=1 -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc-8 -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++-8 -G Ninja
ninja
qemu-aarch64 -L /usr/aarch64-linux-gnu ./tests/dynarmic_tests -d yes

View File

@ -3,7 +3,14 @@
set -e
set -x
apt-get update
apt-get install -y git cmake gcc python ninja-build g++-8-aarch64-linux-gnu qemu-user
# TODO: This isn't ideal.
cd externals
cd dynarmic/externals
git clone https://github.com/MerryMage/ext-boost
cd ..
git clone https://github.com/unicorn-engine/unicorn.git
cd unicorn
UNICORN_ARCHS="arm aarch64" CC=aarch64-linux-gnu-gcc-8 ./make.sh
cd ../..

View File

@ -0,0 +1,4 @@
#!/bin/sh
dynarmic/.travis/build-aarch64-linux/deps.sh
dynarmic/.travis/build-aarch64-linux/build.sh

View File

@ -0,0 +1,4 @@
#!/bin/sh
docker pull ubuntu:18.04
docker run -v $(pwd):/dynarmic ubuntu:18.04 dynarmic/.travis/build-aarch64-linux/docker.sh

View File

@ -3,12 +3,10 @@
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
git clone https://github.com/yuzu-emu/unicorn
cd unicorn
UNICORN_ARCHS=aarch64,arm ./make.sh
cd ../..

View File

@ -3,12 +3,10 @@
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
git clone https://github.com/yuzu-emu/unicorn
cd unicorn
UNICORN_ARCHS="arm aarch64" ./make.sh
cd ../..

View File

@ -16,9 +16,6 @@ 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)
option(DYNARMIC_WARNINGS_AS_ERRORS "Warnings as errors" ${MASTER_PROJECT})
if (NOT DEFINED DYNARMIC_FRONTENDS)
set(DYNARMIC_FRONTENDS "A32;A64" CACHE STRING "Selects which frontends to enable")
endif()
# Default to a Release build
if (NOT CMAKE_BUILD_TYPE)
@ -63,7 +60,6 @@ if (MSVC)
/Zc:inline # Omits inline functions from object-file output.
/Zc:throwingNew # Assumes new (without std::nothrow) never returns null.
/volatile:iso # Use strict standard-abiding volatile semantics
/bigobj # Increase number of sections in .obj files
/DNOMINMAX)
if (DYNARMIC_WARNINGS_AS_ERRORS)
@ -127,7 +123,7 @@ if (DYNARMIC_USE_LLVM)
find_package(LLVM REQUIRED CONFIG)
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(-DDYNARMIC_USE_LLVM ${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(llvm_libs armdesc armdisassembler aarch64desc aarch64disassembler x86desc x86disassembler)
llvm_map_components_to_libnames(llvm_libs aarch64desc aarch64disassembler x86desc x86disassembler)
endif()
if (DYNARMIC_TESTS_USE_UNICORN)

View File

@ -1,12 +1,339 @@
Copyright (C) 2017 MerryMage
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted.
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
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.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

131
README.md
View File

@ -193,134 +193,3 @@ int main(int argc, char** argv) {
return 0;
}
```
Legal
-----
dynarmic is under a 0BSD license. See LICENSE.txt for more details.
dynarmic uses several other libraries, whose licenes are included below:
### catch
```
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
```
### fmt
```
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
### mp
```
Copyright (C) 2017 MerryMage
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted.
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.
```
### xbyak
```
Copyright (c) 2007 MITSUNARI Shigeo
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
Neither the name of the copyright owner nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
ソースコード形式かバイナリ形式か、変更するかしないかを問わず、以下の条件を満た
す場合に限り、再頒布および使用が許可されます。
ソースコードを再頒布する場合、上記の著作権表示、本条件一覧、および下記免責条項
を含めること。
バイナリ形式で再頒布する場合、頒布物に付属のドキュメント等の資料に、上記の著作
権表示、本条件一覧、および下記免責条項を含めること。
書面による特別の許可なしに、本ソフトウェアから派生した製品の宣伝または販売促進
に、著作権者の名前またはコントリビューターの名前を使用してはならない。
本ソフトウェアは、著作権者およびコントリビューターによって「現状のまま」提供さ
れており、明示黙示を問わず、商業的な使用可能性、および特定の目的に対する適合性
に関する暗黙の保証も含め、またそれに限定されない、いかなる保証もありません。
著作権者もコントリビューターも、事由のいかんを問わず、 損害発生の原因いかんを
問わず、かつ責任の根拠が契約であるか厳格責任であるか(過失その他の)不法行為で
あるかを問わず、仮にそのような損害が発生する可能性を知らされていたとしても、
本ソフトウェアの使用によって発生した(代替品または代用サービスの調達、使用の
喪失、データの喪失、利益の喪失、業務の中断も含め、またそれに限定されない)直接
損害、間接損害、偶発的な損害、特別損害、懲罰的損害、または結果損害について、
一切責任を負わないものとします。
```

View File

@ -1,8 +0,0 @@
# Run manually to reformat a file:
# clang-format -i --style=file <file>
Language: Cpp
BasedOnStyle: Google
IndentPPDirectives: AfterHash
IndentCaseLabels: false
AlwaysBreakTemplateDeclarations: false
DerivePointerAlignment: false

View File

@ -1,6 +0,0 @@
<!-- 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.

View File

@ -1,5 +1,4 @@
.vscode/
.vs/
*.iml
.idea/

View File

@ -7,6 +7,7 @@ os: linux
git:
depth: 1
env:
global:
- secure: |-
@ -38,26 +39,6 @@ matrix:
- 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
@ -65,8 +46,8 @@ matrix:
- 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
# clang 6.0 on Linux with C++14
- env: COMPILER=clang++-6.0 BUILD=Debug STANDARD=14
compiler: clang
addons:
apt:
@ -92,6 +73,52 @@ matrix:
# g++ 4.8 on Linux with C++11
- env: COMPILER=g++-4.8 BUILD=Debug STANDARD=11
compiler: gcc
# g++ 4.4 on Linux with C++11
- env: COMPILER=g++-4.4 BUILD=Debug STANDARD=11
compiler: gcc
addons:
apt:
update: true
packages:
- g++-4.4
sources:
- ubuntu-toolchain-r-test
# Android
- language: android
addons:
apt:
update: true
sources:
- ubuntu-toolchain-r-test
packages:
- wget
- unzip
- tree
android:
components:
- tools
- platform-tools
- android-21
env:
- ANDROID=true
before_install:
# Download/Install Gradle
- wget https://services.gradle.org/distributions/gradle-4.10.2-bin.zip
- mkdir -p gradle
- unzip -q -d ./gradle gradle-4.10.2-bin.zip
- export GRADLE=gradle/gradle-4.10.2/bin/gradle
- bash $GRADLE --version
install:
# Accept SDK Licenses + Install NDK
- yes | sdkmanager --update > /dev/null 2>&1
- sdkmanager ndk-bundle > /dev/null 2>&1
before_script:
- pushd ./support
script:
- bash ../$GRADLE clean assemble
after_success:
- popd;
- tree ./libs
before_script:
- if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then export CXX=${COMPILER}; fi

View File

@ -24,38 +24,24 @@ function(join result_var)
set(${result_var} "${result}" PARENT_SCOPE)
endfunction()
# 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})
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)
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.")
if (NOT CMAKE_BUILD_TYPE)
join(doc "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or "
"CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
set(CMAKE_BUILD_TYPE Release CACHE STRING ${doc})
endif ()
option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF)
option(FMT_WERROR "Halt the compilation with an error on compiler warnings."
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_FUZZ "Generate the fuzz target." OFF)
option(FMT_CUDA_TEST "Generate the cuda-test target." OFF)
project(FMT CXX)
project(FMT)
# Get version from core.h
file(READ include/fmt/core.h core_h)
@ -72,9 +58,7 @@ message(STATUS "Version: ${FMT_VERSION}")
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
endif ()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_SOURCE_DIR}/support/cmake")
@ -82,14 +66,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
include(cxx14)
include(CheckCXXCompilerFlag)
list(FIND CMAKE_CXX_COMPILE_FEATURES "cxx_variadic_templates" index)
if (${index} GREATER -1)
# Use cxx_variadic_templates instead of more appropriate cxx_std_11 for
# compatibility with older CMake versions.
set(FMT_REQUIRED_FEATURES cxx_variadic_templates)
endif ()
message(STATUS "Required features: ${FMT_REQUIRED_FEATURES}")
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(PEDANTIC_COMPILE_FLAGS -pedantic-errors -Wall -Wextra -pedantic
-Wold-style-cast -Wundef
@ -98,7 +74,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
-Wcast-align -Wnon-virtual-dtor
-Wctor-dtor-privacy -Wdisabled-optimization
-Winvalid-pch -Woverloaded-virtual
-Wconversion -Wswitch-enum
-Wconversion
-Wno-ctor-dtor-privacy -Wno-format-nonliteral -Wno-shadow)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnoexcept
@ -117,8 +93,7 @@ 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 -Wno-sign-conversion)
check_cxx_compiler_flag(-Wzero-as-null-pointer-constant HAS_NULLPTR_WARNING)
if (HAS_NULLPTR_WARNING)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
@ -142,24 +117,17 @@ if (MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
set(MSBUILD_SETUP "call \"${WINSDK_SETENV}\"")
endif ()
# Set FrameworkPathOverride to get rid of MSB3644 warnings.
join(netfxpath
"C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\"
".NETFramework\\v4.0")
set(netfxpath "C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.0")
file(WRITE run-msbuild.bat "
${MSBUILD_SETUP}
${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)
check_symbol_exists(open io.h HAVE_OPEN)
else ()
check_symbol_exists(strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
check_symbol_exists(open fcntl.h HAVE_OPEN)
endif ()
function(add_headers VAR)
@ -171,17 +139,17 @@ 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 chrono.h color.h core.h format.h format-inl.h locale.h
ostream.h printf.h time.h ranges.h)
set(FMT_SOURCES src/format.cc)
if (HAVE_OPEN)
add_headers(FMT_HEADERS posix.h)
set(FMT_SOURCES ${FMT_SOURCES} src/posix.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 ()
@ -189,42 +157,27 @@ if (FMT_PEDANTIC)
target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
target_compile_features(fmt INTERFACE ${FMT_REQUIRED_FEATURES})
target_include_directories(fmt PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
set(FMT_DEBUG_POSTFIX d CACHE STRING "Debug library postfix.")
set_target_properties(fmt PROPERTIES
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}")
# Set FMT_LIB_NAME for pkg-config fmt.pc. We cannot use the OUTPUT_NAME target
# property because it's not set by default.
set(FMT_LIB_NAME fmt)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(FMT_LIB_NAME ${FMT_LIB_NAME}${FMT_DEBUG_POSTFIX})
endif ()
DEBUG_POSTFIX d)
if (BUILD_SHARED_LIBS)
if (UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
if (UNIX AND NOT APPLE)
# 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)
endif ()
target_compile_definitions(fmt PRIVATE FMT_EXPORT INTERFACE FMT_SHARED)
endif ()
if (FMT_SAFE_DURATION_CAST)
target_compile_definitions(fmt PUBLIC FMT_SAFE_DURATION_CAST)
endif()
add_library(fmt-header-only INTERFACE)
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
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
@ -234,9 +187,8 @@ target_include_directories(fmt-header-only INTERFACE
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}.")
set(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING
"Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.")
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)
@ -247,17 +199,14 @@ if (FMT_INSTALL)
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(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}.")
set(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR}/fmt CACHE STRING
"Installation directory for include files, relative to ${CMAKE_INSTALL_PREFIX}.")
set_verbose(FMT_PKGCONFIG_DIR ${CMAKE_INSTALL_LIBDIR}/pkgconfig CACHE PATH
"Installation directory for pkgconfig (.pc) files, relative to "
"${CMAKE_INSTALL_PREFIX}.")
set(FMT_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH
"Installation directory for pkgconfig (.pc) files, relative to ${CMAKE_INSTALL_PREFIX}.")
# Generate the version, config and target files into the build directory.
write_basic_package_version_file(
@ -286,12 +235,9 @@ if (FMT_INSTALL)
# 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})
DESTINATION ${FMT_LIB_DIR})
install(FILES $<TARGET_PDB_FILE:${INSTALL_TARGETS}>
DESTINATION ${FMT_LIB_DIR} OPTIONAL)
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 ()
@ -305,16 +251,11 @@ if (FMT_TEST)
add_subdirectory(test)
endif ()
# Control fuzzing independent of the unit tests.
if (FMT_FUZZ)
add_subdirectory(test/fuzzing)
endif ()
set(gitignore ${PROJECT_SOURCE_DIR}/.gitignore)
if (MASTER_PROJECT AND EXISTS ${gitignore})
# Get the list of ignored files from .gitignore.
file (STRINGS ${gitignore} lines)
list(REMOVE_ITEM lines /doc/html)
LIST(REMOVE_ITEM lines /doc/html)
foreach (line ${lines})
string(REPLACE "." "[.]" line "${line}")
string(REPLACE "*" ".*" line "${line}")

View File

@ -1,17 +0,0 @@
Contributing to {fmt}
=====================
By submitting a pull request or a patch, you represent that you have the right
to license your contribution to the {fmt} project owners and the community,
agree that your contributions are licensed under the {fmt} license, and agree
to future changes to the licensing.
All C++ code must adhere to [Google C++ Style Guide](
https://google.github.io/styleguide/cppguide.html) with the following
exceptions:
* Exceptions are permitted
* snake_case should be used instead of UpperCamelCase for function and type
names
Thanks for contributing!

12
externals/fmt/CONTRIBUTING.rst vendored Normal file
View File

@ -0,0 +1,12 @@
Contributing to fmt
===================
All C++ code must adhere to `Google C++ Style Guide
<https://google.github.io/styleguide/cppguide.html>`_ with the following
exceptions:
* Exceptions are permitted
* snake_case should be used instead of UpperCamelCase for function and type
names
Thanks for contributing!

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +1,23 @@
Copyright (c) 2012 - present, Victor Zverovich
Copyright (c) 2012 - 2016, Victor Zverovich
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:
All rights reserved.
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
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.
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
--- Optional exception to the license ---
As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into a machine-executable object form of such
source code, you may redistribute such embedded portions in such object form
without including the above copyright and permission notices.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -6,90 +6,90 @@
.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v
: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://img.shields.io/badge/stackoverflow-fmt-blue.svg
:alt: Ask questions at StackOverflow with the tag fmt
:target: https://stackoverflow.com/questions/tagged/fmt
.. image:: https://badges.gitter.im/Join%20Chat.svg
:alt: Join the chat at https://gitter.im/fmtlib/fmt
:target: https://gitter.im/fmtlib/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.
It can be used as a safe and fast alternative to (s)printf and IOStreams.
`Documentation <https://fmt.dev/latest/>`__
`Documentation <http://fmtlib.net/latest/>`__
Q&A: ask questions on `StackOverflow with the tag fmt <https://stackoverflow.com/questions/tagged/fmt>`_.
This is a development branch that implements the C++ standards proposal `P0645
Text Formatting <http://fmtlib.net/Text%20Formatting.html>`__.
Released versions are available from the `Releases page
<https://github.com/fmtlib/fmt/releases>`__.
Features
--------
* Replacement-based `format API <https://fmt.dev/dev/api.html>`_ with
* Replacement-based `format API <http://fmtlib.net/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>`_
* `Format string syntax <http://fmtlib.net/dev/syntax.html>`_ similar to the one
of `str.format <https://docs.python.org/2/library/stdtypes.html#str.format>`_
in Python.
* Safe `printf implementation
<https://fmt.dev/latest/api.html#printf-formatting>`_ including
<http://fmtlib.net/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.
* 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++
* High speed: performance of the format API is close to that of glibc's `printf
<http://en.cppreference.com/w/cpp/io/c/fprintf>`_ and better than the
performance of 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.
<https://github.com/fmtlib/fmt/tree/master/test>`_.
* Safety: the library is fully type safe, errors in format strings can be
reported at compile time, automatic memory management prevents buffer overflow
errors.
* Ease of use: small self-contained code base, no external dependencies,
permissive MIT `license
permissive BSD `license
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_
* `Portability <https://fmt.dev/latest/index.html#portability>`_ with
* `Portability <http://fmtlib.net/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.
See the `documentation <https://fmt.dev/latest/>`_ for more details.
See the `documentation <http://fmtlib.net/latest/>`_ for more details.
Examples
--------
Print ``Hello, world!`` to ``stdout``:
This prints ``Hello, world!`` to stdout:
.. code:: c++
fmt::print("Hello, {}!", "world"); // Python-like format string syntax
fmt::printf("Hello, %s!", "world"); // printf format string syntax
fmt::print("Hello, {}!", "world"); // uses Python-like format string syntax
fmt::printf("Hello, %s!", "world"); // uses printf format string syntax
Format a string and use positional arguments:
Arguments can be accessed by position and arguments' indices can be repeated:
.. code:: c++
std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");
// s == "I'd rather be happy than right."
std::string s = fmt::format("{0}{1}{0}", "abra", "cad");
// s == "abracadabra"
Check a format string at compile time:
Format strings can be checked at compile time:
.. code:: c++
// test.cc
#define FMT_STRING_ALIAS 1
#include <fmt/format.h>
std::string s = format(FMT_STRING("{2}"), 42);
std::string s = format(fmt("{2}"), 42);
.. 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);
std::string s = format(fmt("{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);
@ -98,7 +98,7 @@ Check a format string at compile time:
context_.on_error("argument index out of range");
^
Use {fmt} as a safe portable replacement for ``itoa``
{fmt} can be used as a safe portable replacement for ``itoa``
(`godbolt <https://godbolt.org/g/NXmpU4>`_):
.. code:: c++
@ -106,10 +106,10 @@ Use {fmt} as a safe portable replacement for ``itoa``
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()
// access the string using 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>`_:
Formatting of user-defined types is supported via a simple
`extension API <http://fmtlib.net/latest/api.html#formatting-user-defined-types>`_:
.. code:: c++
@ -121,10 +121,11 @@ Format objects of user-defined types via a simple `extension API
template <>
struct fmt::formatter<date> {
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename ParseContext>
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const date& d, FormatContext& ctx) {
auto format(const date &d, FormatContext &ctx) {
return format_to(ctx.out(), "{}-{}-{}", d.year, d.month, d.day);
}
};
@ -132,60 +133,243 @@ Format objects of user-defined types via a simple `extension API
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>`_
You can create your own functions similar to `format
<http://fmtlib.net/latest/api.html#format>`_ and
`print <http://fmtlib.net/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) {
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) {
void report_error(const char *format, const Args & ... args) {
vreport_error(format, fmt::make_format_args(args...));
}
report_error("file not found: {}", path);
Note that ``vreport_error`` is not parameterized on argument types which can
improve compile times and reduce code size compared to a fully parameterized
improve compile times and reduce code size compared to fully parameterized
version.
Projects using this library
---------------------------
* `0 A.D. <http://play0ad.com/>`_: A free, open-source, cross-platform real-time
strategy game
* `AMPL/MP <https://github.com/ampl/mp>`_:
An open-source library for mathematical programming
* `AvioBook <https://www.aviobook.aero/en>`_: A comprehensive aircraft
operations suite
* `Celestia <https://celestia.space/>`_: Real-time 3D visualization of space
* `Ceph <https://ceph.com/>`_: A scalable distributed storage system
* `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater
vehicle
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
Player vs Player Gaming Network with tweaks
* `KBEngine <http://kbengine.org/>`_: An open-source MMOG server engine
* `Keypirinha <http://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 <http://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
(Lyft)
* `FiveM <https://fivem.net/>`_: a modification framework for GTA V
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to
generate randomized datasets
* `OpenSpace <http://openspaceproject.com/>`_: An open-source astrovisualization
framework
* `PenUltima Online (POL) <http://www.polserver.com/>`_:
An MMO server, compatible with most Ultima Online clients
* `quasardb <https://www.quasardb.net/>`_: A distributed, high-performance,
associative database
* `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster
proxy
* `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 <http://www.salesforce.com/analytics-cloud/overview/>`_:
Business intelligence software
* `Scylla <http://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++
framework for high-performance server applications on modern hardware
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library
* `Stellar <https://www.stellar.org/>`_: Financial platform
* `Touch Surgery <https://www.touchsurgery.com/>`_: Surgery simulator
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: Open-source
MMORPG framework
`More... <https://github.com/search?q=cppformat&type=Code>`_
If you are aware of other projects using this library, please let me know
by `email <mailto:victor.zverovich@gmail.com>`_ or by submitting an
`issue <https://github.com/fmtlib/fmt/issues>`_.
Motivation
----------
So why yet another formatting library?
There are plenty of methods for doing this task, from standard ones like
the printf family of function and IOStreams to Boost Format library and
FastFormat. The reason for creating a new library is that every existing
solution that I found either had serious issues or didn't provide
all the features I needed.
Printf
~~~~~~
The good thing about printf is that it is pretty fast and readily available
being a part of the C standard library. The main drawback is that it
doesn't support user-defined types. Printf also has safety issues although
they are mostly solved with `__attribute__ ((format (printf, ...))
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ in GCC.
There is a POSIX extension that adds positional arguments required for
`i18n <https://en.wikipedia.org/wiki/Internationalization_and_localization>`_
to printf but it is not a part of C99 and may not be available on some
platforms.
IOStreams
~~~~~~~~~
The main issue with IOStreams is best illustrated with an example:
.. code:: c++
std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";
which is a lot of typing compared to printf:
.. code:: c++
printf("%.2f\n", 1.23456);
Matthew Wilson, the author of FastFormat, referred to this situation with
IOStreams as "chevron hell". IOStreams doesn't support positional arguments
by design.
The good part is that IOStreams supports user-defined types and is safe
although error reporting is awkward.
Boost Format library
~~~~~~~~~~~~~~~~~~~~
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 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:
Three features that have no hope of being accommodated within the
current design are:
* Leading zeros (or any other non-space padding)
* 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.
Loki SafeFormat
~~~~~~~~~~~~~~~
SafeFormat is a formatting library which uses printf-like format strings
and is type safe. It doesn't support user-defined types or positional
arguments. It makes unconventional use of ``operator()`` for passing
format arguments.
Tinyformat
~~~~~~~~~~
This library supports printf-like format strings and is very small and
fast. Unfortunately it doesn't support positional arguments and wrapping
it in C++98 is somewhat difficult. Also its performance and code compactness
are limited by IOStreams.
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::Writer`` 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>`_.
Benchmarks
----------
Speed tests
~~~~~~~~~~~
The following speed tests results were generated by building
``tinyformat_test.cpp`` on Ubuntu GNU/Linux 14.04.1 with
``g++-4.8.2 -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"`` or
equivalent is filled 2000000 times with output sent to ``/dev/null``; for
further details see the `source
<https://github.com/fmtlib/format-benchmark/blob/master/tinyformat_test.cpp>`_.
================= ============= ===========
Library Method Run Time, s
================= ============= ===========
libc printf 1.04
libc++ std::ostream 3.05
{fmt} 6.1.1 fmt::print 0.75
Boost Format 1.67 boost::format 7.24
Folly Format folly::format 2.23
libc printf 1.35
libc++ std::ostream 3.42
fmt 534bff7 fmt::print 1.56
tinyformat 2.0.1 tfm::printf 3.73
Boost Format 1.54 boost::format 8.44
Folly Format folly::format 2.54
================= ============= ===========
{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"``
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>`_.
{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>`_:
.. image:: https://user-images.githubusercontent.com/576385/69767160-cdaca400-112f-11ea-9fc5-347c9f83caad.png
:target: https://fmt.dev/unknown_mac64_clang10.0.html
As you can see ``boost::format`` is much slower than the alternative methods; this
is confirmed by `other tests <http://accu.org/index.php/journals/1539>`_.
Tinyformat is quite good coming close to IOStreams. Unfortunately tinyformat
cannot be faster than the IOStreams because it uses them internally.
Performance of fmt is close to that of printf, being `faster than printf on integer
formatting <http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_,
but slower on floating-point formatting which dominates this benchmark.
Compile time and code bloat
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -206,14 +390,15 @@ Method Compile Time, s Executable size, KiB Stripped size, KiB
============= =============== ==================== ==================
printf 2.6 29 26
printf+string 16.4 29 26
iostreams 31.1 59 55
{fmt} 19.0 37 34
IOStreams 31.1 59 55
fmt 19.0 37 34
tinyformat 44.0 103 97
Boost Format 91.9 226 203
Folly Format 115.7 101 88
============= =============== ==================== ==================
As you can see, {fmt} has 60% less overhead in terms of resulting binary code
size compared to iostreams and comes pretty close to ``printf``. Boost Format
As you can see, fmt has 60% less overhead in terms of resulting binary code
size compared to IOStreams and comes pretty close to ``printf``. Boost Format
and Folly Format have the largest overheads.
``printf+string`` is the same as ``printf`` but with extra ``<string>``
@ -226,15 +411,17 @@ Method Compile Time, s Executable size, KiB Stripped size, KiB
============= =============== ==================== ==================
printf 2.2 33 30
printf+string 16.0 33 30
iostreams 28.3 56 52
{fmt} 18.2 59 50
IOStreams 28.3 56 52
fmt 18.2 59 50
tinyformat 32.6 88 82
Boost Format 54.1 365 303
Folly Format 79.9 445 430
============= =============== ==================== ==================
``libc``, ``lib(std)c++`` and ``libfmt`` are all linked as shared libraries to
compare formatting function overhead only. Boost Format is a
header-only library so it doesn't provide any linkage options.
``libc``, ``lib(std)c++`` and ``libfmt`` are all linked as shared
libraries to compare formatting function overhead only. Boost Format
and tinyformat are header-only libraries so they don't provide any
linkage options.
Running the tests
~~~~~~~~~~~~~~~~~
@ -242,7 +429,7 @@ Running the tests
Please refer to `Building the library`__ for the instructions on how to build
the library and run the unit tests.
__ https://fmt.dev/latest/usage.html#building-the-library
__ http://fmtlib.net/latest/usage.html#building-the-library
Benchmarks reside in a separate repository,
`format-benchmarks <https://github.com/fmtlib/format-benchmark>`_,
@ -261,175 +448,6 @@ or the bloat test::
$ make bloat-test
Projects using this library
---------------------------
* `0 A.D. <https://play0ad.com/>`_: A free, open-source, cross-platform real-time
strategy game
* `AMPL/MP <https://github.com/ampl/mp>`_:
An open-source library for mathematical programming
* `AvioBook <https://www.aviobook.aero/en>`_: A comprehensive aircraft
operations suite
* `Celestia <https://celestia.space/>`_: Real-time 3D visualization of space
* `Ceph <https://ceph.com/>`_: A scalable distributed storage system
* `ccache <https://ccache.dev/>`_: A compiler cache
* `CUAUV <http://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
for nonlinear dynamical systems (MIT)
* `Envoy <https://lyft.github.io/envoy/>`_: C++ L7 proxy and communication bus
(Lyft)
* `FiveM <https://fivem.net/>`_: a modification framework for GTA V
* `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
* `PenUltima Online (POL) <https://www.polserver.com/>`_:
An MMO server, compatible with most Ultima Online clients
* `quasardb <https://www.quasardb.net/>`_: A distributed, high-performance,
associative database
* `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster
proxy
* `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
* `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++
framework for high-performance server applications on modern hardware
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library
* `Stellar <https://www.stellar.org/>`_: Financial platform
* `Touch Surgery <https://www.touchsurgery.com/>`_: Surgery simulator
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: Open-source
MMORPG framework
`More... <https://github.com/search?q=fmtlib&type=Code>`_
If you are aware of other projects using this library, please let me know
by `email <mailto:victor.zverovich@gmail.com>`_ or by submitting an
`issue <https://github.com/fmtlib/fmt/issues>`_.
Motivation
----------
So why yet another formatting library?
There are plenty of methods for doing this task, from standard ones like
the printf family of function and iostreams to Boost Format and FastFormat
libraries. The reason for creating a new library is that every existing
solution that I found either had serious issues or didn't provide
all the features I needed.
printf
~~~~~~
The good thing about ``printf`` is that it is pretty fast and readily available
being a part of the C standard library. The main drawback is that it
doesn't support user-defined types. ``printf`` also has safety issues although
they are somewhat mitigated with `__attribute__ ((format (printf, ...))
<https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ in GCC.
There is a POSIX extension that adds positional arguments required for
`i18n <https://en.wikipedia.org/wiki/Internationalization_and_localization>`_
to ``printf`` but it is not a part of C99 and may not be available on some
platforms.
iostreams
~~~~~~~~~
The main issue with iostreams is best illustrated with an example:
.. code:: c++
std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";
which is a lot of typing compared to printf:
.. code:: c++
printf("%.2f\n", 1.23456);
Matthew Wilson, the author of FastFormat, called this "chevron hell". iostreams
don't support positional arguments by design.
The good part is that iostreams support user-defined types and are safe although
error handling is awkward.
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
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:
Three features that have no hope of being accommodated within the
current design are:
* Leading zeros (or any other non-space padding)
* 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.
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
---
@ -456,11 +474,11 @@ A: use ``std::tuple``:
License
-------
{fmt} is distributed under the MIT `license
fmt is distributed under the BSD `license
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_.
The `Format String Syntax
<https://fmt.dev/latest/syntax.html>`_
<http://fmtlib.net/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
@ -472,7 +490,7 @@ It only applies if you distribute the documentation of fmt.
Acknowledgments
---------------
The {fmt} library is maintained by Victor Zverovich (`vitaut
The fmt library is maintained by Victor Zverovich (`vitaut
<https://github.com/vitaut>`_) and Jonathan Müller (`foonathan
<https://github.com/foonathan>`_) with contributions from many other people.
See `Contributors <https://github.com/fmtlib/fmt/graphs/contributors>`_ and
@ -486,10 +504,10 @@ 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/>`_.
<http://clang.llvm.org/doxygen/classclang_1_1Diagnostic.html>`_ in
`Clang <http://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>`_.
<http://docs.python.org/2/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

View File

@ -6,7 +6,7 @@ endif ()
add_custom_target(doc
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.py ${FMT_VERSION}
SOURCES api.rst syntax.rst usage.rst build.py conf.py _templates/layout.html)
SOURCES api.rst syntax.rst build.py conf.py _templates/layout.html)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/
DESTINATION share/doc/fmt OPTIONAL)

View File

@ -58,7 +58,7 @@
<span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
{% for v in versions.split(',') %}
<li><a href="https://fmt.dev/{{v}}">{{v}}</a></li>
<li><a href="http://fmtlib.net/{{v}}">{{v}}</a></li>
{% endfor %}
</ul>
</li>
@ -84,7 +84,7 @@
<div class="jumbotron">
<div class="tb-container">
<h1>{fmt}</h1>
<p class="lead">A modern formatting library</p>
<p class="lead">Small, safe and fast formatting library</p>
<div class="btn-group" role="group">
{% set name = 'fmt' if version.split('.')[0]|int >= 3 else 'cppformat' %}
<a class="btn btn-success"

View File

@ -10,14 +10,12 @@ The {fmt} library API consists of the following parts:
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/chrono.h <chrono-api>`: date and time formatting
* :ref:`fmt/time.h <time-api>`: date and time formatting
* :ref:`fmt/ostream.h <ostream-api>`: ``std::ostream`` support
* :ref:`fmt/printf.h <printf-api>`: ``printf`` formatting
All functions and types provided by the library reside in namespace ``fmt`` and
macros have prefix ``FMT_``.
macros have prefix ``FMT_`` or ``fmt``.
.. _core-api:
@ -25,8 +23,7 @@ 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``.
and a lightweight subset of formatting functions.
The following functions use :ref:`format string syntax <syntax>`
similar to that of Python's `str.format
@ -42,25 +39,24 @@ participate in an overload resolution if the latter is not a string.
.. _format:
.. doxygenfunction:: format(const S&, Args&&...)
.. doxygenfunction:: vformat(const S&, basic_format_args<buffer_context<Char>>)
.. doxygenfunction:: format(const S&, const Args&...)
.. doxygenfunction:: vformat(const S&, basic_format_args<typename buffer_context<Char>::type>)
.. _print:
.. doxygenfunction:: print(const S&, Args&&...)
.. doxygenfunction:: print(const S&, const Args&...)
.. doxygenfunction:: vprint(string_view, format_args)
.. doxygenfunction:: print(std::FILE *, const S&, Args&&...)
.. doxygenfunction:: print(std::FILE *, const S&, const Args&...)
.. doxygenfunction:: vprint(std::FILE *, string_view, format_args)
.. doxygenfunction:: vprint(std::FILE *, wstring_view, wformat_args)
Named Arguments
Named arguments
---------------
.. doxygenfunction:: fmt::arg(const S&, const T&)
.. doxygenfunction:: fmt::arg(string_view, const T&)
Named arguments are not supported in compile-time checks at the moment.
Argument Lists
Argument lists
--------------
.. doxygenfunction:: fmt::make_format_args(const Args&...)
@ -85,19 +81,6 @@ Compatibility
.. doxygentypedef:: fmt::string_view
.. doxygentypedef:: fmt::wstring_view
Locale
------
All formatting is locale-independent by default. Use the ``'n'`` format
specifier to insert the appropriate number separator characters from the
locale::
#include <fmt/core.h>
#include <locale>
std::locale::global(std::locale("en_US.UTF-8"));
auto s = fmt::format("{:n}", 1000000); // s == "1,000,000"
.. _format-api:
Format API
@ -106,16 +89,12 @@ Format API
``fmt/format.h`` defines the full format API providing compile-time format
string checks, output iterator and user-defined type support.
Compile-time Format String Checks
Compile-time format string checks
---------------------------------
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
.. doxygendefine:: FMT_STRING
Formatting User-defined Types
Formatting user-defined types
-----------------------------
To make a user-defined type formattable, specialize the ``formatter<T>`` struct
@ -125,56 +104,32 @@ template and implement ``parse`` and ``format`` methods::
struct point { double x, y; };
namespace fmt {
template <>
struct fmt::formatter<point> {
// Presentation format: 'f' - fixed, 'e' - exponential.
char presentation = 'f';
struct formatter<point> {
template <typename ParseContext>
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); }
// Parses format specifications of the form ['f' | 'e'].
constexpr auto parse(format_parse_context& ctx) {
// [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
//
// fmt::format("{:f} - point of interest", point{1, 2});
//
// the range will contain "f} - point of interest". The formatter should
// 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 '}'.
// 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");
// Return an iterator past the end of the parsed range:
return it;
}
// Formats the point p using the parsed format specification (presentation)
// stored in this formatter.
template <typename FormatContext>
auto format(const point& p, FormatContext& ctx) {
// ctx.out() is an output iterator to write to.
return format_to(
ctx.out(),
presentation == 'f' ? "({:.1f}, {:.1f})" : "({:.1e}, {:.1e})",
p.x, p.y);
auto format(const point &p, FormatContext &ctx) {
return format_to(ctx.begin(), "({:.1f}, {:.1f})", p.x, p.y);
}
};
}
Then you can pass objects of type ``point`` to any formatting function::
point p = {1, 2};
std::string s = fmt::format("{:f}", p);
std::string s = fmt::format("{}", p);
// s == "(1.0, 2.0)"
You can also reuse existing formatters via inheritance or composition, for
example::
In the example above the ``formatter<point>::parse`` function ignores the
contents of the format string referred to by ``ctx.begin()`` so the object will
always be formatted in the same way. See ``formatter<tm>::parse`` in
:file:`fmt/time.h` for an advanced example of how to parse the format string and
customize the formatted output.
You can also reuse existing formatters, for example::
enum class color {red, green, blue};
@ -182,7 +137,7 @@ example::
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) {
string_view name = "unknown";
switch (c) {
case color::red: name = "red"; break;
@ -222,14 +177,15 @@ You can also write a formatter for a hierarchy of classes::
fmt::print("{}", a); // prints "B"
}
.. doxygenclass:: fmt::basic_format_parse_context
:members:
This section shows how to define a custom format function for a user-defined
type. The next section describes how to get ``fmt`` to use a conventional stream
output ``operator<<`` when one is defined for a user-defined type.
Output Iterator Support
Output iterator support
-----------------------
.. doxygenfunction:: fmt::format_to(OutputIt, const S&, Args&&...)
.. doxygenfunction:: fmt::format_to_n(OutputIt, std::size_t, string_view, Args&&...)
.. doxygenfunction:: fmt::format_to(OutputIt, const S&, const Args&...)
.. doxygenfunction:: fmt::format_to_n(OutputIt, std::size_t, string_view, const Args&...)
.. doxygenstruct:: fmt::format_to_n_result
:members:
@ -245,8 +201,6 @@ The following user-defined literals are defined in ``fmt/format.h``.
Utilities
---------
.. doxygenstruct:: fmt::is_char
.. doxygentypedef:: fmt::char_t
.. doxygenfunction:: fmt::formatted_size(string_view, const Args&...)
@ -255,17 +209,13 @@ Utilities
.. doxygenfunction:: fmt::to_wstring(const T&)
.. doxygenfunction:: fmt::to_string_view(const Char *)
.. doxygenfunction:: fmt::join(const Range&, string_view)
.. doxygenfunction:: fmt::join(It, It, string_view)
.. doxygenfunction:: fmt::to_string_view(basic_string_view<Char>)
.. doxygenclass:: fmt::basic_memory_buffer
:protected-members:
:members:
System Errors
System errors
-------------
fmt does not use ``errno`` to communicate errors to the user, but it may call
@ -282,7 +232,7 @@ the value of ``errno`` being preserved by library functions.
.. _formatstrings:
Custom Allocators
Custom allocators
-----------------
The {fmt} library supports custom dynamic memory allocators.
@ -308,7 +258,7 @@ allocator::
template <typename ...Args>
inline custom_string format(custom_allocator alloc,
fmt::string_view format_str,
const Args& ... args) {
const Args & ... args) {
return vformat(alloc, format_str, fmt::make_format_args(args...));
}
@ -317,27 +267,27 @@ 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
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>>;
using arg_formatter =
fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>>;
// 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) {}
custom_arg_formatter(fmt::format_context &ctx,
fmt::format_specs *spec = nullptr)
: arg_formatter(ctx, spec) {}
using arg_formatter::operator();
auto operator()(int value) {
if (specs() && specs()->type == 'x')
if (spec().type() == 'x')
return (*this)(static_cast<unsigned>(value)); // convert to unsigned and format
return arg_formatter::operator()(value);
}
@ -352,7 +302,7 @@ custom argument formatter class::
template <typename ...Args>
inline std::string custom_format(
fmt::string_view format_str, const Args&... args) {
fmt::string_view format_str, const Args &... args) {
return custom_vformat(format_str, fmt::make_format_args(args...));
}
@ -361,41 +311,16 @@ custom argument formatter class::
.. doxygenclass:: fmt::arg_formatter
:members:
.. _ranges-api:
.. _time-api:
Ranges and Tuple Formatting
===========================
The library also supports convenient formatting of ranges and tuples::
#include <fmt/ranges.h>
std::tuple<char, int, float> t{'a', 1, 2.0f};
// Prints "('a', 1, 2.0)"
fmt::print("{}", t);
NOTE: currently, the overload of ``fmt::join`` for iterables exists in the main
``format.h`` header, but expect this to change in the future.
Using ``fmt::join``, you can separate tuple elements with a custom separator::
#include <fmt/ranges.h>
std::tuple<int, char> t = {1, 'a'};
// Prints "1, a"
fmt::print("{}", fmt::join(t, ", "));
.. _chrono-api:
Date and Time Formatting
Date and time formatting
========================
The library supports `strftime
<http://en.cppreference.com/w/cpp/chrono/c/strftime>`_-like date and time
formatting::
#include <fmt/chrono.h>
#include <fmt/time.h>
std::time_t t = std::time(nullptr);
// Prints "The date is 2016-04-29." (with the current date)
@ -406,7 +331,7 @@ The format string syntax is described in the documentation of
.. _ostream-api:
``std::ostream`` Support
``std::ostream`` support
========================
``fmt/ostream.h`` provides ``std::ostream`` support including formatting of
@ -419,7 +344,7 @@ user-defined types that have overloaded ``operator<<``::
public:
date(int year, int month, int day): year_(year), month_(month), day_(day) {}
friend std::ostream& operator<<(std::ostream& os, const date& d) {
friend std::ostream &operator<<(std::ostream &os, const date &d) {
return os << d.year_ << '-' << d.month_ << '-' << d.day_;
}
};
@ -427,11 +352,11 @@ user-defined types that have overloaded ``operator<<``::
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:: print(std::basic_ostream<fmt::char_t<S>>&, const S&, const Args&...)
.. _printf-api:
``printf`` Formatting
``printf`` formatting
=====================
The header ``fmt/printf.h`` provides ``printf``-like formatting functionality.
@ -445,6 +370,6 @@ argument type doesn't match its format specification.
.. doxygenfunction:: fprintf(std::FILE *, const S&, const Args&...)
.. doxygenfunction:: fprintf(std::basic_ostream<Char>&, const S&, const Args&...)
.. doxygenfunction:: fprintf(std::basic_ostream<fmt::char_t<S>>&, const S&, const Args&...)
.. doxygenfunction:: sprintf(const S&, const Args&...)

View File

@ -6,7 +6,7 @@ import errno, os, shutil, sys, tempfile
from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE
from distutils.version import LooseVersion
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']
def pip_install(package, commit=None, **kwargs):
"Install package using pip."
@ -74,7 +74,7 @@ def build_docs(version='dev', **kwargs):
GENERATE_MAN = NO
GENERATE_RTF = NO
CASE_SENSE_NAMES = NO
INPUT = {0}/core.h {0}/format.h {0}/os.h {0}/ostream.h \
INPUT = {0}/core.h {0}/format.h {0}/ostream.h \
{0}/printf.h {0}/time.h
QUIET = YES
JAVADOC_AUTOBRIEF = YES
@ -94,7 +94,7 @@ def build_docs(version='dev', **kwargs):
"FMT_BEGIN_NAMESPACE=namespace fmt {{" \
"FMT_END_NAMESPACE=}}" \
"FMT_STRING_ALIAS=1" \
"FMT_ENABLE_IF(B)="
"FMT_ENABLE_IF_T(B, T)=T"
EXCLUDE_SYMBOLS = fmt::internal::* StringValue write_str
'''.format(include_dir, doxyxml_dir).encode('UTF-8'))
if p.returncode != 0:

View File

@ -1,18 +1,17 @@
Overview
========
**{fmt}** is an open-source formatting library providing a fast and safe
alternative to C stdio and C++ iostreams.
**fmt** (formerly cppformat) is an open-source formatting library.
It can be used as a fast and safe alternative to printf and IOStreams.
.. raw:: html
<div class="panel panel-default">
<div class="panel-heading">What users say:</div>
<div class="panel-body">
Thanks for creating this library. Its been a hole in C++ for
a long time. Ive used both <code>boost::format</code> and
<code>loki::SPrintf</code>, and neither felt like the right answer.
This does.
Thanks for creating this library. Its been a hole in C++ for a long
time. Ive used both boost::format and loki::SPrintf, and neither felt
like the right answer. This does.
</div>
</div>
@ -21,13 +20,12 @@ alternative to C stdio and C++ iostreams.
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>`_
than common standard library implementations.
The replacement-based Format API provides a safe alternative to ``printf``,
``sprintf`` and friends with comparable or `better performance
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
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
Python:
`str.format <http://docs.python.org/3/library/stdtypes.html#str.format>`_
in Python:
.. code:: c++
@ -62,7 +60,7 @@ The Format API also supports positional arguments useful for localization:
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:
what goes where when multiple values are being inserted:
.. code:: c++
@ -74,10 +72,21 @@ an alternative, slightly terser syntax for named arguments:
.. code:: c++
using namespace fmt::literals;
fmt::print("Hello, {name}! The answer is {number}. Goodbye, {name}.",
"name"_a="World", "number"_a=42);
The ``_format`` suffix may be used to format string literals similar to Python:
.. code:: c++
std::string message = "{0}{1}{0}"_format("abra", "cad");
Other than the placement of the format string on the left of the operator,
``_format`` is functionally identical to ``fmt::format``. In order to use the
literal operators, they must be made visible with the directive
``using namespace fmt::literals;``. Note that this brings in only ``_a`` and
``_format`` but nothing else from the ``fmt`` namespace.
.. _safety:
Safety
@ -97,10 +106,10 @@ string", because the argument ``"forty-two"`` is a string while the format code
.. code:: c++
format(FMT_STRING("The answer is {:d}"), "forty-two");
format(fmt("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.
relaxed ``constexpr``.
The following code
@ -120,7 +129,7 @@ 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.
Compact Binary Code
Compact binary code
-------------------
The library is designed to produce compact per-call compiled code. For example
@ -165,16 +174,15 @@ The library is highly portable and relies only on a small set of C++11 features:
* decltype
* trailing return types
* 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
These are available since GCC 4.4, Clang 2.9 and MSVC 18.0 (2013). 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.
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,
output of ``printf`` is platform-dependent in this case. For example,
.. code::
@ -187,9 +195,9 @@ always prints ``inf``.
Ease of Use
-----------
{fmt} has a small self-contained code base with the core library consisting of
fmt has a small self-contained code base with the core library consisting of
just three header files and no external dependencies.
A permissive MIT `license <https://github.com/fmtlib/fmt#license>`_ allows
A permissive BSD `license <https://github.com/fmtlib/fmt#license>`_ allows
using the library both in open-source and commercial projects.
.. raw:: html

View File

@ -76,19 +76,19 @@ The general form of a *standard format specifier* is:
.. productionlist:: sf
format_spec: [[`fill`]`align`][`sign`]["#"]["0"][`width`]["." `precision`][`type`]
fill: <a character other than '{' or '}'>
align: "<" | ">" | "^"
fill: <a character other than '{', '}' or '\0'>
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"
type: `int_type` | "a" | "A" | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s"
int_type: "b" | "B" | "d" | "n" | "o" | "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
it, which must be one of the alignment options. If the second character of
*format_spec* is not a valid alignment option, then it is assumed that both the
fill character and the alignment option are absent.
The *fill* character can be any character other than '{', '}' or '\\0'. The
presence of a fill character is signaled by the character following it, which
must be one of the alignment options. If the second character of *format_spec*
is not a valid alignment option, then it is assumed that both the fill character
and the alignment option are absent.
The meaning of the various alignment options is as follows:
@ -101,6 +101,11 @@ The meaning of the various alignment options is as follows:
| ``'>'`` | Forces the field to be right-aligned within the |
| | available space (this is the default for numbers). |
+---------+----------------------------------------------------------+
| ``'='`` | Forces the padding to be placed after the sign (if any) |
| | but before the digits. This is used for printing fields |
| | in the form '+000000120'. This alignment option is only |
| | valid for numeric types. |
+---------+----------------------------------------------------------+
| ``'^'`` | Forces the field to be centered within the available |
| | space. |
+---------+----------------------------------------------------------+
@ -143,17 +148,15 @@ conversions, trailing zeros are not removed from the result.
.. ifconfig:: False
The ``','`` option signals the use of a comma for a thousands separator.
For a locale aware separator, use the ``'L'`` integer presentation type
For a locale aware separator, use the ``'n'`` integer presentation type
instead.
*width* is a decimal integer defining the minimum field width. If not
specified, then the field width will be determined by the content.
Preceding the *width* field by a zero (``'0'``) character enables sign-aware
zero-padding for numeric types. It forces the padding to be placed after the
sign or base (if any) but before the digits. This is used for printing fields in
the form '+000000120'. This option is only valid for numeric types and it has no
effect on formatting of infinity and NaN.
Preceding the *width* field by a zero (``'0'``) character enables
sign-aware zero-padding for numeric types. This is equivalent to a *fill*
character of ``'0'`` with an *alignment* type of ``'='``.
The *precision* is a decimal number indicating how many digits should be
displayed after the decimal point for a floating-point value formatted with
@ -214,9 +217,9 @@ 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. |
| ``'n'`` | Number. 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'``. |
+---------+----------------------------------------------------------+
@ -241,7 +244,7 @@ The available presentation types for floating-point values are:
| | notation using the letter 'e' to indicate the exponent. |
+---------+----------------------------------------------------------+
| ``'E'`` | Exponent notation. Same as ``'e'`` except it uses an |
| | upper-case ``'E'`` as the separator character. |
| | upper-case 'E' as the separator character. |
+---------+----------------------------------------------------------+
| ``'f'`` | Fixed point. Displays the number as a fixed-point |
| | number. |
@ -261,16 +264,11 @@ 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 | The same as ``'g'``. |
+---------+----------------------------------------------------------+
Floating-point formatting is locale-dependent.
.. ifconfig:: False
+---------+----------------------------------------------------------+
@ -305,7 +303,7 @@ The available presentation types for pointers are:
.. _formatexamples:
Format Examples
Format examples
===============
This section contains examples of the format syntax and comparison with
@ -320,94 +318,72 @@ following examples.
Accessing arguments by position::
fmt::format("{0}, {1}, {2}", 'a', 'b', 'c');
format("{0}, {1}, {2}", 'a', 'b', 'c');
// Result: "a, b, c"
fmt::format("{}, {}, {}", 'a', 'b', 'c');
format("{}, {}, {}", 'a', 'b', 'c');
// Result: "a, b, c"
fmt::format("{2}, {1}, {0}", 'a', 'b', 'c');
format("{2}, {1}, {0}", 'a', 'b', 'c');
// Result: "c, b, a"
fmt::format("{0}{1}{0}", "abra", "cad"); // arguments' indices can be repeated
format("{0}{1}{0}", "abra", "cad"); // arguments' indices can be repeated
// Result: "abracadabra"
Aligning the text and specifying a width::
fmt::format("{:<30}", "left aligned");
format("{:<30}", "left aligned");
// Result: "left aligned "
fmt::format("{:>30}", "right aligned");
format("{:>30}", "right aligned");
// Result: " right aligned"
fmt::format("{:^30}", "centered");
format("{:^30}", "centered");
// Result: " centered "
fmt::format("{:*^30}", "centered"); // use '*' as a fill char
format("{:*^30}", "centered"); // use '*' as a fill char
// Result: "***********centered***********"
Dynamic width::
fmt::format("{:<{}}", "left aligned", 30);
format("{:<{}}", "left aligned", 30);
// Result: "left aligned "
Dynamic precision::
fmt::format("{:.{}f}", 3.14, 1);
format("{:.{}f}", 3.14, 1);
// Result: "3.1"
Replacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign::
fmt::format("{:+f}; {:+f}", 3.14, -3.14); // show it always
format("{:+f}; {:+f}", 3.14, -3.14); // show it always
// Result: "+3.140000; -3.140000"
fmt::format("{: f}; {: f}", 3.14, -3.14); // show a space for positive numbers
format("{: f}; {: f}", 3.14, -3.14); // show a space for positive numbers
// Result: " 3.140000; -3.140000"
fmt::format("{:-f}; {:-f}", 3.14, -3.14); // show only the minus -- same as '{:f}; {:f}'
format("{:-f}; {:-f}", 3.14, -3.14); // show only the minus -- same as '{:f}; {:f}'
// Result: "3.140000; -3.140000"
Replacing ``%x`` and ``%o`` and converting the value to different bases::
fmt::format("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
format("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
// Result: "int: 42; hex: 2a; oct: 52; bin: 101010"
// with 0x or 0 or 0b as prefix:
fmt::format("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42);
format("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42);
// Result: "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"
Padded hex byte with prefix and always prints both hex characters::
fmt::format("{:#04x}", 0);
format("{:#04x}", 0);
// Result: "0x00"
Box drawing using Unicode fill::
fmt::print(
"┌{0:─^{2}}┐\n"
"│{1: ^{2}}│\n"
"└{0:─^{2}}┘\n", "", "Hello, world!", 20);
prints::
┌────────────────────┐
│ Hello, world! │
└────────────────────┘
Using type-specific formatting::
#include <fmt/chrono.h>
auto t = tm();
t.tm_year = 2010 - 1900;
t.tm_mon = 6;
t.tm_mday = 4;
t.tm_hour = 12;
t.tm_min = 15;
t.tm_sec = 58;
fmt::print("{:%Y-%m-%d %H:%M:%S}", t);
// Prints: 2010-08-04 12:15:58
Using the comma as a thousands separator::
#include <fmt/locale.h>
auto s = fmt::format(std::locale("en_US.UTF-8"), "{:L}", 1234567890);
// s == "1,234,567,890"
.. ifconfig:: False
Using the comma as a thousands separator::
format("{:,}", 1234567890);
'1,234,567,890'
Using type-specific formatting::
>>> import datetime
>>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)
Format("{:%Y-%m-%d %H:%M:%S}") << d)
'2010-07-04 12:15:58'
Nesting arguments and more complex examples::
>>> for align, text in zip('<^>', ['left', 'center', 'right']):
@ -436,3 +412,4 @@ Using the comma as a thousands separator::
9 9 11 1001
10 A 12 1010
11 B 13 1011

View File

@ -2,15 +2,21 @@
Usage
*****
To use the {fmt} library, add :file:`fmt/core.h`, :file:`fmt/format.h`,
:file:`fmt/format-inl.h`, :file:`src/format.cc` and optionally other headers
from a `release archive <https://github.com/fmtlib/fmt/releases/latest>`_ or
the `Git repository <https://github.com/fmtlib/fmt>`_ to your project.
To use the fmt library, add :file:`format.h` and :file:`format.cc` from
a `release archive <https://github.com/fmtlib/fmt/releases/latest>`_
or the `Git repository <https://github.com/fmtlib/fmt>`_ to your project.
Alternatively, you can :ref:`build the library with CMake <building>`.
If you are using Visual C++ with precompiled headers, you might need to add
the line ::
#include "stdafx.h"
before other includes in :file:`format.cc`.
.. _building:
Building the Library
Building the library
====================
The included `CMake build script`__ can be used to build the fmt
@ -25,7 +31,7 @@ workflow starts with::
mkdir build # Create a directory to hold the build output.
cd build
cmake .. # Generate native build scripts.
cmake <path/to/fmt> # Generate native build scripts.
where :file:`{<path/to/fmt>}` is a path to the ``fmt`` repository.
@ -52,14 +58,8 @@ To build a `shared library`__ set the ``BUILD_SHARED_LIBS`` CMake variable to
__ http://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries
Installing the Library
======================
After building the library you can install it on a Unix-like system by running
:command:`sudo make install`.
Usage with CMake
================
Header-only usage with CMake
============================
You can add the ``fmt`` library directory into your project and include it in
your ``CMakeLists.txt`` file::
@ -79,11 +79,11 @@ You can detect and use an installed version of {fmt} as follows::
find_package(fmt)
target_link_libraries(<your-target> fmt::fmt)
Setting up your target to use a header-only version of ``fmt`` is equally easy::
Setting up your target to use a header-only version of ``fmt`` is equaly easy::
target_link_libraries(<your-target> PRIVATE fmt::fmt-header-only)
target_link_libraries(<your-target> PRIVATE fmt-header-only)
Building the Documentation
Building the documentation
==========================
To build the documentation you need the following software installed on your
@ -103,33 +103,7 @@ the previous section. Then compile the ``doc`` target/project, for example::
make doc
This will generate the HTML documentation in ``doc/html``.
Conda
=====
fmt can be installed on Linux, macOS and Windows with
`Conda <https://docs.conda.io/en/latest/>`__, using its
`conda-forge <https://conda-forge.org>`__
`package <https://github.com/conda-forge/fmt-feedstock>`__, as follows::
conda install -c conda-forge fmt
Vcpkg
=====
You can download and install fmt using the `vcpkg
<https://github.com/Microsoft/vcpkg>`__ dependency manager::
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install fmt
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.
Android NDK
===========

File diff suppressed because it is too large Load Diff

View File

@ -12,149 +12,184 @@
FMT_BEGIN_NAMESPACE
#ifdef FMT_DEPRECATED_COLORS
// color and (v)print_colored are deprecated.
enum color { black, red, green, yellow, blue, magenta, cyan, white };
FMT_API void vprint_colored(color c, string_view format, format_args args);
FMT_API void vprint_colored(color c, wstring_view format, wformat_args args);
template <typename... Args>
inline void print_colored(color c, string_view format_str,
const Args & ... args) {
vprint_colored(c, format_str, make_format_args(args...));
}
template <typename... Args>
inline void print_colored(color c, wstring_view format_str,
const Args & ... args) {
vprint_colored(c, format_str, make_format_args<wformat_context>(args...));
}
inline void vprint_colored(color c, string_view format, format_args args) {
char escape[] = "\x1b[30m";
escape[3] = static_cast<char>('0' + c);
std::fputs(escape, stdout);
vprint(format, args);
std::fputs(internal::data::RESET_COLOR, stdout);
}
inline void vprint_colored(color c, wstring_view format, wformat_args args) {
wchar_t escape[] = L"\x1b[30m";
escape[3] = static_cast<wchar_t>('0' + c);
std::fputws(escape, stdout);
vprint(format, args);
std::fputws(internal::data::WRESET_COLOR, stdout);
}
#else
enum class color : uint32_t {
alice_blue = 0xF0F8FF, // rgb(240,248,255)
antique_white = 0xFAEBD7, // rgb(250,235,215)
aqua = 0x00FFFF, // rgb(0,255,255)
aquamarine = 0x7FFFD4, // rgb(127,255,212)
azure = 0xF0FFFF, // rgb(240,255,255)
beige = 0xF5F5DC, // rgb(245,245,220)
bisque = 0xFFE4C4, // rgb(255,228,196)
black = 0x000000, // rgb(0,0,0)
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
blue = 0x0000FF, // rgb(0,0,255)
blue_violet = 0x8A2BE2, // rgb(138,43,226)
brown = 0xA52A2A, // rgb(165,42,42)
burly_wood = 0xDEB887, // rgb(222,184,135)
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
chartreuse = 0x7FFF00, // rgb(127,255,0)
chocolate = 0xD2691E, // rgb(210,105,30)
coral = 0xFF7F50, // rgb(255,127,80)
cornflower_blue = 0x6495ED, // rgb(100,149,237)
cornsilk = 0xFFF8DC, // rgb(255,248,220)
crimson = 0xDC143C, // rgb(220,20,60)
cyan = 0x00FFFF, // rgb(0,255,255)
dark_blue = 0x00008B, // rgb(0,0,139)
dark_cyan = 0x008B8B, // rgb(0,139,139)
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
dark_gray = 0xA9A9A9, // rgb(169,169,169)
dark_green = 0x006400, // rgb(0,100,0)
dark_khaki = 0xBDB76B, // rgb(189,183,107)
dark_magenta = 0x8B008B, // rgb(139,0,139)
dark_olive_green = 0x556B2F, // rgb(85,107,47)
dark_orange = 0xFF8C00, // rgb(255,140,0)
dark_orchid = 0x9932CC, // rgb(153,50,204)
dark_red = 0x8B0000, // rgb(139,0,0)
dark_salmon = 0xE9967A, // rgb(233,150,122)
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
dark_turquoise = 0x00CED1, // rgb(0,206,209)
dark_violet = 0x9400D3, // rgb(148,0,211)
deep_pink = 0xFF1493, // rgb(255,20,147)
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
dim_gray = 0x696969, // rgb(105,105,105)
dodger_blue = 0x1E90FF, // rgb(30,144,255)
fire_brick = 0xB22222, // rgb(178,34,34)
floral_white = 0xFFFAF0, // rgb(255,250,240)
forest_green = 0x228B22, // rgb(34,139,34)
fuchsia = 0xFF00FF, // rgb(255,0,255)
gainsboro = 0xDCDCDC, // rgb(220,220,220)
ghost_white = 0xF8F8FF, // rgb(248,248,255)
gold = 0xFFD700, // rgb(255,215,0)
golden_rod = 0xDAA520, // rgb(218,165,32)
gray = 0x808080, // rgb(128,128,128)
green = 0x008000, // rgb(0,128,0)
green_yellow = 0xADFF2F, // rgb(173,255,47)
honey_dew = 0xF0FFF0, // rgb(240,255,240)
hot_pink = 0xFF69B4, // rgb(255,105,180)
indian_red = 0xCD5C5C, // rgb(205,92,92)
indigo = 0x4B0082, // rgb(75,0,130)
ivory = 0xFFFFF0, // rgb(255,255,240)
khaki = 0xF0E68C, // rgb(240,230,140)
lavender = 0xE6E6FA, // rgb(230,230,250)
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
lawn_green = 0x7CFC00, // rgb(124,252,0)
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
light_blue = 0xADD8E6, // rgb(173,216,230)
light_coral = 0xF08080, // rgb(240,128,128)
light_cyan = 0xE0FFFF, // rgb(224,255,255)
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
light_gray = 0xD3D3D3, // rgb(211,211,211)
light_green = 0x90EE90, // rgb(144,238,144)
light_pink = 0xFFB6C1, // rgb(255,182,193)
light_salmon = 0xFFA07A, // rgb(255,160,122)
light_sea_green = 0x20B2AA, // rgb(32,178,170)
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
light_slate_gray = 0x778899, // rgb(119,136,153)
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
light_yellow = 0xFFFFE0, // rgb(255,255,224)
lime = 0x00FF00, // rgb(0,255,0)
lime_green = 0x32CD32, // rgb(50,205,50)
linen = 0xFAF0E6, // rgb(250,240,230)
magenta = 0xFF00FF, // rgb(255,0,255)
maroon = 0x800000, // rgb(128,0,0)
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
medium_blue = 0x0000CD, // rgb(0,0,205)
medium_orchid = 0xBA55D3, // rgb(186,85,211)
medium_purple = 0x9370DB, // rgb(147,112,219)
medium_sea_green = 0x3CB371, // rgb(60,179,113)
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
medium_violet_red = 0xC71585, // rgb(199,21,133)
midnight_blue = 0x191970, // rgb(25,25,112)
mint_cream = 0xF5FFFA, // rgb(245,255,250)
misty_rose = 0xFFE4E1, // rgb(255,228,225)
moccasin = 0xFFE4B5, // rgb(255,228,181)
navajo_white = 0xFFDEAD, // rgb(255,222,173)
navy = 0x000080, // rgb(0,0,128)
old_lace = 0xFDF5E6, // rgb(253,245,230)
olive = 0x808000, // rgb(128,128,0)
olive_drab = 0x6B8E23, // rgb(107,142,35)
orange = 0xFFA500, // rgb(255,165,0)
orange_red = 0xFF4500, // rgb(255,69,0)
orchid = 0xDA70D6, // rgb(218,112,214)
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
pale_green = 0x98FB98, // rgb(152,251,152)
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
pale_violet_red = 0xDB7093, // rgb(219,112,147)
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
peach_puff = 0xFFDAB9, // rgb(255,218,185)
peru = 0xCD853F, // rgb(205,133,63)
pink = 0xFFC0CB, // rgb(255,192,203)
plum = 0xDDA0DD, // rgb(221,160,221)
powder_blue = 0xB0E0E6, // rgb(176,224,230)
purple = 0x800080, // rgb(128,0,128)
rebecca_purple = 0x663399, // rgb(102,51,153)
red = 0xFF0000, // rgb(255,0,0)
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
royal_blue = 0x4169E1, // rgb(65,105,225)
saddle_brown = 0x8B4513, // rgb(139,69,19)
salmon = 0xFA8072, // rgb(250,128,114)
sandy_brown = 0xF4A460, // rgb(244,164,96)
sea_green = 0x2E8B57, // rgb(46,139,87)
sea_shell = 0xFFF5EE, // rgb(255,245,238)
sienna = 0xA0522D, // rgb(160,82,45)
silver = 0xC0C0C0, // rgb(192,192,192)
sky_blue = 0x87CEEB, // rgb(135,206,235)
slate_blue = 0x6A5ACD, // rgb(106,90,205)
slate_gray = 0x708090, // rgb(112,128,144)
snow = 0xFFFAFA, // rgb(255,250,250)
spring_green = 0x00FF7F, // rgb(0,255,127)
steel_blue = 0x4682B4, // rgb(70,130,180)
tan = 0xD2B48C, // rgb(210,180,140)
teal = 0x008080, // rgb(0,128,128)
thistle = 0xD8BFD8, // rgb(216,191,216)
tomato = 0xFF6347, // rgb(255,99,71)
turquoise = 0x40E0D0, // rgb(64,224,208)
violet = 0xEE82EE, // rgb(238,130,238)
wheat = 0xF5DEB3, // rgb(245,222,179)
white = 0xFFFFFF, // rgb(255,255,255)
white_smoke = 0xF5F5F5, // rgb(245,245,245)
yellow = 0xFFFF00, // rgb(255,255,0)
yellow_green = 0x9ACD32 // rgb(154,205,50)
}; // enum class color
alice_blue = 0xF0F8FF, // rgb(240,248,255)
antique_white = 0xFAEBD7, // rgb(250,235,215)
aqua = 0x00FFFF, // rgb(0,255,255)
aquamarine = 0x7FFFD4, // rgb(127,255,212)
azure = 0xF0FFFF, // rgb(240,255,255)
beige = 0xF5F5DC, // rgb(245,245,220)
bisque = 0xFFE4C4, // rgb(255,228,196)
black = 0x000000, // rgb(0,0,0)
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
blue = 0x0000FF, // rgb(0,0,255)
blue_violet = 0x8A2BE2, // rgb(138,43,226)
brown = 0xA52A2A, // rgb(165,42,42)
burly_wood = 0xDEB887, // rgb(222,184,135)
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
chartreuse = 0x7FFF00, // rgb(127,255,0)
chocolate = 0xD2691E, // rgb(210,105,30)
coral = 0xFF7F50, // rgb(255,127,80)
cornflower_blue = 0x6495ED, // rgb(100,149,237)
cornsilk = 0xFFF8DC, // rgb(255,248,220)
crimson = 0xDC143C, // rgb(220,20,60)
cyan = 0x00FFFF, // rgb(0,255,255)
dark_blue = 0x00008B, // rgb(0,0,139)
dark_cyan = 0x008B8B, // rgb(0,139,139)
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
dark_gray = 0xA9A9A9, // rgb(169,169,169)
dark_green = 0x006400, // rgb(0,100,0)
dark_khaki = 0xBDB76B, // rgb(189,183,107)
dark_magenta = 0x8B008B, // rgb(139,0,139)
dark_olive_green = 0x556B2F, // rgb(85,107,47)
dark_orange = 0xFF8C00, // rgb(255,140,0)
dark_orchid = 0x9932CC, // rgb(153,50,204)
dark_red = 0x8B0000, // rgb(139,0,0)
dark_salmon = 0xE9967A, // rgb(233,150,122)
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
dark_turquoise = 0x00CED1, // rgb(0,206,209)
dark_violet = 0x9400D3, // rgb(148,0,211)
deep_pink = 0xFF1493, // rgb(255,20,147)
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
dim_gray = 0x696969, // rgb(105,105,105)
dodger_blue = 0x1E90FF, // rgb(30,144,255)
fire_brick = 0xB22222, // rgb(178,34,34)
floral_white = 0xFFFAF0, // rgb(255,250,240)
forest_green = 0x228B22, // rgb(34,139,34)
fuchsia = 0xFF00FF, // rgb(255,0,255)
gainsboro = 0xDCDCDC, // rgb(220,220,220)
ghost_white = 0xF8F8FF, // rgb(248,248,255)
gold = 0xFFD700, // rgb(255,215,0)
golden_rod = 0xDAA520, // rgb(218,165,32)
gray = 0x808080, // rgb(128,128,128)
green = 0x008000, // rgb(0,128,0)
green_yellow = 0xADFF2F, // rgb(173,255,47)
honey_dew = 0xF0FFF0, // rgb(240,255,240)
hot_pink = 0xFF69B4, // rgb(255,105,180)
indian_red = 0xCD5C5C, // rgb(205,92,92)
indigo = 0x4B0082, // rgb(75,0,130)
ivory = 0xFFFFF0, // rgb(255,255,240)
khaki = 0xF0E68C, // rgb(240,230,140)
lavender = 0xE6E6FA, // rgb(230,230,250)
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
lawn_green = 0x7CFC00, // rgb(124,252,0)
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
light_blue = 0xADD8E6, // rgb(173,216,230)
light_coral = 0xF08080, // rgb(240,128,128)
light_cyan = 0xE0FFFF, // rgb(224,255,255)
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
light_gray = 0xD3D3D3, // rgb(211,211,211)
light_green = 0x90EE90, // rgb(144,238,144)
light_pink = 0xFFB6C1, // rgb(255,182,193)
light_salmon = 0xFFA07A, // rgb(255,160,122)
light_sea_green = 0x20B2AA, // rgb(32,178,170)
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
light_slate_gray = 0x778899, // rgb(119,136,153)
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
light_yellow = 0xFFFFE0, // rgb(255,255,224)
lime = 0x00FF00, // rgb(0,255,0)
lime_green = 0x32CD32, // rgb(50,205,50)
linen = 0xFAF0E6, // rgb(250,240,230)
magenta = 0xFF00FF, // rgb(255,0,255)
maroon = 0x800000, // rgb(128,0,0)
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
medium_blue = 0x0000CD, // rgb(0,0,205)
medium_orchid = 0xBA55D3, // rgb(186,85,211)
medium_purple = 0x9370DB, // rgb(147,112,219)
medium_sea_green = 0x3CB371, // rgb(60,179,113)
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
medium_violet_red = 0xC71585, // rgb(199,21,133)
midnight_blue = 0x191970, // rgb(25,25,112)
mint_cream = 0xF5FFFA, // rgb(245,255,250)
misty_rose = 0xFFE4E1, // rgb(255,228,225)
moccasin = 0xFFE4B5, // rgb(255,228,181)
navajo_white = 0xFFDEAD, // rgb(255,222,173)
navy = 0x000080, // rgb(0,0,128)
old_lace = 0xFDF5E6, // rgb(253,245,230)
olive = 0x808000, // rgb(128,128,0)
olive_drab = 0x6B8E23, // rgb(107,142,35)
orange = 0xFFA500, // rgb(255,165,0)
orange_red = 0xFF4500, // rgb(255,69,0)
orchid = 0xDA70D6, // rgb(218,112,214)
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
pale_green = 0x98FB98, // rgb(152,251,152)
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
pale_violet_red = 0xDB7093, // rgb(219,112,147)
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
peach_puff = 0xFFDAB9, // rgb(255,218,185)
peru = 0xCD853F, // rgb(205,133,63)
pink = 0xFFC0CB, // rgb(255,192,203)
plum = 0xDDA0DD, // rgb(221,160,221)
powder_blue = 0xB0E0E6, // rgb(176,224,230)
purple = 0x800080, // rgb(128,0,128)
rebecca_purple = 0x663399, // rgb(102,51,153)
red = 0xFF0000, // rgb(255,0,0)
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
royal_blue = 0x4169E1, // rgb(65,105,225)
saddle_brown = 0x8B4513, // rgb(139,69,19)
salmon = 0xFA8072, // rgb(250,128,114)
sandy_brown = 0xF4A460, // rgb(244,164,96)
sea_green = 0x2E8B57, // rgb(46,139,87)
sea_shell = 0xFFF5EE, // rgb(255,245,238)
sienna = 0xA0522D, // rgb(160,82,45)
silver = 0xC0C0C0, // rgb(192,192,192)
sky_blue = 0x87CEEB, // rgb(135,206,235)
slate_blue = 0x6A5ACD, // rgb(106,90,205)
slate_gray = 0x708090, // rgb(112,128,144)
snow = 0xFFFAFA, // rgb(255,250,250)
spring_green = 0x00FF7F, // rgb(0,255,127)
steel_blue = 0x4682B4, // rgb(70,130,180)
tan = 0xD2B48C, // rgb(210,180,140)
teal = 0x008080, // rgb(0,128,128)
thistle = 0xD8BFD8, // rgb(216,191,216)
tomato = 0xFF6347, // rgb(255,99,71)
turquoise = 0x40E0D0, // rgb(64,224,208)
violet = 0xEE82EE, // rgb(238,130,238)
wheat = 0xF5DEB3, // rgb(245,222,179)
white = 0xFFFFFF, // rgb(255,255,255)
white_smoke = 0xF5F5F5, // rgb(245,245,245)
yellow = 0xFFFF00, // rgb(255,255,0)
yellow_green = 0x9ACD32 // rgb(154,205,50)
}; // enum class color
enum class terminal_color : uint8_t {
black = 30,
@ -173,26 +208,27 @@ enum class terminal_color : uint8_t {
bright_magenta,
bright_cyan,
bright_white
};
}; // enum class terminal_color
enum class emphasis : uint8_t {
bold = 1,
italic = 1 << 1,
underline = 1 << 2,
strikethrough = 1 << 3
};
}; // enum class emphasis
// rgb is a struct for red, green and blue colors.
// Using the name "rgb" makes some editors show the color in a tooltip.
// We use rgb as name because some editors will show it as color direct in the
// editor.
struct rgb {
FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {}
FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {}
FMT_CONSTEXPR rgb(uint32_t hex)
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {}
FMT_CONSTEXPR rgb(color hex)
: r((uint32_t(hex) >> 16) & 0xFF),
g((uint32_t(hex) >> 8) & 0xFF),
b(uint32_t(hex) & 0xFF) {}
FMT_CONSTEXPR_DECL rgb() : r(0), g(0), b(0) {}
FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_)
: r(r_), g(g_), b(b_) {}
FMT_CONSTEXPR_DECL rgb(uint32_t hex)
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b((hex) & 0xFF) {}
FMT_CONSTEXPR_DECL rgb(color hex)
: r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF),
b(uint32_t(hex) & 0xFF) {}
uint8_t r;
uint8_t g;
uint8_t b;
@ -202,17 +238,19 @@ namespace internal {
// 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() FMT_NOEXCEPT
: is_rgb(), value{} {}
FMT_CONSTEXPR color_type(color rgb_color) FMT_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{} {
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(rgb rgb_color) FMT_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) FMT_NOEXCEPT
: is_rgb(), value{} {
value.term_color = static_cast<uint8_t>(term_color);
}
bool is_rgb;
@ -221,23 +259,21 @@ struct color_type {
uint32_t rgb_color;
} value;
};
} // namespace internal
} // namespace internal
// Experimental text formatting support.
class text_style {
public:
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
: set_foreground_color(),
set_background_color(),
ems(em) {}
: set_foreground_color(), set_background_color(), ems(em) {}
FMT_CONSTEXPR text_style& operator|=(const text_style& 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 OR a terminal color"));
throw format_error("can't OR a terminal color");
foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color;
}
@ -246,7 +282,7 @@ class text_style {
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 OR a terminal color"));
throw format_error("can't OR a terminal color");
background_color.value.rgb_color |= rhs.background_color.value.rgb_color;
}
@ -255,18 +291,18 @@ class text_style {
return *this;
}
friend FMT_CONSTEXPR text_style operator|(text_style lhs,
const text_style& rhs) {
friend FMT_CONSTEXPR
text_style operator|(text_style lhs, const text_style &rhs) {
return lhs |= rhs;
}
FMT_CONSTEXPR text_style& operator&=(const text_style& 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"));
throw format_error("can't AND a terminal color");
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
}
@ -275,7 +311,7 @@ class text_style {
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"));
throw format_error("can't AND a terminal color");
background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
}
@ -284,8 +320,8 @@ class text_style {
return *this;
}
friend FMT_CONSTEXPR text_style operator&(text_style lhs,
const text_style& rhs) {
friend FMT_CONSTEXPR
text_style operator&(text_style lhs, const text_style &rhs) {
return lhs &= rhs;
}
@ -299,32 +335,32 @@ class text_style {
return static_cast<uint8_t>(ems) != 0;
}
FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT {
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
assert(has_foreground() && "no foreground specified for this style");
return foreground_color;
}
FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT {
FMT_ASSERT(has_background(), "no background specified for this style");
assert(has_background() && "no background specified for this style");
return background_color;
}
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
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() {
if (is_foreground) {
foreground_color = text_color;
set_foreground_color = true;
} else {
background_color = text_color;
set_background_color = true;
}
}
private:
FMT_CONSTEXPR text_style(bool is_foreground,
internal::color_type text_color) FMT_NOEXCEPT
: set_foreground_color(),
set_background_color(),
ems() {
if (is_foreground) {
foreground_color = text_color;
set_foreground_color = true;
} else {
background_color = text_color;
set_background_color = true;
}
}
friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground)
FMT_NOEXCEPT;
@ -352,17 +388,19 @@ FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
namespace internal {
template <typename Char> struct ansi_color_escape {
template <typename Char>
struct ansi_color_escape {
FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,
const char* esc) FMT_NOEXCEPT {
const char * esc) FMT_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 == internal::data::BACKGROUND_COLOR;
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;
if (is_background)
value += 10u;
std::size_t index = 0;
buffer[index++] = static_cast<Char>('\x1b');
@ -384,7 +422,7 @@ template <typename Char> struct ansi_color_escape {
buffer[i] = static_cast<Char>(esc[i]);
}
rgb color(text_color.value.rgb_color);
to_esc(color.r, buffer + 7, ';');
to_esc(color.r, buffer + 7, ';');
to_esc(color.g, buffer + 11, ';');
to_esc(color.b, buffer + 15, 'm');
buffer[19] = static_cast<Char>(0);
@ -392,15 +430,19 @@ template <typename Char> struct ansi_color_escape {
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::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;
std::size_t index = 0;
for (int i = 0; i < 4; ++i) {
if (!em_codes[i]) continue;
if (!em_codes[i])
continue;
buffer[index++] = static_cast<Char>('\x1b');
buffer[index++] = static_cast<Char>('[');
buffer[index++] = static_cast<Char>('0' + em_codes[i]);
@ -408,17 +450,12 @@ 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 FMT_NOEXCEPT { return buffer; }
FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT {
return buffer + std::char_traits<Char>::length(buffer);
}
private:
private:
Char buffer[7u + 3u * 4u + 1u];
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
static FMT_CONSTEXPR void to_esc(uint8_t c, Char *out,
char delimiter) FMT_NOEXCEPT {
out[0] = static_cast<Char>('0' + c / 100);
out[1] = static_cast<Char>('0' + c / 10 % 10);
@ -428,81 +465,77 @@ template <typename Char> struct ansi_color_escape {
};
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);
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);
}
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);
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);
}
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) FMT_NOEXCEPT {
return ansi_color_escape<Char>(em);
}
template <typename Char>
inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT {
inline void fputs(const Char *chars, FILE *stream) FMT_NOEXCEPT {
std::fputs(chars, stream);
}
template <>
inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT {
inline void fputs<wchar_t>(const wchar_t *chars, FILE *stream) FMT_NOEXCEPT {
std::fputws(chars, stream);
}
template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
fputs(internal::data::reset_color, stream);
}
template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
fputs(internal::data::wreset_color, stream);
}
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);
inline void reset_color(FILE *stream) FMT_NOEXCEPT {
fputs(internal::data::RESET_COLOR, stream);
}
template <typename Char>
void vformat_to(basic_memory_buffer<Char>& buf, const text_style& ts,
basic_string_view<Char> format_str,
basic_format_args<buffer_context<Char>> args) {
template <>
inline void reset_color<wchar_t>(FILE *stream) FMT_NOEXCEPT {
fputs(internal::data::WRESET_COLOR, stream);
}
// The following specialiazation disables using std::FILE as a character type,
// which is needed because or else
// fmt::print(stderr, fmt::emphasis::bold, "");
// would take stderr (a std::FILE *) as the format string.
template <>
struct is_string<std::FILE *> : std::false_type {};
template <>
struct is_string<const std::FILE *> : std::false_type {};
} // namespace internal
template <
typename S, typename Char = typename internal::char_t<S>::type>
void vprint(std::FILE *f, const text_style &ts, const S &format,
basic_format_args<typename buffer_context<Char>::type> args) {
bool has_style = false;
if (ts.has_emphasis()) {
has_style = true;
auto emphasis = internal::make_emphasis<Char>(ts.get_emphasis());
buf.append(emphasis.begin(), emphasis.end());
internal::fputs<Char>(
internal::make_emphasis<Char>(ts.get_emphasis()), f);
}
if (ts.has_foreground()) {
has_style = true;
auto foreground =
internal::make_foreground_color<Char>(ts.get_foreground());
buf.append(foreground.begin(), foreground.end());
internal::fputs<Char>(
internal::make_foreground_color<Char>(ts.get_foreground()), f);
}
if (ts.has_background()) {
has_style = true;
auto background =
internal::make_background_color<Char>(ts.get_background());
buf.append(background.begin(), background.end());
internal::fputs<Char>(
internal::make_background_color<Char>(ts.get_background()), f);
}
vprint(f, format, args);
if (has_style) {
internal::reset_color<Char>(f);
}
internal::vformat_to(buf, format_str, args);
if (has_style) internal::reset_color<Char>(buf);
}
} // namespace internal
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_memory_buffer<Char> buf;
internal::vformat_to(buf, ts, to_string_view(format), args);
buf.push_back(Char(0));
internal::fputs(buf.data(), f);
}
/**
@ -512,14 +545,15 @@ void vprint(std::FILE* f, const text_style& ts, const S& format,
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
*/
template <typename S, typename... Args,
FMT_ENABLE_IF(internal::is_string<S>::value)>
void print(std::FILE* f, const text_style& ts, const S& format_str,
const Args&... args) {
template <typename String, typename... Args>
typename std::enable_if<internal::is_string<String>::value>::type print(
std::FILE *f, const text_style &ts, const String &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));
typedef typename internal::char_t<String>::type char_t;
typedef typename buffer_context<char_t>::type context_t;
format_arg_store<context_t, Args...> as{args...};
vprint(f, ts, format_str, basic_format_args<context_t>(as));
}
/**
@ -529,39 +563,14 @@ void print(std::FILE* f, const text_style& ts, const S& format_str,
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
*/
template <typename S, typename... Args,
FMT_ENABLE_IF(internal::is_string<S>::value)>
void print(const text_style& ts, const S& format_str, const Args&... args) {
template <typename String, typename... Args>
typename std::enable_if<internal::is_string<String>::value>::type print(
const text_style &ts, const String &format_str,
const Args &... args) {
return print(stdout, ts, format_str, args...);
}
template <typename S, typename Char = char_t<S>>
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);
return fmt::to_string(buf);
}
/**
\rst
Formats arguments and returns the result as a string using ANSI
escape sequences to specify text formatting.
**Example**::
#include <fmt/color.h>
std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red),
"The answer is {}", 42);
\endrst
*/
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...));
}
#endif
FMT_END_NAMESPACE

View File

@ -1,595 +0,0 @@
// Formatting library for C++ - experimental format string compilation
//
// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_COMPILE_H_
#define FMT_COMPILE_H_
#include <vector>
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace internal {
// 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 PartHandler>
class format_string_compiler : public error_handler {
private:
using part = format_part<Char>;
PartHandler handler_;
part part_;
basic_string_view<Char> format_str_;
basic_format_parse_context<Char> parse_context_;
public:
FMT_CONSTEXPR format_string_compiler(basic_string_view<Char> format_str,
PartHandler handler)
: handler_(handler),
format_str_(format_str),
parse_context_(format_str) {}
FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
if (begin != end)
handler_(part::make_text({begin, to_unsigned(end - begin)}));
}
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);
return it;
}
};
// 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 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)));
}
// 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);
});
}
const parts_container& parts() const { return compiled_parts; }
};
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;
}
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>;
FMT_CONSTEXPR explicit compiled_format_base(basic_string_view<char_type>) {}
// 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);
#else
static const unsigned num_format_parts = 1;
#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;
}
};
template <typename S, typename... Args>
class compiled_format : private compiled_format_base<S> {
public:
using typename compiled_format_base<S>::char_type;
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
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) {
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
if constexpr (N == 0)
return first;
else
return get<N - 1>(rest...);
}
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>()...))>;
};
template <int N, typename T>
using get_type = typename get_type_impl<N, T>::type;
template <typename T> struct is_compiled_format : std::false_type {};
template <typename Char> struct text {
basic_string_view<Char> data;
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);
}
};
template <typename Char>
struct is_compiled_format<text<Char>> : std::true_type {};
template <typename Char>
constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
size_t size) {
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, 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);
}
// 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);
}
};
template <typename Char, typename T, int N>
struct is_compiled_format<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 {
out = lhs.format(out, args...);
return rhs.format(out, args...);
}
};
template <typename L, typename R>
struct is_compiled_format<concat<L, R>> : std::true_type {};
template <typename L, typename R>
constexpr concat<L, R> make_concat(L lhs, R rhs) {
return {lhs, rhs};
}
struct unknown_format {};
template <typename Char>
constexpr size_t parse_text(basic_string_view<Char> str, size_t pos) {
for (size_t size = str.size(); pos != size; ++pos) {
if (str[pos] == '{' || str[pos] == '}') break;
}
return pos;
}
template <typename Args, size_t POS, int ID, typename S>
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()) {
constexpr auto tail = compile_format_string<Args, POS, ID>(format_str);
if constexpr (std::is_same<remove_cvref_t<decltype(tail)>,
unknown_format>())
return tail;
else
return make_concat(head, tail);
} else {
return head;
}
}
// 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;
if constexpr (str[POS] == '{') {
if (POS + 1 == str.size())
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 {
return unknown_format();
}
} else if constexpr (str[POS] == '}') {
if (POS + 1 == str.size())
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));
} else {
return result;
}
}
}
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);
}
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) {
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 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 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)>
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...);
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();
}
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

@ -8,66 +8,65 @@
#ifndef FMT_LOCALE_H_
#define FMT_LOCALE_H_
#include <locale>
#include "format.h"
#include <locale>
FMT_BEGIN_NAMESPACE
namespace internal {
template <typename Char>
typename buffer_context<Char>::iterator vformat_to(
const std::locale& loc, buffer<Char>& buf,
typename buffer_context<Char>::type::iterator vformat_to(
const std::locale &loc, basic_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));
basic_format_args<typename buffer_context<Char>::type> args) {
typedef back_insert_range<basic_buffer<Char> > range;
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) {
const std::locale &loc, basic_string_view<Char> format_str,
basic_format_args<typename buffer_context<Char>::type> 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>>
template <typename S, typename Char = FMT_CHAR(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) {
const std::locale &loc, const S &format_str,
basic_format_args<typename buffer_context<Char>::type> 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) {
template <typename S, typename... Args>
inline std::basic_string<FMT_CHAR(S)> format(
const std::locale &loc, const S &format_str, const Args &... args) {
return internal::vformat(
loc, to_string_view(format_str),
internal::make_args_checked<Args...>(format_str, args...));
loc, to_string_view(format_str),
*internal::checked_args<S, 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>;
template <typename String, typename OutputIt, typename... Args>
inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
OutputIt>::type
vformat_to(OutputIt out, const std::locale &loc, const String &format_str,
typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {
typedef output_range<OutputIt, FMT_CHAR(String)> range;
return vformat_to<arg_formatter<range>>(
range(out), to_string_view(format_str), args, internal::locale_ref(loc));
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) {
template <typename OutputIt, typename S, typename... Args>
inline typename std::enable_if<
internal::is_string<S>::value &&
internal::is_output_iterator<OutputIt>::value, OutputIt>::type
format_to(OutputIt out, const std::locale &loc, const S &format_str,
const Args &... args) {
internal::check_format_string<Args...>(format_str);
using context = format_context_t<OutputIt, char_t<S>>;
typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context;
format_arg_store<context, Args...> as{args...};
return vformat_to(out, loc, to_string_view(format_str),
basic_format_args<context>(as));

View File

@ -1,392 +0,0 @@
// Formatting library for C++ - optional OS-specific functionality
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#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
#if defined __APPLE__ || defined(__FreeBSD__)
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
#endif
#include "format.h"
// 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
#endif
#ifndef FMT_POSIX
# if defined(_WIN32) && !defined(__MINGW32__)
// Fix warnings about deprecated symbols.
# define FMT_POSIX(call) _##call
# else
# define FMT_POSIX(call) call
# endif
#endif
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
#ifdef FMT_SYSTEM
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
#else
# define FMT_SYSTEM(call) call
# ifdef _WIN32
// Fix warnings about deprecated symbols.
# define FMT_POSIX_CALL(call) ::_##call
# else
# define FMT_POSIX_CALL(call) ::call
# endif
#endif
// Retries the expression while it evaluates to error_result and errno
// equals to EINTR.
#ifndef _WIN32
# define FMT_RETRY_VAL(result, expression, error_result) \
do { \
(result) = (expression); \
} while ((result) == (error_result) && errno == EINTR)
#else
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
#endif
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
FMT_BEGIN_NAMESPACE
/**
\rst
A reference to a null-terminated string. It can be constructed from a C
string or ``std::string``.
You can use one of the following type aliases for common character types:
+---------------+-----------------------------+
| Type | Definition |
+===============+=============================+
| cstring_view | basic_cstring_view<char> |
+---------------+-----------------------------+
| wcstring_view | basic_cstring_view<wchar_t> |
+---------------+-----------------------------+
This class is most useful as a parameter type to allow passing
different types of strings to a function, for example::
template <typename... Args>
std::string format(cstring_view format_str, const Args & ... args);
format("{}", 42);
format(std::string("{}"), 42);
\endrst
*/
template <typename Char> class basic_cstring_view {
private:
const Char* data_;
public:
/** Constructs a string reference object from a C string. */
basic_cstring_view(const Char* s) : data_(s) {}
/**
\rst
Constructs a string reference from an ``std::string`` object.
\endrst
*/
basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {}
/** Returns the pointer to a C string. */
const Char* c_str() const { return data_; }
};
using cstring_view = basic_cstring_view<char>;
using wcstring_view = basic_cstring_view<wchar_t>;
// An error code.
class error_code {
private:
int value_;
public:
explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}
int get() const FMT_NOEXCEPT { return value_; }
};
#ifdef _WIN32
namespace internal {
// 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 {
private:
memory_buffer buffer_;
public:
utf16_to_utf8() {}
FMT_API explicit utf16_to_utf8(wstring_view 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]; }
std::string str() const { return std::string(&buffer_[0], size()); }
// 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 void format_windows_error(buffer<char>& out, int error_code,
string_view message) FMT_NOEXCEPT;
} // namespace internal
/** A Windows error. */
class windows_error : public system_error {
private:
FMT_API void init(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
.. 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".
**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...));
}
};
// 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;
#endif // _WIN32
// A buffered file.
class buffered_file {
private:
FILE* file_;
friend class file;
explicit buffered_file(FILE* f) : file_(f) {}
public:
buffered_file(const buffered_file&) = delete;
void operator=(const buffered_file&) = delete;
// Constructs a buffered_file object which doesn't represent any file.
buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
// Destroys the object closing the file it represents if any.
FMT_API ~buffered_file() FMT_NOEXCEPT;
public:
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
other.file_ = nullptr;
}
buffered_file& operator=(buffered_file&& other) {
close();
file_ = other.file_;
other.file_ = nullptr;
return *this;
}
// Opens a file.
FMT_API buffered_file(cstring_view filename, cstring_view mode);
// Closes the file.
FMT_API void close();
// Returns the pointer to a FILE object representing this file.
FILE* get() const FMT_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;
void vprint(string_view format_str, format_args args) {
fmt::vprint(file_, format_str, args);
}
template <typename... Args>
inline void print(string_view format_str, const Args&... args) {
vprint(format_str, 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
// 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 {
private:
int fd_; // File descriptor.
// Constructs a file object with a given descriptor.
explicit file(int fd) : fd_(fd) {}
public:
// Possible values for the oflag argument to the constructor.
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.
};
// Constructs a file object which doesn't represent any file.
file() FMT_NOEXCEPT : fd_(-1) {}
// Opens a file and constructs a file object representing this file.
FMT_API 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& operator=(file&& other) FMT_NOEXCEPT {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
// Destroys the object closing the file it represents if any.
FMT_API ~file() FMT_NOEXCEPT;
// Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT { return fd_; }
// Closes the file.
FMT_API void close();
// Returns the file size. The size has signed type for consistency with
// stat::st_size.
FMT_API 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);
// 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);
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
FMT_API 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);
// 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;
// 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);
// 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);
};
// 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;
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;
}
};
using Locale FMT_DEPRECATED_ALIAS = locale;
#endif // FMT_LOCALE
FMT_END_NAMESPACE
#endif // FMT_OS_H_

View File

@ -8,21 +8,22 @@
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
#include <ostream>
#include "format.h"
#include <ostream>
FMT_BEGIN_NAMESPACE
namespace internal {
template <class Char> class formatbuf : public std::basic_streambuf<Char> {
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;
typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
buffer<Char>& buffer_;
basic_buffer<Char> &buffer_;
public:
formatbuf(buffer<Char>& buf) : buffer_(buf) {}
formatbuf(basic_buffer<Char> &buffer) : buffer_(buffer) {}
protected:
// The put-area is actually always empty. This makes the implementation
@ -38,36 +39,33 @@ template <class Char> class formatbuf : public std::basic_streambuf<Char> {
return ch;
}
std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE {
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> {
template <typename Char>
struct test_stream : std::basic_ostream<Char> {
private:
struct null;
// 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);
void operator<<(null);
};
// 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<< (e.g. not a member of std::ostream).
template <typename T, typename Char>
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 decltype(
internal::declval<test_stream<Char>&>()
<< internal::declval<U>(), std::true_type()) test(int);
template <typename> static std::false_type test(...);
template <typename>
static std::false_type test(...);
using result = decltype(test<T>(0));
typedef decltype(test<T>(0)) result;
public:
static const bool value = result::value;
@ -75,54 +73,65 @@ template <typename T, typename Char> class is_streamable {
// Write the content of buf to os.
template <typename Char>
void write(std::basic_ostream<Char>& os, buffer<Char>& buf) {
const Char* buf_data = buf.data();
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
unsigned_streamsize size = buf.size();
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
void write(std::basic_ostream<Char> &os, basic_buffer<Char> &buf) {
const Char *data = buf.data();
typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize;
UnsignedStreamSize size = buf.size();
UnsignedStreamSize max_size =
internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
do {
unsigned_streamsize n = size <= max_size ? size : max_size;
os.write(buf_data, static_cast<std::streamsize>(n));
buf_data += n;
UnsignedStreamSize n = size <= max_size ? size : max_size;
os.write(data, static_cast<std::streamsize>(n));
data += n;
size -= n;
} while (size != 0);
}
template <typename Char, typename T>
void format_value(buffer<Char>& buf, const T& value,
locale_ref loc = locale_ref()) {
formatbuf<Char> format_buf(buf);
void format_value(basic_buffer<Char> &buffer, const T &value) {
internal::formatbuf<Char> format_buf(buffer);
std::basic_ostream<Char> output(&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);
output << value;
buf.resize(buf.size());
buffer.resize(buffer.size());
}
} // namespace internal
// Disable conversion to int if T has an overloaded operator<< which is a free
// function (not a member of std::ostream).
template <typename T, typename Char>
struct convert_to_int<T, Char, void> {
static const bool value =
convert_to_int<T, Char, int>::value &&
!internal::is_streamable<T, Char>::value;
};
// 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>>
struct formatter<T, Char,
typename std::enable_if<
internal::is_streamable<T, Char>::value &&
!internal::format_type<
typename buffer_context<Char>::type, T>::value>::type>
: formatter<basic_string_view<Char>, Char> {
template <typename Context>
auto format(const T& value, Context& ctx) -> decltype(ctx.out()) {
auto format(const T &value, Context &ctx) -> decltype(ctx.out()) {
basic_memory_buffer<Char> buffer;
format_value(buffer, value, ctx.locale());
internal::format_value(buffer, value);
basic_string_view<Char> str(buffer.data(), buffer.size());
return formatter<basic_string_view<Char>, Char>::format(str, ctx);
}
};
} // namespace internal
template <typename Char>
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
inline void vprint(std::basic_ostream<Char> &os,
basic_string_view<Char> format_str,
basic_format_args<typename buffer_context<Char>::type> args) {
basic_memory_buffer<Char> buffer;
internal::vformat_to(buffer, format_str, args);
internal::write(os, buffer);
}
/**
\rst
Prints formatted data to the stream *os*.
@ -132,11 +141,12 @@ 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...));
template <typename S, typename... Args>
inline typename std::enable_if<internal::is_string<S>::value>::type
print(std::basic_ostream<FMT_CHAR(S)> &os, const S &format_str,
const Args & ... args) {
internal::checked_args<S, Args...> ca(format_str, args...);
vprint(os, to_string_view(format_str), *ca);
}
FMT_END_NAMESPACE

View File

@ -1,2 +1,324 @@
#include "os.h"
#warning "fmt/posix.h is deprecated; use fmt/os.h instead"
// A C++ interface to POSIX functions.
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_POSIX_H_
#define FMT_POSIX_H_
#if defined(__MINGW32__) || defined(__CYGWIN__)
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
# undef __STRICT_ANSI__
#endif
#include <errno.h>
#include <fcntl.h> // for O_RDONLY
#include <locale.h> // for locale_t
#include <stdio.h>
#include <stdlib.h> // for strtod_l
#include <cstddef>
#if defined __APPLE__ || defined(__FreeBSD__)
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
#endif
#include "format.h"
#ifndef FMT_POSIX
# if defined(_WIN32) && !defined(__MINGW32__)
// Fix warnings about deprecated symbols.
# define FMT_POSIX(call) _##call
# else
# define FMT_POSIX(call) call
# endif
#endif
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
#ifdef FMT_SYSTEM
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
#else
# define FMT_SYSTEM(call) call
# ifdef _WIN32
// Fix warnings about deprecated symbols.
# define FMT_POSIX_CALL(call) ::_##call
# else
# define FMT_POSIX_CALL(call) ::call
# endif
#endif
// Retries the expression while it evaluates to error_result and errno
// equals to EINTR.
#ifndef _WIN32
# define FMT_RETRY_VAL(result, expression, error_result) \
do { \
result = (expression); \
} while (result == error_result && errno == EINTR)
#else
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
#endif
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
FMT_BEGIN_NAMESPACE
/**
\rst
A reference to a null-terminated string. It can be constructed from a C
string or ``std::string``.
You can use one of the following typedefs for common character types:
+---------------+-----------------------------+
| Type | Definition |
+===============+=============================+
| cstring_view | basic_cstring_view<char> |
+---------------+-----------------------------+
| wcstring_view | basic_cstring_view<wchar_t> |
+---------------+-----------------------------+
This class is most useful as a parameter type to allow passing
different types of strings to a function, for example::
template <typename... Args>
std::string format(cstring_view format_str, const Args & ... args);
format("{}", 42);
format(std::string("{}"), 42);
\endrst
*/
template <typename Char>
class basic_cstring_view {
private:
const Char *data_;
public:
/** Constructs a string reference object from a C string. */
basic_cstring_view(const Char *s) : data_(s) {}
/**
\rst
Constructs a string reference from an ``std::string`` object.
\endrst
*/
basic_cstring_view(const std::basic_string<Char> &s) : data_(s.c_str()) {}
/** Returns the pointer to a C string. */
const Char *c_str() const { return data_; }
};
typedef basic_cstring_view<char> cstring_view;
typedef basic_cstring_view<wchar_t> wcstring_view;
// An error code.
class error_code {
private:
int value_;
public:
explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}
int get() const FMT_NOEXCEPT { return value_; }
};
// A buffered file.
class buffered_file {
private:
FILE *file_;
friend class file;
explicit buffered_file(FILE *f) : file_(f) {}
public:
// Constructs a buffered_file object which doesn't represent any file.
buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {}
// Destroys the object closing the file it represents if any.
FMT_API ~buffered_file() FMT_NOEXCEPT;
private:
buffered_file(const buffered_file &) = delete;
void operator=(const buffered_file &) = delete;
public:
buffered_file(buffered_file &&other) FMT_NOEXCEPT : file_(other.file_) {
other.file_ = FMT_NULL;
}
buffered_file& operator=(buffered_file &&other) {
close();
file_ = other.file_;
other.file_ = FMT_NULL;
return *this;
}
// Opens a file.
FMT_API buffered_file(cstring_view filename, cstring_view mode);
// Closes the file.
FMT_API void close();
// Returns the pointer to a FILE object representing this file.
FILE *get() const FMT_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;
void vprint(string_view format_str, format_args args) {
fmt::vprint(file_, format_str, args);
}
template <typename... Args>
inline void print(string_view format_str, const Args & ... args) {
vprint(format_str, make_format_args(args...));
}
};
// A file. Closed file is represented by a file object with descriptor -1.
// Methods that are not declared with FMT_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 {
private:
int fd_; // File descriptor.
// Constructs a file object with a given descriptor.
explicit file(int fd) : fd_(fd) {}
public:
// Possible values for the oflag argument to the constructor.
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.
};
// Constructs a file object which doesn't represent any file.
file() FMT_NOEXCEPT : fd_(-1) {}
// Opens a file and constructs a file object representing this file.
FMT_API file(cstring_view path, int oflag);
private:
file(const file &) = delete;
void operator=(const file &) = delete;
public:
file(file &&other) FMT_NOEXCEPT : fd_(other.fd_) {
other.fd_ = -1;
}
file& operator=(file &&other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
// Destroys the object closing the file it represents if any.
FMT_API ~file() FMT_NOEXCEPT;
// Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT { return fd_; }
// Closes the file.
FMT_API void close();
// Returns the file size. The size has signed type for consistency with
// stat::st_size.
FMT_API 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);
// 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);
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
FMT_API 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);
// 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;
// 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);
// 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);
};
// Returns the memory page size.
long getpagesize();
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
!defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__) && \
!defined(__NEWLIB_H__)
# define FMT_LOCALE
#endif
#ifdef FMT_LOCALE
// A "C" numeric locale.
class Locale {
private:
# ifdef _MSC_VER
typedef _locale_t locale_t;
enum { LC_NUMERIC_MASK = LC_NUMERIC };
static locale_t newlocale(int category_mask, const char *locale, locale_t) {
return _create_locale(category_mask, locale);
}
static void freelocale(locale_t locale) {
_free_locale(locale);
}
static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {
return _strtod_l(nptr, endptr, locale);
}
# endif
locale_t locale_;
Locale(const Locale &) = delete;
void operator=(const Locale &) = delete;
public:
typedef locale_t Type;
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) {
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 = FMT_NULL;
double result = strtod_l(str, &end, locale_);
str = end;
return result;
}
};
#endif // FMT_LOCALE
FMT_END_NAMESPACE
#endif // FMT_POSIX_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// Formatting library for C++ - experimental range support
// Formatting library for C++ - the core API
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
@ -12,21 +12,20 @@
#ifndef FMT_RANGES_H_
#define FMT_RANGES_H_
#include <initializer_list>
#include <type_traits>
#include "format.h"
#include <type_traits>
// output only up to N items from the range.
#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT
# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256
# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256
#endif
FMT_BEGIN_NAMESPACE
template <typename Char> struct formatting_base {
template <typename Char>
struct formatting_base {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
};
@ -34,8 +33,7 @@ template <typename Char> struct formatting_base {
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.
FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range.
Char prefix;
Char delimiter;
Char postfix;
@ -57,75 +55,87 @@ struct formatting_tuple : formatting_base<Char> {
namespace internal {
template <typename RangeT, typename OutputIterator>
OutputIterator copy(const RangeT& range, OutputIterator out) {
void copy(const RangeT &range, OutputIterator out) {
for (auto it = range.begin(), end = range.end(); it != end; ++it)
*out++ = *it;
return out;
}
template <typename OutputIterator>
OutputIterator copy(const char* str, OutputIterator out) {
while (*str) *out++ = *str++;
return out;
void copy(const char *str, OutputIterator out) {
const char *p_curr = str;
while (*p_curr) {
*out++ = *p_curr++;
}
}
template <typename OutputIterator>
OutputIterator copy(char ch, OutputIterator out) {
void copy(char ch, OutputIterator out) {
*out++ = ch;
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 T>
class is_like_std_string {
template <typename U>
static auto check(U* p)
-> decltype((void)p->find('a'), p->length(), (void)p->data(), int());
template <typename> static void check(...);
static auto check(U *p) ->
decltype(p->find('a'), p->length(), 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;
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
};
template <typename Char>
struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {};
template <typename... Ts> struct conditional_helper {};
template <typename... Ts>
struct conditional_helper {};
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
template <typename T, typename _ = void>
struct is_range_ : std::false_type {};
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
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 is_range_<T, typename std::conditional<
false,
conditional_helper<decltype(internal::declval<T>().begin()),
decltype(internal::declval<T>().end())>,
void>::type> : std::true_type {};
#endif
/// tuple_size and tuple_element check.
template <typename T> class is_tuple_like_ {
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(...);
static auto check(U *p) ->
decltype(std::tuple_size<U>::value,
internal::declval<typename std::tuple_element<0, U>::type>(), int());
template <typename>
static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
};
// Check for integer_sequence
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 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 index_sequence = std::index_sequence<N...>;
template <std::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;
template <typename T, T... N>
struct integer_sequence {
typedef T value_type;
static FMT_CONSTEXPR std::size_t size() { return sizeof...(N); }
static FMT_CONSTEXPR std::size_t size() {
return sizeof...(N);
}
};
template <std::size_t... N>
@ -141,7 +151,7 @@ using make_index_sequence = make_integer_sequence<std::size_t, N>;
#endif
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) FMT_NOEXCEPT {
using std::get;
// using free function get<I>(T) now.
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
@ -149,25 +159,26 @@ void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT {
}
template <class T>
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes(
T const&) {
return {};
}
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value>
get_indexes(T const &) { return {}; }
template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
template <class Tuple, class F>
void for_each(Tuple &&tup, F &&f) {
const auto indexes = get_indexes(tup);
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&) {
template<typename Arg>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
typename std::enable_if<
!is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
return add_space ? " {}" : "{}";
}
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&) {
template<typename Arg>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
typename std::enable_if<
is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
return add_space ? " \"{}\"" : "\"{}\"";
}
@ -175,58 +186,61 @@ 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"\"{}\"";
return add_space ? L" \"{}\"" : L"\"{}\"";
}
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
return add_space ? " '{}'" : "'{}'";
return add_space ? " '{}'" : "'{}'";
}
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
return add_space ? L" '{}'" : L"'{}'";
return add_space ? L" '{}'" : L"'{}'";
}
} // namespace internal
template <typename T> struct is_tuple_like {
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;
internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value;
};
template <typename TupleT, typename Char>
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
private:
struct formatter<TupleT, Char,
typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> {
private:
// C++11 generic lambda for format()
template <typename FormatContext> struct format_each {
template <typename T> void operator()(const T& v) {
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);
internal::copy(formatting.delimiter, out);
}
out = format_to(out,
internal::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), v),
v);
format_to(out,
internal::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), v),
v);
++i;
}
formatting_tuple<Char>& formatting;
std::size_t& i;
typename std::add_lvalue_reference<decltype(
std::declval<FormatContext>().out())>::type out;
typename std::add_lvalue_reference<decltype(std::declval<FormatContext>().out())>::type out;
};
public:
public:
formatting_tuple<Char> formatting;
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
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 format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) {
auto out = ctx.out();
std::size_t i = 0;
internal::copy(formatting.prefix, out);
@ -241,147 +255,54 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
}
};
template <typename T, typename Char> struct is_range {
template <typename T>
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;
internal::is_range_<T>::value && !internal::is_like_std_string<T>::value;
};
template <typename RangeT, typename Char>
struct formatter<RangeT, Char,
enable_if_t<fmt::is_range<RangeT, Char>::value>> {
typename std::enable_if<fmt::is_range<RangeT>::value>::type> {
formatting_range<Char> formatting;
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
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());
typename FormatContext::iterator format(
const RangeT &values, FormatContext &ctx) {
auto out = ctx.out();
internal::copy(formatting.prefix, 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);
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
internal::copy(formatting.delimiter, out);
}
out = format_to(out,
internal::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), *it),
*it);
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>");
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>
typename FormatContext::iterator format(
const tuple_arg_join<Char, T...>& value, FormatContext& ctx) {
return format(value, ctx, internal::make_index_sequence<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)...);
}
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.
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
internal::copy(formatting.postfix, out);
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) {
out = std::copy(value.sep.begin(), value.sep.end(), out);
ctx.advance_to(out);
return format_args(value, ctx, args...);
}
return out;
}
};
/**
\rst
Returns an object that formats `tuple` with elements separated by `sep`.
**Example**::
std::tuple<int, char> t = {1, 'a'};
fmt::print("{}", fmt::join(t, ", "));
// Output: "1, a"
\endrst
*/
template <typename... T>
FMT_CONSTEXPR tuple_arg_join<char, T...> join(const std::tuple<T...>& tuple,
string_view sep) {
return {tuple, sep};
}
template <typename... T>
FMT_CONSTEXPR tuple_arg_join<wchar_t, T...> join(const std::tuple<T...>& tuple,
wstring_view sep) {
return {tuple, sep};
}
/**
\rst
Returns an object that formats `initializer_list` with elements separated by
`sep`.
**Example**::
fmt::print("{}", fmt::join({1, 2, 3}, ", "));
// Output: "1, 2, 3"
\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) {
return join(std::begin(list), std::end(list), sep);
}
FMT_END_NAMESPACE
#endif // FMT_RANGES_H_
#endif // FMT_RANGES_H_

160
externals/fmt/include/fmt/time.h vendored Normal file
View File

@ -0,0 +1,160 @@
// Formatting library for C++ - time formatting
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_TIME_H_
#define FMT_TIME_H_
#include "format.h"
#include <ctime>
#include <locale>
FMT_BEGIN_NAMESPACE
// Prevents expansion of a preceding token as a function-style macro.
// Usage: f FMT_NOMACRO()
#define FMT_NOMACRO
namespace internal{
inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
inline null<> localtime_s(...) { return null<>(); }
inline null<> gmtime_r(...) { return null<>(); }
inline null<> gmtime_s(...) { return null<>(); }
} // namespace internal
// Thread-safe replacement for std::localtime
inline std::tm localtime(std::time_t time) {
struct dispatcher {
std::time_t time_;
std::tm tm_;
dispatcher(std::time_t t): time_(t) {}
bool run() {
using namespace fmt::internal;
return handle(localtime_r(&time_, &tm_));
}
bool handle(std::tm *tm) { return tm != FMT_NULL; }
bool handle(internal::null<>) {
using namespace fmt::internal;
return fallback(localtime_s(&tm_, &time_));
}
bool fallback(int res) { return res == 0; }
#if !FMT_MSC_VER
bool fallback(internal::null<>) {
using namespace fmt::internal;
std::tm *tm = std::localtime(&time_);
if (tm) tm_ = *tm;
return tm != FMT_NULL;
}
#endif
};
dispatcher lt(time);
// Too big time values may be unsupported.
if (!lt.run())
FMT_THROW(format_error("time_t value out of range"));
return lt.tm_;
}
// Thread-safe replacement for std::gmtime
inline std::tm gmtime(std::time_t time) {
struct dispatcher {
std::time_t time_;
std::tm tm_;
dispatcher(std::time_t t): time_(t) {}
bool run() {
using namespace fmt::internal;
return handle(gmtime_r(&time_, &tm_));
}
bool handle(std::tm *tm) { return tm != FMT_NULL; }
bool handle(internal::null<>) {
using namespace fmt::internal;
return fallback(gmtime_s(&tm_, &time_));
}
bool fallback(int res) { return res == 0; }
#if !FMT_MSC_VER
bool fallback(internal::null<>) {
std::tm *tm = std::gmtime(&time_);
if (tm) tm_ = *tm;
return tm != FMT_NULL;
}
#endif
};
dispatcher gt(time);
// Too big time values may be unsupported.
if (!gt.run())
FMT_THROW(format_error("time_t value out of range"));
return gt.tm_;
}
namespace internal {
inline std::size_t strftime(char *str, std::size_t count, const char *format,
const std::tm *time) {
return std::strftime(str, count, format, time);
}
inline std::size_t strftime(wchar_t *str, std::size_t count,
const wchar_t *format, const std::tm *time) {
return std::wcsftime(str, count, format, time);
}
}
template <typename Char>
struct formatter<std::tm, Char> {
template <typename ParseContext>
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
auto it = ctx.begin();
if (it != ctx.end() && *it == ':')
++it;
auto end = it;
while (end != ctx.end() && *end != '}')
++end;
tm_format.reserve(internal::to_unsigned(end - it + 1));
tm_format.append(it, end);
tm_format.push_back('\0');
return end;
}
template <typename FormatContext>
auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {
basic_memory_buffer<Char> buf;
std::size_t start = buf.size();
for (;;) {
std::size_t size = buf.capacity() - start;
std::size_t count =
internal::strftime(&buf[start], size, &tm_format[0], &tm);
if (count != 0) {
buf.resize(start + count);
break;
}
if (size >= tm_format.size() * 256) {
// If the buffer is 256 times larger than the format string, assume
// that `strftime` gives an empty result. There doesn't seem to be a
// better way to distinguish the two cases:
// https://github.com/fmtlib/fmt/issues/367
break;
}
const std::size_t MIN_GROWTH = 10;
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
}
return std::copy(buf.begin(), buf.end(), ctx.out());
}
basic_memory_buffer<Char> tm_format;
};
FMT_END_NAMESPACE
#endif // FMT_TIME_H_

View File

@ -8,168 +8,51 @@
#include "fmt/format-inl.h"
FMT_BEGIN_NAMESPACE
namespace internal {
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;
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
template FMT_API internal::locale_ref::locale_ref(const std::locale& loc);
template struct internal::basic_data<void>;
template FMT_API internal::locale_ref::locale_ref(const std::locale &loc);
template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
#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 void internal::buffer<char>::append(const char*, const char*);
template FMT_API void internal::basic_buffer<char>::append(const char *, const char *);
template FMT_API void internal::arg_map<format_context>::init(
const basic_format_args<format_context>& args);
const basic_format_args<format_context> &args);
template FMT_API int internal::char_traits<char>::format_float(
char *, std::size_t, const char *, int, double);
template FMT_API int internal::char_traits<char>::format_float(
char *, std::size_t, const char *, int, long double);
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>);
internal::buffer &, 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>&);
template FMT_API void internal::sprintf_format(
double, internal::buffer &, core_format_specs);
template FMT_API void internal::sprintf_format(
long double, internal::buffer &, core_format_specs);
// 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 void internal::buffer<wchar_t>::append(const wchar_t*,
const wchar_t*);
template FMT_API void internal::basic_buffer<wchar_t>::append(
const wchar_t *, const wchar_t *);
template FMT_API void internal::arg_map<wformat_context>::init(
const basic_format_args<wformat_context> &);
template FMT_API int internal::char_traits<wchar_t>::format_float(
wchar_t *, std::size_t, const wchar_t *, int, double);
template FMT_API int internal::char_traits<wchar_t>::format_float(
wchar_t *, std::size_t, const wchar_t *, int, long double);
template FMT_API std::wstring internal::vformat<wchar_t>(
wstring_view, basic_format_args<wformat_context>);

View File

@ -1,316 +0,0 @@
// Formatting library for C++ - optional OS-specific functionality
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
// Disable bogus MSVC warnings.
#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "fmt/os.h"
#include <climits>
#if FMT_USE_FCNTL
# include <sys/stat.h>
# include <sys/types.h>
# ifndef _WIN32
# include <unistd.h>
# else
# ifndef WIN32_LEAN_AND_MEAN
# 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
# endif
# endif // _WIN32
#endif // FMT_USE_FCNTL
#ifdef _WIN32
# include <windows.h>
#endif
#ifdef fileno
# undef fileno
#endif
namespace {
#ifdef _WIN32
// Return type of read and write functions.
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
// Return type of read and write functions.
using RWResult = ssize_t;
inline std::size_t convert_rwcount(std::size_t count) { return count; }
#endif
} // namespace
FMT_BEGIN_NAMESPACE
#ifdef _WIN32
internal::utf16_to_utf8::utf16_to_utf8(wstring_view 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) {
if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER;
int s_size = static_cast<int>(s.size());
if (s_size == 0) {
// WideCharToMultiByte does not support zero length, handle separately.
buffer_.resize(1);
buffer_[0] = 0;
return 0;
}
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, nullptr, 0,
nullptr, nullptr);
if (length == 0) return GetLastError();
buffer_.resize(length + 1);
length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0],
length, nullptr, nullptr);
if (length == 0) return GetLastError();
buffer_[length] = 0;
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));
}
void internal::format_windows_error(internal::buffer<char>& out, int error_code,
string_view message) FMT_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;
}
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);
}
#endif // _WIN32
buffered_file::~buffered_file() FMT_NOEXCEPT {
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
report_system_error(errno, "cannot close file");
}
buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())),
nullptr);
if (!file_)
FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str()));
}
void buffered_file::close() {
if (!file_) return;
int result = FMT_SYSTEM(fclose(file_));
file_ = nullptr;
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_));
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;
# if defined(_WIN32) && !defined(__MINGW32__)
fd_ = -1;
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
# else
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
# endif
if (fd_ == -1)
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
}
file::~file() FMT_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)
report_system_error(errno, "cannot close file");
}
void file::close() {
if (fd_ == -1) return;
// Don't retry close in case of EINTR!
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
int result = FMT_POSIX_CALL(close(fd_));
fd_ = -1;
if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
}
long long file::size() const {
# ifdef _WIN32
// Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
// is less than 0x0500 as is the case with some default MinGW builds.
// Both functions support large file sizes.
DWORD size_upper = 0;
HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));
DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper));
if (size_lower == INVALID_FILE_SIZE) {
DWORD error = GetLastError();
if (error != NO_ERROR)
FMT_THROW(windows_error(GetLastError(), "cannot get file size"));
}
unsigned long long long_size = size_upper;
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
# else
using Stat = struct stat;
Stat file_stat = Stat();
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
FMT_THROW(system_error(errno, "cannot get file attributes"));
static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
"return type of file::size is not large enough");
return file_stat.st_size;
# endif
}
std::size_t file::read(void* buffer, std::size_t count) {
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);
}
std::size_t file::write(const void* buffer, std::size_t count) {
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);
}
file file::dup(int fd) {
// Don't retry as dup doesn't return EINTR.
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
int new_fd = FMT_POSIX_CALL(dup(fd));
if (new_fd == -1)
FMT_THROW(system_error(errno, "cannot duplicate file descriptor {}", fd));
return file(new_fd);
}
void file::dup2(int fd) {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) {
FMT_THROW(system_error(errno, "cannot duplicate file descriptor {} to {}",
fd_, fd));
}
}
void file::dup2(int fd, error_code& ec) FMT_NOEXCEPT {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) ec = error_code(errno);
}
void file::pipe(file& read_end, file& write_end) {
// Close the descriptors first to make sure that assignments don't throw
// and there are no leaks.
read_end.close();
write_end.close();
int fds[2] = {};
# ifdef _WIN32
// Make the default pipe capacity same as on Linux 2.6.11+.
enum { DEFAULT_CAPACITY = 65536 };
int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
# else
// Don't retry as the pipe function doesn't return EINTR.
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
int result = FMT_POSIX_CALL(pipe(fds));
# endif
if (result != 0) FMT_THROW(system_error(errno, "cannot create pipe"));
// The following assignments don't throw because read_fd and write_fd
// are closed.
read_end = file(fds[0]);
write_end = file(fds[1]);
}
buffered_file file::fdopen(const char* mode) {
// Don't retry as fdopen doesn't return EINTR.
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
if (!f)
FMT_THROW(
system_error(errno, "cannot associate stream with file descriptor"));
buffered_file bf(f);
fd_ = -1;
return bf;
}
long getpagesize() {
# ifdef _WIN32
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwPageSize;
# else
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
if (size < 0) FMT_THROW(system_error(errno, "cannot get memory page size"));
return size;
# endif
}
#endif // FMT_USE_FCNTL
FMT_END_NAMESPACE

244
externals/fmt/src/posix.cc vendored Normal file
View File

@ -0,0 +1,244 @@
// A C++ interface to POSIX functions.
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
// Disable bogus MSVC warnings.
#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "fmt/posix.h"
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
# include <unistd.h>
#else
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
# include <io.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
# endif
#endif // _WIN32
#ifdef fileno
# undef fileno
#endif
namespace {
#ifdef _WIN32
// Return type of read and write functions.
typedef int RWResult;
// 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
// Return type of read and write functions.
typedef ssize_t RWResult;
inline std::size_t convert_rwcount(std::size_t count) { return count; }
#endif
}
FMT_BEGIN_NAMESPACE
buffered_file::~buffered_file() FMT_NOEXCEPT {
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
report_system_error(errno, "cannot close file");
}
buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
FMT_RETRY_VAL(file_,
FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), FMT_NULL);
if (!file_)
FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str()));
}
void buffered_file::close() {
if (!file_)
return;
int result = FMT_SYSTEM(fclose(file_));
file_ = FMT_NULL;
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_));
if (fd == -1)
FMT_THROW(system_error(errno, "cannot get file descriptor"));
return fd;
}
file::file(cstring_view path, int oflag) {
int mode = S_IRUSR | S_IWUSR;
#if defined(_WIN32) && !defined(__MINGW32__)
fd_ = -1;
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
#else
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
#endif
if (fd_ == -1)
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
}
file::~file() FMT_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)
report_system_error(errno, "cannot close file");
}
void file::close() {
if (fd_ == -1)
return;
// Don't retry close in case of EINTR!
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
int result = FMT_POSIX_CALL(close(fd_));
fd_ = -1;
if (result != 0)
FMT_THROW(system_error(errno, "cannot close file"));
}
long long file::size() const {
#ifdef _WIN32
// Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
// is less than 0x0500 as is the case with some default MinGW builds.
// Both functions support large file sizes.
DWORD size_upper = 0;
HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));
DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper));
if (size_lower == INVALID_FILE_SIZE) {
DWORD error = GetLastError();
if (error != NO_ERROR)
FMT_THROW(windows_error(GetLastError(), "cannot get file size"));
}
unsigned long long long_size = size_upper;
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
#else
typedef struct stat Stat;
Stat file_stat = Stat();
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
FMT_THROW(system_error(errno, "cannot get file attributes"));
static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
"return type of file::size is not large enough");
return file_stat.st_size;
#endif
}
std::size_t file::read(void *buffer, std::size_t count) {
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);
}
std::size_t file::write(const void *buffer, std::size_t count) {
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);
}
file file::dup(int fd) {
// Don't retry as dup doesn't return EINTR.
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
int new_fd = FMT_POSIX_CALL(dup(fd));
if (new_fd == -1)
FMT_THROW(system_error(errno, "cannot duplicate file descriptor {}", fd));
return file(new_fd);
}
void file::dup2(int fd) {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) {
FMT_THROW(system_error(errno,
"cannot duplicate file descriptor {} to {}", fd_, fd));
}
}
void file::dup2(int fd, error_code &ec) FMT_NOEXCEPT {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1)
ec = error_code(errno);
}
void file::pipe(file &read_end, file &write_end) {
// Close the descriptors first to make sure that assignments don't throw
// and there are no leaks.
read_end.close();
write_end.close();
int fds[2] = {};
#ifdef _WIN32
// Make the default pipe capacity same as on Linux 2.6.11+.
enum { DEFAULT_CAPACITY = 65536 };
int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
#else
// Don't retry as the pipe function doesn't return EINTR.
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
int result = FMT_POSIX_CALL(pipe(fds));
#endif
if (result != 0)
FMT_THROW(system_error(errno, "cannot create pipe"));
// The following assignments don't throw because read_fd and write_fd
// are closed.
read_end = file(fds[0]);
write_end = file(fds[1]);
}
buffered_file file::fdopen(const char *mode) {
// Don't retry as fdopen doesn't return EINTR.
FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode));
if (!f)
FMT_THROW(system_error(errno,
"cannot associate stream with file descriptor"));
buffered_file bf(f);
fd_ = -1;
return bf;
}
long getpagesize() {
#ifdef _WIN32
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwPageSize;
#else
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
if (size < 0)
FMT_THROW(system_error(errno, "cannot get memory page size"));
return size;
#endif
}
FMT_END_NAMESPACE

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +0,0 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# A vagrant config for testing against gcc-4.8.
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/xenial64"
config.vm.provider "virtualbox" do |vb|
vb.memory = "4096"
end
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y g++ make wget git
wget -q https://github.com/Kitware/CMake/releases/download/v3.14.4/cmake-3.14.4-Linux-x86_64.tar.gz
tar xzf cmake-3.14.4-Linux-x86_64.tar.gz
ln -s `pwd`/cmake-3.14.4-Linux-x86_64/bin/cmake /usr/local/bin
SHELL
end

View File

@ -23,17 +23,14 @@ else:
# Add MSBuild 14.0 to PATH as described in
# http://help.appveyor.com/discussions/problems/2229-v140-not-found-on-vs2105rc.
os.environ['PATH'] = r'C:\Program Files (x86)\MSBuild\15.0\Bin;' + path
if image == 'Visual Studio 2019':
generator = 'Visual Studio 16 2019'
if platform == 'x64':
cmake_command.extend(['-A', 'x64'])
else:
if image == 'Visual Studio 2015':
generator = 'Visual Studio 14 2015'
elif image == 'Visual Studio 2017':
generator = 'Visual Studio 15 2017'
if platform == 'x64':
generator += ' Win64'
if image == 'Visual Studio 2013':
generator = 'Visual Studio 12 2013'
elif image == 'Visual Studio 2015':
generator = 'Visual Studio 14 2015'
elif image == 'Visual Studio 2017':
generator = 'Visual Studio 15 2017'
if platform == 'x64':
generator += ' Win64'
cmake_command.append('-G' + generator)
build_command = ['cmake', '--build', '.', '--config', config, '--', '/m:4']
test_command = ['ctest', '-C', config]

View File

@ -4,27 +4,20 @@ configuration:
clone_depth: 1
image:
- Visual Studio 2015
- Visual Studio 2019
- Visual Studio 2017
platform:
- Win32
- x64
image:
- Visual Studio 2013
- Visual Studio 2015
- Visual Studio 2017
environment:
CTEST_OUTPUT_ON_FAILURE: 1
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

View File

@ -9,12 +9,10 @@ buildscript {
//
// https://developer.android.com/studio/releases/gradle-plugin
//
// 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 3.1.3 here is the version of [Android Gradle Plugin]
// Accroding to URL above you will need Gradle 4.4 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:3.1.3'
}
}
repositories {
@ -45,8 +43,8 @@ android {
defaultConfig {
minSdkVersion 21 // Android 5.0+
targetSdkVersion 25 // Follow Compile SDK
versionCode 21 // Follow release count
versionName "5.3.0" // Follow Official version
versionCode 20 // Follow release count
versionName "5.2.1" // Follow Official version
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {

View File

@ -48,6 +48,43 @@ endif ()
set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG})
# Check if variadic templates are working and not affected by GCC bug 39653:
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39653
check_cxx_source_compiles("
template <class T, class ...Types>
struct S { typedef typename S<Types...>::type type; };
int main() {}" SUPPORTS_VARIADIC_TEMPLATES)
if (NOT SUPPORTS_VARIADIC_TEMPLATES)
set (SUPPORTS_VARIADIC_TEMPLATES OFF)
endif ()
# Check if initializer lists are supported.
check_cxx_source_compiles("
#include <initializer_list>
int main() {}" SUPPORTS_INITIALIZER_LIST)
if (NOT SUPPORTS_INITIALIZER_LIST)
set (SUPPORTS_INITIALIZER_LIST OFF)
endif ()
# Check if enum bases are available
check_cxx_source_compiles("
enum C : char {A};
int main() {}"
SUPPORTS_ENUM_BASE)
if (NOT SUPPORTS_ENUM_BASE)
set (SUPPORTS_ENUM_BASE OFF)
endif ()
# Check if type traits are available
check_cxx_source_compiles("
#include <type_traits>
class C { void operator=(const C&); };
int main() { static_assert(!std::is_copy_assignable<C>::value, \"\"); }"
SUPPORTS_TYPE_TRAITS)
if (NOT SUPPORTS_TYPE_TRAITS)
set (SUPPORTS_TYPE_TRAITS OFF)
endif ()
# Check if user-defined literals are available
check_cxx_source_compiles("
void operator\"\" _udl(long double);
@ -57,14 +94,4 @@ 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,11 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
Name: fmt
Description: A modern formatting library
Version: @FMT_VERSION@
Libs: -L${libdir} -l@FMT_LIB_NAME@
Libs: -L${libdir} -lfmt
Cflags: -I${includedir}

View File

@ -0,0 +1,11 @@
@echo on
rem This scripts configures build environment and runs CMake.
rem Use it instead of running CMake directly when building with
rem the Microsoft SDK toolchain rather than Visual Studio.
rem It is used in the same way as cmake, for example:
rem
rem run-cmake -G "Visual Studio 10 Win64" .
for /F "delims=" %%i IN ('cmake "-DPRINT_PATH=1" -P %~dp0/FindSetEnv.cmake') DO set setenv=%%i
if NOT "%setenv%" == "" call "%setenv%"
cmake %*

View File

@ -5,9 +5,6 @@
Usage:
manage.py release [<branch>]
manage.py site
For the release command $FMT_TOKEN should contain a GitHub personal access token
obtained from https://github.com/settings/tokens.
"""
from __future__ import print_function
@ -137,7 +134,7 @@ def update_site(env):
if not os.path.exists(contents):
os.rename(os.path.join(target_doc_dir, 'index.rst'), contents)
# Fix issues in reference.rst/api.rst.
for filename in ['reference.rst', 'api.rst', 'index.rst']:
for filename in ['reference.rst', 'api.rst']:
pattern = re.compile('doxygenfunction.. (bin|oct|hexu|hex)$', re.M)
with rewrite(os.path.join(target_doc_dir, filename)) as b:
b.data = b.data.replace('std::ostream &', 'std::ostream&')
@ -145,8 +142,6 @@ def update_site(env):
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('aa long', 'a long')
# Fix a broken link in index.rst.
index = os.path.join(target_doc_dir, 'index.rst')
with rewrite(index) as b:

View File

@ -1,2 +1,2 @@
If you are not redirected automatically, follow the
`link to the fmt documentation <https://fmt.dev/latest/>`_.
`link to the fmt documentation <http://fmtlib.net/latest/>`_.

View File

@ -2,15 +2,15 @@
{% block extrahead %}
<meta charset="UTF-8">
<meta http-equiv="refresh" content="1;url=https://fmt.dev/latest/">
<meta http-equiv="refresh" content="1;url=http://fmtlib.net/latest/">
<script type="text/javascript">
window.location.href = "https://fmt.dev/latest/"
window.location.href = "http://fmtlib.net/latest/"
</script>
<title>Page Redirection</title>
{% endblock %}
{% block document %}
If you are not redirected automatically, follow the <a href='https://fmt.dev/latest/'>link to the fmt documentation</a>.
If you are not redirected automatically, follow the <a href='http://fmtlib.net/latest/'>link to the fmt documentation</a>.
{% endblock %}
{% block footer %}

View File

@ -83,25 +83,19 @@ 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.
# Configure 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)
cmake_flags, cwd=build_dir)
# Build the library.
check_call(['cmake', '--build','.'], cwd=build_dir)
# Build library.
check_call(['make', '-j4'], cwd=build_dir)
# Test the library.
# Test library.
env = os.environ.copy()
env['CTEST_OUTPUT_ON_FAILURE'] = '1'
if call(['make', 'test'], env=env, cwd=build_dir):
@ -109,7 +103,7 @@ if call(['make', 'test'], env=env, cwd=build_dir):
print(f.read())
sys.exit(-1)
# Install the library.
# Install library.
check_call(['make', 'install'], cwd=build_dir)
# Test installation.

View File

@ -17,18 +17,13 @@ else ()
target_compile_definitions(gmock PUBLIC GTEST_HAS_PTHREAD=0)
endif ()
target_compile_definitions(gmock PUBLIC GTEST_LANG_CXX11=0)
if (NOT SUPPORTS_VARIADIC_TEMPLATES OR NOT SUPPORTS_INITIALIZER_LIST)
target_compile_definitions(gmock PUBLIC GTEST_LANG_CXX11=0)
endif ()
# Workaround a bug in implementation of variadic templates in MSVC11.
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.
@ -38,13 +33,15 @@ endif ()
# Silence MSVC tr1 deprecation warning in gmock.
target_compile_definitions(gmock
PUBLIC _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1)
PUBLIC _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=0)
#------------------------------------------------------------------------------
# Build the actual library tests
set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc)
add_library(test-main STATIC ${TEST_MAIN_SRC})
target_compile_definitions(test-main PUBLIC
FMT_USE_FILE_DESCRIPTORS=$<BOOL:${HAVE_OPEN}>)
target_include_directories(test-main SYSTEM PUBLIC gtest gmock)
target_link_libraries(test-main gmock fmt)
@ -77,53 +74,44 @@ function(add_fmt_test name)
target_link_libraries(${name} test-main)
# Define if certain C++ features can be used.
target_compile_definitions(${name} PRIVATE
FMT_USE_TYPE_TRAITS=$<BOOL:${SUPPORTS_TYPE_TRAITS}>
FMT_USE_ENUM_BASE=$<BOOL:${SUPPORTS_ENUM_BASE}>)
if (FMT_PEDANTIC)
target_compile_options(${name} PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
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(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)
endif ()
add_fmt_test(locale-test)
add_fmt_test(ostream-test)
add_fmt_test(compile-test)
add_fmt_test(printf-test)
add_fmt_test(time-test)
add_fmt_test(custom-formatter-test)
add_fmt_test(ranges-test)
add_fmt_test(scan-test)
if (NOT MSVC_BUILD_STATIC)
if (HAVE_OPEN)
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_compile_definitions(posix-mock-test PRIVATE FMT_USE_FILE_DESCRIPTORS=1)
target_link_libraries(posix-mock-test gmock)
target_include_directories(posix-mock-test SYSTEM PUBLIC gtest gmock)
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)
add_fmt_test(posix-test)
endif ()
add_fmt_executable(header-only-test
@ -138,41 +126,41 @@ else ()
target_compile_definitions(header-only-test PRIVATE FMT_HEADER_ONLY=1)
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)
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_include_directories(noexception-test SYSTEM PUBLIC gtest gmock)
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)
# Test that the library compiles without windows.h.
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_library(no-windows-h-test ../src/format.cc)
target_include_directories(
noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_options(noexception-test PRIVATE -fno-exceptions)
no-windows-h-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_definitions(no-windows-h-test PRIVATE FMT_USE_WINDOWS_H=0)
if (FMT_PEDANTIC)
target_compile_options(noexception-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
target_compile_options(no-windows-h-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
target_include_directories(no-windows-h-test SYSTEM PUBLIC gtest gmock)
endif ()
# Test that the library compiles without locale.
add_library(nolocale-test ../src/format.cc)
target_include_directories(
nolocale-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_definitions(
nolocale-test PRIVATE FMT_STATIC_THOUSANDS_SEPARATOR=1)
add_test(compile-error-test ${CMAKE_CTEST_COMMAND}
add_test(compile-test ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMAKE_CURRENT_SOURCE_DIR}/compile-error-test"
"${CMAKE_CURRENT_BINARY_DIR}/compile-error-test"
"${CMAKE_CURRENT_SOURCE_DIR}/compile-test"
"${CMAKE_CURRENT_BINARY_DIR}/compile-test"
--build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
@ -214,23 +202,3 @@ if (FMT_PEDANTIC AND NOT WIN32)
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
"-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)
if (${CMAKE_VERSION} VERSION_LESS 3.15)
find_package(CUDA 9.0)
else ()
include(CheckLanguage)
check_language(CUDA)
if (CMAKE_CUDA_COMPILER)
enable_language(CUDA OPTIONAL)
set(CUDA_FOUND TRUE)
endif ()
endif ()
if (CUDA_FOUND)
add_subdirectory(cuda-test)
add_test(NAME cuda-test COMMAND fmt-in-cuda-test)
endif ()
endif ()

View File

@ -8,21 +8,15 @@
#include "fmt/core.h"
#include "gtest.h"
TEST(AssertTest, Fail) {
#if GTEST_HAS_DEATH_TEST
EXPECT_DEBUG_DEATH(FMT_ASSERT(false, "don't panic!"), "don't panic!");
# define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \
EXPECT_DEBUG_DEATH(statement, regex)
#else
fmt::print("warning: death tests are not supported\n");
# define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \
GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
#endif
}
bool test_condition = false;
TEST(AssertTest, DanglingElse) {
bool executed_else = false;
if (test_condition)
FMT_ASSERT(true, "");
else
executed_else = true;
EXPECT_TRUE(executed_else);
TEST(AssertTest, Fail) {
EXPECT_DEBUG_DEATH_IF_SUPPORTED(
FMT_ASSERT(false, "don't panic!"), "don't panic!");
}

View File

@ -5,10 +5,6 @@
//
// For the license information refer to format.h.
#ifdef WIN32
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "fmt/chrono.h"
#include "gtest-extra.h"
@ -38,71 +34,21 @@ std::tm make_second(int s) {
return time;
}
std::string format_tm(const std::tm& time, const char* spec,
const std::locale& loc) {
auto& facet = std::use_facet<std::time_put<char>>(loc);
std::string format_tm(const std::tm &time, const char *spec,
const std::locale &loc) {
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));
return os.str();
}
TEST(TimeTest, Format) {
std::tm 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));
}
TEST(TimeTest, GrowBuffer) {
std::string s = "{:";
for (int i = 0; i < 30; ++i) s += "%c";
s += "}\n";
std::time_t t = std::time(nullptr);
fmt::format(s, *std::localtime(&t));
}
TEST(TimeTest, FormatToEmptyContainer) {
std::string s;
auto time = std::tm();
time.tm_sec = 42;
fmt::format_to(std::back_inserter(s), "{:%S}", time);
EXPECT_EQ(s, "42");
}
TEST(TimeTest, EmptyResult) { EXPECT_EQ("", fmt::format("{}", std::tm())); }
static bool EqualTime(const std::tm& lhs, const std::tm& rhs) {
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 &&
lhs.tm_wday == rhs.tm_wday && lhs.tm_yday == rhs.tm_yday &&
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(TimeTest, GMTime) {
std::time_t t = std::time(nullptr);
std::tm tm = *std::gmtime(&t);
EXPECT_TRUE(EqualTime(tm, fmt::gmtime(t)));
}
#define EXPECT_TIME(spec, time, duration) \
{ \
std::locale loc("ja_JP.utf8"); \
EXPECT_EQ(format_tm(time, spec, loc), \
#define EXPECT_TIME(spec, time, duration) { \
std::locale loc("ja_JP.utf8"); \
EXPECT_EQ(format_tm(time, spec, loc), \
fmt::format(loc, "{:" spec "}", duration)); \
}
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
TEST(ChronoTest, FormatDefault) {
EXPECT_EQ("42s", fmt::format("{}", std::chrono::seconds(42)));
EXPECT_EQ("42as",
@ -137,54 +83,12 @@ TEST(ChronoTest, FormatDefault) {
fmt::format("{}", std::chrono::duration<int, std::exa>(42)));
EXPECT_EQ("42m", fmt::format("{}", std::chrono::minutes(42)));
EXPECT_EQ("42h", fmt::format("{}", std::chrono::hours(42)));
EXPECT_EQ(
"42[15]s",
fmt::format("{}", std::chrono::duration<int, std::ratio<15, 1>>(42)));
EXPECT_EQ(
"42[15/4]s",
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)));
EXPECT_EQ("42[15]s",
fmt::format("{}",
std::chrono::duration<int, std::ratio<15, 1>>(42)));
EXPECT_EQ("42[15/4]s",
fmt::format("{}",
std::chrono::duration<int, std::ratio<15, 4>>(42)));
}
TEST(ChronoTest, Align) {
@ -199,8 +103,7 @@ TEST(ChronoTest, Align) {
fmt::format("{:>12%H:%M:%S}", std::chrono::seconds(12345)));
EXPECT_EQ("~~03:25:45~~",
fmt::format("{:~^12%H:%M:%S}", std::chrono::seconds(12345)));
EXPECT_EQ("03:25:45 ",
fmt::format("{:{}%H:%M:%S}", std::chrono::seconds(12345), 12));
}
TEST(ChronoTest, FormatSpecs) {
@ -228,8 +131,6 @@ TEST(ChronoTest, FormatSpecs) {
fmt::format("{:%H:%M:%S}", std::chrono::seconds(12345)));
EXPECT_EQ("03:25", fmt::format("{:%R}", std::chrono::seconds(12345)));
EXPECT_EQ("03:25:45", fmt::format("{:%T}", std::chrono::seconds(12345)));
EXPECT_EQ("12345", fmt::format("{:%Q}", std::chrono::seconds(12345)));
EXPECT_EQ("s", fmt::format("{:%q}", std::chrono::seconds(12345)));
}
TEST(ChronoTest, InvalidSpecs) {
@ -250,6 +151,8 @@ TEST(ChronoTest, InvalidSpecs) {
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("{:%q}", sec), fmt::format_error,
"invalid format");
EXPECT_THROW_MSG(fmt::format("{:%Eq}", sec), fmt::format_error,
"invalid format");
EXPECT_THROW_MSG(fmt::format("{:%Oq}", sec), fmt::format_error,
@ -257,14 +160,13 @@ TEST(ChronoTest, InvalidSpecs) {
}
TEST(ChronoTest, Locale) {
const char* loc_name = "ja_JP.utf8";
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&) {
}
} catch (const std::runtime_error &) {}
if (!has_locale) {
fmt::print("{} locale is missing.\n", loc_name);
return;
@ -281,106 +183,3 @@ TEST(ChronoTest, Locale) {
EXPECT_TIME("%r", time, sec);
EXPECT_TIME("%p", time, sec);
}
typedef std::chrono::duration<double, std::milli> dms;
TEST(ChronoTest, FormatDefaultFP) {
typedef std::chrono::duration<float> fs;
EXPECT_EQ("1.234s", fmt::format("{}", fs(1.234)));
typedef std::chrono::duration<float, std::milli> fms;
EXPECT_EQ("1.234ms", fmt::format("{}", fms(1.234)));
typedef std::chrono::duration<double> ds;
EXPECT_EQ("1.234s", fmt::format("{}", ds(1.234)));
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");
EXPECT_EQ("1.2ms", fmt::format("{:.1}", dms(1.234)));
EXPECT_EQ("1.23ms", fmt::format("{:.{}}", dms(1.234), 2));
}
TEST(ChronoTest, FormatFullSpecs) {
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)));
}
TEST(ChronoTest, FormatSimpleQq) {
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;
EXPECT_EQ("1.234 ms", fmt::format("{:%Q %q}", fms(1.234)));
typedef std::chrono::duration<double> ds;
EXPECT_EQ("1.234 s", fmt::format("{:%Q %q}", ds(1.234)));
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");
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) {
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)));
}
TEST(ChronoTest, InvalidWidthId) {
EXPECT_THROW(fmt::format("{:{o}", std::chrono::seconds(0)),
fmt::format_error);
}
TEST(ChronoTest, InvalidColons) {
EXPECT_THROW(fmt::format("{0}=:{0::", std::chrono::seconds(0)),
fmt::format_error);
}
TEST(ChronoTest, NegativeDurations) {
EXPECT_EQ("-12345", fmt::format("{:%Q}", std::chrono::seconds(-12345)));
EXPECT_EQ("-03:25:45",
fmt::format("{:%H:%M:%S}", std::chrono::seconds(-12345)));
EXPECT_EQ("-00:01",
fmt::format("{:%M:%S}", std::chrono::duration<double>(-1)));
EXPECT_EQ("s", fmt::format("{:%q}", std::chrono::seconds(-12345)));
EXPECT_EQ("-00.127",
fmt::format("{:%S}",
std::chrono::duration<signed char, std::milli>{-127}));
auto min = std::numeric_limits<int>::min();
EXPECT_EQ(fmt::format("{}", min),
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));
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)),
"1as");
EXPECT_EQ(fmt::format("{:%R}", std::chrono::duration<char, std::mega>{2}),
"03:33");
EXPECT_EQ(fmt::format("{:%T}", std::chrono::duration<char, std::mega>{2}),
"03:33:20");
}
#endif // FMT_STATIC_THOUSANDS_SEPARATOR

View File

@ -1,85 +0,0 @@
// Formatting library for C++ - color tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// 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");
}
TEST(ColorsTest, 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::italic, "italic"),
"\x1b[3mitalic\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::underline, "underline"),
"\x1b[4munderline\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::strikethrough, "strikethrough"),
"\x1b[9mstrikethrough\x1b[0m");
EXPECT_EQ(
fmt::format(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"),
"\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold error"),
"\x1b[1mbold error\x1b[0m");
EXPECT_EQ(fmt::format(fg(fmt::color::blue), "blue log"),
"\x1b[38;2;000;000;255mblue log\x1b[0m");
EXPECT_EQ(fmt::format(fmt::text_style(), "hi"), "hi");
EXPECT_EQ(fmt::format(fg(fmt::terminal_color::red), "tred"),
"\x1b[31mtred\x1b[0m");
EXPECT_EQ(fmt::format(bg(fmt::terminal_color::cyan), "tcyan"),
"\x1b[46mtcyan\x1b[0m");
EXPECT_EQ(fmt::format(fg(fmt::terminal_color::bright_green), "tbgreen"),
"\x1b[92mtbgreen\x1b[0m");
EXPECT_EQ(fmt::format(bg(fmt::terminal_color::bright_magenta), "tbmagenta"),
"\x1b[105mtbmagenta\x1b[0m");
EXPECT_EQ(fmt::format(fg(fmt::terminal_color::red), "{}", "foo"),
"\x1b[31mfoo\x1b[0m");
}

View File

@ -1,143 +0,0 @@
// 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 <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 "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(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("{:{}.{}} {:{}}"));
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'
}
#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));
}
#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(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 {};
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);
}
};
FMT_END_NAMESPACE
TEST(CompileTest, FormatUserDefinedType) {
auto f = fmt::compile<formattable>("{}");
EXPECT_EQ(fmt::format(f, formattable()), "foo");
}
TEST(CompileTest, EmptyFormatString) {
auto f = fmt::compile<>("");
EXPECT_EQ(fmt::format(f), "");
}

View File

@ -11,16 +11,17 @@
#include <functional>
#include <iterator>
#include <limits>
#include <memory>
#include <string>
#include <type_traits>
#include <memory>
#include "test-assert.h"
#include "gmock.h"
#include "test-assert.h"
// Check if fmt/core.h compiles with windows.h included before it.
#ifdef _WIN32
# include <windows.h>
# include <windows.h>
#endif
#include "fmt/core.h"
@ -29,9 +30,9 @@
#undef max
using fmt::basic_format_arg;
using fmt::string_view;
using fmt::internal::buffer;
using fmt::internal::basic_buffer;
using fmt::internal::value;
using fmt::string_view;
using testing::_;
using testing::StrictMock;
@ -41,23 +42,24 @@ namespace {
struct test_struct {};
template <typename Context, typename T>
basic_format_arg<Context> make_arg(const T& value) {
basic_format_arg<Context> make_arg(const T &value) {
return fmt::internal::make_arg<Context>(value);
}
} // namespace
FMT_BEGIN_NAMESPACE
template <typename Char> struct formatter<test_struct, Char> {
template <typename Char>
struct formatter<test_struct, Char> {
template <typename ParseContext>
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
typedef std::back_insert_iterator<buffer<Char>> iterator;
typedef std::back_insert_iterator<basic_buffer<Char>> iterator;
auto format(test_struct, basic_format_context<iterator, char>& ctx)
auto format(test_struct, basic_format_context<iterator, char> &ctx)
-> decltype(ctx.out()) {
const Char* test = "test";
const Char *test = "test";
return std::copy_n(test, std::strlen(test), ctx.out());
}
};
@ -65,29 +67,31 @@ FMT_END_NAMESPACE
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
TEST(BufferTest, Noncopyable) {
EXPECT_FALSE(std::is_copy_constructible<buffer<char>>::value);
# if !FMT_MSC_VER
EXPECT_FALSE(std::is_copy_constructible<basic_buffer<char> >::value);
#if !FMT_MSC_VER
// std::is_copy_assignable is broken in MSVC2013.
EXPECT_FALSE(std::is_copy_assignable<buffer<char>>::value);
# endif
EXPECT_FALSE(std::is_copy_assignable<basic_buffer<char> >::value);
#endif
}
TEST(BufferTest, Nonmoveable) {
EXPECT_FALSE(std::is_move_constructible<buffer<char>>::value);
# if !FMT_MSC_VER
EXPECT_FALSE(std::is_move_constructible<basic_buffer<char> >::value);
#if !FMT_MSC_VER
// std::is_move_assignable is broken in MSVC2013.
EXPECT_FALSE(std::is_move_assignable<buffer<char>>::value);
# endif
EXPECT_FALSE(std::is_move_assignable<basic_buffer<char> >::value);
#endif
}
#endif
// A test buffer with a dummy grow method.
template <typename T> struct test_buffer : buffer<T> {
void grow(std::size_t capacity) { this->set(nullptr, capacity); }
template <typename T>
struct test_buffer : basic_buffer<T> {
void grow(std::size_t capacity) { this->set(FMT_NULL, capacity); }
};
template <typename T> struct mock_buffer : buffer<T> {
MOCK_METHOD1(do_grow, void(std::size_t capacity));
template <typename T>
struct mock_buffer : basic_buffer<T> {
MOCK_METHOD1(do_grow, void (std::size_t capacity));
void grow(std::size_t capacity) {
this->set(this->data(), capacity);
@ -95,14 +99,14 @@ template <typename T> struct mock_buffer : buffer<T> {
}
mock_buffer() {}
mock_buffer(T* data) { this->set(data, 0); }
mock_buffer(T* data, std::size_t capacity) { this->set(data, capacity); }
mock_buffer(T *data) { this->set(data, 0); }
mock_buffer(T *data, std::size_t capacity) { this->set(data, capacity); }
};
TEST(BufferTest, Ctor) {
{
mock_buffer<int> buffer;
EXPECT_EQ(nullptr, buffer.data());
EXPECT_EQ(FMT_NULL, &buffer[0]);
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
EXPECT_EQ(static_cast<size_t>(0), buffer.capacity());
}
@ -126,18 +130,13 @@ TEST(BufferTest, Ctor) {
struct dying_buffer : test_buffer<int> {
MOCK_METHOD0(die, void());
~dying_buffer() { die(); }
private:
virtual void avoid_weak_vtable();
};
void dying_buffer::avoid_weak_vtable() {}
TEST(BufferTest, VirtualDtor) {
typedef StrictMock<dying_buffer> stict_mock_buffer;
stict_mock_buffer* mock_buffer = new stict_mock_buffer();
stict_mock_buffer *mock_buffer = new stict_mock_buffer();
EXPECT_CALL(*mock_buffer, die());
buffer<int>* buffer = mock_buffer;
basic_buffer<int> *buffer = mock_buffer;
delete buffer;
}
@ -148,7 +147,7 @@ TEST(BufferTest, Access) {
EXPECT_EQ(11, buffer[0]);
buffer[3] = 42;
EXPECT_EQ(42, *(&buffer[0] + 3));
const fmt::internal::buffer<char>& const_buffer = buffer;
const basic_buffer<char> &const_buffer = buffer;
EXPECT_EQ(42, const_buffer[3]);
}
@ -183,7 +182,7 @@ TEST(BufferTest, Clear) {
TEST(BufferTest, Append) {
char data[15];
mock_buffer<char> buffer(data, 10);
const char* test = "test";
const char *test = "test";
buffer.append(test, test + 5);
EXPECT_STREQ(test, &buffer[0]);
EXPECT_EQ(5u, buffer.size());
@ -198,7 +197,7 @@ TEST(BufferTest, Append) {
TEST(BufferTest, AppendAllocatesEnoughStorage) {
char data[19];
mock_buffer<char> buffer(data, 10);
const char* test = "abcdefgh";
const char *test = "abcdefgh";
buffer.resize(10);
EXPECT_CALL(buffer, do_grow(19));
buffer.append(test, test + 9);
@ -212,31 +211,35 @@ TEST(ArgTest, FormatArgs) {
struct custom_context {
typedef char char_type;
template <typename T> struct formatter_type {
template <typename ParseContext>
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename T>
struct formatter_type {
struct type {
template <typename ParseContext>
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
const char* format(const T&, custom_context& ctx) {
ctx.called = true;
return nullptr;
}
const char *format(const T &, custom_context& ctx) {
ctx.called = true;
return FMT_NULL;
}
};
};
bool called;
fmt::format_parse_context ctx;
fmt::format_parse_context& parse_context() { return ctx; }
void advance_to(const char*) {}
fmt::format_parse_context parse_context() {
return fmt::format_parse_context("");
}
void advance_to(const char *) {}
};
TEST(ArgTest, MakeValueWithCustomContext) {
test_struct t;
fmt::internal::value<custom_context> arg(
fmt::internal::arg_mapper<custom_context>().map(t));
custom_context ctx = {false, fmt::format_parse_context("")};
arg.custom.format(&t, ctx.parse_context(), ctx);
fmt::internal::value<custom_context> arg =
fmt::internal::make_value<custom_context>(t);
custom_context ctx = {false};
arg.custom.format(&t, ctx);
EXPECT_TRUE(ctx.called);
}
@ -246,35 +249,40 @@ template <typename Char>
bool operator==(custom_value<Char> lhs, custom_value<Char> rhs) {
return lhs.value == rhs.value;
}
} // namespace internal
}
FMT_END_NAMESPACE
// Use a unique result type to make sure that there are no undesirable
// conversions.
struct test_result {};
template <typename T> struct mock_visitor {
template <typename U> struct result { typedef test_result type; };
template <typename T>
struct mock_visitor {
template <typename U>
struct result { typedef test_result type; };
mock_visitor() {
ON_CALL(*this, visit(_)).WillByDefault(testing::Return(test_result()));
}
MOCK_METHOD1_T(visit, test_result(T value));
MOCK_METHOD0_T(unexpected, void());
MOCK_METHOD1_T(visit, test_result (T value));
MOCK_METHOD0_T(unexpected, void ());
test_result operator()(T value) { return visit(value); }
template <typename U> test_result operator()(U) {
template <typename U>
test_result operator()(U) {
unexpected();
return test_result();
}
};
template <typename T> struct visit_type { typedef T Type; };
template <typename T>
struct visit_type { typedef T Type; };
#define VISIT_TYPE(Type_, visit_type_) \
template <> struct visit_type<Type_> { typedef visit_type_ Type; }
template <> \
struct visit_type<Type_> { typedef visit_type_ Type; }
VISIT_TYPE(signed char, int);
VISIT_TYPE(unsigned char, unsigned);
@ -289,30 +297,30 @@ VISIT_TYPE(long, long long);
VISIT_TYPE(unsigned long, unsigned long long);
#endif
#define CHECK_ARG_(Char, expected, value) \
{ \
testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
EXPECT_CALL(visitor, visit(expected)); \
typedef std::back_insert_iterator<buffer<Char>> iterator; \
fmt::visit_format_arg( \
visitor, make_arg<fmt::basic_format_context<iterator, Char>>(value)); \
}
VISIT_TYPE(float, double);
#define CHECK_ARG(value, typename_) \
{ \
typedef decltype(value) value_type; \
typename_ visit_type<value_type>::Type expected = value; \
CHECK_ARG_(char, expected, value) \
CHECK_ARG_(wchar_t, expected, value) \
}
#define CHECK_ARG_(Char, expected, value) { \
testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
EXPECT_CALL(visitor, visit(expected)); \
typedef std::back_insert_iterator<basic_buffer<Char>> iterator; \
fmt::visit(visitor, \
make_arg<fmt::basic_format_context<iterator, Char>>(value)); \
}
template <typename T> class NumericArgTest : public testing::Test {};
#define CHECK_ARG(value, typename_) { \
typedef decltype(value) value_type; \
typename_ visit_type<value_type>::Type expected = value; \
CHECK_ARG_(char, expected, value) \
CHECK_ARG_(wchar_t, expected, value) \
}
typedef ::testing::Types<bool, signed char, unsigned char, signed,
unsigned short, int, unsigned, long, unsigned long,
long long, unsigned long long, float, double,
long double>
Types;
template <typename T>
class NumericArgTest : public testing::Test {};
typedef ::testing::Types<
bool, signed char, unsigned char, signed, unsigned short,
int, unsigned, long, unsigned long, long long, unsigned long long,
float, double, long double> Types;
TYPED_TEST_CASE(NumericArgTest, Types);
template <typename T>
@ -322,7 +330,7 @@ typename std::enable_if<std::is_integral<T>::value, T>::type test_value() {
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
test_value() {
test_value() {
return static_cast<T>(4.2);
}
@ -340,8 +348,8 @@ TEST(ArgTest, CharArg) {
TEST(ArgTest, StringArg) {
char str_data[] = "test";
char* str = str_data;
const char* cstr = str;
char *str = str_data;
const char *cstr = str;
CHECK_ARG_(char, cstr, str);
string_view sref(str);
@ -350,8 +358,8 @@ TEST(ArgTest, StringArg) {
TEST(ArgTest, WStringArg) {
wchar_t str_data[] = L"test";
wchar_t* str = str_data;
const wchar_t* cstr = str;
wchar_t *str = str_data;
const wchar_t *cstr = str;
fmt::wstring_view sref(str);
CHECK_ARG_(wchar_t, cstr, str);
@ -361,8 +369,8 @@ TEST(ArgTest, WStringArg) {
}
TEST(ArgTest, PointerArg) {
void* p = nullptr;
const void* cp = nullptr;
void *p = FMT_NULL;
const void *cp = FMT_NULL;
CHECK_ARG_(char, cp, p);
CHECK_ARG_(wchar_t, cp, p);
CHECK_ARG(cp, );
@ -371,15 +379,14 @@ TEST(ArgTest, PointerArg) {
struct check_custom {
test_result operator()(
fmt::basic_format_arg<fmt::format_context>::handle h) const {
struct test_buffer : fmt::internal::buffer<char> {
struct test_buffer : fmt::internal::basic_buffer<char> {
char data[10];
test_buffer() : fmt::internal::buffer<char>(data, 0, 10) {}
test_buffer() : fmt::internal::basic_buffer<char>(data, 0, 10) {}
void grow(std::size_t) {}
} buffer;
fmt::internal::buffer<char>& base = buffer;
fmt::format_parse_context parse_ctx("");
fmt::format_context ctx(std::back_inserter(base), fmt::format_args());
h.format(parse_ctx, ctx);
fmt::internal::basic_buffer<char> &base = buffer;
fmt::format_context ctx(std::back_inserter(base), "", fmt::format_args());
h.format(ctx);
EXPECT_EQ("test", std::string(buffer.data, buffer.size()));
return test_result();
}
@ -388,135 +395,30 @@ struct check_custom {
TEST(ArgTest, CustomArg) {
test_struct test;
typedef mock_visitor<fmt::basic_format_arg<fmt::format_context>::handle>
visitor;
visitor;
testing::StrictMock<visitor> v;
EXPECT_CALL(v, visit(_)).WillOnce(testing::Invoke(check_custom()));
fmt::visit_format_arg(v, make_arg<fmt::format_context>(test));
fmt::visit(v, make_arg<fmt::format_context>(test));
}
TEST(ArgTest, VisitInvalidArg) {
testing::StrictMock<mock_visitor<fmt::monostate>> visitor;
testing::StrictMock< mock_visitor<fmt::monostate> > visitor;
EXPECT_CALL(visitor, visit(_));
fmt::basic_format_arg<fmt::format_context> arg;
fmt::visit_format_arg(visitor, arg);
}
TEST(FormatDynArgsTest, Basic) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(42);
store.push_back("abc1");
store.push_back(1.5f);
std::string result = fmt::vformat("{} and {} and {}", store);
EXPECT_EQ("42 and abc1 and 1.5", result);
}
TEST(FormatDynArgsTest, StringsAndRefs) {
// 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';
std::string 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(FormatDynArgsTest, CustomFormat) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
custom_type c{};
store.push_back(c);
++c.i;
store.push_back(c);
++c.i;
store.push_back(std::cref(c));
++c.i;
std::string result = fmt::vformat("{} and {} and {}", store);
EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
}
TEST(FormatDynArgsTest, NamedArgByRef) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
// Note: fmt::arg() constructs an object which holds a reference
// to its value. It's not an aggregate, so it doesn't extend the
// reference lifetime. As a result, it's a very bad idea passing temporary
// as a named argument value. Only GCC with optimization level >0
// complains about this.
//
// A real life usecase is when you have both name and value alive
// guarantee their lifetime and thus don't want them to be copied into
// storages.
int a1_val{42};
auto a1 = fmt::arg("a1_", a1_val);
store.push_back(std::cref(a1));
std::string result = fmt::vformat("{a1_}", // and {} and {}",
store);
EXPECT_EQ("42", 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(FormatDynArgsTest, ThrowOnCopy) {
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(StringViewTest, ValueType) {
static_assert(std::is_same<string_view::value_type, char>::value, "");
visit(visitor, arg);
}
TEST(StringViewTest, Length) {
// Test that string_view::size() returns string length, not buffer size.
// Test that StringRef::size() returns string length, not buffer size.
char str[100] = "some string";
EXPECT_EQ(std::strlen(str), string_view(str).size());
EXPECT_LT(std::strlen(str), sizeof(str));
}
// Check string_view's comparison operator.
template <template <typename> class Op> void check_op() {
const char* inputs[] = {"foo", "fop", "fo"};
template <template <typename> class Op>
void check_op() {
const char *inputs[] = {"foo", "fop", "fo"};
std::size_t num_inputs = sizeof(inputs) / sizeof(*inputs);
for (std::size_t i = 0; i < num_inputs; ++i) {
for (std::size_t j = 0; j < num_inputs; ++j) {
@ -540,105 +442,63 @@ TEST(StringViewTest, Compare) {
check_op<std::greater_equal>();
}
struct enabled_formatter {};
struct disabled_formatter {};
struct disabled_formatter_convertible {
operator int() const { return 42; }
};
enum basic_enum {};
FMT_BEGIN_NAMESPACE
template <> struct formatter<enabled_formatter> {
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
auto format(enabled_formatter, format_context& ctx) -> decltype(ctx.out()) {
return ctx.out();
}
};
FMT_END_NAMESPACE
TEST(CoreTest, HasFormatter) {
using fmt::has_formatter;
using context = fmt::format_context;
static_assert(has_formatter<enabled_formatter, context>::value, "");
static_assert(!has_formatter<disabled_formatter, context>::value, "");
static_assert(!has_formatter<disabled_formatter_convertible, context>::value,
"");
TEST(CoreTest, ConvertToInt) {
EXPECT_FALSE((fmt::convert_to_int<char, char>::value));
EXPECT_FALSE((fmt::convert_to_int<const char *, char>::value));
EXPECT_TRUE((fmt::convert_to_int<basic_enum, char>::value));
}
struct convertible_to_int {
operator int() const { return 42; }
};
enum enum_with_underlying_type : char {};
struct convertible_to_c_string {
operator const char*() const { return "foo"; }
};
FMT_BEGIN_NAMESPACE
template <> struct formatter<convertible_to_int> {
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
auto format(convertible_to_int, format_context& ctx) -> decltype(ctx.out()) {
return std::copy_n("foo", 3, ctx.out());
}
};
template <> struct formatter<convertible_to_c_string> {
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
auto format(convertible_to_c_string, format_context& ctx)
-> decltype(ctx.out()) {
return std::copy_n("bar", 3, ctx.out());
}
};
FMT_END_NAMESPACE
TEST(CoreTest, FormatterOverridesImplicitConversion) {
EXPECT_EQ(fmt::format("{}", convertible_to_int()), "foo");
EXPECT_EQ(fmt::format("{}", convertible_to_c_string()), "bar");
TEST(CoreTest, IsEnumConvertibleToInt) {
EXPECT_TRUE((fmt::convert_to_int<enum_with_underlying_type, char>::value));
}
namespace my_ns {
template <typename Char> class my_string {
template <typename Char>
class my_string {
public:
my_string(const Char* s) : s_(s) {}
const Char* data() const FMT_NOEXCEPT { return s_.data(); }
my_string(const Char *s) : s_(s) {}
const Char * data() const FMT_NOEXCEPT { return s_.data(); }
std::size_t length() const FMT_NOEXCEPT { return s_.size(); }
operator const Char*() const { return s_.c_str(); }
private:
std::basic_string<Char> s_;
};
template <typename Char>
inline fmt::basic_string_view<Char> to_string_view(const my_string<Char>& s)
FMT_NOEXCEPT {
return {s.data(), s.length()};
inline fmt::basic_string_view<Char>
to_string_view(const my_string<Char> &s) FMT_NOEXCEPT {
return { s.data(), s.length() };
}
struct non_string {};
} // namespace my_ns
}
namespace FakeQt {
class QString {
public:
QString(const wchar_t* s) : s_(std::make_shared<std::wstring>(s)) {}
const wchar_t* utf16() const FMT_NOEXCEPT { return s_->data(); }
QString(const wchar_t *s) : s_(std::make_shared<std::wstring>(s)) {}
const wchar_t *utf16() const FMT_NOEXCEPT { return s_->data(); }
int size() const FMT_NOEXCEPT { return static_cast<int>(s_->size()); }
#ifdef FMT_STRING_VIEW
operator FMT_STRING_VIEW<wchar_t>() const FMT_NOEXCEPT { return *s_; }
#endif
private:
std::shared_ptr<std::wstring> s_;
};
inline fmt::basic_string_view<wchar_t> to_string_view(const QString& s)
FMT_NOEXCEPT {
return {s.utf16(), static_cast<std::size_t>(s.size())};
inline fmt::basic_string_view<wchar_t> to_string_view(
const QString &s) FMT_NOEXCEPT {
return {s.utf16(),
static_cast<std::size_t>(s.size())};
}
}
} // namespace FakeQt
template <typename T> class IsStringTest : public testing::Test {};
template <typename T>
class IsStringTest : public testing::Test {};
typedef ::testing::Types<char, wchar_t, char16_t, char32_t> StringCharTypes;
TYPED_TEST_CASE(IsStringTest, StringCharTypes);
@ -646,30 +506,30 @@ TYPED_TEST_CASE(IsStringTest, StringCharTypes);
namespace {
template <typename Char>
struct derived_from_string_view : fmt::basic_string_view<Char> {};
} // namespace
}
TYPED_TEST(IsStringTest, IsString) {
EXPECT_TRUE(fmt::internal::is_string<TypeParam*>::value);
EXPECT_TRUE(fmt::internal::is_string<const TypeParam*>::value);
EXPECT_TRUE(fmt::internal::is_string<TypeParam[2]>::value);
EXPECT_TRUE(fmt::internal::is_string<const TypeParam[2]>::value);
EXPECT_TRUE(fmt::internal::is_string<std::basic_string<TypeParam>>::value);
EXPECT_TRUE((fmt::internal::is_string<TypeParam *>::value));
EXPECT_TRUE((fmt::internal::is_string<const TypeParam *>::value));
EXPECT_TRUE((fmt::internal::is_string<TypeParam[2]>::value));
EXPECT_TRUE((fmt::internal::is_string<const TypeParam[2]>::value));
EXPECT_TRUE((fmt::internal::is_string<std::basic_string<TypeParam>>::value));
EXPECT_TRUE(
fmt::internal::is_string<fmt::basic_string_view<TypeParam>>::value);
(fmt::internal::is_string<fmt::basic_string_view<TypeParam>>::value));
EXPECT_TRUE(
fmt::internal::is_string<derived_from_string_view<TypeParam>>::value);
using string_view = fmt::internal::std_string_view<TypeParam>;
EXPECT_TRUE(std::is_empty<string_view>::value !=
fmt::internal::is_string<string_view>::value);
EXPECT_TRUE(fmt::internal::is_string<my_ns::my_string<TypeParam>>::value);
EXPECT_FALSE(fmt::internal::is_string<my_ns::non_string>::value);
EXPECT_TRUE(fmt::internal::is_string<FakeQt::QString>::value);
(fmt::internal::is_string<derived_from_string_view<TypeParam>>::value));
#ifdef FMT_STRING_VIEW
EXPECT_TRUE((fmt::internal::is_string<FMT_STRING_VIEW<TypeParam>>::value));
#endif
EXPECT_TRUE((fmt::internal::is_string<my_ns::my_string<TypeParam>>::value));
EXPECT_FALSE((fmt::internal::is_string<my_ns::non_string>::value));
EXPECT_TRUE((fmt::internal::is_string<FakeQt::QString>::value));
}
TEST(CoreTest, Format) {
// This should work without including fmt/format.h.
#ifdef FMT_FORMAT_H_
# error fmt/format.h must not be included in the core test
# error fmt/format.h must not be included in the core test
#endif
EXPECT_EQ(fmt::format("{}", 42), "42");
}
@ -677,7 +537,7 @@ TEST(CoreTest, Format) {
TEST(CoreTest, FormatTo) {
// This should work without including fmt/format.h.
#ifdef FMT_FORMAT_H_
# error fmt/format.h must not be included in the core test
# error fmt/format.h must not be included in the core test
#endif
std::string s;
fmt::format_to(std::back_inserter(s), "{}", 42);
@ -691,18 +551,15 @@ TEST(CoreTest, ToStringViewForeignStrings) {
EXPECT_EQ(to_string_view(my_string<wchar_t>(L"42")), L"42");
EXPECT_EQ(to_string_view(QString(L"42")), L"42");
fmt::internal::type type =
fmt::internal::mapped_type_constant<my_string<char>,
fmt::format_context>::value;
EXPECT_EQ(type, fmt::internal::type::string_type);
type = fmt::internal::mapped_type_constant<my_string<wchar_t>,
fmt::wformat_context>::value;
EXPECT_EQ(type, fmt::internal::type::string_type);
fmt::internal::get_type<fmt::format_context, my_string<char>>::value;
EXPECT_EQ(type, fmt::internal::string_type);
type =
fmt::internal::mapped_type_constant<QString, fmt::wformat_context>::value;
EXPECT_EQ(type, fmt::internal::type::string_type);
fmt::internal::get_type<fmt::wformat_context, my_string<wchar_t>>::value;
EXPECT_EQ(type, fmt::internal::string_type);
type = fmt::internal::get_type<fmt::wformat_context, QString>::value;
EXPECT_EQ(type, fmt::internal::string_type);
// Does not compile: only wide format contexts are compatible with QString!
// type = fmt::internal::mapped_type_constant<QString,
// fmt::format_context>::value;
// type = fmt::internal::get_type<fmt::format_context, QString>::value;
}
TEST(CoreTest, FormatForeignStrings) {
@ -715,10 +572,6 @@ TEST(CoreTest, FormatForeignStrings) {
EXPECT_EQ(fmt::format(my_string<wchar_t>(L"{}"), QString(L"42")), L"42");
}
struct implicitly_convertible_to_string {
operator std::string() const { return "foo"; }
};
struct implicitly_convertible_to_string_view {
operator fmt::string_view() const { return "foo"; }
};
@ -728,7 +581,7 @@ TEST(FormatterTest, FormatImplicitlyConvertibleToStringView) {
}
// std::is_constructible is broken in MSVC until version 2015.
#if !FMT_MSC_VER || FMT_MSC_VER >= 1900
#if FMT_USE_EXPLICIT && (!FMT_MSC_VER || FMT_MSC_VER >= 1900)
struct explicitly_convertible_to_string_view {
explicit operator fmt::string_view() const { return "foo"; }
};
@ -737,17 +590,6 @@ TEST(FormatterTest, FormatExplicitlyConvertibleToStringView) {
EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_view()));
}
# ifdef FMT_USE_STRING_VIEW
struct explicitly_convertible_to_std_string_view {
explicit operator std::string_view() const { return "foo"; }
};
TEST(FormatterTest, FormatExplicitlyConvertibleToStdStringView) {
EXPECT_EQ("foo",
fmt::format("{}", explicitly_convertible_to_std_string_view()));
}
# endif
struct explicitly_convertible_to_wstring_view {
explicit operator fmt::wstring_view() const { return L"foo"; }
};
@ -756,15 +598,16 @@ TEST(FormatterTest, FormatExplicitlyConvertibleToWStringView) {
EXPECT_EQ(L"foo",
fmt::format(L"{}", explicitly_convertible_to_wstring_view()));
}
#endif
struct disabled_rvalue_conversion {
operator const char*() const& { return "foo"; }
operator const char*() & { return "foo"; }
operator const char*() const&& = delete;
operator const char*() && = delete;
struct explicitly_convertible_to_string_like {
template <
typename String,
typename = typename std::enable_if<
std::is_constructible<String, const char*, std::size_t>::value>::type>
FMT_EXPLICIT operator String() const { return String("foo", 3u); }
};
TEST(FormatterTest, DisabledRValueConversion) {
EXPECT_EQ("foo", fmt::format("{}", disabled_rvalue_conversion()));
TEST(FormatterTest, FormatExplicitlyConvertibleToStringLike) {
EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_like()));
}
#endif

View File

@ -1,73 +0,0 @@
# We can find some usecases which follow the guide of CMake which uses
# `enable_language(CUDA)` instead of `find_package(CUDA)` and let the CMake
# built-in functions use NVCC.
# See: https://cmake.org/cmake/help/latest/module/FindCUDA.html#replacement
#
# However, this requires CMake version 3.10 or higher and we can't be sure most
# of the CUDA projects are using those.
#
# This test relies on `find_package(CUDA)` in the parent CMake config.
# These can be updated when NVCC becomes ready for C++ 17 features
# https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#cpp14-language-features
set(CMAKE_CUDA_STANDARD 14)
set(CMAKE_CUDA_STANDARD_REQUIRED 14)
# In this test, we assume that the user is going to compile CUDA source code
# with some libraries (fmt in this case).
#
# In addition to that, this test invokes both the C++ host compiler and NVCC
# by providing another (non-CUDA) C++ source code.
if (${CMAKE_VERSION} VERSION_LESS 3.15)
# https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html
list(APPEND CUDA_NVCC_FLAGS "-std=c++14")
if (MSVC)
# This is the solution of pytorch:
# https://github.com/pytorch/pytorch/pull/7118
list(APPEND CUDA_NVCC_FLAGS "-Xcompiler" "/std:c++14")
list(APPEND CUDA_NVCC_FLAGS "-Xcompiler" "/Zc:__cplusplus")
# for the reason of this -Xcompiler options, see below.
endif ()
cuda_add_executable(fmt-in-cuda-test cuda-cpp14.cu cpp14.cc)
target_compile_features(fmt-in-cuda-test PRIVATE cxx_std_14)
if (MSVC)
# This part is for (non-CUDA) C++ code. MSVC can define incorrect
# `__cplusplus` macro. Fix for the issue is to use additional compiler flag.
#
# See Also:
# https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
# https://github.com/Microsoft/vscode-cpptools/issues/2595
target_compile_options(fmt-in-cuda-test PRIVATE /Zc:__cplusplus /permissive-)
endif ()
else()
# now using a "new" way of handling CUDA
add_executable(fmt-in-cuda-test cuda-cpp14.cu cpp14.cc)
set_target_properties(fmt-in-cuda-test PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
target_compile_features(fmt-in-cuda-test PRIVATE cxx_std_14)
if (MSVC)
# with MSVC, 'cxx_std_14' will only propagate to the host code (MSVC), but will
# not set __cplusplus correctly anyway, while nvcc will ignore it.
# If specified for nvcc on the command line as '-std=c++14' nvcc will emit this
# message instead:
# nvcc warning : The -std=c++14 flag is not supported with the configured host
# compiler. Flag will be ignored.
set_property(SOURCE cuda-cpp14.cu APPEND PROPERTY
COMPILE_OPTIONS -Xcompiler /std:c++14 -Xcompiler /Zc:__cplusplus)
set_property(SOURCE cpp14.cc APPEND PROPERTY
COMPILE_OPTIONS /std:c++14 /Zc:__cplusplus)
endif()
endif()
get_target_property(IN_USE_CUDA_STANDARD fmt-in-cuda-test CUDA_STANDARD)
message(STATUS "cuda_standard: ${IN_USE_CUDA_STANDARD}")
get_target_property(IN_USE_CUDA_STANDARD_REQUIRED
fmt-in-cuda-test CUDA_STANDARD_REQUIRED)
message(STATUS "cuda_standard_required: ${IN_USE_CUDA_STANDARD_REQUIRED}")
# We don't use PUBLIC or other keyword for reasons explained in the
# CUDA_LINK_LIBRARIES_KEYWORD section in
# https://cmake.org/cmake/help/latest/module/FindCUDA.html
target_link_libraries(fmt-in-cuda-test fmt::fmt)

View File

@ -1,11 +0,0 @@
#include <fmt/core.h>
// The purpose of this part is to ensure NVCC's host compiler also supports
// the standard version. See 'cuda-cpp14.cu'.
//
// https://en.cppreference.com/w/cpp/preprocessor/replace#Predefined_macros
static_assert(__cplusplus >= 201402L, "expect C++ 2014 for host compiler");
auto make_message_cpp() -> std::string {
return fmt::format("host compiler \t: __cplusplus == {}", __cplusplus);
}

View File

@ -1,28 +0,0 @@
// Direct NVCC command line example:
//
// nvcc ./cuda-cpp14.cu -x cu -I"../include" -l"fmtd" -L"../build/Debug" \
// -std=c++14 -Xcompiler /std:c++14 -Xcompiler /Zc:__cplusplus
// Ensure that we are using the latest C++ standard for NVCC
// The version is C++14
//
// https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#c-cplusplus-language-support
// https://en.cppreference.com/w/cpp/preprocessor/replace#Predefined_macros
static_assert(__cplusplus >= 201402L, "expect C++ 2014 for nvcc");
#include <fmt/core.h>
#include <cuda.h>
#include <iostream>
extern auto make_message_cpp() -> std::string;
extern auto make_message_cuda() -> std::string;
int main() {
std::cout << make_message_cuda() << std::endl;
std::cout << make_message_cpp() << std::endl;
}
auto make_message_cuda() -> std::string {
return fmt::format("nvcc compiler \t: __cplusplus == {}", __cplusplus);
}

View File

@ -5,10 +5,6 @@
//
// 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"
@ -17,22 +13,22 @@
// 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>> {
class custom_arg_formatter :
public fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>> {
public:
using range = fmt::buffer_range<char>;
typedef fmt::back_insert_range<fmt::internal::buffer> range;
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) {}
custom_arg_formatter(
fmt::format_context &ctx, fmt::format_specs *s = FMT_NULL)
: base(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;
if (round(value * pow(10, spec()->precision)) == 0.0)
value = 0;
return base::operator()(value);
}
};
@ -45,7 +41,7 @@ std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) {
}
template <typename... Args>
std::string custom_format(const char* format_str, const Args&... 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);
}

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_

View File

@ -1,6 +0,0 @@
// Copyright (c) 2020 Vladimir Solontsov
// SPDX-License-Identifier: MIT Licence
#include <fmt/core.h>
#include "gtest-extra.h"

View File

@ -10,243 +10,75 @@
#include "test-assert.h"
// Include format.cc instead of format.h to test implementation.
#include "../src/format.cc"
#include "fmt/color.h"
#include "fmt/printf.h"
#include <algorithm>
#include <cstring>
#include "../src/format.cc"
#include "fmt/printf.h"
#include "gmock.h"
#include "gtest-extra.h"
#include "util.h"
#undef min
#undef max
using fmt::internal::bigint;
#if FMT_HAS_CPP_ATTRIBUTE(noreturn)
# define FMT_NORETURN [[noreturn]]
#else
# define FMT_NORETURN
#endif
using fmt::internal::fp;
using fmt::internal::max_value;
static_assert(!std::is_copy_constructible<bigint>::value, "");
static_assert(!std::is_copy_assignable<bigint>::value, "");
TEST(BigIntTest, Construct) {
EXPECT_EQ("", fmt::format("{}", bigint()));
EXPECT_EQ("42", fmt::format("{}", bigint(0x42)));
EXPECT_EQ("123456789abcedf0", fmt::format("{}", bigint(0x123456789abcedf0)));
}
TEST(BigIntTest, Compare) {
bigint n1(42);
bigint n2(42);
EXPECT_EQ(compare(n1, n2), 0);
n2 <<= 32;
EXPECT_LT(compare(n1, n2), 0);
bigint n3(43);
EXPECT_LT(compare(n1, n3), 0);
EXPECT_GT(compare(n3, n1), 0);
bigint n4(42 * 0x100000001);
EXPECT_LT(compare(n2, n4), 0);
EXPECT_GT(compare(n4, n2), 0);
}
TEST(BigIntTest, AddCompare) {
EXPECT_LT(
add_compare(bigint(0xffffffff), bigint(0xffffffff), bigint(1) <<= 64), 0);
EXPECT_LT(add_compare(bigint(1) <<= 32, bigint(1), bigint(1) <<= 96), 0);
EXPECT_GT(add_compare(bigint(1) <<= 32, bigint(0), bigint(0xffffffff)), 0);
EXPECT_GT(add_compare(bigint(0), bigint(1) <<= 32, bigint(0xffffffff)), 0);
EXPECT_GT(add_compare(bigint(42), bigint(1), bigint(42)), 0);
EXPECT_GT(add_compare(bigint(0xffffffff), bigint(1), bigint(0xffffffff)), 0);
EXPECT_LT(add_compare(bigint(10), bigint(10), bigint(22)), 0);
EXPECT_LT(add_compare(bigint(0x100000010), bigint(0x100000010),
bigint(0x300000010)),
0);
EXPECT_GT(add_compare(bigint(0x1ffffffff), bigint(0x100000002),
bigint(0x300000000)),
0);
EXPECT_EQ(add_compare(bigint(0x1ffffffff), bigint(0x100000002),
bigint(0x300000001)),
0);
EXPECT_LT(add_compare(bigint(0x1ffffffff), bigint(0x100000002),
bigint(0x300000002)),
0);
EXPECT_LT(add_compare(bigint(0x1ffffffff), bigint(0x100000002),
bigint(0x300000003)),
0);
}
TEST(BigIntTest, ShiftLeft) {
bigint n(0x42);
n <<= 0;
EXPECT_EQ("42", fmt::format("{}", n));
n <<= 1;
EXPECT_EQ("84", fmt::format("{}", n));
n <<= 25;
EXPECT_EQ("108000000", fmt::format("{}", n));
}
TEST(BigIntTest, Multiply) {
bigint n(0x42);
EXPECT_THROW(n *= 0, assertion_failure);
n *= 1;
EXPECT_EQ("42", fmt::format("{}", n));
n *= 2;
EXPECT_EQ("84", fmt::format("{}", n));
n *= 0x12345678;
EXPECT_EQ("962fc95e0", fmt::format("{}", n));
bigint bigmax(max_value<uint32_t>());
bigmax *= max_value<uint32_t>();
EXPECT_EQ("fffffffe00000001", fmt::format("{}", bigmax));
bigmax.assign(max_value<uint64_t>());
bigmax *= max_value<uint64_t>();
EXPECT_EQ("fffffffffffffffe0000000000000001", fmt::format("{}", bigmax));
}
TEST(BigIntTest, Accumulator) {
fmt::internal::accumulator acc;
EXPECT_EQ(acc.lower, 0);
EXPECT_EQ(acc.upper, 0);
acc.upper = 12;
acc.lower = 34;
EXPECT_EQ(static_cast<uint32_t>(acc), 34);
acc += 56;
EXPECT_EQ(acc.lower, 90);
acc += fmt::internal::max_value<uint64_t>();
EXPECT_EQ(acc.upper, 13);
EXPECT_EQ(acc.lower, 89);
acc >>= 32;
EXPECT_EQ(acc.upper, 0);
EXPECT_EQ(acc.lower, 13 * 0x100000000);
}
TEST(BigIntTest, Square) {
bigint n0(0);
n0.square();
EXPECT_EQ("0", fmt::format("{}", n0));
bigint n1(0x100);
n1.square();
EXPECT_EQ("10000", fmt::format("{}", n1));
bigint n2(0xfffffffff);
n2.square();
EXPECT_EQ("ffffffffe000000001", fmt::format("{}", n2));
bigint n3(max_value<uint64_t>());
n3.square();
EXPECT_EQ("fffffffffffffffe0000000000000001", fmt::format("{}", n3));
bigint n4;
n4.assign_pow10(10);
EXPECT_EQ("2540be400", fmt::format("{}", n4));
}
TEST(BigIntTest, DivModAssignZeroDivisor) {
bigint zero(0);
EXPECT_THROW(bigint(0).divmod_assign(zero), assertion_failure);
EXPECT_THROW(bigint(42).divmod_assign(zero), assertion_failure);
}
TEST(BigIntTest, DivModAssignSelf) {
bigint n(100);
EXPECT_THROW(n.divmod_assign(n), assertion_failure);
}
TEST(BigIntTest, DivModAssignUnaligned) {
// (42 << 340) / pow(10, 100):
bigint n1(42);
n1 <<= 340;
bigint n2;
n2.assign_pow10(100);
int result = n1.divmod_assign(n2);
EXPECT_EQ(result, 9406);
EXPECT_EQ("10f8353019583bfc29ffc8f564e1b9f9d819dbb4cf783e4507eca1539220p96",
fmt::format("{}", n1));
}
TEST(BigIntTest, DivModAssign) {
// 100 / 10:
bigint n1(100);
int result = n1.divmod_assign(bigint(10));
EXPECT_EQ(result, 10);
EXPECT_EQ("0", fmt::format("{}", n1));
// pow(10, 100) / (42 << 320):
n1.assign_pow10(100);
result = n1.divmod_assign(bigint(42) <<= 320);
EXPECT_EQ(result, 111);
EXPECT_EQ("13ad2594c37ceb0b2784c4ce0bf38ace408e211a7caab24308a82e8f10p96",
fmt::format("{}", n1));
// 42 / 100:
bigint n2(42);
n1.assign_pow10(2);
result = n2.divmod_assign(n1);
EXPECT_EQ(result, 0);
EXPECT_EQ("2a", fmt::format("{}", n2));
}
template <bool is_iec559> void run_double_tests() {
template <bool is_iec559>
void test_construct_from_double() {
fmt::print("warning: double is not IEC559, skipping FP tests\n");
}
template <> void run_double_tests<true>() {
// Construct from double.
EXPECT_EQ(fp(1.23), fp(0x13ae147ae147aeu, -52));
// Compute boundaries:
fp value;
// Normalized & not power of 2 - equidistant boundaries:
auto b = value.assign_with_boundaries(1.23);
EXPECT_EQ(value, fp(0x0013ae147ae147ae, -52));
EXPECT_EQ(b.lower, 0x9d70a3d70a3d6c00);
EXPECT_EQ(b.upper, 0x9d70a3d70a3d7400);
// Normalized power of 2 - lower boundary is closer:
b = value.assign_with_boundaries(1.9807040628566084e+28); // 2**94
EXPECT_EQ(value, fp(0x0010000000000000, 42));
EXPECT_EQ(b.lower, 0x7ffffffffffffe00);
EXPECT_EQ(b.upper, 0x8000000000000400);
// Smallest normalized double - equidistant boundaries:
b = value.assign_with_boundaries(2.2250738585072014e-308);
EXPECT_EQ(value, fp(0x0010000000000000, -1074));
EXPECT_EQ(b.lower, 0x7ffffffffffffc00);
EXPECT_EQ(b.upper, 0x8000000000000400);
// Subnormal - equidistant boundaries:
b = value.assign_with_boundaries(4.9406564584124654e-324);
EXPECT_EQ(value, fp(0x0000000000000001, -1074));
EXPECT_EQ(b.lower, 0x4000000000000000);
EXPECT_EQ(b.upper, 0xc000000000000000);
template <>
void test_construct_from_double<true>() {
auto v = fp(1.23);
EXPECT_EQ(v.f, 0x13ae147ae147aeu);
EXPECT_EQ(v.e, -52);
}
TEST(FPTest, DoubleTests) {
run_double_tests<std::numeric_limits<double>::is_iec559>();
TEST(FPTest, ConstructFromDouble) {
test_construct_from_double<std::numeric_limits<double>::is_iec559>();
}
TEST(FPTest, Normalize) {
const auto v = fp(0xbeef, 42);
auto normalized = normalize(v);
EXPECT_EQ(0xbeef000000000000, normalized.f);
EXPECT_EQ(-6, normalized.e);
auto v = fp(0xbeef, 42);
v.normalize();
EXPECT_EQ(0xbeef000000000000, v.f);
EXPECT_EQ(-6, v.e);
}
TEST(FPTest, ComputeFloatBoundaries) {
struct {
double x, lower, upper;
} tests[] = {
// regular
{1.5f, 1.4999999403953552, 1.5000000596046448},
// boundary
{1.0f, 0.9999999701976776, 1.0000000596046448},
// min normal
{1.1754944e-38f, 1.1754942807573643e-38, 1.1754944208872107e-38},
// max subnormal
{1.1754942e-38f, 1.1754941406275179e-38, 1.1754942807573643e-38},
// min subnormal
{1e-45f, 7.006492321624085e-46, 2.1019476964872256e-45},
};
for (auto test : tests) {
fp vlower = normalize(fp(test.lower));
fp vupper = normalize(fp(test.upper));
vlower.f >>= vupper.e - vlower.e;
vlower.e = vupper.e;
fp value;
auto b = value.assign_float_with_boundaries(test.x);
EXPECT_EQ(vlower.f, b.lower);
EXPECT_EQ(vupper.f, b.upper);
}
TEST(FPTest, ComputeBoundariesSubnormal) {
auto v = fp(0xbeef, 42);
fp lower, upper;
v.compute_boundaries(lower, upper);
EXPECT_EQ(0xbeee800000000000, lower.f);
EXPECT_EQ(-6, lower.e);
EXPECT_EQ(0xbeef800000000000, upper.f);
EXPECT_EQ(-6, upper.e);
}
TEST(FPTest, ComputeBoundaries) {
auto v = fp(0x10000000000000, 42);
fp lower, upper;
v.compute_boundaries(lower, upper);
EXPECT_EQ(0x7ffffffffffffe00, lower.f);
EXPECT_EQ(31, lower.e);
EXPECT_EQ(0x8000000000000400, upper.f);
EXPECT_EQ(31, upper.e);
}
TEST(FPTest, Subtract) {
auto v = fp(123, 1) - fp(102, 1);
EXPECT_EQ(v.f, 21u);
EXPECT_EQ(v.e, 1);
}
TEST(FPTest, Multiply) {
@ -266,87 +98,33 @@ TEST(FPTest, GetCachedPower) {
EXPECT_LE(exp, fp.e);
int dec_exp_step = 8;
EXPECT_LE(fp.e, exp + dec_exp_step * log2(10));
EXPECT_DOUBLE_EQ(pow(10, dec_exp), ldexp(static_cast<double>(fp.f), fp.e));
EXPECT_DOUBLE_EQ(pow(10, dec_exp), ldexp(fp.f, fp.e));
}
}
TEST(FPTest, GetRoundDirection) {
using fmt::internal::get_round_direction;
using fmt::internal::round_direction;
EXPECT_EQ(round_direction::down, get_round_direction(100, 50, 0));
EXPECT_EQ(round_direction::up, get_round_direction(100, 51, 0));
EXPECT_EQ(round_direction::down, get_round_direction(100, 40, 10));
EXPECT_EQ(round_direction::up, get_round_direction(100, 60, 10));
for (size_t i = 41; i < 60; ++i)
EXPECT_EQ(round_direction::unknown, get_round_direction(100, i, 10));
uint64_t max = max_value<uint64_t>();
EXPECT_THROW(get_round_direction(100, 100, 0), assertion_failure);
EXPECT_THROW(get_round_direction(100, 0, 100), assertion_failure);
EXPECT_THROW(get_round_direction(100, 0, 50), assertion_failure);
// Check that remainder + error doesn't overflow.
EXPECT_EQ(round_direction::up, get_round_direction(max, max - 1, 2));
// Check that 2 * (remainder + error) doesn't overflow.
EXPECT_EQ(round_direction::unknown,
get_round_direction(max, max / 2 + 1, max / 2));
// Check that remainder - error doesn't overflow.
EXPECT_EQ(round_direction::unknown, get_round_direction(100, 40, 41));
// Check that 2 * (remainder - error) doesn't overflow.
EXPECT_EQ(round_direction::up, get_round_direction(max, max - 1, 1));
}
TEST(FPTest, FixedHandler) {
struct handler : fmt::internal::fixed_handler {
char buffer[10];
handler(int prec = 0) : fmt::internal::fixed_handler() {
buf = buffer;
precision = prec;
}
};
int exp = 0;
handler().on_digit('0', 100, 99, 0, exp, false);
EXPECT_THROW(handler().on_digit('0', 100, 100, 0, exp, false),
assertion_failure);
namespace digits = fmt::internal::digits;
EXPECT_EQ(handler(1).on_digit('0', 100, 10, 10, exp, false), digits::done);
// Check that divisor - error doesn't overflow.
EXPECT_EQ(handler(1).on_digit('0', 100, 10, 101, exp, false), digits::error);
// Check that 2 * error doesn't overflow.
uint64_t max = max_value<uint64_t>();
EXPECT_EQ(handler(1).on_digit('0', max, 10, max - 1, exp, false),
digits::error);
}
TEST(FPTest, GrisuFormatCompilesWithNonIEEEDouble) {
TEST(FPTest, Grisu2FormatCompilesWithNonIEEEDouble) {
fmt::memory_buffer buf;
format_float(0.42, -1, fmt::internal::float_specs(), buf);
grisu2_format(4.2f, buf, fmt::core_format_specs());
}
template <typename T> struct value_extractor {
T operator()(T value) { return value; }
template <typename T>
struct ValueExtractor: fmt::internal::function<T> {
T operator()(T value) {
return value;
}
template <typename U> FMT_NORETURN T operator()(U) {
template <typename U>
FMT_NORETURN T operator()(U) {
throw std::runtime_error(fmt::format("invalid type {}", typeid(U).name()));
}
#if FMT_USE_INT128
// Apple Clang does not define typeid for __int128_t and __uint128_t.
FMT_NORETURN T operator()(fmt::internal::int128_t) {
throw std::runtime_error("invalid type __int128_t");
}
FMT_NORETURN T operator()(fmt::internal::uint128_t) {
throw std::runtime_error("invalid type __uint128_t");
}
#endif
};
TEST(FormatTest, ArgConverter) {
long long value = max_value<long long>();
long long value = std::numeric_limits<long long>::max();
auto arg = fmt::internal::make_arg<fmt::format_context>(value);
fmt::visit_format_arg(
fmt::internal::arg_converter<long long, fmt::format_context>(arg, 'd'),
arg);
EXPECT_EQ(value, fmt::visit_format_arg(value_extractor<long long>(), arg));
visit(fmt::internal::arg_converter<long long, fmt::format_context>(arg, 'd'),
arg);
EXPECT_EQ(value, visit(ValueExtractor<long long>(), arg));
}
TEST(FormatTest, FormatNegativeNaN) {
@ -358,11 +136,11 @@ TEST(FormatTest, FormatNegativeNaN) {
}
TEST(FormatTest, StrError) {
char* message = nullptr;
char *message = FMT_NULL;
char buffer[BUFFER_SIZE];
EXPECT_ASSERT(fmt::internal::safe_strerror(EDOM, message = nullptr, 0),
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = FMT_NULL, 0),
"invalid buffer");
EXPECT_ASSERT(fmt::internal::safe_strerror(EDOM, message = buffer, 0),
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = buffer, 0),
"invalid buffer");
buffer[0] = 'x';
#if defined(_GNU_SOURCE) && !defined(__COVERITY__)
@ -373,19 +151,17 @@ TEST(FormatTest, StrError) {
int error_code = EDOM;
#endif
int result =
fmt::internal::safe_strerror(error_code, message = buffer, BUFFER_SIZE);
int result = fmt::safe_strerror(error_code, message = buffer, BUFFER_SIZE);
EXPECT_EQ(result, 0);
std::size_t message_size = std::strlen(message);
EXPECT_GE(BUFFER_SIZE - 1u, message_size);
EXPECT_EQ(get_system_error(error_code), message);
// safe_strerror never uses buffer on MinGW.
#if !defined(__MINGW32__) && !defined(__sun)
result =
fmt::internal::safe_strerror(error_code, message = buffer, message_size);
#ifndef __MINGW32__
result = fmt::safe_strerror(error_code, message = buffer, message_size);
EXPECT_EQ(ERANGE, result);
result = fmt::internal::safe_strerror(error_code, message = buffer, 1);
result = fmt::safe_strerror(error_code, message = buffer, 1);
EXPECT_EQ(buffer, message); // Message should point to buffer.
EXPECT_EQ(ERANGE, result);
EXPECT_STREQ("", message);
@ -397,14 +173,14 @@ TEST(FormatTest, FormatErrorCode) {
{
fmt::memory_buffer buffer;
format_to(buffer, "garbage");
fmt::internal::format_error_code(buffer, 42, "test");
fmt::format_error_code(buffer, 42, "test");
EXPECT_EQ("test: " + msg, to_string(buffer));
}
{
fmt::memory_buffer buffer;
std::string prefix(fmt::inline_buffer_size - msg.size() - sep.size() + 1,
'x');
fmt::internal::format_error_code(buffer, 42, prefix);
std::string prefix(
fmt::inline_buffer_size - msg.size() - sep.size() + 1, 'x');
fmt::format_error_code(buffer, 42, prefix);
EXPECT_EQ(msg, to_string(buffer));
}
int codes[] = {42, -1};
@ -412,49 +188,59 @@ TEST(FormatTest, FormatErrorCode) {
// Test maximum buffer size.
msg = fmt::format("error {}", codes[i]);
fmt::memory_buffer buffer;
std::string prefix(fmt::inline_buffer_size - msg.size() - sep.size(), 'x');
fmt::internal::format_error_code(buffer, codes[i], prefix);
std::string prefix(
fmt::inline_buffer_size - msg.size() - sep.size(), 'x');
fmt::format_error_code(buffer, codes[i], prefix);
EXPECT_EQ(prefix + sep + msg, to_string(buffer));
std::size_t size = fmt::inline_buffer_size;
EXPECT_EQ(size, buffer.size());
buffer.resize(0);
// Test with a message that doesn't fit into the buffer.
prefix += 'x';
fmt::internal::format_error_code(buffer, codes[i], prefix);
fmt::format_error_code(buffer, codes[i], prefix);
EXPECT_EQ(msg, to_string(buffer));
}
}
TEST(FormatTest, CountCodePoints) {
#ifndef __cpp_char8_t
using fmt::char8_t;
#endif
EXPECT_EQ(
4, fmt::internal::count_code_points(
fmt::basic_string_view<fmt::internal::char8_type>(
reinterpret_cast<const fmt::internal::char8_type*>("ёжик"))));
EXPECT_EQ(4, fmt::internal::count_code_points(fmt::u8string_view("ёжик")));
}
// Tests fmt::internal::count_digits for integer type Int.
template <typename Int> void test_count_digits() {
for (Int i = 0; i < 10; ++i) EXPECT_EQ(1u, fmt::internal::count_digits(i));
for (Int i = 1, n = 1, end = max_value<Int>() / 10; n <= end; ++i) {
n *= 10;
EXPECT_EQ(i, fmt::internal::count_digits(n - 1));
EXPECT_EQ(i + 1, fmt::internal::count_digits(n));
}
}
TEST(UtilTest, CountDigits) {
test_count_digits<uint32_t>();
test_count_digits<uint64_t>();
}
TEST(UtilTest, WriteUIntPtr) {
fmt::memory_buffer buf;
fmt::internal::writer writer(buf);
writer.write_pointer(
fmt::internal::fallback_uintptr(reinterpret_cast<void*>(0xface)),
nullptr);
EXPECT_EQ("0xface", to_string(buf));
TEST(ColorsTest, Colors) {
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");
}

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +0,0 @@
# ignore artifacts from the build.sh script
build-*/

View File

@ -1,38 +0,0 @@
# Copyright (c) 2019, Paul Dreik
# License: see LICENSE.rst in the fmt root directory
# settings this links in a main. useful for reproducing,
# kcov, gdb, afl, valgrind.
# (note that libFuzzer can also reproduce, just pass it the files)
option(FMT_FUZZ_LINKMAIN "enables the reproduce mode, instead of libFuzzer" On)
# For oss-fuzz - insert $LIB_FUZZING_ENGINE into the link flags, but only for
# the fuzz targets, otherwise the cmake configuration step fails.
set(FMT_FUZZ_LDFLAGS "" CACHE STRING "LDFLAGS for the fuzz targets")
# Find all fuzzers.
set(SOURCES
chrono_duration.cpp
named_arg.cpp
one_arg.cpp
sprintf.cpp
two_args.cpp
)
macro(implement_fuzzer sourcefile)
get_filename_component(basename ${sourcefile} NAME_WE)
set(name fuzzer_${basename})
add_executable(${name} ${sourcefile} fuzzer_common.h)
if (FMT_FUZZ_LINKMAIN)
target_sources(${name} PRIVATE main.cpp)
endif ()
target_link_libraries(${name} PRIVATE fmt)
if (FMT_FUZZ_LDFLAGS)
target_link_libraries(${name} PRIVATE ${FMT_FUZZ_LDFLAGS})
endif ()
target_compile_features(${name} PRIVATE cxx_generic_lambdas)
endmacro ()
foreach (X IN ITEMS ${SOURCES})
implement_fuzzer(${X})
endforeach ()

View File

@ -1,43 +0,0 @@
# FMT Fuzzer
Fuzzing has revealed [several bugs](https://github.com/fmtlib/fmt/issues?&q=is%3Aissue+fuzz)
in fmt. It is a part of the continous fuzzing at
[oss-fuzz](https://github.com/google/oss-fuzz).
The source code is modified to make the fuzzing possible without locking up on
resource exhaustion:
```cpp
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if(spec.precision>100000) {
throw std::runtime_error("fuzz mode - avoiding large precision");
}
#endif
```
This macro is the defacto standard for making fuzzing practically possible, see
[the libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode).
## Running the fuzzers locally
There is a [helper script](build.sh) to build the fuzzers, which has only been
tested on Debian and Ubuntu linux so far. There should be no problems fuzzing on
Windows (using clang>=8) or on Mac, but the script will probably not work out of
the box.
Something along
```sh
mkdir build
cd build
export CXX=clang++
export CXXFLAGS="-fsanitize=fuzzer-no-link -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION= -g"
cmake .. -DFMT_SAFE_DURATION_CAST=On -DFMT_FUZZ=On -DFMT_FUZZ_LINKMAIN=Off -DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer"
cmake --build .
```
should work to build the fuzzers for all platforms which clang supports.
Execute a fuzzer with for instance
```sh
cd build
export UBSAN_OPTIONS=halt_on_error=1
mkdir out_chrono
bin/fuzzer_chrono_duration out_chrono
```

View File

@ -1,110 +0,0 @@
#!/bin/sh
#
# Creates fuzzer builds of various kinds
# - reproduce mode (no fuzzing, just enables replaying data through the fuzzers)
# - oss-fuzz emulated mode (makes sure a simulated invocation by oss-fuzz works)
# - libFuzzer build (you will need clang)
# - afl build (you will need afl)
#
#
# Copyright (c) 2019 Paul Dreik
#
# License: see LICENSE.rst in the fmt root directory
set -e
me=$(basename $0)
root=$(readlink -f "$(dirname "$0")/../..")
echo $me: root=$root
here=$(pwd)
CXXFLAGSALL="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION= -g"
CMAKEFLAGSALL="$root -GNinja -DCMAKE_BUILD_TYPE=Debug -DFMT_DOC=Off -DFMT_TEST=Off -DFMT_FUZZ=On -DCMAKE_CXX_STANDARD=17"
#builds the fuzzers as one would do if using afl or just making
#binaries for reproducing.
builddir=$here/build-fuzzers-reproduce
mkdir -p $builddir
cd $builddir
CXX="ccache g++" CXXFLAGS="$CXXFLAGSALL" cmake \
$CMAKEFLAGSALL
cmake --build $builddir
#for performance analysis of the fuzzers
builddir=$here/build-fuzzers-perfanalysis
mkdir -p $builddir
cd $builddir
CXX="ccache g++" CXXFLAGS="$CXXFLAGSALL -g" cmake \
$CMAKEFLAGSALL \
-DFMT_FUZZ_LINKMAIN=On \
-DCMAKE_BUILD_TYPE=Release
cmake --build $builddir
#builds the fuzzers as oss-fuzz does
builddir=$here/build-fuzzers-ossfuzz
mkdir -p $builddir
cd $builddir
CXX="clang++" \
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link" cmake \
cmake $CMAKEFLAGSALL \
-DFMT_FUZZ_LINKMAIN=Off \
-DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer"
cmake --build $builddir
#builds fuzzers for local fuzzing with libfuzzer with asan+usan
builddir=$here/build-fuzzers-libfuzzer
mkdir -p $builddir
cd $builddir
CXX="clang++" \
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link,address,undefined" cmake \
cmake $CMAKEFLAGSALL \
-DFMT_FUZZ_LINKMAIN=Off \
-DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer"
cmake --build $builddir
#builds fuzzers for local fuzzing with libfuzzer with asan only
builddir=$here/build-fuzzers-libfuzzer-addr
mkdir -p $builddir
cd $builddir
CXX="clang++" \
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link,undefined" cmake \
cmake $CMAKEFLAGSALL \
-DFMT_FUZZ_LINKMAIN=Off \
-DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer"
cmake --build $builddir
#builds a fast fuzzer for making coverage fast
builddir=$here/build-fuzzers-fast
mkdir -p $builddir
cd $builddir
CXX="clang++" \
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link -O3" cmake \
cmake $CMAKEFLAGSALL \
-DFMT_FUZZ_LINKMAIN=Off \
-DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer" \
-DCMAKE_BUILD_TYPE=Release
cmake --build $builddir
#builds fuzzers for local fuzzing with afl
builddir=$here/build-fuzzers-afl
mkdir -p $builddir
cd $builddir
CXX="afl-g++" \
CXXFLAGS="$CXXFLAGSALL -fsanitize=address,undefined" \
cmake $CMAKEFLAGSALL \
-DFMT_FUZZ_LINKMAIN=On
cmake --build $builddir
echo $me: all good

View File

@ -1,152 +0,0 @@
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <fmt/chrono.h>
#include <cstdint>
#include <limits>
#include <stdexcept>
#include <type_traits>
#include <vector>
#include "fuzzer_common.h"
template <typename Item, typename Ratio>
void invoke_inner(fmt::string_view formatstring, const Item item) {
const std::chrono::duration<Item, Ratio> value(item);
try {
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(formatstring, value);
#else
fmt::memory_buffer buf;
fmt::format_to(buf, formatstring, value);
#endif
} catch (std::exception& /*e*/) {
}
}
// Item is the underlying type for duration (int, long etc)
template <typename Item>
void invoke_outer(const uint8_t* Data, std::size_t Size, const int scaling) {
// always use a fixed location of the data
using fmt_fuzzer::Nfixed;
constexpr auto N = sizeof(Item);
static_assert(N <= Nfixed, "fixed size is too small");
if (Size <= Nfixed + 1) {
return;
}
const Item item = fmt_fuzzer::assignFromBuf<Item>(Data);
// fast forward
Data += Nfixed;
Size -= Nfixed;
// Data is already allocated separately in libFuzzer so reading past
// the end will most likely be detected anyway
const auto formatstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
// doit_impl<Item,std::yocto>(buf.data(),item);
// doit_impl<Item,std::zepto>(buf.data(),item);
switch (scaling) {
case 1:
invoke_inner<Item, std::atto>(formatstring, item);
break;
case 2:
invoke_inner<Item, std::femto>(formatstring, item);
break;
case 3:
invoke_inner<Item, std::pico>(formatstring, item);
break;
case 4:
invoke_inner<Item, std::nano>(formatstring, item);
break;
case 5:
invoke_inner<Item, std::micro>(formatstring, item);
break;
case 6:
invoke_inner<Item, std::milli>(formatstring, item);
break;
case 7:
invoke_inner<Item, std::centi>(formatstring, item);
break;
case 8:
invoke_inner<Item, std::deci>(formatstring, item);
break;
case 9:
invoke_inner<Item, std::deca>(formatstring, item);
break;
case 10:
invoke_inner<Item, std::kilo>(formatstring, item);
break;
case 11:
invoke_inner<Item, std::mega>(formatstring, item);
break;
case 12:
invoke_inner<Item, std::giga>(formatstring, item);
break;
case 13:
invoke_inner<Item, std::tera>(formatstring, item);
break;
case 14:
invoke_inner<Item, std::peta>(formatstring, item);
break;
case 15:
invoke_inner<Item, std::exa>(formatstring, item);
}
// doit_impl<Item,std::zeta>(buf.data(),item);
// doit_impl<Item,std::yotta>(buf.data(),item);
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, std::size_t Size) {
if (Size <= 4) {
return 0;
}
const auto representation = Data[0];
const auto scaling = Data[1];
Data += 2;
Size -= 2;
switch (representation) {
case 1:
invoke_outer<char>(Data, Size, scaling);
break;
case 2:
invoke_outer<unsigned char>(Data, Size, scaling);
break;
case 3:
invoke_outer<signed char>(Data, Size, scaling);
break;
case 4:
invoke_outer<short>(Data, Size, scaling);
break;
case 5:
invoke_outer<unsigned short>(Data, Size, scaling);
break;
case 6:
invoke_outer<int>(Data, Size, scaling);
break;
case 7:
invoke_outer<unsigned int>(Data, Size, scaling);
break;
case 8:
invoke_outer<long>(Data, Size, scaling);
break;
case 9:
invoke_outer<unsigned long>(Data, Size, scaling);
break;
case 10:
invoke_outer<float>(Data, Size, scaling);
break;
case 11:
invoke_outer<double>(Data, Size, scaling);
break;
case 12:
invoke_outer<long double>(Data, Size, scaling);
break;
default:
break;
}
return 0;
}

View File

@ -1,67 +0,0 @@
#ifndef FUZZER_COMMON_H
#define FUZZER_COMMON_H
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <cstdint> // std::uint8_t
#include <cstring> // memcpy
#include <type_traits> // trivially copyable
// one can format to either a string, or a buf. buf is faster,
// but one may be interested in formatting to a string instead to
// verify it works as intended. to avoid a combinatoric explosion,
// select this at compile time instead of dynamically from the fuzz data
#define FMT_FUZZ_FORMAT_TO_STRING 0
// if fmt is given a buffer that is separately allocated,
// chances that address sanitizer detects out of bound reads is
// much higher. However, it slows down the fuzzing.
#define FMT_FUZZ_SEPARATE_ALLOCATION 1
// To let the the fuzzer mutation be efficient at cross pollinating
// between different types, use a fixed size format.
// The same bit pattern, interpreted as another type,
// is likely interesting.
// For this, we must know the size of the largest possible type in use.
// There are some problems on travis, claiming Nfixed is not a constant
// expression which seems to be an issue with older versions of libstdc++
#if _GLIBCXX_RELEASE >= 7
# include <algorithm>
namespace fmt_fuzzer {
constexpr auto Nfixed = std::max(sizeof(long double), sizeof(std::intmax_t));
}
#else
namespace fmt_fuzzer {
constexpr auto Nfixed = 16;
}
#endif
namespace fmt_fuzzer {
// view data as a c char pointer.
template <typename T> inline const char* as_chars(const T* data) {
return static_cast<const char*>(static_cast<const void*>(data));
}
// view data as a byte pointer
template <typename T> inline const std::uint8_t* as_bytes(const T* data) {
return static_cast<const std::uint8_t*>(static_cast<const void*>(data));
}
// blits bytes from Data to form an (assumed trivially constructible) object
// of type Item
template <class Item> inline Item assignFromBuf(const std::uint8_t* Data) {
Item item{};
std::memcpy(&item, Data, sizeof(Item));
return item;
}
// reads a boolean value by looking at the first byte from Data
template <> inline bool assignFromBuf<bool>(const std::uint8_t* Data) {
return !!Data[0];
}
} // namespace fmt_fuzzer
#endif // FUZZER_COMMON_H

View File

@ -1,21 +0,0 @@
#include <cassert>
#include <fstream>
#include <sstream>
#include <vector>
#include "fuzzer_common.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, std::size_t Size);
int main(int argc, char* argv[]) {
for (int i = 1; i < argc; ++i) {
std::ifstream in(argv[i]);
assert(in);
in.seekg(0, std::ios_base::end);
const auto pos = in.tellg();
assert(pos >= 0);
in.seekg(0, std::ios_base::beg);
std::vector<char> buf(static_cast<std::size_t>(pos));
in.read(buf.data(), static_cast<long>(buf.size()));
assert(in.gcount() == pos);
LLVMFuzzerTestOneInput(fmt_fuzzer::as_bytes(buf.data()), buf.size());
}
}

View File

@ -1,128 +0,0 @@
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <fmt/chrono.h>
#include <fmt/core.h>
#include <cstdint>
#include <stdexcept>
#include <type_traits>
#include <vector>
#include "fuzzer_common.h"
template <typename Item1>
void invoke_fmt(const uint8_t* Data, std::size_t Size, unsigned int argsize) {
constexpr auto N1 = sizeof(Item1);
static_assert(N1 <= fmt_fuzzer::Nfixed, "Nfixed too small");
if (Size <= fmt_fuzzer::Nfixed) {
return;
}
const Item1 item1 = fmt_fuzzer::assignFromBuf<Item1>(Data);
Data += fmt_fuzzer::Nfixed;
Size -= fmt_fuzzer::Nfixed;
// how many chars should be used for the argument name?
if (argsize <= 0 || argsize >= Size) {
return;
}
// allocating buffers separately is slower, but increases chances
// of detecting memory errors
#if FMT_FUZZ_SEPARATE_ALLOCATION
std::vector<char> argnamebuffer(argsize);
std::memcpy(argnamebuffer.data(), Data, argsize);
auto argname = fmt::string_view(argnamebuffer.data(), argsize);
#else
auto argname = fmt::string_view(fmt_fuzzer::as_chars(Data), argsize);
#endif
Data += argsize;
Size -= argsize;
#if FMT_FUZZ_SEPARATE_ALLOCATION
// allocates as tight as possible, making it easier to catch buffer overruns.
std::vector<char> fmtstringbuffer(Size);
std::memcpy(fmtstringbuffer.data(), Data, Size);
auto fmtstring = fmt::string_view(fmtstringbuffer.data(), Size);
#else
auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
#endif
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(fmtstring, fmt::arg(argname, item1));
#else
fmt::memory_buffer outbuf;
fmt::format_to(outbuf, fmtstring, fmt::arg(argname, item1));
#endif
}
// for dynamic dispatching to an explicit instantiation
template <typename Callback> void invoke(int index, Callback callback) {
switch (index) {
case 0:
callback(bool{});
break;
case 1:
callback(char{});
break;
case 2:
using sc = signed char;
callback(sc{});
break;
case 3:
using uc = unsigned char;
callback(uc{});
break;
case 4:
callback(short{});
break;
case 5:
using us = unsigned short;
callback(us{});
break;
case 6:
callback(int{});
break;
case 7:
callback(unsigned{});
break;
case 8:
callback(long{});
break;
case 9:
using ul = unsigned long;
callback(ul{});
break;
case 10:
callback(float{});
break;
case 11:
callback(double{});
break;
case 12:
using LD = long double;
callback(LD{});
break;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, std::size_t Size) {
if (Size <= 3) {
return 0;
}
// switch types depending on the first byte of the input
const auto first = Data[0] & 0x0F;
const unsigned int second = (Data[0] & 0xF0) >> 4;
Data++;
Size--;
auto outerfcn = [=](auto param1) {
invoke_fmt<decltype(param1)>(Data, Size, second);
};
try {
invoke(first, outerfcn);
} catch (std::exception& /*e*/) {
}
return 0;
}

View File

@ -1,131 +0,0 @@
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <fmt/core.h>
#include <cstdint>
#include <stdexcept>
#include <type_traits>
#include <vector>
#include <fmt/chrono.h>
#include "fuzzer_common.h"
using fmt_fuzzer::Nfixed;
template <typename Item>
void invoke_fmt(const uint8_t* Data, std::size_t Size) {
constexpr auto N = sizeof(Item);
static_assert(N <= Nfixed, "Nfixed is too small");
if (Size <= Nfixed) {
return;
}
const Item item = fmt_fuzzer::assignFromBuf<Item>(Data);
Data += Nfixed;
Size -= Nfixed;
#if FMT_FUZZ_SEPARATE_ALLOCATION
// allocates as tight as possible, making it easier to catch buffer overruns.
std::vector<char> fmtstringbuffer(Size);
std::memcpy(fmtstringbuffer.data(), Data, Size);
auto fmtstring = fmt::string_view(fmtstringbuffer.data(), Size);
#else
auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
#endif
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(fmtstring, item);
#else
fmt::memory_buffer message;
fmt::format_to(message, fmtstring, item);
#endif
}
void invoke_fmt_time(const uint8_t* Data, std::size_t Size) {
using Item = std::time_t;
constexpr auto N = sizeof(Item);
static_assert(N <= Nfixed, "Nfixed too small");
if (Size <= Nfixed) {
return;
}
const Item item = fmt_fuzzer::assignFromBuf<Item>(Data);
Data += Nfixed;
Size -= Nfixed;
#if FMT_FUZZ_SEPARATE_ALLOCATION
// allocates as tight as possible, making it easier to catch buffer overruns.
std::vector<char> fmtstringbuffer(Size);
std::memcpy(fmtstringbuffer.data(), Data, Size);
auto fmtstring = fmt::string_view(fmtstringbuffer.data(), Size);
#else
auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
#endif
auto* b = std::localtime(&item);
if (b) {
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(fmtstring, *b);
#else
fmt::memory_buffer message;
fmt::format_to(message, fmtstring, *b);
#endif
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, std::size_t Size) {
if (Size <= 3) {
return 0;
}
const auto first = Data[0];
Data++;
Size--;
try {
switch (first) {
case 0:
invoke_fmt<bool>(Data, Size);
break;
case 1:
invoke_fmt<char>(Data, Size);
break;
case 2:
invoke_fmt<unsigned char>(Data, Size);
break;
case 3:
invoke_fmt<signed char>(Data, Size);
break;
case 4:
invoke_fmt<short>(Data, Size);
break;
case 5:
invoke_fmt<unsigned short>(Data, Size);
break;
case 6:
invoke_fmt<int>(Data, Size);
break;
case 7:
invoke_fmt<unsigned int>(Data, Size);
break;
case 8:
invoke_fmt<long>(Data, Size);
break;
case 9:
invoke_fmt<unsigned long>(Data, Size);
break;
case 10:
invoke_fmt<float>(Data, Size);
break;
case 11:
invoke_fmt<double>(Data, Size);
break;
case 12:
invoke_fmt<long double>(Data, Size);
break;
case 13:
invoke_fmt_time(Data, Size);
break;
default:
break;
}
} catch (std::exception& /*e*/) {
}
return 0;
}

View File

@ -1,116 +0,0 @@
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <fmt/format.h>
#include <fmt/printf.h>
#include <cstdint>
#include <stdexcept>
#include "fuzzer_common.h"
using fmt_fuzzer::Nfixed;
template <typename Item1, typename Item2>
void invoke_fmt(const uint8_t* Data, std::size_t Size) {
constexpr auto N1 = sizeof(Item1);
constexpr auto N2 = sizeof(Item2);
static_assert(N1 <= Nfixed, "size1 exceeded");
static_assert(N2 <= Nfixed, "size2 exceeded");
if (Size <= Nfixed + Nfixed) {
return;
}
Item1 item1 = fmt_fuzzer::assignFromBuf<Item1>(Data);
Data += Nfixed;
Size -= Nfixed;
Item2 item2 = fmt_fuzzer::assignFromBuf<Item2>(Data);
Data += Nfixed;
Size -= Nfixed;
auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(fmtstring, item1, item2);
#else
fmt::memory_buffer message;
fmt::format_to(message, fmtstring, item1, item2);
#endif
}
// for dynamic dispatching to an explicit instantiation
template <typename Callback> void invoke(int index, Callback callback) {
switch (index) {
case 0:
callback(bool{});
break;
case 1:
callback(char{});
break;
case 2:
using sc = signed char;
callback(sc{});
break;
case 3:
using uc = unsigned char;
callback(uc{});
break;
case 4:
callback(short{});
break;
case 5:
using us = unsigned short;
callback(us{});
break;
case 6:
callback(int{});
break;
case 7:
callback(unsigned{});
break;
case 8:
callback(long{});
break;
case 9:
using ul = unsigned long;
callback(ul{});
break;
case 10:
callback(float{});
break;
case 11:
callback(double{});
break;
case 12:
using LD = long double;
callback(LD{});
break;
case 13:
using ptr = void*;
callback(ptr{});
break;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, std::size_t Size) {
if (Size <= 3) {
return 0;
}
// switch types depending on the first byte of the input
const auto first = Data[0] & 0x0F;
const auto second = (Data[0] & 0xF0) >> 4;
Data++;
Size--;
auto outer = [=](auto param1) {
auto inner = [=](auto param2) {
invoke_fmt<decltype(param1), decltype(param2)>(Data, Size);
};
invoke(second, inner);
};
try {
invoke(first, outer);
} catch (std::exception& /*e*/) {
}
return 0;
}

View File

@ -1,112 +0,0 @@
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <fmt/format.h>
#include <cstdint>
#include <stdexcept>
#include <type_traits>
#include "fuzzer_common.h"
constexpr auto Nfixed = fmt_fuzzer::Nfixed;
template <typename Item1, typename Item2>
void invoke_fmt(const uint8_t* Data, std::size_t Size) {
constexpr auto N1 = sizeof(Item1);
constexpr auto N2 = sizeof(Item2);
static_assert(N1 <= Nfixed, "size1 exceeded");
static_assert(N2 <= Nfixed, "size2 exceeded");
if (Size <= Nfixed + Nfixed) {
return;
}
const Item1 item1 = fmt_fuzzer::assignFromBuf<Item1>(Data);
Data += Nfixed;
Size -= Nfixed;
const Item2 item2 = fmt_fuzzer::assignFromBuf<Item2>(Data);
Data += Nfixed;
Size -= Nfixed;
auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(fmtstring, item1, item2);
#else
fmt::memory_buffer message;
fmt::format_to(message, fmtstring, item1, item2);
#endif
}
// for dynamic dispatching to an explicit instantiation
template <typename Callback> void invoke(int index, Callback callback) {
switch (index) {
case 0:
callback(bool{});
break;
case 1:
callback(char{});
break;
case 2:
using sc = signed char;
callback(sc{});
break;
case 3:
using uc = unsigned char;
callback(uc{});
break;
case 4:
callback(short{});
break;
case 5:
using us = unsigned short;
callback(us{});
break;
case 6:
callback(int{});
break;
case 7:
callback(unsigned{});
break;
case 8:
callback(long{});
break;
case 9:
using ul = unsigned long;
callback(ul{});
break;
case 10:
callback(float{});
break;
case 11:
callback(double{});
break;
case 12:
using LD = long double;
callback(LD{});
break;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, std::size_t Size) {
if (Size <= 3) {
return 0;
}
// switch types depending on the first byte of the input
const auto first = Data[0] & 0x0F;
const auto second = (Data[0] & 0xF0) >> 4;
Data++;
Size--;
auto outer = [=](auto param1) {
auto inner = [=](auto param2) {
invoke_fmt<decltype(param1), decltype(param2)>(Data, Size);
};
invoke(second, inner);
};
try {
invoke(first, outer);
} catch (std::exception& /*e*/) {
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,75 +0,0 @@
// Formatting library for C++ - Grisu tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/format.h"
#include "gtest.h"
static bool reported_skipped;
#undef TEST
#define TEST(test_fixture, test_name) \
void test_fixture##test_name(); \
GTEST_TEST(test_fixture, test_name) { \
if (FMT_USE_GRISU) { \
test_fixture##test_name(); \
} else if (!reported_skipped) { \
reported_skipped = true; \
fmt::print("Skipping Grisu tests.\n"); \
} \
} \
void test_fixture##test_name()
TEST(GrisuTest, NaN) {
auto nan = std::numeric_limits<double>::quiet_NaN();
EXPECT_EQ("nan", fmt::format("{}", nan));
EXPECT_EQ("-nan", fmt::format("{}", -nan));
}
TEST(GrisuTest, Inf) {
auto inf = std::numeric_limits<double>::infinity();
EXPECT_EQ("inf", fmt::format("{}", inf));
EXPECT_EQ("-inf", fmt::format("{}", -inf));
}
TEST(GrisuTest, Zero) { EXPECT_EQ("0.0", fmt::format("{}", 0.0)); }
TEST(GrisuTest, Round) {
EXPECT_EQ("1.9156918820264798e-56",
fmt::format("{}", 1.9156918820264798e-56));
EXPECT_EQ("0.0000", fmt::format("{:.4f}", 7.2809479766055470e-15));
}
TEST(GrisuTest, Prettify) {
EXPECT_EQ("0.0001", fmt::format("{}", 1e-4));
EXPECT_EQ("1e-05", fmt::format("{}", 1e-5));
EXPECT_EQ("9.999e-05", fmt::format("{}", 9.999e-5));
EXPECT_EQ("10000000000.0", fmt::format("{}", 1e10));
EXPECT_EQ("100000000000.0", fmt::format("{}", 1e11));
EXPECT_EQ("12340000000.0", fmt::format("{}", 1234e7));
EXPECT_EQ("12.34", fmt::format("{}", 1234e-2));
EXPECT_EQ("0.001234", fmt::format("{}", 1234e-6));
EXPECT_EQ("0.1", fmt::format("{}", 0.1f));
EXPECT_EQ("0.10000000149011612", fmt::format("{}", double(0.1f)));
}
TEST(GrisuTest, ZeroPrecision) { EXPECT_EQ("1", fmt::format("{:.0}", 1.0)); }
TEST(GrisuTest, Fallback) {
EXPECT_EQ("1e+23", fmt::format("{}", 1e23));
EXPECT_EQ("9e-265", fmt::format("{}", 9e-265));
EXPECT_EQ("5.423717798060526e+125",
fmt::format("{}", 5.423717798060526e+125));
EXPECT_EQ("1.372371880954233e-288",
fmt::format("{}", 1.372371880954233e-288));
EXPECT_EQ("55388492.622190244", fmt::format("{}", 55388492.622190244));
EXPECT_EQ("2.2506787569811123e-253",
fmt::format("{}", 2.2506787569811123e-253));
EXPECT_EQ("1103618912042992.8", fmt::format("{}", 1103618912042992.8));
// pow(2, -25) - assymetric boundaries:
EXPECT_EQ("2.9802322387695312e-08",
fmt::format("{}", 2.9802322387695312e-08));
}

View File

@ -7,22 +7,23 @@
#include "gtest-extra.h"
#include <gtest/gtest-spi.h>
#include <algorithm>
#include <cstring>
#include <memory>
#include <algorithm>
#include <stdexcept>
#include <gtest/gtest-spi.h>
#if defined(_WIN32) && !defined(__MINGW32__)
# include <crtdbg.h> // for _CrtSetReportMode
#endif // _WIN32
# include <crtdbg.h> // for _CrtSetReportMode
#endif // _WIN32
#include "util.h"
using testing::internal::scoped_ptr;
namespace {
// This is used to suppress coverity warnings about untrusted values.
std::string sanitize(const std::string& s) {
std::string sanitize(const std::string &s) {
std::string result;
for (std::string::const_iterator i = s.begin(), end = s.end(); i != end; ++i)
result.push_back(static_cast<char>(*i & 0xff));
@ -52,9 +53,11 @@ int SingleEvaluationTest::b_;
void do_nothing() {}
FMT_NORETURN void throw_exception() { throw std::runtime_error("test"); }
void throw_exception() {
throw std::runtime_error("test");
}
FMT_NORETURN void throw_system_error() {
void throw_system_error() {
throw fmt::system_error(EDOM, "test");
}
@ -69,42 +72,43 @@ TEST_F(SingleEvaluationTest, FailedEXPECT_THROW_MSG) {
// Tests that when EXPECT_SYSTEM_ERROR fails, it evaluates its message argument
// exactly once.
TEST_F(SingleEvaluationTest, FailedEXPECT_SYSTEM_ERROR) {
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, p_++),
"01234");
EXPECT_NONFATAL_FAILURE(
EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, p_++), "01234");
EXPECT_EQ(s_ + 1, p_);
}
// Tests that when EXPECT_WRITE fails, it evaluates its message argument
// exactly once.
TEST_F(SingleEvaluationTest, FailedEXPECT_WRITE) {
EXPECT_NONFATAL_FAILURE(
EXPECT_WRITE(stdout, std::printf("test"), p_++), "01234");
EXPECT_EQ(s_ + 1, p_);
}
// Tests that assertion arguments are evaluated exactly once.
TEST_F(SingleEvaluationTest, ExceptionTests) {
// successful EXPECT_THROW_MSG
EXPECT_THROW_MSG(
{ // NOLINT
a_++;
throw_exception();
},
std::exception, (b_++, "test"));
EXPECT_THROW_MSG({ // NOLINT
a_++;
throw_exception();
}, std::exception, (b_++, "test"));
EXPECT_EQ(1, a_);
EXPECT_EQ(1, b_);
// failed EXPECT_THROW_MSG, throws different type
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(
{ // NOLINT
a_++;
throw_exception();
},
std::logic_error, (b_++, "test")),
"throws a different type");
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG({ // NOLINT
a_++;
throw_exception();
}, std::logic_error, (b_++, "test")), "throws a different type");
EXPECT_EQ(2, a_);
EXPECT_EQ(2, b_);
// failed EXPECT_THROW_MSG, throws an exception with different message
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(
{ // NOLINT
a_++;
throw_exception();
},
std::exception, (b_++, "other")),
"throws an exception with a different message");
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG({ // NOLINT
a_++;
throw_exception();
}, std::exception, (b_++, "other")),
"throws an exception with a different message");
EXPECT_EQ(3, a_);
EXPECT_EQ(3, b_);
@ -117,95 +121,56 @@ TEST_F(SingleEvaluationTest, ExceptionTests) {
TEST_F(SingleEvaluationTest, SystemErrorTests) {
// successful EXPECT_SYSTEM_ERROR
EXPECT_SYSTEM_ERROR(
{ // NOLINT
a_++;
throw_system_error();
},
EDOM, (b_++, "test"));
EXPECT_SYSTEM_ERROR({ // NOLINT
a_++;
throw_system_error();
}, EDOM, (b_++, "test"));
EXPECT_EQ(1, a_);
EXPECT_EQ(1, b_);
// failed EXPECT_SYSTEM_ERROR, throws different type
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(
{ // NOLINT
a_++;
throw_exception();
},
EDOM, (b_++, "test")),
"throws a different type");
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR({ // NOLINT
a_++;
throw_exception();
}, EDOM, (b_++, "test")), "throws a different type");
EXPECT_EQ(2, a_);
EXPECT_EQ(2, b_);
// failed EXPECT_SYSTEM_ERROR, throws an exception with different message
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(
{ // NOLINT
a_++;
throw_system_error();
},
EDOM, (b_++, "other")),
"throws an exception with a different message");
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR({ // NOLINT
a_++;
throw_system_error();
}, EDOM, (b_++, "other")),
"throws an exception with a different message");
EXPECT_EQ(3, a_);
EXPECT_EQ(3, b_);
// failed EXPECT_SYSTEM_ERROR, throws nothing
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(a_++, EDOM, (b_++, "test")),
"throws nothing");
EXPECT_NONFATAL_FAILURE(
EXPECT_SYSTEM_ERROR(a_++, EDOM, (b_++, "test")), "throws nothing");
EXPECT_EQ(4, a_);
EXPECT_EQ(4, b_);
}
#if FMT_USE_FCNTL
// Tests that when EXPECT_WRITE fails, it evaluates its message argument
// exactly once.
TEST_F(SingleEvaluationTest, FailedEXPECT_WRITE) {
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), p_++),
"01234");
EXPECT_EQ(s_ + 1, p_);
}
// Tests that assertion arguments are evaluated exactly once.
TEST_F(SingleEvaluationTest, WriteTests) {
// successful EXPECT_WRITE
EXPECT_WRITE(stdout,
{ // NOLINT
a_++;
std::printf("test");
},
(b_++, "test"));
EXPECT_WRITE(stdout, { // NOLINT
a_++;
std::printf("test");
}, (b_++, "test"));
EXPECT_EQ(1, a_);
EXPECT_EQ(1, b_);
// failed EXPECT_WRITE
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout,
{ // NOLINT
a_++;
std::printf("test");
},
(b_++, "other")),
"Actual: test");
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, { // NOLINT
a_++;
std::printf("test");
}, (b_++, "other")), "Actual: test");
EXPECT_EQ(2, a_);
EXPECT_EQ(2, b_);
}
// Tests EXPECT_WRITE.
TEST(ExpectTest, EXPECT_WRITE) {
EXPECT_WRITE(stdout, do_nothing(), "");
EXPECT_WRITE(stdout, std::printf("test"), "test");
EXPECT_WRITE(stderr, std::fprintf(stderr, "test"), "test");
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("that"), "this"),
"Expected: this\n"
" Actual: that");
}
TEST(StreamingAssertionsTest, EXPECT_WRITE) {
EXPECT_WRITE(stdout, std::printf("test"), "test") << "unexpected failure";
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), "other")
<< "expected failure",
"expected failure");
}
#endif // FMT_USE_FCNTL
// Tests that the compiler will not complain about unreachable code in the
// EXPECT_THROW_MSG macro.
TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) {
@ -214,8 +179,8 @@ TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) {
EXPECT_THROW_MSG(throw runtime_error(""), runtime_error, "");
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(n++, runtime_error, ""), "");
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(throw 1, runtime_error, ""), "");
EXPECT_NONFATAL_FAILURE(
EXPECT_THROW_MSG(throw runtime_error("a"), runtime_error, "b"), "");
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(
throw runtime_error("a"), runtime_error, "b"), "");
}
// Tests that the compiler will not complain about unreachable code in the
@ -225,9 +190,8 @@ TEST(ExpectSystemErrorTest, DoesNotGenerateUnreachableCodeWarning) {
EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "test"), EDOM, "test");
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(n++, EDOM, ""), "");
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw 1, EDOM, ""), "");
EXPECT_NONFATAL_FAILURE(
EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "aaa"), EDOM, "bbb"),
"");
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(
throw fmt::system_error(EDOM, "aaa"), EDOM, "bbb"), "");
}
TEST(AssertionSyntaxTest, ExceptionAssertionBehavesLikeSingleStatement) {
@ -299,13 +263,23 @@ TEST(ExpectTest, EXPECT_SYSTEM_ERROR) {
format_system_error(EDOM, "test")));
}
// Tests EXPECT_WRITE.
TEST(ExpectTest, EXPECT_WRITE) {
EXPECT_WRITE(stdout, do_nothing(), "");
EXPECT_WRITE(stdout, std::printf("test"), "test");
EXPECT_WRITE(stderr, std::fprintf(stderr, "test"), "test");
EXPECT_NONFATAL_FAILURE(
EXPECT_WRITE(stdout, std::printf("that"), "this"),
"Expected: this\n"
" Actual: that");
}
TEST(StreamingAssertionsTest, EXPECT_THROW_MSG) {
EXPECT_THROW_MSG(throw_exception(), std::exception, "test")
<< "unexpected failure";
EXPECT_NONFATAL_FAILURE(
EXPECT_THROW_MSG(throw_exception(), std::exception, "other")
<< "expected failure",
"expected failure");
<< "expected failure", "expected failure");
}
TEST(StreamingAssertionsTest, EXPECT_SYSTEM_ERROR) {
@ -313,8 +287,15 @@ TEST(StreamingAssertionsTest, EXPECT_SYSTEM_ERROR) {
<< "unexpected failure";
EXPECT_NONFATAL_FAILURE(
EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "other")
<< "expected failure",
"expected failure");
<< "expected failure", "expected failure");
}
TEST(StreamingAssertionsTest, EXPECT_WRITE) {
EXPECT_WRITE(stdout, std::printf("test"), "test")
<< "unexpected failure";
EXPECT_NONFATAL_FAILURE(
EXPECT_WRITE(stdout, std::printf("test"), "other")
<< "expected failure", "expected failure");
}
TEST(UtilTest, FormatSystemError) {
@ -323,7 +304,7 @@ TEST(UtilTest, FormatSystemError) {
EXPECT_EQ(to_string(out), format_system_error(EDOM, "test message"));
}
#if FMT_USE_FCNTL
#if FMT_USE_FILE_DESCRIPTORS
using fmt::buffered_file;
using fmt::error_code;
@ -359,10 +340,10 @@ TEST(OutputRedirectTest, FlushErrorInCtor) {
// Put a character in a file buffer.
EXPECT_EQ('x', fputc('x', f.get()));
FMT_POSIX(close(write_fd));
std::unique_ptr<OutputRedirect> redir{nullptr};
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())), EBADF,
"cannot flush stream");
redir.reset(nullptr);
scoped_ptr<OutputRedirect> redir{FMT_NULL};
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
EBADF, "cannot flush stream");
redir.reset(FMT_NULL);
write_copy.dup2(write_fd); // "undo" close or dtor will fail
}
@ -371,10 +352,9 @@ TEST(OutputRedirectTest, DupErrorInCtor) {
int fd = (f.fileno)();
file copy = file::dup(fd);
FMT_POSIX(close(fd));
std::unique_ptr<OutputRedirect> redir{nullptr};
EXPECT_SYSTEM_ERROR_NOASSERT(
redir.reset(new OutputRedirect(f.get())), EBADF,
fmt::format("cannot duplicate file descriptor {}", fd));
scoped_ptr<OutputRedirect> redir{FMT_NULL};
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
EBADF, fmt::format("cannot duplicate file descriptor {}", fd));
copy.dup2(fd); // "undo" close or dtor will fail
}
@ -403,8 +383,8 @@ TEST(OutputRedirectTest, FlushErrorInRestoreAndRead) {
// Put a character in a file buffer.
EXPECT_EQ('x', fputc('x', f.get()));
FMT_POSIX(close(write_fd));
EXPECT_SYSTEM_ERROR_NOASSERT(redir.restore_and_read(), EBADF,
"cannot flush stream");
EXPECT_SYSTEM_ERROR_NOASSERT(redir.restore_and_read(),
EBADF, "cannot flush stream");
write_copy.dup2(write_fd); // "undo" close or dtor will fail
}
@ -414,20 +394,18 @@ TEST(OutputRedirectTest, ErrorInDtor) {
int write_fd = write_end.descriptor();
file write_copy = write_end.dup(write_fd);
buffered_file f = write_end.fdopen("w");
std::unique_ptr<OutputRedirect> redir(new OutputRedirect(f.get()));
scoped_ptr<OutputRedirect> redir(new OutputRedirect(f.get()));
// Put a character in a file buffer.
EXPECT_EQ('x', fputc('x', f.get()));
EXPECT_WRITE(stderr,
{
// The close function must be called inside EXPECT_WRITE,
// otherwise the system may recycle closed file descriptor when
// redirecting the output in EXPECT_STDERR and the second close
// will break output redirection.
FMT_POSIX(close(write_fd));
SUPPRESS_ASSERT(redir.reset(nullptr));
},
format_system_error(EBADF, "cannot flush stream"));
write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail
EXPECT_WRITE(stderr, {
// The close function must be called inside EXPECT_WRITE, otherwise
// the system may recycle closed file descriptor when redirecting the
// output in EXPECT_STDERR and the second close will break output
// redirection.
FMT_POSIX(close(write_fd));
SUPPRESS_ASSERT(redir.reset(FMT_NULL));
}, format_system_error(EBADF, "cannot flush stream"));
write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail
}
#endif // FMT_USE_FILE_DESCRIPTORS

View File

@ -7,28 +7,30 @@
#include "gtest-extra.h"
#if FMT_USE_FCNTL
#if FMT_USE_FILE_DESCRIPTORS
using fmt::file;
void OutputRedirect::flush() {
# if EOF != -1
# error "FMT_RETRY assumes return value of -1 indicating failure"
# endif
#if EOF != -1
# error "FMT_RETRY assumes return value of -1 indicating failure"
#endif
int result = 0;
FMT_RETRY(result, fflush(file_));
if (result != 0) throw fmt::system_error(errno, "cannot flush stream");
if (result != 0)
throw fmt::system_error(errno, "cannot flush stream");
}
void OutputRedirect::restore() {
if (original_.descriptor() == -1) return; // Already restored.
if (original_.descriptor() == -1)
return; // Already restored.
flush();
// Restore the original file.
original_.dup2(FMT_POSIX(fileno(file_)));
original_.close();
}
OutputRedirect::OutputRedirect(FILE* f) : file_(f) {
OutputRedirect::OutputRedirect(FILE *f) : file_(f) {
flush();
int fd = FMT_POSIX(fileno(f));
// Create a file object referring to the original file.
@ -43,7 +45,7 @@ OutputRedirect::OutputRedirect(FILE* f) : file_(f) {
OutputRedirect::~OutputRedirect() FMT_NOEXCEPT {
try {
restore();
} catch (const std::exception& e) {
} catch (const std::exception &e) {
std::fputs(e.what(), stderr);
}
}
@ -54,7 +56,8 @@ std::string OutputRedirect::restore_and_read() {
// Read everything from the pipe.
std::string content;
if (read_end_.descriptor() == -1) return content; // Already read.
if (read_end_.descriptor() == -1)
return content; // Already read.
enum { BUFFER_SIZE = 4096 };
char buffer[BUFFER_SIZE];
std::size_t count = 0;
@ -66,7 +69,7 @@ std::string OutputRedirect::restore_and_read() {
return content;
}
std::string read(file& f, std::size_t count) {
std::string read(file &f, std::size_t count) {
std::string buffer(count, '\0');
std::size_t n = 0, offset = 0;
do {
@ -78,7 +81,7 @@ std::string read(file& f, std::size_t count) {
return buffer;
}
#endif // FMT_USE_FCNTL
#endif // FMT_USE_FILE_DESCRIPTORS
std::string format_system_error(int error_code, fmt::string_view message) {
fmt::memory_buffer out;

View File

@ -10,59 +10,70 @@
#include <string>
#include "gmock.h"
#include "fmt/os.h"
#include "fmt/core.h"
#ifndef FMT_USE_FILE_DESCRIPTORS
# define FMT_USE_FILE_DESCRIPTORS 0
#endif
#if FMT_USE_FILE_DESCRIPTORS
# include "fmt/posix.h"
#endif
#define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
std::string gtest_expected_message = expected_message; \
bool gtest_caught_expected = false; \
try { \
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
} catch (expected_exception const& e) { \
if (gtest_expected_message != e.what()) { \
gtest_ar << #statement \
" throws an exception with a different message.\n" \
<< "Expected: " << gtest_expected_message << "\n" \
<< " Actual: " << e.what(); \
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
} \
gtest_caught_expected = true; \
} catch (...) { \
gtest_ar << "Expected: " #statement \
" throws an exception of type " #expected_exception \
".\n Actual: it throws a different type."; \
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
} \
if (!gtest_caught_expected) { \
gtest_ar << "Expected: " #statement \
" throws an exception of type " #expected_exception \
".\n Actual: it throws nothing."; \
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
} \
} else \
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \
: fail(gtest_ar.failure_message())
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
std::string gtest_expected_message = expected_message; \
bool gtest_caught_expected = false; \
try { \
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
} \
catch (expected_exception const& e) { \
if (gtest_expected_message != e.what()) { \
gtest_ar \
<< #statement " throws an exception with a different message.\n" \
<< "Expected: " << gtest_expected_message << "\n" \
<< " Actual: " << e.what(); \
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
} \
gtest_caught_expected = true; \
} \
catch (...) { \
gtest_ar << \
"Expected: " #statement " throws an exception of type " \
#expected_exception ".\n Actual: it throws a different type."; \
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
} \
if (!gtest_caught_expected) { \
gtest_ar << \
"Expected: " #statement " throws an exception of type " \
#expected_exception ".\n Actual: it throws nothing."; \
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
} \
} else \
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
fail(gtest_ar.failure_message())
// Tests that the statement throws the expected exception and the exception's
// what() method returns expected message.
#define EXPECT_THROW_MSG(statement, expected_exception, expected_message) \
FMT_TEST_THROW_(statement, expected_exception, expected_message, \
GTEST_NONFATAL_FAILURE_)
FMT_TEST_THROW_(statement, expected_exception, \
expected_message, GTEST_NONFATAL_FAILURE_)
std::string format_system_error(int error_code, fmt::string_view message);
#define EXPECT_SYSTEM_ERROR(statement, error_code, message) \
EXPECT_THROW_MSG(statement, fmt::system_error, \
format_system_error(error_code, message))
EXPECT_THROW_MSG(statement, fmt::system_error, \
format_system_error(error_code, message))
#if FMT_USE_FCNTL
#if FMT_USE_FILE_DESCRIPTORS
// Captures file output by redirecting it to a pipe.
// The output it can handle is limited by the pipe capacity.
class OutputRedirect {
private:
FILE* file_;
FILE *file_;
fmt::file original_; // Original file passed to redirector.
fmt::file read_end_; // Read end of the pipe where the output is redirected.
@ -72,7 +83,7 @@ class OutputRedirect {
void restore();
public:
explicit OutputRedirect(FILE* file);
explicit OutputRedirect(FILE *file);
~OutputRedirect() FMT_NOEXCEPT;
// Restores the original file, reads output from the pipe into a string
@ -80,28 +91,29 @@ class OutputRedirect {
std::string restore_and_read();
};
# define FMT_TEST_WRITE_(statement, expected_output, file, fail) \
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
std::string gtest_expected_output = expected_output; \
OutputRedirect gtest_redir(file); \
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
std::string gtest_output = gtest_redir.restore_and_read(); \
if (gtest_output != gtest_expected_output) { \
gtest_ar << #statement " produces different output.\n" \
<< "Expected: " << gtest_expected_output << "\n" \
<< " Actual: " << gtest_output; \
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
} \
} else \
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \
: fail(gtest_ar.failure_message())
#define FMT_TEST_WRITE_(statement, expected_output, file, fail) \
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
std::string gtest_expected_output = expected_output; \
OutputRedirect gtest_redir(file); \
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
std::string gtest_output = gtest_redir.restore_and_read(); \
if (gtest_output != gtest_expected_output) { \
gtest_ar \
<< #statement " produces different output.\n" \
<< "Expected: " << gtest_expected_output << "\n" \
<< " Actual: " << gtest_output; \
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
} \
} else \
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
fail(gtest_ar.failure_message())
// Tests that the statement writes the expected output to file.
# define EXPECT_WRITE(file, statement, expected_output) \
#define EXPECT_WRITE(file, statement, expected_output) \
FMT_TEST_WRITE_(statement, expected_output, file, GTEST_NONFATAL_FAILURE_)
# ifdef _MSC_VER
#ifdef _MSC_VER
// Suppresses Windows assertions on invalid file descriptors, making
// POSIX functions return proper error codes instead of crashing on Windows.
@ -110,45 +122,40 @@ class SuppressAssert {
_invalid_parameter_handler original_handler_;
int original_report_mode_;
static void handle_invalid_parameter(const wchar_t*, const wchar_t*,
const wchar_t*, unsigned, uintptr_t) {}
static void handle_invalid_parameter(const wchar_t *,
const wchar_t *, const wchar_t *, unsigned , uintptr_t) {}
public:
SuppressAssert()
: original_handler_(
_set_invalid_parameter_handler(handle_invalid_parameter)),
original_report_mode_(_CrtSetReportMode(_CRT_ASSERT, 0)) {}
: original_handler_(_set_invalid_parameter_handler(handle_invalid_parameter)),
original_report_mode_(_CrtSetReportMode(_CRT_ASSERT, 0)) {
}
~SuppressAssert() {
_set_invalid_parameter_handler(original_handler_);
_CrtSetReportMode(_CRT_ASSERT, original_report_mode_);
}
};
# define SUPPRESS_ASSERT(statement) \
{ \
SuppressAssert sa; \
statement; \
}
# else
# define SUPPRESS_ASSERT(statement) statement
# endif // _MSC_VER
# define SUPPRESS_ASSERT(statement) { SuppressAssert sa; statement; }
#else
# define SUPPRESS_ASSERT(statement) statement
#endif // _MSC_VER
# define EXPECT_SYSTEM_ERROR_NOASSERT(statement, error_code, message) \
EXPECT_SYSTEM_ERROR(SUPPRESS_ASSERT(statement), error_code, message)
#define EXPECT_SYSTEM_ERROR_NOASSERT(statement, error_code, message) \
EXPECT_SYSTEM_ERROR(SUPPRESS_ASSERT(statement), error_code, message)
// Attempts to read count characters from a file.
std::string read(fmt::file& f, std::size_t count);
std::string read(fmt::file &f, std::size_t count);
# define EXPECT_READ(file, expected_content) \
EXPECT_EQ(expected_content, read(file, std::strlen(expected_content)))
#define EXPECT_READ(file, expected_content) \
EXPECT_EQ(expected_content, read(file, std::strlen(expected_content)))
#else
# define EXPECT_WRITE(file, statement, expected_output) SUCCEED()
#endif // FMT_USE_FCNTL
#endif // FMT_USE_FILE_DESCRIPTORS
template <typename Mock> struct ScopedMock : testing::StrictMock<Mock> {
template <typename Mock>
struct ScopedMock : testing::StrictMock<Mock> {
ScopedMock() { Mock::instance = this; }
~ScopedMock() { Mock::instance = nullptr; }
~ScopedMock() { Mock::instance = FMT_NULL; }
};
#endif // FMT_GTEST_EXTRA_H_

View File

@ -8,82 +8,27 @@
#include "fmt/locale.h"
#include "gmock.h"
using fmt::internal::max_value;
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
template <typename Char> struct numpunct : std::numpunct<Char> {
template <typename Char>
struct numpunct : std::numpunct<Char> {
protected:
Char do_decimal_point() const FMT_OVERRIDE { return '?'; }
std::string do_grouping() const FMT_OVERRIDE { return "\03"; }
Char do_thousands_sep() const FMT_OVERRIDE { return '~'; }
};
template <typename Char> struct no_grouping : std::numpunct<Char> {
protected:
Char do_decimal_point() const FMT_OVERRIDE { return '.'; }
std::string do_grouping() const FMT_OVERRIDE { return ""; }
Char do_thousands_sep() const FMT_OVERRIDE { return ','; }
};
template <typename Char> struct special_grouping : std::numpunct<Char> {
protected:
Char do_decimal_point() const FMT_OVERRIDE { return '.'; }
std::string do_grouping() const FMT_OVERRIDE { return "\03\02"; }
Char do_thousands_sep() const FMT_OVERRIDE { return ','; }
};
template <typename Char> struct small_grouping : std::numpunct<Char> {
protected:
Char do_decimal_point() const FMT_OVERRIDE { return '.'; }
std::string do_grouping() const FMT_OVERRIDE { return "\01"; }
Char do_thousands_sep() const FMT_OVERRIDE { return ','; }
};
TEST(LocaleTest, DoubleDecimalPoint) {
std::locale loc(std::locale(), new numpunct<char>());
EXPECT_EQ("1?23", fmt::format(loc, "{:n}", 1.23));
}
TEST(LocaleTest, Format) {
std::locale loc(std::locale(), new numpunct<char>());
EXPECT_EQ("1234567", fmt::format(std::locale(), "{:n}", 1234567));
EXPECT_EQ("1,234,567", fmt::format(std::locale(), "{:n}", 1234567));
EXPECT_EQ("1~234~567", fmt::format(loc, "{:n}", 1234567));
fmt::format_arg_store<fmt::format_context, int> as{1234567};
EXPECT_EQ("1~234~567", fmt::vformat(loc, "{:n}", fmt::format_args(as)));
std::string s;
fmt::format_to(std::back_inserter(s), loc, "{:n}", 1234567);
EXPECT_EQ("1~234~567", s);
std::locale no_grouping_loc(std::locale(), new no_grouping<char>());
EXPECT_EQ("1234567", fmt::format(no_grouping_loc, "{:n}", 1234567));
std::locale special_grouping_loc(std::locale(), new special_grouping<char>());
EXPECT_EQ("1,23,45,678", fmt::format(special_grouping_loc, "{:n}", 12345678));
std::locale small_grouping_loc(std::locale(), new small_grouping<char>());
EXPECT_EQ("4,2,9,4,9,6,7,2,9,5",
fmt::format(small_grouping_loc, "{:n}", max_value<uint32_t>()));
}
TEST(LocaleTest, WFormat) {
std::locale loc(std::locale(), new numpunct<wchar_t>());
EXPECT_EQ(L"1234567", fmt::format(std::locale(), L"{:n}", 1234567));
EXPECT_EQ(L"1,234,567", fmt::format(std::locale(), L"{:n}", 1234567));
EXPECT_EQ(L"1~234~567", fmt::format(loc, L"{:n}", 1234567));
fmt::format_arg_store<fmt::wformat_context, int> as{1234567};
EXPECT_EQ(L"1~234~567", fmt::vformat(loc, L"{:n}", fmt::wformat_args(as)));
EXPECT_EQ(L"1234567", fmt::format(std::locale("C"), L"{:n}", 1234567));
std::locale no_grouping_loc(std::locale(), new no_grouping<wchar_t>());
EXPECT_EQ(L"1234567", fmt::format(no_grouping_loc, L"{:n}", 1234567));
std::locale special_grouping_loc(std::locale(),
new special_grouping<wchar_t>());
EXPECT_EQ(L"1,23,45,678",
fmt::format(special_grouping_loc, L"{:n}", 12345678));
std::locale small_grouping_loc(std::locale(), new small_grouping<wchar_t>());
EXPECT_EQ(L"4,2,9,4,9,6,7,2,9,5",
fmt::format(small_grouping_loc, L"{:n}", max_value<uint32_t>()));
}
#endif // FMT_STATIC_THOUSANDS_SEPARATOR

View File

@ -8,51 +8,53 @@
#ifndef FMT_MOCK_ALLOCATOR_H_
#define FMT_MOCK_ALLOCATOR_H_
#include "fmt/format.h"
#include "gmock.h"
#include "fmt/format.h"
template <typename T> class mock_allocator {
template <typename T>
class mock_allocator {
public:
mock_allocator() {}
mock_allocator(const mock_allocator&) {}
mock_allocator(const mock_allocator &) {}
typedef T value_type;
MOCK_METHOD1_T(allocate, T*(std::size_t n));
MOCK_METHOD2_T(deallocate, void(T* p, std::size_t n));
MOCK_METHOD1_T(allocate, T* (std::size_t n));
MOCK_METHOD2_T(deallocate, void (T* p, std::size_t n));
};
template <typename Allocator> class allocator_ref {
template <typename Allocator>
class allocator_ref {
private:
Allocator* alloc_;
Allocator *alloc_;
void move(allocator_ref& other) {
void move(allocator_ref &other) {
alloc_ = other.alloc_;
other.alloc_ = nullptr;
other.alloc_ = FMT_NULL;
}
public:
typedef typename Allocator::value_type value_type;
explicit allocator_ref(Allocator* alloc = nullptr) : alloc_(alloc) {}
explicit allocator_ref(Allocator *alloc = FMT_NULL) : alloc_(alloc) {}
allocator_ref(const allocator_ref& other) : alloc_(other.alloc_) {}
allocator_ref(allocator_ref&& other) { move(other); }
allocator_ref(const allocator_ref &other) : alloc_(other.alloc_) {}
allocator_ref(allocator_ref &&other) { move(other); }
allocator_ref& operator=(allocator_ref&& other) {
allocator_ref& operator=(allocator_ref &&other) {
assert(this != &other);
move(other);
return *this;
}
allocator_ref& operator=(const allocator_ref& other) {
allocator_ref& operator=(const allocator_ref &other) {
alloc_ = other.alloc_;
return *this;
}
public:
Allocator* get() const { return alloc_; }
Allocator *get() const { return alloc_; }
value_type* allocate(std::size_t n) {
return std::allocator_traits<Allocator>::allocate(*alloc_, n);
return fmt::internal::allocate(*alloc_, n);
}
void deallocate(value_type* p, std::size_t n) { alloc_->deallocate(p, n); }
};

View File

@ -6,21 +6,6 @@
// For the license information refer to format.h.
#define FMT_STRING_ALIAS 1
#include "fmt/format.h"
struct test {};
// Test that there is no issues with specializations when fmt/ostream.h is
// included after fmt/format.h.
namespace fmt {
template <> struct formatter<test> : formatter<int> {
template <typename FormatContext>
typename FormatContext::iterator format(const test&, FormatContext& ctx) {
return formatter<int>::format(42, ctx);
}
};
} // namespace fmt
#include "fmt/ostream.h"
#include <sstream>
@ -31,56 +16,51 @@ template <> struct formatter<test> : formatter<int> {
using fmt::format;
using fmt::format_error;
static std::ostream& operator<<(std::ostream& os, const Date& d) {
static std::ostream &operator<<(std::ostream &os, const Date &d) {
os << d.year() << '-' << d.month() << '-' << d.day();
return os;
}
static std::wostream& operator<<(std::wostream& os, const Date& d) {
static std::wostream &operator<<(std::wostream &os, const Date &d) {
os << d.year() << L'-' << d.month() << L'-' << d.day();
return os;
}
// Make sure that overloaded comma operators do no harm to is_streamable.
struct type_with_comma_op {};
template <typename T> void operator,(type_with_comma_op, const T&);
template <typename T> type_with_comma_op operator<<(T&, const Date&);
enum streamable_enum {};
static std::ostream& operator<<(std::ostream& os, streamable_enum) {
return os << "streamable_enum";
enum TestEnum {};
static std::ostream &operator<<(std::ostream &os, TestEnum) {
return os << "TestEnum";
}
static std::wostream& operator<<(std::wostream& os, streamable_enum) {
return os << L"streamable_enum";
static std::wostream &operator<<(std::wostream &os, TestEnum) {
return os << L"TestEnum";
}
enum unstreamable_enum {};
enum TestEnum2 {A};
TEST(OStreamTest, Enum) {
EXPECT_EQ("streamable_enum", fmt::format("{}", streamable_enum()));
EXPECT_EQ("0", fmt::format("{}", unstreamable_enum()));
EXPECT_EQ(L"streamable_enum", fmt::format(L"{}", streamable_enum()));
EXPECT_EQ(L"0", fmt::format(L"{}", unstreamable_enum()));
EXPECT_FALSE((fmt::convert_to_int<TestEnum, char>::value));
EXPECT_EQ("TestEnum", fmt::format("{}", TestEnum()));
EXPECT_EQ("0", fmt::format("{}", A));
EXPECT_FALSE((fmt::convert_to_int<TestEnum, wchar_t>::value));
EXPECT_EQ(L"TestEnum", fmt::format(L"{}", TestEnum()));
EXPECT_EQ(L"0", fmt::format(L"{}", A));
}
using range = fmt::buffer_range<char>;
typedef fmt::back_insert_range<fmt::internal::buffer> range;
struct test_arg_formatter : fmt::arg_formatter<range> {
fmt::format_parse_context parse_ctx;
test_arg_formatter(fmt::format_context& ctx, fmt::format_specs& s)
: fmt::arg_formatter<range>(ctx, &parse_ctx, &s), parse_ctx("") {}
struct test_arg_formatter: fmt::arg_formatter<range> {
test_arg_formatter(fmt::format_context &ctx, fmt::format_specs &s)
: fmt::arg_formatter<range>(ctx, &s) {}
};
TEST(OStreamTest, CustomArg) {
fmt::memory_buffer buffer;
fmt::internal::buffer<char>& base = buffer;
fmt::format_context ctx(std::back_inserter(base), fmt::format_args());
fmt::internal::buffer &base = buffer;
fmt::format_context ctx(std::back_inserter(base), "", fmt::format_args());
fmt::format_specs spec;
test_arg_formatter af(ctx, spec);
fmt::visit_format_arg(
af, fmt::internal::make_arg<fmt::format_context>(streamable_enum()));
EXPECT_EQ("streamable_enum", std::string(buffer.data(), buffer.size()));
visit(af, fmt::internal::make_arg<fmt::format_context>(TestEnum()));
EXPECT_EQ("TestEnum", std::string(buffer.data(), buffer.size()));
}
TEST(OStreamTest, Format) {
@ -95,22 +75,20 @@ TEST(OStreamTest, Format) {
TEST(OStreamTest, FormatSpecs) {
EXPECT_EQ("def ", format("{0:<5}", TestString("def")));
EXPECT_EQ(" def", format("{0:>5}", TestString("def")));
#if FMT_NUMERIC_ALIGN
EXPECT_THROW_MSG(format("{0:=5}", TestString("def")), format_error,
"format specifier requires numeric argument");
#endif
EXPECT_THROW_MSG(format("{0:=5}", TestString("def")),
format_error, "format specifier requires numeric argument");
EXPECT_EQ(" def ", format("{0:^5}", TestString("def")));
EXPECT_EQ("def**", format("{0:*<5}", TestString("def")));
EXPECT_THROW_MSG(format("{0:+}", TestString()), format_error,
"format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0:-}", TestString()), format_error,
"format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0: }", TestString()), format_error,
"format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0:#}", TestString()), format_error,
"format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0:05}", TestString()), format_error,
"format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0:+}", TestString()),
format_error, "format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0:-}", TestString()),
format_error, "format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0: }", TestString()),
format_error, "format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0:#}", TestString()),
format_error, "format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0:05}", TestString()),
format_error, "format specifier requires numeric argument");
EXPECT_EQ("test ", format("{0:13}", TestString("test")));
EXPECT_EQ("test ", format("{0:{1}}", TestString("test"), 13));
EXPECT_EQ("te", format("{0:.2}", TestString("test")));
@ -118,7 +96,7 @@ TEST(OStreamTest, FormatSpecs) {
}
struct EmptyTest {};
static std::ostream& operator<<(std::ostream& os, EmptyTest) {
static std::ostream &operator<<(std::ostream &os, EmptyTest) {
return os << "";
}
@ -138,36 +116,37 @@ TEST(OStreamTest, Print) {
TEST(OStreamTest, WriteToOStream) {
std::ostringstream os;
fmt::memory_buffer buffer;
const char* foo = "foo";
const char *foo = "foo";
buffer.append(foo, foo + std::strlen(foo));
fmt::internal::write(os, buffer);
EXPECT_EQ("foo", os.str());
}
TEST(OStreamTest, WriteToOStreamMaxSize) {
std::size_t max_size = fmt::internal::max_value<std::size_t>();
std::streamsize max_streamsize = fmt::internal::max_value<std::streamsize>();
if (max_size <= fmt::internal::to_unsigned(max_streamsize)) return;
std::size_t max_size = std::numeric_limits<std::size_t>::max();
std::streamsize max_streamsize = std::numeric_limits<std::streamsize>::max();
if (max_size <= fmt::internal::to_unsigned(max_streamsize))
return;
struct test_buffer : fmt::internal::buffer<char> {
struct test_buffer : fmt::internal::buffer {
explicit test_buffer(std::size_t size) { resize(size); }
void grow(std::size_t) {}
} buffer(max_size);
struct mock_streambuf : std::streambuf {
MOCK_METHOD2(xsputn, std::streamsize(const void* s, std::streamsize n));
std::streamsize xsputn(const char* s, std::streamsize n) {
const void* v = s;
MOCK_METHOD2(xsputn, std::streamsize (const void *s, std::streamsize n));
std::streamsize xsputn(const char *s, std::streamsize n) {
const void *v = s;
return xsputn(v, n);
}
} streambuf;
struct test_ostream : std::ostream {
explicit test_ostream(mock_streambuf& buffer) : std::ostream(&buffer) {}
explicit test_ostream(mock_streambuf &buffer) : std::ostream(&buffer) {}
} os(streambuf);
testing::InSequence sequence;
const char* data = nullptr;
const char *data = FMT_NULL;
typedef std::make_unsigned<std::streamsize>::type ustreamsize;
ustreamsize size = max_size;
do {
@ -187,40 +166,18 @@ TEST(OStreamTest, Join) {
#if FMT_USE_CONSTEXPR
TEST(OStreamTest, ConstexprString) {
EXPECT_EQ("42", format(FMT_STRING("{}"), std::string("42")));
EXPECT_EQ("a string", format(FMT_STRING("{0}"), TestString("a string")));
EXPECT_EQ("42", format(fmt("{}"), std::string("42")));
}
#endif
namespace fmt_test {
struct ABC {};
template <typename Output> Output& operator<<(Output& out, ABC) {
template <typename Output> Output &operator<<(Output &out, ABC) {
out << "ABC";
return out;
}
} // namespace fmt_test
template <typename T> struct TestTemplate {};
template <typename T>
std::ostream& operator<<(std::ostream& os, TestTemplate<T>) {
return os << 1;
}
namespace fmt {
template <typename T> struct formatter<TestTemplate<T>> : formatter<int> {
template <typename FormatContext>
typename FormatContext::iterator format(TestTemplate<T>, FormatContext& ctx) {
return formatter<int>::format(2, ctx);
}
};
} // namespace fmt
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 407
TEST(OStreamTest, Template) {
EXPECT_EQ("2", fmt::format("{}", TestTemplate<int>()));
}
} // namespace fmt_test
TEST(FormatTest, FormatToN) {
char buffer[4];
@ -234,7 +191,6 @@ TEST(FormatTest, FormatToN) {
EXPECT_EQ(buffer + 3, result.out);
EXPECT_EQ("xABx", fmt::string_view(buffer, 4));
}
#endif
#if FMT_USE_USER_DEFINED_LITERALS
TEST(FormatTest, UDL) {
@ -242,51 +198,3 @@ TEST(FormatTest, UDL) {
EXPECT_EQ("{}"_format("test"), "test");
}
#endif
template <typename T> struct convertible {
T value;
explicit convertible(const T& val) : value(val) {}
operator T() const { return value; }
};
TEST(OStreamTest, DisableBuiltinOStreamOperators) {
EXPECT_EQ("42", fmt::format("{:d}", convertible<unsigned short>(42)));
EXPECT_EQ(L"42", fmt::format(L"{:d}", convertible<unsigned short>(42)));
EXPECT_EQ("foo", fmt::format("{}", convertible<const char*>("foo")));
}
struct explicitly_convertible_to_string_like {
template <typename String,
typename = typename std::enable_if<std::is_constructible<
String, const char*, std::size_t>::value>::type>
explicit operator String() const {
return String("foo", 3u);
}
};
std::ostream& operator<<(std::ostream& os,
explicitly_convertible_to_string_like) {
return os << "bar";
}
TEST(FormatterTest, FormatExplicitlyConvertibleToStringLike) {
EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like()));
}
#ifdef FMT_USE_STRING_VIEW
struct explicitly_convertible_to_std_string_view {
explicit operator fmt::internal::std_string_view<char>() const {
return {"foo", 3u};
}
};
std::ostream& operator<<(std::ostream& os,
explicitly_convertible_to_std_string_view) {
return os << "bar";
}
TEST(FormatterTest, FormatExplicitlyConvertibleToStdStringView) {
EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like()));
}
#endif // FMT_USE_STRING_VIEW

View File

@ -6,24 +6,21 @@
// For the license information refer to format.h.
// Disable bogus MSVC warnings.
#ifndef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS
#ifdef _MSC_VER
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "posix-mock.h"
#include "../src/posix.cc"
#include <errno.h>
#include <fcntl.h>
#include <climits>
#include <memory>
#include "../src/os.cc"
#ifdef _WIN32
# include <io.h>
# undef max
# undef ERROR
# include <io.h>
# undef max
# undef ERROR
#endif
#include "gmock.h"
@ -32,10 +29,12 @@
using fmt::buffered_file;
using fmt::error_code;
using fmt::file;
using testing::internal::scoped_ptr;
using testing::_;
using testing::Return;
using testing::StrEq;
using testing::Return;
namespace {
int open_count;
@ -53,25 +52,25 @@ std::size_t read_nbyte;
std::size_t write_nbyte;
bool sysconf_error;
enum { NONE, MAX_SIZE, ERROR } fstat_sim;
} // namespace
enum FStatSimulation { NONE, MAX_SIZE, ERROR } fstat_sim;
}
#define EMULATE_EINTR(func, error_result) \
if (func##_count != 0) { \
if (func##_count++ != 3) { \
errno = EINTR; \
return error_result; \
} \
if (func##_count != 0) { \
if (func##_count++ != 3) { \
errno = EINTR; \
return error_result; \
} \
}
#ifndef _MSC_VER
int test::open(const char* path, int oflag, int mode) {
int test::open(const char *path, int oflag, int mode) {
EMULATE_EINTR(open, -1);
return ::open(path, oflag, mode);
}
#else
errno_t test::sopen_s(int* pfh, const char* filename, int oflag, int shflag,
int pmode) {
errno_t test::sopen_s(
int* pfh, const char *filename, int oflag, int shflag, int pmode) {
EMULATE_EINTR(open, EINTR);
return _sopen_s(pfh, filename, oflag, shflag, pmode);
}
@ -81,7 +80,8 @@ errno_t test::sopen_s(int* pfh, const char* filename, int oflag, int shflag,
long test::sysconf(int name) {
long result = ::sysconf(name);
if (!sysconf_error) return result;
if (!sysconf_error)
return result;
// Simulate an error.
errno = EINVAL;
return -1;
@ -89,9 +89,10 @@ long test::sysconf(int name) {
static off_t max_file_size() { return std::numeric_limits<off_t>::max(); }
int test::fstat(int fd, struct stat* buf) {
int test::fstat(int fd, struct stat *buf) {
int result = ::fstat(fd, buf);
if (fstat_sim == MAX_SIZE) buf->st_size = max_file_size();
if (fstat_sim == MAX_SIZE)
buf->st_size = max_file_size();
return result;
}
@ -131,18 +132,18 @@ int test::dup2(int fildes, int fildes2) {
return ::FMT_POSIX(dup2(fildes, fildes2));
}
FILE* test::fdopen(int fildes, const char* mode) {
EMULATE_EINTR(fdopen, nullptr);
FILE *test::fdopen(int fildes, const char *mode) {
EMULATE_EINTR(fdopen, FMT_NULL);
return ::FMT_POSIX(fdopen(fildes, mode));
}
test::ssize_t test::read(int fildes, void* buf, test::size_t nbyte) {
test::ssize_t test::read(int fildes, void *buf, test::size_t nbyte) {
read_nbyte = nbyte;
EMULATE_EINTR(read, -1);
return ::FMT_POSIX(read(fildes, buf, nbyte));
}
test::ssize_t test::write(int fildes, const void* buf, test::size_t nbyte) {
test::ssize_t test::write(int fildes, const void *buf, test::size_t nbyte) {
write_nbyte = nbyte;
EMULATE_EINTR(write, -1);
return ::FMT_POSIX(write(fildes, buf, nbyte));
@ -154,23 +155,23 @@ int test::pipe(int fildes[2]) {
return ::pipe(fildes);
}
#else
int test::pipe(int* pfds, unsigned psize, int textmode) {
int test::pipe(int *pfds, unsigned psize, int textmode) {
EMULATE_EINTR(pipe, -1);
return _pipe(pfds, psize, textmode);
}
#endif
FILE* test::fopen(const char* filename, const char* mode) {
EMULATE_EINTR(fopen, nullptr);
FILE *test::fopen(const char *filename, const char *mode) {
EMULATE_EINTR(fopen, FMT_NULL);
return ::fopen(filename, mode);
}
int test::fclose(FILE* stream) {
int test::fclose(FILE *stream) {
EMULATE_EINTR(fclose, EOF);
return ::fclose(stream);
}
int(test::fileno)(FILE* stream) {
int (test::fileno)(FILE *stream) {
EMULATE_EINTR(fileno, -1);
#ifdef fileno
return FMT_POSIX(fileno(stream));
@ -180,18 +181,18 @@ int(test::fileno)(FILE* stream) {
}
#ifndef _WIN32
# define EXPECT_RETRY(statement, func, message) \
func##_count = 1; \
statement; \
EXPECT_EQ(4, func##_count); \
# define EXPECT_RETRY(statement, func, message) \
func##_count = 1; \
statement; \
EXPECT_EQ(4, func##_count); \
func##_count = 0;
# define EXPECT_EQ_POSIX(expected, actual) EXPECT_EQ(expected, actual)
# define EXPECT_EQ_POSIX(expected, actual) EXPECT_EQ(expected, actual)
#else
# define EXPECT_RETRY(statement, func, message) \
func##_count = 1; \
# define EXPECT_RETRY(statement, func, message) \
func##_count = 1; \
EXPECT_SYSTEM_ERROR(statement, EINTR, message); \
func##_count = 0;
# define EXPECT_EQ_POSIX(expected, actual)
# define EXPECT_EQ_POSIX(expected, actual)
#endif
static void write_file(fmt::cstring_view filename, fmt::string_view content) {
@ -199,48 +200,42 @@ static void write_file(fmt::cstring_view filename, fmt::string_view content) {
f.print("{}", content);
}
#if FMT_USE_FCNTL
using fmt::file;
TEST(UtilTest, GetPageSize) {
# ifdef _WIN32
#ifdef _WIN32
SYSTEM_INFO si = {};
GetSystemInfo(&si);
EXPECT_EQ(si.dwPageSize, fmt::getpagesize());
# else
#else
EXPECT_EQ(sysconf(_SC_PAGESIZE), fmt::getpagesize());
sysconf_error = true;
EXPECT_SYSTEM_ERROR(fmt::getpagesize(), EINVAL,
"cannot get memory page size");
EXPECT_SYSTEM_ERROR(
fmt::getpagesize(), EINVAL, "cannot get memory page size");
sysconf_error = false;
# endif
#endif
}
TEST(FileTest, OpenRetry) {
write_file("temp", "there must be something here");
std::unique_ptr<file> f{nullptr};
EXPECT_RETRY(f.reset(new file("temp", file::RDONLY)), open,
"cannot open file temp");
# ifndef _WIN32
write_file("test", "there must be something here");
scoped_ptr<file> f{FMT_NULL};
EXPECT_RETRY(f.reset(new file("test", file::RDONLY)),
open, "cannot open file test");
#ifndef _WIN32
char c = 0;
f->read(&c, 1);
# endif
#endif
}
TEST(FileTest, CloseNoRetryInDtor) {
file read_end, write_end;
file::pipe(read_end, write_end);
std::unique_ptr<file> f(new file(std::move(read_end)));
scoped_ptr<file> f(new file(std::move(read_end)));
int saved_close_count = 0;
EXPECT_WRITE(
stderr,
{
close_count = 1;
f.reset(nullptr);
saved_close_count = close_count;
close_count = 0;
},
format_system_error(EINTR, "cannot close file") + "\n");
EXPECT_WRITE(stderr, {
close_count = 1;
f.reset(FMT_NULL);
saved_close_count = close_count;
close_count = 0;
}, format_system_error(EINTR, "cannot close file") + "\n");
EXPECT_EQ(2, saved_close_count);
}
@ -255,26 +250,26 @@ TEST(FileTest, CloseNoRetry) {
TEST(FileTest, Size) {
std::string content = "top secret, destroy before reading";
write_file("temp", content);
file f("temp", file::RDONLY);
write_file("test", content);
file f("test", file::RDONLY);
EXPECT_GE(f.size(), 0);
EXPECT_EQ(content.size(), static_cast<unsigned long long>(f.size()));
# ifdef _WIN32
#ifdef _WIN32
fmt::memory_buffer message;
fmt::internal::format_windows_error(message, ERROR_ACCESS_DENIED,
"cannot get file size");
fmt::internal::format_windows_error(
message, ERROR_ACCESS_DENIED, "cannot get file size");
fstat_sim = ERROR;
EXPECT_THROW_MSG(f.size(), fmt::windows_error, fmt::to_string(message));
fstat_sim = NONE;
# else
#else
f.close();
EXPECT_SYSTEM_ERROR(f.size(), EBADF, "cannot get file attributes");
# endif
#endif
}
TEST(FileTest, MaxSize) {
write_file("temp", "");
file f("temp", file::RDONLY);
write_file("test", "");
file f("test", file::RDONLY);
fstat_sim = MAX_SIZE;
EXPECT_GE(f.size(), 0);
EXPECT_EQ(max_file_size(), f.size());
@ -289,8 +284,8 @@ TEST(FileTest, ReadRetry) {
write_end.close();
char buffer[SIZE];
std::size_t count = 0;
EXPECT_RETRY(count = read_end.read(buffer, SIZE), read,
"cannot read from file");
EXPECT_RETRY(count = read_end.read(buffer, SIZE),
read, "cannot read from file");
EXPECT_EQ_POSIX(static_cast<std::streamsize>(SIZE), count);
}
@ -299,25 +294,26 @@ TEST(FileTest, WriteRetry) {
file::pipe(read_end, write_end);
enum { SIZE = 4 };
std::size_t count = 0;
EXPECT_RETRY(count = write_end.write("test", SIZE), write,
"cannot write to file");
EXPECT_RETRY(count = write_end.write("test", SIZE),
write, "cannot write to file");
write_end.close();
# ifndef _WIN32
#ifndef _WIN32
EXPECT_EQ(static_cast<std::streamsize>(SIZE), count);
char buffer[SIZE + 1];
read_end.read(buffer, SIZE);
buffer[SIZE] = '\0';
EXPECT_STREQ("test", buffer);
# endif
#endif
}
# ifdef _WIN32
#ifdef _WIN32
TEST(FileTest, ConvertReadCount) {
file read_end, write_end;
file::pipe(read_end, write_end);
char c;
std::size_t size = UINT_MAX;
if (sizeof(unsigned) != sizeof(std::size_t)) ++size;
if (sizeof(unsigned) != sizeof(std::size_t))
++size;
read_count = 1;
read_nbyte = 0;
EXPECT_THROW(read_end.read(&c, size), fmt::system_error);
@ -330,20 +326,20 @@ TEST(FileTest, ConvertWriteCount) {
file::pipe(read_end, write_end);
char c;
std::size_t size = UINT_MAX;
if (sizeof(unsigned) != sizeof(std::size_t)) ++size;
if (sizeof(unsigned) != sizeof(std::size_t))
++size;
write_count = 1;
write_nbyte = 0;
EXPECT_THROW(write_end.write(&c, size), fmt::system_error);
write_count = 0;
EXPECT_EQ(UINT_MAX, write_nbyte);
}
# endif
#endif
TEST(FileTest, DupNoRetry) {
int stdout_fd = FMT_POSIX(fileno(stdout));
dup_count = 1;
EXPECT_SYSTEM_ERROR(
file::dup(stdout_fd), EINTR,
EXPECT_SYSTEM_ERROR(file::dup(stdout_fd), EINTR,
fmt::format("cannot duplicate file descriptor {}", stdout_fd));
dup_count = 0;
}
@ -352,8 +348,8 @@ TEST(FileTest, Dup2Retry) {
int stdout_fd = FMT_POSIX(fileno(stdout));
file f1 = file::dup(stdout_fd), f2 = file::dup(stdout_fd);
EXPECT_RETRY(f1.dup2(f2.descriptor()), dup2,
fmt::format("cannot duplicate file descriptor {} to {}",
f1.descriptor(), f2.descriptor()));
fmt::format("cannot duplicate file descriptor {} to {}",
f1.descriptor(), f2.descriptor()));
}
TEST(FileTest, Dup2NoExceptRetry) {
@ -362,19 +358,19 @@ TEST(FileTest, Dup2NoExceptRetry) {
error_code ec;
dup2_count = 1;
f1.dup2(f2.descriptor(), ec);
# ifndef _WIN32
#ifndef _WIN32
EXPECT_EQ(4, dup2_count);
# else
#else
EXPECT_EQ(EINTR, ec.get());
# endif
#endif
dup2_count = 0;
}
TEST(FileTest, PipeNoRetry) {
file read_end, write_end;
pipe_count = 1;
EXPECT_SYSTEM_ERROR(file::pipe(read_end, write_end), EINTR,
"cannot create pipe");
EXPECT_SYSTEM_ERROR(
file::pipe(read_end, write_end), EINTR, "cannot create pipe");
pipe_count = 0;
}
@ -382,37 +378,34 @@ TEST(FileTest, FdopenNoRetry) {
file read_end, write_end;
file::pipe(read_end, write_end);
fdopen_count = 1;
EXPECT_SYSTEM_ERROR(read_end.fdopen("r"), EINTR,
"cannot associate stream with file descriptor");
EXPECT_SYSTEM_ERROR(read_end.fdopen("r"),
EINTR, "cannot associate stream with file descriptor");
fdopen_count = 0;
}
TEST(BufferedFileTest, OpenRetry) {
write_file("temp", "there must be something here");
std::unique_ptr<buffered_file> f{nullptr};
EXPECT_RETRY(f.reset(new buffered_file("temp", "r")), fopen,
"cannot open file temp");
# ifndef _WIN32
write_file("test", "there must be something here");
scoped_ptr<buffered_file> f{FMT_NULL};
EXPECT_RETRY(f.reset(new buffered_file("test", "r")),
fopen, "cannot open file test");
#ifndef _WIN32
char c = 0;
if (fread(&c, 1, 1, f->get()) < 1)
throw fmt::system_error(errno, "fread failed");
# endif
#endif
}
TEST(BufferedFileTest, CloseNoRetryInDtor) {
file read_end, write_end;
file::pipe(read_end, write_end);
std::unique_ptr<buffered_file> f(new buffered_file(read_end.fdopen("r")));
scoped_ptr<buffered_file> f(new buffered_file(read_end.fdopen("r")));
int saved_fclose_count = 0;
EXPECT_WRITE(
stderr,
{
fclose_count = 1;
f.reset(nullptr);
saved_fclose_count = fclose_count;
fclose_count = 0;
},
format_system_error(EINTR, "cannot close file") + "\n");
EXPECT_WRITE(stderr, {
fclose_count = 1;
f.reset(FMT_NULL);
saved_fclose_count = fclose_count;
fclose_count = 0;
}, format_system_error(EINTR, "cannot close file") + "\n");
EXPECT_EQ(2, saved_fclose_count);
}
@ -435,123 +428,111 @@ TEST(BufferedFileTest, FilenoNoRetry) {
EXPECT_EQ(2, fileno_count);
fileno_count = 0;
}
#endif // FMT_USE_FCNTL
struct test_mock {
static test_mock* instance;
} * test_mock::instance;
struct TestMock {
static TestMock *instance;
} *TestMock::instance;
TEST(ScopedMock, Scope) {
{
ScopedMock<test_mock> mock;
EXPECT_EQ(&mock, test_mock::instance);
test_mock& copy = mock;
ScopedMock<TestMock> mock;
EXPECT_EQ(&mock, TestMock::instance);
TestMock &copy = mock;
static_cast<void>(copy);
}
EXPECT_EQ(nullptr, test_mock::instance);
EXPECT_EQ(FMT_NULL, TestMock::instance);
}
#ifdef FMT_LOCALE
typedef fmt::locale::type locale_type;
typedef fmt::Locale::Type LocaleType;
struct locale_mock {
static locale_mock* instance;
MOCK_METHOD3(newlocale, locale_type(int category_mask, const char* locale,
locale_type base));
MOCK_METHOD1(freelocale, void(locale_type locale));
struct LocaleMock {
static LocaleMock *instance;
MOCK_METHOD3(newlocale, LocaleType (int category_mask, const char *locale,
LocaleType base));
MOCK_METHOD1(freelocale, void (LocaleType locale));
MOCK_METHOD3(strtod_l,
double(const char* nptr, char** endptr, locale_type locale));
} * locale_mock::instance;
MOCK_METHOD3(strtod_l, double (const char *nptr, char **endptr,
LocaleType locale));
} *LocaleMock::instance;
# ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4273)
# ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Winconsistent-dllimport"
# endif
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4273)
_locale_t _create_locale(int category, const char* locale) {
return locale_mock::instance->newlocale(category, locale, 0);
_locale_t _create_locale(int category, const char *locale) {
return LocaleMock::instance->newlocale(category, locale, 0);
}
void _free_locale(_locale_t locale) {
locale_mock::instance->freelocale(locale);
LocaleMock::instance->freelocale(locale);
}
double _strtod_l(const char* nptr, char** endptr, _locale_t locale) {
return locale_mock::instance->strtod_l(nptr, endptr, locale);
double _strtod_l(const char *nptr, char **endptr, _locale_t locale) {
return LocaleMock::instance->strtod_l(nptr, endptr, locale);
}
# ifdef __clang__
# pragma clang diagnostic pop
# endif
# pragma warning(pop)
# endif
# pragma warning(pop)
#endif
# if defined(__THROW) && FMT_GCC_VERSION > 0 && FMT_GCC_VERSION <= 408
# define FMT_LOCALE_THROW __THROW
# else
# define FMT_LOCALE_THROW
# endif
#if defined(__THROW) && FMT_GCC_VERSION > 0 && FMT_GCC_VERSION <= 408
#define FMT_LOCALE_THROW __THROW
#else
#define FMT_LOCALE_THROW
#endif
# if defined(__APPLE__) || \
(defined(__FreeBSD__) && __FreeBSD_version < 1200002)
LocaleType newlocale(int category_mask, const char *locale, LocaleType base) FMT_LOCALE_THROW {
return LocaleMock::instance->newlocale(category_mask, locale, base);
}
#if defined(__APPLE__) || (defined(__FreeBSD__) && __FreeBSD_version < 1200002)
typedef int FreeLocaleResult;
# else
#else
typedef void FreeLocaleResult;
# endif
#endif
FreeLocaleResult freelocale(locale_type locale) FMT_LOCALE_THROW {
locale_mock::instance->freelocale(locale);
FreeLocaleResult freelocale(LocaleType locale) FMT_LOCALE_THROW {
LocaleMock::instance->freelocale(locale);
return FreeLocaleResult();
}
double strtod_l(const char* nptr, char** endptr,
locale_type locale) FMT_LOCALE_THROW {
return locale_mock::instance->strtod_l(nptr, endptr, locale);
double strtod_l(const char *nptr, char **endptr, LocaleType locale) FMT_LOCALE_THROW {
return LocaleMock::instance->strtod_l(nptr, endptr, locale);
}
# undef FMT_LOCALE_THROW
# ifndef _WIN32
locale_t test::newlocale(int category_mask, const char* locale, locale_t base) {
return locale_mock::instance->newlocale(category_mask, locale, base);
}
#undef FMT_LOCALE_THROW
TEST(LocaleTest, LocaleMock) {
ScopedMock<locale_mock> mock;
locale_type locale = reinterpret_cast<locale_type>(11);
ScopedMock<LocaleMock> mock;
LocaleType locale = reinterpret_cast<LocaleType>(11);
EXPECT_CALL(mock, newlocale(222, StrEq("foo"), locale));
FMT_SYSTEM(newlocale(222, "foo", locale));
newlocale(222, "foo", locale);
}
# endif
TEST(LocaleTest, Locale) {
# ifndef LC_NUMERIC_MASK
#ifndef LC_NUMERIC_MASK
enum { LC_NUMERIC_MASK = LC_NUMERIC };
# endif
ScopedMock<locale_mock> mock;
locale_type impl = reinterpret_cast<locale_type>(42);
EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), nullptr))
#endif
ScopedMock<LocaleMock> mock;
LocaleType impl = reinterpret_cast<LocaleType>(42);
EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), FMT_NULL))
.WillOnce(Return(impl));
EXPECT_CALL(mock, freelocale(impl));
fmt::locale loc;
EXPECT_EQ(impl, loc.get());
fmt::Locale locale;
EXPECT_EQ(impl, locale.get());
}
TEST(LocaleTest, Strtod) {
ScopedMock<locale_mock> mock;
ScopedMock<LocaleMock> mock;
EXPECT_CALL(mock, newlocale(_, _, _))
.WillOnce(Return(reinterpret_cast<locale_type>(42)));
.WillOnce(Return(reinterpret_cast<LocaleType>(42)));
EXPECT_CALL(mock, freelocale(_));
fmt::locale loc;
const char* str = "4.2";
fmt::Locale locale;
const char *str = "4.2";
char end = 'x';
EXPECT_CALL(mock, strtod_l(str, _, loc.get()))
EXPECT_CALL(mock, strtod_l(str, _, locale.get()))
.WillOnce(testing::DoAll(testing::SetArgPointee<1>(&end), Return(777)));
EXPECT_EQ(777, loc.strtod(str));
EXPECT_EQ(777, locale.strtod(str));
EXPECT_EQ(&end, str);
}

View File

@ -9,17 +9,13 @@
#define FMT_POSIX_TEST_H
#include <errno.h>
#include <locale.h>
#include <stdio.h>
#ifdef __APPLE__
# include <xlocale.h>
#endif
#ifdef _WIN32
# include <windows.h>
# include <windows.h>
#else
# include <sys/param.h> // for FreeBSD version
# include <sys/types.h> // for ssize_t
# include <sys/param.h> // for FreeBSD version
# include <sys/types.h> // for ssize_t
#endif
#ifndef _MSC_VER
@ -32,13 +28,13 @@ namespace test {
// Size type for read and write.
typedef size_t size_t;
typedef ssize_t ssize_t;
int open(const char* path, int oflag, int mode);
int fstat(int fd, struct stat* buf);
int open(const char *path, int oflag, int mode);
int fstat(int fd, struct stat *buf);
#else
typedef unsigned size_t;
typedef int ssize_t;
errno_t sopen_s(int* pfh, const char* filename, int oflag, int shflag,
int pmode);
errno_t sopen_s(
int* pfh, const char *filename, int oflag, int shflag, int pmode);
#endif
#ifndef _WIN32
@ -52,24 +48,20 @@ int close(int fildes);
int dup(int fildes);
int dup2(int fildes, int fildes2);
FILE* fdopen(int fildes, const char* mode);
FILE *fdopen(int fildes, const char *mode);
ssize_t read(int fildes, void* buf, size_t nbyte);
ssize_t write(int fildes, const void* buf, size_t nbyte);
ssize_t read(int fildes, void *buf, size_t nbyte);
ssize_t write(int fildes, const void *buf, size_t nbyte);
#ifndef _WIN32
int pipe(int fildes[2]);
#else
int pipe(int* pfds, unsigned psize, int textmode);
int pipe(int *pfds, unsigned psize, int textmode);
#endif
FILE* fopen(const char* filename, const char* mode);
int fclose(FILE* stream);
int(fileno)(FILE* stream);
#if defined(FMT_LOCALE) && !defined(_WIN32)
locale_t newlocale(int category_mask, const char* locale, locale_t base);
#endif
FILE *fopen(const char *filename, const char *mode);
int fclose(FILE *stream);
int (fileno)(FILE *stream);
} // namespace test
#define FMT_SYSTEM(call) test::call

View File

@ -1,4 +1,4 @@
// Formatting library for C++ - tests of the OS-specific functionality
// Formatting library for C++ - tests of the C++ interface to POSIX functions
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
@ -7,139 +7,21 @@
#include <cstdlib> // std::exit
#include <cstring>
#include <memory>
#include "fmt/os.h"
#include "fmt/posix.h"
#include "gtest-extra.h"
#include "util.h"
#ifdef fileno
# undef fileno
# undef fileno
#endif
using fmt::buffered_file;
using fmt::error_code;
#ifdef _WIN32
# include <windows.h>
TEST(UtilTest, UTF16ToUTF8) {
std::string s = "ёжик";
fmt::internal::utf16_to_utf8 u(L"\x0451\x0436\x0438\x043A");
EXPECT_EQ(s, u.str());
EXPECT_EQ(s.size(), u.size());
}
TEST(UtilTest, UTF16ToUTF8EmptyString) {
std::string s = "";
fmt::internal::utf16_to_utf8 u(L"");
EXPECT_EQ(s, u.str());
EXPECT_EQ(s.size(), u.size());
}
template <typename Converter, typename Char>
void check_utf_conversion_error(
const char* message,
fmt::basic_string_view<Char> str = fmt::basic_string_view<Char>(0, 1)) {
fmt::memory_buffer out;
fmt::internal::format_windows_error(out, ERROR_INVALID_PARAMETER, message);
fmt::system_error error(0, "");
try {
(Converter)(str);
} catch (const fmt::system_error& e) {
error = e;
}
EXPECT_EQ(ERROR_INVALID_PARAMETER, error.error_code());
EXPECT_EQ(fmt::to_string(out), error.what());
}
TEST(UtilTest, UTF16ToUTF8Error) {
check_utf_conversion_error<fmt::internal::utf16_to_utf8, wchar_t>(
"cannot convert string from UTF-16 to UTF-8");
}
TEST(UtilTest, UTF16ToUTF8Convert) {
fmt::internal::utf16_to_utf8 u;
EXPECT_EQ(ERROR_INVALID_PARAMETER, u.convert(fmt::wstring_view(0, 1)));
EXPECT_EQ(ERROR_INVALID_PARAMETER,
u.convert(fmt::wstring_view(L"foo", INT_MAX + 1u)));
}
TEST(UtilTest, FormatWindowsError) {
LPWSTR message = 0;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
0, ERROR_FILE_EXISTS,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&message), 0, 0);
fmt::internal::utf16_to_utf8 utf8_message(message);
LocalFree(message);
fmt::memory_buffer actual_message;
fmt::internal::format_windows_error(actual_message, ERROR_FILE_EXISTS,
"test");
EXPECT_EQ(fmt::format("test: {}", utf8_message.str()),
fmt::to_string(actual_message));
actual_message.resize(0);
auto max_size = fmt::internal::max_value<size_t>();
fmt::internal::format_windows_error(actual_message, ERROR_FILE_EXISTS,
fmt::string_view(0, max_size));
EXPECT_EQ(fmt::format("error {}", ERROR_FILE_EXISTS),
fmt::to_string(actual_message));
}
TEST(UtilTest, FormatLongWindowsError) {
LPWSTR message = 0;
// this error code is not available on all Windows platforms and
// Windows SDKs, so do not fail the test if the error string cannot
// be retrieved.
const int provisioning_not_allowed =
0x80284013L /*TBS_E_PROVISIONING_NOT_ALLOWED*/;
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
0, static_cast<DWORD>(provisioning_not_allowed),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&message), 0, 0) == 0) {
return;
}
fmt::internal::utf16_to_utf8 utf8_message(message);
LocalFree(message);
fmt::memory_buffer actual_message;
fmt::internal::format_windows_error(actual_message, provisioning_not_allowed,
"test");
EXPECT_EQ(fmt::format("test: {}", utf8_message.str()),
fmt::to_string(actual_message));
}
TEST(UtilTest, WindowsError) {
fmt::system_error error(0, "");
try {
throw fmt::windows_error(ERROR_FILE_EXISTS, "test {}", "error");
} catch (const fmt::system_error& e) {
error = e;
}
fmt::memory_buffer message;
fmt::internal::format_windows_error(message, ERROR_FILE_EXISTS, "test error");
EXPECT_EQ(to_string(message), error.what());
EXPECT_EQ(ERROR_FILE_EXISTS, error.error_code());
}
TEST(UtilTest, ReportWindowsError) {
fmt::memory_buffer out;
fmt::internal::format_windows_error(out, ERROR_FILE_EXISTS, "test error");
out.push_back('\n');
EXPECT_WRITE(stderr,
fmt::report_windows_error(ERROR_FILE_EXISTS, "test error"),
fmt::to_string(out));
}
#endif // _WIN32
#if FMT_USE_FCNTL
using fmt::file;
using testing::internal::scoped_ptr;
// Checks if the file is open by reading one character from it.
static bool isopen(int fd) {
char buffer;
@ -163,9 +45,9 @@ static file open_file() {
}
// Attempts to write a string to a file.
static void write(file& f, fmt::string_view s) {
static void write(file &f, fmt::string_view s) {
std::size_t num_chars_left = s.size();
const char* ptr = s.data();
const char *ptr = s.data();
do {
std::size_t count = f.write(ptr, num_chars_left);
ptr += count;
@ -177,26 +59,26 @@ static void write(file& f, fmt::string_view s) {
TEST(BufferedFileTest, DefaultCtor) {
buffered_file f;
EXPECT_TRUE(f.get() == nullptr);
EXPECT_TRUE(f.get() == FMT_NULL);
}
TEST(BufferedFileTest, MoveCtor) {
buffered_file bf = open_buffered_file();
FILE* fp = bf.get();
EXPECT_TRUE(fp != nullptr);
FILE *fp = bf.get();
EXPECT_TRUE(fp != FMT_NULL);
buffered_file bf2(std::move(bf));
EXPECT_EQ(fp, bf2.get());
EXPECT_TRUE(bf.get() == nullptr);
EXPECT_TRUE(bf.get() == FMT_NULL);
}
TEST(BufferedFileTest, MoveAssignment) {
buffered_file bf = open_buffered_file();
FILE* fp = bf.get();
EXPECT_TRUE(fp != nullptr);
FILE *fp = bf.get();
EXPECT_TRUE(fp != FMT_NULL);
buffered_file bf2;
bf2 = std::move(bf);
EXPECT_EQ(fp, bf2.get());
EXPECT_TRUE(bf.get() == nullptr);
EXPECT_TRUE(bf.get() == FMT_NULL);
}
TEST(BufferedFileTest, MoveAssignmentClosesFile) {
@ -208,13 +90,13 @@ TEST(BufferedFileTest, MoveAssignmentClosesFile) {
}
TEST(BufferedFileTest, MoveFromTemporaryInCtor) {
FILE* fp = nullptr;
FILE *fp = FMT_NULL;
buffered_file f(open_buffered_file(&fp));
EXPECT_EQ(fp, f.get());
}
TEST(BufferedFileTest, MoveFromTemporaryInAssignment) {
FILE* fp = nullptr;
FILE *fp = FMT_NULL;
buffered_file f;
f = open_buffered_file(&fp);
EXPECT_EQ(fp, f.get());
@ -237,24 +119,22 @@ TEST(BufferedFileTest, CloseFileInDtor) {
}
TEST(BufferedFileTest, CloseErrorInDtor) {
std::unique_ptr<buffered_file> f(new buffered_file(open_buffered_file()));
EXPECT_WRITE(stderr,
{
// The close function must be called inside EXPECT_WRITE,
// otherwise the system may recycle closed file descriptor when
// redirecting the output in EXPECT_STDERR and the second close
// will break output redirection.
FMT_POSIX(close(f->fileno()));
SUPPRESS_ASSERT(f.reset(nullptr));
},
format_system_error(EBADF, "cannot close file") + "\n");
scoped_ptr<buffered_file> f(new buffered_file(open_buffered_file()));
EXPECT_WRITE(stderr, {
// The close function must be called inside EXPECT_WRITE, otherwise
// the system may recycle closed file descriptor when redirecting the
// output in EXPECT_STDERR and the second close will break output
// redirection.
FMT_POSIX(close(f->fileno()));
SUPPRESS_ASSERT(f.reset(FMT_NULL));
}, format_system_error(EBADF, "cannot close file") + "\n");
}
TEST(BufferedFileTest, Close) {
buffered_file f = open_buffered_file();
int fd = f.fileno();
f.close();
EXPECT_TRUE(f.get() == nullptr);
EXPECT_TRUE(f.get() == FMT_NULL);
EXPECT_TRUE(isclosed(fd));
}
@ -262,24 +142,22 @@ TEST(BufferedFileTest, CloseError) {
buffered_file f = open_buffered_file();
FMT_POSIX(close(f.fileno()));
EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
EXPECT_TRUE(f.get() == nullptr);
EXPECT_TRUE(f.get() == FMT_NULL);
}
TEST(BufferedFileTest, Fileno) {
buffered_file f;
# ifndef __COVERITY__
#ifndef __COVERITY__
// fileno on a null FILE pointer either crashes or returns an error.
// Disable Coverity because this is intentional.
EXPECT_DEATH_IF_SUPPORTED(
{
try {
f.fileno();
} catch (const fmt::system_error&) {
std::exit(1);
}
},
"");
# endif
EXPECT_DEATH_IF_SUPPORTED({
try {
f.fileno();
} catch (const fmt::system_error&) {
std::exit(1);
}
}, "");
#endif
f = open_buffered_file();
EXPECT_TRUE(f.fileno() != -1);
file copy = file::dup(f.fileno());
@ -292,7 +170,7 @@ TEST(FileTest, DefaultCtor) {
}
TEST(FileTest, OpenBufferedFileInCtor) {
FILE* fp = safe_fopen("test-file", "w");
FILE *fp = safe_fopen("test-file", "w");
std::fputs(FILE_CONTENT, fp);
std::fclose(fp);
file f("test-file", file::RDONLY);
@ -300,8 +178,8 @@ TEST(FileTest, OpenBufferedFileInCtor) {
}
TEST(FileTest, OpenBufferedFileError) {
EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY), ENOENT,
"cannot open file nonexistent");
EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY),
ENOENT, "cannot open file nonexistent");
}
TEST(FileTest, MoveCtor) {
@ -331,7 +209,7 @@ TEST(FileTest, MoveAssignmentClosesFile) {
EXPECT_TRUE(isclosed(old_fd));
}
static file OpenBufferedFile(int& fd) {
static file OpenBufferedFile(int &fd) {
file f = open_file();
fd = f.descriptor();
return f;
@ -368,17 +246,15 @@ TEST(FileTest, CloseFileInDtor) {
}
TEST(FileTest, CloseErrorInDtor) {
std::unique_ptr<file> f(new file(open_file()));
EXPECT_WRITE(stderr,
{
// The close function must be called inside EXPECT_WRITE,
// otherwise the system may recycle closed file descriptor when
// redirecting the output in EXPECT_STDERR and the second close
// will break output redirection.
FMT_POSIX(close(f->descriptor()));
SUPPRESS_ASSERT(f.reset(nullptr));
},
format_system_error(EBADF, "cannot close file") + "\n");
scoped_ptr<file> f(new file(open_file()));
EXPECT_WRITE(stderr, {
// The close function must be called inside EXPECT_WRITE, otherwise
// the system may recycle closed file descriptor when redirecting the
// output in EXPECT_STDERR and the second close will break output
// redirection.
FMT_POSIX(close(f->descriptor()));
SUPPRESS_ASSERT(f.reset(FMT_NULL));
}, format_system_error(EBADF, "cannot close file") + "\n");
}
TEST(FileTest, Close) {
@ -431,13 +307,13 @@ TEST(FileTest, Dup) {
EXPECT_EQ(FILE_CONTENT, read(copy, std::strlen(FILE_CONTENT)));
}
# ifndef __COVERITY__
#ifndef __COVERITY__
TEST(FileTest, DupError) {
int value = -1;
EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value), EBADF,
"cannot duplicate file descriptor -1");
EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value),
EBADF, "cannot duplicate file descriptor -1");
}
# endif
#endif
TEST(FileTest, Dup2) {
file f = open_file();
@ -449,9 +325,8 @@ TEST(FileTest, Dup2) {
TEST(FileTest, Dup2Error) {
file f = open_file();
EXPECT_SYSTEM_ERROR_NOASSERT(
f.dup2(-1), EBADF,
fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor()));
EXPECT_SYSTEM_ERROR_NOASSERT(f.dup2(-1), EBADF,
fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor()));
}
TEST(FileTest, Dup2NoExcept) {
@ -487,12 +362,17 @@ TEST(FileTest, Fdopen) {
EXPECT_EQ(read_fd, FMT_POSIX(fileno(read_end.fdopen("r").get())));
}
# ifdef FMT_LOCALE
TEST(FileTest, FdopenError) {
file f;
EXPECT_SYSTEM_ERROR_NOASSERT(
f.fdopen("r"), EBADF, "cannot associate stream with file descriptor");
}
#ifdef FMT_LOCALE
TEST(LocaleTest, Strtod) {
fmt::locale loc;
fmt::Locale locale;
const char *start = "4.2", *ptr = start;
EXPECT_EQ(4.2, loc.strtod(ptr));
EXPECT_EQ(4.2, locale.strtod(ptr));
EXPECT_EQ(start + 3, ptr);
}
# endif
#endif // FMT_USE_FCNTL
#endif

View File

@ -5,19 +5,17 @@
//
// For the license information refer to format.h.
#include "fmt/printf.h"
#include <cctype>
#include <climits>
#include <cstring>
#include "fmt/core.h"
#include "fmt/printf.h"
#include "gtest-extra.h"
#include "util.h"
using fmt::format;
using fmt::format_error;
using fmt::internal::max_value;
const unsigned BIG_NUM = INT_MAX + 1u;
@ -37,17 +35,17 @@ static std::wstring make_positional(fmt::wstring_view format) {
// A wrapper around fmt::sprintf to workaround bogus warnings about invalid
// format strings in MSVC.
template <typename... Args>
std::string test_sprintf(fmt::string_view format, const Args&... args) {
std::string test_sprintf(fmt::string_view format, const Args &... args) {
return fmt::sprintf(format, args...);
}
template <typename... Args>
std::wstring test_sprintf(fmt::wstring_view format, const Args&... args) {
std::wstring test_sprintf(fmt::wstring_view format, const Args &... args) {
return fmt::sprintf(format, args...);
}
#define EXPECT_PRINTF(expected_output, format, arg) \
#define EXPECT_PRINTF(expected_output, format, arg) \
EXPECT_EQ(expected_output, test_sprintf(format, arg)) \
<< "format: " << format; \
<< "format: " << format; \
EXPECT_EQ(expected_output, fmt::sprintf(make_positional(format), arg))
TEST(PrintfTest, NoArgs) {
@ -71,10 +69,11 @@ TEST(PrintfTest, Escape) {
TEST(PrintfTest, PositionalArgs) {
EXPECT_EQ("42", test_sprintf("%1$d", 42));
EXPECT_EQ("before 42", test_sprintf("before %1$d", 42));
EXPECT_EQ("42 after", test_sprintf("%1$d after", 42));
EXPECT_EQ("42 after", test_sprintf("%1$d after",42));
EXPECT_EQ("before 42 after", test_sprintf("before %1$d after", 42));
EXPECT_EQ("answer = 42", test_sprintf("%1$s = %2$d", "answer", 42));
EXPECT_EQ("42 is the answer", test_sprintf("%2$d is the %1$s", "answer", 42));
EXPECT_EQ("42 is the answer",
test_sprintf("%2$d is the %1$s", "answer", 42));
EXPECT_EQ("abracadabra", test_sprintf("%1$s%2$s%1$s", "abra", "cad"));
}
@ -83,46 +82,46 @@ TEST(PrintfTest, AutomaticArgIndexing) {
}
TEST(PrintfTest, NumberIsTooBigInArgIndex) {
EXPECT_THROW_MSG(test_sprintf(format("%{}$", BIG_NUM)), format_error,
"number is too big");
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM)), format_error,
"number is too big");
EXPECT_THROW_MSG(test_sprintf(format("%{}$", BIG_NUM)),
format_error, "number is too big");
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM)),
format_error, "number is too big");
}
TEST(PrintfTest, SwitchArgIndexing) {
EXPECT_THROW_MSG(test_sprintf("%1$d%", 1, 2), format_error,
"cannot switch from manual to automatic argument indexing");
EXPECT_THROW_MSG(test_sprintf("%1$d%", 1, 2),
format_error, "cannot switch from manual to automatic argument indexing");
EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
format_error, "number is too big");
EXPECT_THROW_MSG(test_sprintf("%1$d%d", 1, 2), format_error,
"cannot switch from manual to automatic argument indexing");
format_error, "number is too big");
EXPECT_THROW_MSG(test_sprintf("%1$d%d", 1, 2),
format_error, "cannot switch from manual to automatic argument indexing");
EXPECT_THROW_MSG(test_sprintf("%d%1$", 1, 2), format_error,
"cannot switch from automatic to manual argument indexing");
EXPECT_THROW_MSG(test_sprintf(format("%d%{}$d", BIG_NUM), 1, 2), format_error,
"number is too big");
EXPECT_THROW_MSG(test_sprintf("%d%1$d", 1, 2), format_error,
"cannot switch from automatic to manual argument indexing");
EXPECT_THROW_MSG(test_sprintf("%d%1$", 1, 2),
format_error, "cannot switch from automatic to manual argument indexing");
EXPECT_THROW_MSG(test_sprintf(format("%d%{}$d", BIG_NUM), 1, 2),
format_error, "number is too big");
EXPECT_THROW_MSG(test_sprintf("%d%1$d", 1, 2),
format_error, "cannot switch from automatic to manual argument indexing");
// Indexing errors override width errors.
EXPECT_THROW_MSG(test_sprintf(format("%d%1${}d", BIG_NUM), 1, 2),
format_error, "number is too big");
format_error, "number is too big");
EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
format_error, "number is too big");
format_error, "number is too big");
}
TEST(PrintfTest, InvalidArgIndex) {
EXPECT_THROW_MSG(test_sprintf("%0$d", 42), format_error,
"argument index out of range");
"argument index out of range");
EXPECT_THROW_MSG(test_sprintf("%2$d", 42), format_error,
"argument index out of range");
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", INT_MAX), 42), format_error,
"argument index out of range");
"argument index out of range");
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", INT_MAX), 42),
format_error, "argument index out of range");
EXPECT_THROW_MSG(test_sprintf("%2$", 42), format_error,
"argument index out of range");
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM), 42), format_error,
"number is too big");
EXPECT_THROW_MSG(test_sprintf("%2$", 42),
format_error, "argument index out of range");
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM), 42),
format_error, "number is too big");
}
TEST(PrintfTest, DefaultAlignRight) {
@ -176,8 +175,8 @@ TEST(PrintfTest, HashFlag) {
EXPECT_PRINTF("0x42", "%#x", 0x42);
EXPECT_PRINTF("0X42", "%#X", 0x42);
EXPECT_PRINTF(fmt::format("0x{:x}", static_cast<unsigned>(-0x42)), "%#x",
-0x42);
EXPECT_PRINTF(
fmt::format("0x{:x}", static_cast<unsigned>(-0x42)), "%#x", -0x42);
EXPECT_PRINTF("0", "%#x", 0);
EXPECT_PRINTF("0x0042", "%#06x", 0x42);
@ -209,23 +208,23 @@ TEST(PrintfTest, Width) {
// Width cannot be specified twice.
EXPECT_THROW_MSG(test_sprintf("%5-5d", 42), format_error,
"invalid type specifier");
"invalid type specifier");
EXPECT_THROW_MSG(test_sprintf(format("%{}d", BIG_NUM), 42), format_error,
"number is too big");
EXPECT_THROW_MSG(test_sprintf(format("%1${}d", BIG_NUM), 42), format_error,
"number is too big");
EXPECT_THROW_MSG(test_sprintf(format("%{}d", BIG_NUM), 42),
format_error, "number is too big");
EXPECT_THROW_MSG(test_sprintf(format("%1${}d", BIG_NUM), 42),
format_error, "number is too big");
}
TEST(PrintfTest, DynamicWidth) {
EXPECT_EQ(" 42", test_sprintf("%*d", 5, 42));
EXPECT_EQ("42 ", test_sprintf("%*d", -5, 42));
EXPECT_THROW_MSG(test_sprintf("%*d", 5.0, 42), format_error,
"width is not integer");
"width is not integer");
EXPECT_THROW_MSG(test_sprintf("%*d"), format_error,
"argument index out of range");
"argument index out of range");
EXPECT_THROW_MSG(test_sprintf("%*d", BIG_NUM, 42), format_error,
"number is too big");
"number is too big");
}
TEST(PrintfTest, IntPrecision) {
@ -254,7 +253,8 @@ TEST(PrintfTest, FloatPrecision) {
safe_sprintf(buffer, "%.3e", 1234.5678);
EXPECT_PRINTF(buffer, "%.3e", 1234.5678);
EXPECT_PRINTF("1234.568", "%.3f", 1234.5678);
EXPECT_PRINTF("1.23e+03", "%.3g", 1234.5678);
safe_sprintf(buffer, "%.3g", 1234.5678);
EXPECT_PRINTF(buffer, "%.3g", 1234.5678);
safe_sprintf(buffer, "%.3a", 1234.5678);
EXPECT_PRINTF(buffer, "%.3a", 1234.5678);
}
@ -267,22 +267,24 @@ TEST(PrintfTest, DynamicPrecision) {
EXPECT_EQ("00042", test_sprintf("%.*d", 5, 42));
EXPECT_EQ("42", test_sprintf("%.*d", -5, 42));
EXPECT_THROW_MSG(test_sprintf("%.*d", 5.0, 42), format_error,
"precision is not integer");
"precision is not integer");
EXPECT_THROW_MSG(test_sprintf("%.*d"), format_error,
"argument index out of range");
"argument index out of range");
EXPECT_THROW_MSG(test_sprintf("%.*d", BIG_NUM, 42), format_error,
"number is too big");
"number is too big");
if (sizeof(long long) != sizeof(int)) {
long long prec = static_cast<long long>(INT_MIN) - 1;
EXPECT_THROW_MSG(test_sprintf("%.*d", prec, 42), format_error,
"number is too big");
}
"number is too big");
}
}
template <typename T> struct make_signed { typedef T type; };
template <typename T>
struct make_signed { typedef T type; };
#define SPECIALIZE_MAKE_SIGNED(T, S) \
template <> struct make_signed<T> { typedef S type; }
template <> \
struct make_signed<T> { typedef S type; }
SPECIALIZE_MAKE_SIGNED(char, signed char);
SPECIALIZE_MAKE_SIGNED(unsigned char, signed char);
@ -293,23 +295,24 @@ SPECIALIZE_MAKE_SIGNED(unsigned long long, long long);
// Test length format specifier ``length_spec``.
template <typename T, typename U>
void TestLength(const char* length_spec, U value) {
void TestLength(const char *length_spec, U value) {
long long signed_value = 0;
unsigned long long unsigned_value = 0;
// Apply integer promotion to the argument.
unsigned long long max = max_value<U>();
using std::numeric_limits;
unsigned long long max = numeric_limits<U>::max();
using fmt::internal::const_check;
if (const_check(max <= static_cast<unsigned>(max_value<int>()))) {
if (const_check(max <= static_cast<unsigned>(numeric_limits<int>::max()))) {
signed_value = static_cast<int>(value);
unsigned_value = static_cast<unsigned long long>(value);
} else if (const_check(max <= max_value<unsigned>())) {
unsigned_value = static_cast<unsigned>(value);
} else if (const_check(max <= numeric_limits<unsigned>::max())) {
signed_value = static_cast<unsigned>(value);
unsigned_value = static_cast<unsigned long long>(value);
unsigned_value = static_cast<unsigned>(value);
}
if (sizeof(U) <= sizeof(int) && sizeof(int) < sizeof(T)) {
signed_value = static_cast<long long>(value);
unsigned_value = static_cast<unsigned long long>(
static_cast<typename std::make_unsigned<unsigned>::type>(value));
unsigned_value =
static_cast<typename std::make_unsigned<unsigned>::type>(value);
} else {
signed_value = static_cast<typename make_signed<T>::type>(value);
unsigned_value = static_cast<typename std::make_unsigned<T>::type>(value);
@ -332,28 +335,27 @@ void TestLength(const char* length_spec, U value) {
EXPECT_PRINTF(os.str(), fmt::format("%{}X", length_spec), value);
}
template <typename T> void TestLength(const char* length_spec) {
T min = std::numeric_limits<T>::min(), max = max_value<T>();
template <typename T>
void TestLength(const char *length_spec) {
T min = std::numeric_limits<T>::min(), max = std::numeric_limits<T>::max();
TestLength<T>(length_spec, 42);
TestLength<T>(length_spec, -42);
TestLength<T>(length_spec, min);
TestLength<T>(length_spec, max);
long long long_long_min = std::numeric_limits<long long>::min();
if (static_cast<long long>(min) > long_long_min)
TestLength<T>(length_spec, static_cast<long long>(min) - 1);
unsigned long long long_long_max = max_value<long long>();
TestLength<T>(length_spec, static_cast<long long>(min) - 1);
unsigned long long long_long_max = std::numeric_limits<long long>::max();
if (static_cast<unsigned long long>(max) < long_long_max)
TestLength<T>(length_spec, static_cast<long long>(max) + 1);
TestLength<T>(length_spec, std::numeric_limits<short>::min());
TestLength<T>(length_spec, max_value<unsigned short>());
TestLength<T>(length_spec, std::numeric_limits<unsigned short>::max());
TestLength<T>(length_spec, std::numeric_limits<int>::min());
TestLength<T>(length_spec, max_value<int>());
TestLength<T>(length_spec, std::numeric_limits<int>::max());
TestLength<T>(length_spec, std::numeric_limits<unsigned>::min());
TestLength<T>(length_spec, max_value<unsigned>());
TestLength<T>(length_spec, std::numeric_limits<unsigned>::max());
TestLength<T>(length_spec, std::numeric_limits<long long>::min());
TestLength<T>(length_spec, max_value<long long>());
TestLength<T>(length_spec, std::numeric_limits<long long>::max());
TestLength<T>(length_spec, std::numeric_limits<unsigned long long>::min());
TestLength<T>(length_spec, max_value<unsigned long long>());
TestLength<T>(length_spec, std::numeric_limits<unsigned long long>::max());
}
TEST(PrintfTest, Length) {
@ -369,9 +371,9 @@ TEST(PrintfTest, Length) {
TestLength<intmax_t>("j");
TestLength<std::size_t>("z");
TestLength<std::ptrdiff_t>("t");
long double max = max_value<long double>();
EXPECT_PRINTF(fmt::format("{:.6}", max), "%g", max);
EXPECT_PRINTF(fmt::format("{:.6}", max), "%Lg", max);
long double max = std::numeric_limits<long double>::max();
EXPECT_PRINTF(fmt::format("{}", max), "%g", max);
EXPECT_PRINTF(fmt::format("{}", max), "%Lg", max);
}
TEST(PrintfTest, Bool) {
@ -392,7 +394,7 @@ TEST(PrintfTest, Int) {
TEST(PrintfTest, long_long) {
// fmt::printf allows passing long long arguments to %d without length
// specifiers.
long long max = max_value<long long>();
long long max = std::numeric_limits<long long>::max();
EXPECT_PRINTF(fmt::format("{}", max), "%d", max);
}
@ -409,9 +411,6 @@ TEST(PrintfTest, Float) {
EXPECT_PRINTF(buffer, "%E", 392.65);
EXPECT_PRINTF("392.65", "%g", 392.65);
EXPECT_PRINTF("392.65", "%G", 392.65);
EXPECT_PRINTF("392", "%g", 392.0);
EXPECT_PRINTF("392", "%G", 392.0);
EXPECT_PRINTF("4.56e-07", "%g", 0.000000456);
safe_sprintf(buffer, "%a", -392.65);
EXPECT_EQ(buffer, format("{:a}", -392.65));
safe_sprintf(buffer, "%A", -392.65);
@ -429,44 +428,44 @@ TEST(PrintfTest, Inf) {
TEST(PrintfTest, Char) {
EXPECT_PRINTF("x", "%c", 'x');
int max = max_value<int>();
int max = std::numeric_limits<int>::max();
EXPECT_PRINTF(fmt::format("{}", static_cast<char>(max)), "%c", max);
// EXPECT_PRINTF("x", "%lc", L'x');
//EXPECT_PRINTF("x", "%lc", L'x');
EXPECT_PRINTF(L"x", L"%c", L'x');
EXPECT_PRINTF(fmt::format(L"{}", static_cast<wchar_t>(max)), L"%c", max);
}
TEST(PrintfTest, String) {
EXPECT_PRINTF("abc", "%s", "abc");
const char* null_str = nullptr;
const char *null_str = FMT_NULL;
EXPECT_PRINTF("(null)", "%s", null_str);
EXPECT_PRINTF(" (null)", "%10s", null_str);
EXPECT_PRINTF(L"abc", L"%s", L"abc");
const wchar_t* null_wstr = nullptr;
const wchar_t *null_wstr = FMT_NULL;
EXPECT_PRINTF(L"(null)", L"%s", null_wstr);
EXPECT_PRINTF(L" (null)", L"%10s", null_wstr);
}
TEST(PrintfTest, Pointer) {
int n;
void* p = &n;
void *p = &n;
EXPECT_PRINTF(fmt::format("{}", p), "%p", p);
p = nullptr;
p = FMT_NULL;
EXPECT_PRINTF("(nil)", "%p", p);
EXPECT_PRINTF(" (nil)", "%10p", p);
const char* s = "test";
const char *s = "test";
EXPECT_PRINTF(fmt::format("{:p}", s), "%p", s);
const char* null_str = nullptr;
const char *null_str = FMT_NULL;
EXPECT_PRINTF("(nil)", "%p", null_str);
p = &n;
EXPECT_PRINTF(fmt::format(L"{}", p), L"%p", p);
p = nullptr;
p = FMT_NULL;
EXPECT_PRINTF(L"(nil)", L"%p", p);
EXPECT_PRINTF(L" (nil)", L"%10p", p);
const wchar_t* w = L"test";
const wchar_t *w = L"test";
EXPECT_PRINTF(fmt::format(L"{:p}", w), L"%p", w);
const wchar_t* null_wstr = nullptr;
const wchar_t *null_wstr = FMT_NULL;
EXPECT_PRINTF(L"(nil)", L"%p", null_wstr);
}
@ -474,18 +473,16 @@ TEST(PrintfTest, Location) {
// TODO: test %n
}
enum test_enum { answer = 42 };
enum E { A = 42 };
TEST(PrintfTest, Enum) {
EXPECT_PRINTF("42", "%d", answer);
volatile test_enum volatile_enum = answer;
EXPECT_PRINTF("42", "%d", volatile_enum);
EXPECT_PRINTF("42", "%d", A);
}
#if FMT_USE_FCNTL
#if FMT_USE_FILE_DESCRIPTORS
TEST(PrintfTest, Examples) {
const char* weekday = "Thursday";
const char* month = "August";
const char *weekday = "Thursday";
const char *month = "August";
int day = 21;
EXPECT_WRITE(stdout, fmt::printf("%1$s, %3$d %2$s", weekday, month, day),
"Thursday, 21 August");
@ -499,12 +496,12 @@ TEST(PrintfTest, PrintfError) {
}
#endif
TEST(PrintfTest, WideString) { EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc")); }
TEST(PrintfTest, WideString) {
EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc"));
}
TEST(PrintfTest, PrintfCustom) {
// The test is disabled for now because it requires decoupling
// fallback_formatter::format from format_context.
//EXPECT_EQ("abc", test_sprintf("%s", TestString("abc")));
EXPECT_EQ("abc", test_sprintf("%s", TestString("abc")));
}
TEST(PrintfTest, OStream) {
@ -523,7 +520,7 @@ TEST(PrintfTest, VPrintf) {
EXPECT_WRITE(stdout, fmt::vfprintf(std::cout, "%d", args), "42");
}
template <typename... Args>
template<typename... Args>
void check_format_string_regression(fmt::string_view s, const Args&... args) {
fmt::sprintf(s, args...);
}
@ -532,90 +529,41 @@ TEST(PrintfTest, CheckFormatStringRegression) {
check_format_string_regression("%c%s", 'x', "");
}
TEST(PrintfTest, FixedLargeExponent) {
EXPECT_EQ("1000000000000000000000", fmt::sprintf("%.*f", -13, 1e21));
}
TEST(PrintfTest, VSPrintfMakeArgsExample) {
fmt::format_arg_store<fmt::printf_context, int, const char*> as{42,
"something"};
fmt::format_arg_store<fmt::printf_context, int, const char *> as{
42, "something"};
fmt::basic_format_args<fmt::printf_context> args(as);
EXPECT_EQ("[42] something happened", fmt::vsprintf("[%d] %s happened", args));
EXPECT_EQ(
"[42] something happened", fmt::vsprintf("[%d] %s happened", args));
auto as2 = fmt::make_printf_args(42, "something");
fmt::basic_format_args<fmt::printf_context> args2(as2);
EXPECT_EQ("[42] something happened",
fmt::vsprintf("[%d] %s happened", args2));
// The older gcc versions can't cast the return value.
#if !defined(__GNUC__) || (__GNUC__ > 4)
EXPECT_EQ("[42] something happened",
fmt::vsprintf("[%d] %s happened",
{fmt::make_printf_args(42, "something")}));
EXPECT_EQ(
"[42] something happened", fmt::vsprintf("[%d] %s happened", args2));
//the older gcc versions can't cast the return value
#if !defined(__GNUC__) || (__GNUC__ > 4)
EXPECT_EQ(
"[42] something happened",
fmt::vsprintf(
"[%d] %s happened", fmt::make_printf_args(42, "something")));
#endif
}
TEST(PrintfTest, VSPrintfMakeWArgsExample) {
fmt::format_arg_store<fmt::wprintf_context, int, const wchar_t*> as{
42, L"something"};
fmt::format_arg_store<fmt::wprintf_context, int, const wchar_t *> as{
42, L"something"};
fmt::basic_format_args<fmt::wprintf_context> args(as);
EXPECT_EQ(L"[42] something happened",
fmt::vsprintf(L"[%d] %s happened", args));
auto as2 = fmt::make_wprintf_args(42, L"something");
EXPECT_EQ(
L"[42] something happened",
fmt::vsprintf(L"[%d] %s happened", args));
auto as2 = fmt::make_wprintf_args(42, L"something");
fmt::basic_format_args<fmt::wprintf_context> args2(as2);
EXPECT_EQ(L"[42] something happened",
fmt::vsprintf(L"[%d] %s happened", args2));
EXPECT_EQ(
L"[42] something happened", fmt::vsprintf(L"[%d] %s happened", args2));
// the older gcc versions can't cast the return value
#if !defined(__GNUC__) || (__GNUC__ > 4)
EXPECT_EQ(L"[42] something happened",
fmt::vsprintf(L"[%d] %s happened",
{fmt::make_wprintf_args(42, L"something")}));
EXPECT_EQ(
L"[42] something happened",
fmt::vsprintf(
L"[%d] %s happened", fmt::make_wprintf_args(42, L"something")));
#endif
}
typedef fmt::printf_arg_formatter<fmt::buffer_range<char>> formatter_t;
typedef fmt::basic_printf_context<formatter_t::iterator, char> context_t;
// A custom printf argument formatter that doesn't print `-` for floating-point
// values rounded to 0.
class custom_printf_arg_formatter : public formatter_t {
public:
using formatter_t::iterator;
custom_printf_arg_formatter(formatter_t::iterator iter,
formatter_t::format_specs& specs, context_t& ctx)
: formatter_t(iter, specs, ctx) {}
using formatter_t::operator();
#if FMT_MSC_VER > 0 && FMT_MSC_VER <= 1804
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
iterator operator()(T value){
#else
iterator operator()(double value) {
#endif
// Comparing a float to 0.0 is safe.
if (round(value * pow(10, specs()->precision)) == 0.0) value = 0;
return formatter_t::operator()(value);
}
}
;
typedef fmt::basic_format_args<context_t> format_args_t;
std::string custom_vformat(fmt::string_view format_str, format_args_t args) {
fmt::memory_buffer buffer;
fmt::vprintf<custom_printf_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_printf_args(args...);
return custom_vformat(format_str, {va});
}
TEST(PrintfTest, CustomFormat) {
EXPECT_EQ("0.00", custom_format("%.2f", -.00001));
EXPECT_EQ("0.00", custom_format("%.2f", .00001));
EXPECT_EQ("1.00", custom_format("%.2f", 1.00001));
EXPECT_EQ("-1.00", custom_format("%.2f", -1.00001));
}

View File

@ -9,18 +9,17 @@
// All Rights Reserved
// {fmt} support for ranges, containers and types tuple interface.
#include "fmt/ranges.h"
#include "gtest.h"
// Check if 'if constexpr' is supported.
/// Check if 'if constexpr' is supported.
#if (__cplusplus > 201402L) || \
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
# include <array>
# include <map>
# include <string>
# include <vector>
#include "fmt/ranges.h"
#include "gtest.h"
#include <vector>
#include <array>
#include <map>
#include <string>
TEST(RangesTest, FormatVector) {
std::vector<int32_t> iv{1, 2, 3, 5, 7, 11};
@ -40,46 +39,21 @@ TEST(RangesTest, FormatMap) {
}
TEST(RangesTest, FormatPair) {
std::pair<int64_t, float> pa1{42, 1.5f};
EXPECT_EQ("(42, 1.5)", fmt::format("{}", pa1));
std::pair<int64_t, float> pa1{42, 3.14159265358979f};
EXPECT_EQ("(42, 3.14159)", fmt::format("{}", pa1));
}
TEST(RangesTest, FormatTuple) {
std::tuple<int64_t, float, std::string, char> t{42, 1.5f, "this is tuple",
'i'};
EXPECT_EQ("(42, 1.5, \"this is tuple\", 'i')", fmt::format("{}", t));
EXPECT_EQ("()", fmt::format("{}", std::tuple<>()));
}
TEST(RangesTest, JoinTuple) {
// Value tuple args
std::tuple<char, int, float> t1 = std::make_tuple('a', 1, 2.0f);
EXPECT_EQ("(a, 1, 2.0)", fmt::format("({})", fmt::join(t1, ", ")));
// Testing lvalue tuple args
int x = 4;
std::tuple<char, int&> t2{'b', x};
EXPECT_EQ("b + 4", fmt::format("{}", fmt::join(t2, " + ")));
// Empty tuple
std::tuple<> t3;
EXPECT_EQ("", fmt::format("{}", fmt::join(t3, "|")));
// Single element tuple
std::tuple<float> t4{4.0f};
EXPECT_EQ("4.0", fmt::format("{}", fmt::join(t4, "/")));
}
TEST(RangesTest, JoinInitializerList) {
EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join({1, 2, 3}, ", ")));
EXPECT_EQ("fmt rocks !",
fmt::format("{}", fmt::join({"fmt", "rocks", "!"}, " ")));
std::tuple<int64_t, float, std::string, char> tu1{42, 3.14159265358979f,
"this is tuple", 'i'};
EXPECT_EQ("(42, 3.14159, \"this is tuple\", 'i')", fmt::format("{}", tu1));
}
struct my_struct {
int32_t i;
std::string str; // can throw
template <std::size_t N> decltype(auto) get() const noexcept {
template <std::size_t N>
decltype(auto) get() const noexcept {
if constexpr (N == 0)
return i;
else if constexpr (N == 1)
@ -87,7 +61,8 @@ struct my_struct {
}
};
template <std::size_t N> decltype(auto) get(const my_struct& s) noexcept {
template <std::size_t N>
decltype(auto) get(const my_struct& s) noexcept {
return s.get<N>();
}
@ -96,7 +71,8 @@ namespace std {
template <>
struct tuple_size<my_struct> : std::integral_constant<std::size_t, 2> {};
template <std::size_t N> struct tuple_element<N, my_struct> {
template <std::size_t N>
struct tuple_element<N, my_struct> {
using type = decltype(std::declval<my_struct>().get<N>());
};
@ -107,36 +83,5 @@ TEST(RangesTest, FormatStruct) {
EXPECT_EQ("(13, \"my struct\")", fmt::format("{}", mst));
}
TEST(RangesTest, FormatTo) {
char buf[10];
auto end = fmt::format_to(buf, "{}", std::vector{1, 2, 3});
*end = '\0';
EXPECT_STREQ(buf, "{1, 2, 3}");
}
struct path_like {
const path_like* begin() const;
const path_like* end() const;
operator std::string() const;
};
TEST(RangesTest, PathLike) {
EXPECT_FALSE((fmt::is_range<path_like, char>::value));
}
#endif // (__cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >
// 201402L && _MSC_VER >= 1910)
#ifdef FMT_USE_STRING_VIEW
struct string_like {
const char* begin();
const char* end();
explicit operator fmt::string_view() const { return "foo"; }
explicit operator std::string_view() const { return "foo"; }
};
TEST(RangesTest, FormatStringLike) {
EXPECT_EQ("foo", fmt::format("{}", string_like()));
}
#endif // FMT_USE_STRING_VIEW

View File

@ -1,114 +0,0 @@
// Formatting library for C++ - scanning API test
//
// Copyright (c) 2019 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include <time.h>
#include <climits>
#include "gmock.h"
#include "gtest-extra.h"
#include "scan.h"
TEST(ScanTest, ReadText) {
fmt::string_view s = "foo";
auto end = fmt::scan(s, "foo");
EXPECT_EQ(end, s.end());
EXPECT_THROW_MSG(fmt::scan("fob", "foo"), fmt::format_error, "invalid input");
}
TEST(ScanTest, ReadInt) {
int n = 0;
fmt::scan("42", "{}", n);
EXPECT_EQ(n, 42);
fmt::scan("-42", "{}", n);
EXPECT_EQ(n, -42);
}
TEST(ScanTest, ReadLongLong) {
long long n = 0;
fmt::scan("42", "{}", n);
EXPECT_EQ(n, 42);
fmt::scan("-42", "{}", n);
EXPECT_EQ(n, -42);
}
TEST(ScanTest, ReadUInt) {
unsigned n = 0;
fmt::scan("42", "{}", n);
EXPECT_EQ(n, 42);
EXPECT_THROW_MSG(fmt::scan("-42", "{}", n), fmt::format_error,
"invalid input");
}
TEST(ScanTest, ReadULongLong) {
unsigned long long n = 0;
fmt::scan("42", "{}", n);
EXPECT_EQ(n, 42);
EXPECT_THROW_MSG(fmt::scan("-42", "{}", n), fmt::format_error,
"invalid input");
}
TEST(ScanTest, ReadString) {
std::string s;
fmt::scan("foo", "{}", s);
EXPECT_EQ(s, "foo");
}
TEST(ScanTest, ReadStringView) {
fmt::string_view s;
fmt::scan("foo", "{}", s);
EXPECT_EQ(s, "foo");
}
#ifndef _WIN32
namespace fmt {
template <> struct scanner<tm> {
std::string format;
scan_parse_context::iterator parse(scan_parse_context& ctx) {
auto it = ctx.begin();
if (it != ctx.end() && *it == ':') ++it;
auto end = it;
while (end != ctx.end() && *end != '}') ++end;
format.reserve(internal::to_unsigned(end - it + 1));
format.append(it, end);
format.push_back('\0');
return end;
}
template <class ScanContext>
typename ScanContext::iterator scan(tm& t, ScanContext& ctx) {
auto result = strptime(ctx.begin(), format.c_str(), &t);
if (!result) throw format_error("failed to parse time");
return result;
}
};
} // namespace fmt
TEST(ScanTest, ReadCustom) {
const char* input = "Date: 1985-10-25";
auto t = tm();
fmt::scan(input, "Date: {0:%Y-%m-%d}", t);
EXPECT_EQ(t.tm_year, 85);
EXPECT_EQ(t.tm_mon, 9);
EXPECT_EQ(t.tm_mday, 25);
}
#endif
TEST(ScanTest, InvalidFormat) {
EXPECT_THROW_MSG(fmt::scan("", "{}"), fmt::format_error,
"argument index out of range");
EXPECT_THROW_MSG(fmt::scan("", "{"), fmt::format_error,
"invalid format string");
}
TEST(ScanTest, Example) {
std::string key;
int value;
fmt::scan("answer = 42", "{} = {}", key, value);
EXPECT_EQ(key, "answer");
EXPECT_EQ(value, 42);
}

View File

@ -1,237 +0,0 @@
// Formatting library for C++ - scanning API proof of concept
//
// Copyright (c) 2019 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include <array>
#include <cassert>
#include <climits>
#include "fmt/format.h"
FMT_BEGIN_NAMESPACE
template <typename T, typename Char = char> struct scanner {
// A deleted default constructor indicates a disabled scanner.
scanner() = delete;
};
class scan_parse_context {
private:
string_view format_;
public:
using iterator = string_view::iterator;
explicit FMT_CONSTEXPR scan_parse_context(string_view format)
: format_(format) {}
FMT_CONSTEXPR iterator begin() const { return format_.begin(); }
FMT_CONSTEXPR iterator end() const { return format_.end(); }
void advance_to(iterator it) {
format_.remove_prefix(internal::to_unsigned(it - begin()));
}
};
struct scan_context {
private:
string_view input_;
public:
using iterator = const char*;
explicit scan_context(string_view input) : input_(input) {}
iterator begin() const { return input_.data(); }
iterator end() const { return begin() + input_.size(); }
void advance_to(iterator it) {
input_.remove_prefix(internal::to_unsigned(it - begin()));
}
};
namespace internal {
enum class scan_type {
none_type,
int_type,
uint_type,
long_long_type,
ulong_long_type,
string_type,
string_view_type,
custom_type
};
struct custom_scan_arg {
void* value;
void (*scan)(void* arg, scan_parse_context& parse_ctx, scan_context& ctx);
};
class scan_arg {
public:
scan_type type;
union {
int* int_value;
unsigned* uint_value;
long long* long_long_value;
unsigned long long* ulong_long_value;
std::string* string;
fmt::string_view* string_view;
custom_scan_arg custom;
// TODO: more types
};
scan_arg() : type(scan_type::none_type) {}
scan_arg(int& value) : type(scan_type::int_type), int_value(&value) {}
scan_arg(unsigned& value) : type(scan_type::uint_type), uint_value(&value) {}
scan_arg(long long& value)
: type(scan_type::long_long_type), long_long_value(&value) {}
scan_arg(unsigned long long& value)
: type(scan_type::ulong_long_type), ulong_long_value(&value) {}
scan_arg(std::string& value) : type(scan_type::string_type), string(&value) {}
scan_arg(fmt::string_view& value)
: type(scan_type::string_view_type), string_view(&value) {}
template <typename T> scan_arg(T& value) : type(scan_type::custom_type) {
custom.value = &value;
custom.scan = scan_custom_arg<T>;
}
private:
template <typename T>
static void scan_custom_arg(void* arg, scan_parse_context& parse_ctx,
scan_context& ctx) {
scanner<T> s;
parse_ctx.advance_to(s.parse(parse_ctx));
ctx.advance_to(s.scan(*static_cast<T*>(arg), ctx));
}
};
} // namespace internal
struct scan_args {
int size;
const internal::scan_arg* data;
template <size_t N>
scan_args(const std::array<internal::scan_arg, N>& store)
: size(N), data(store.data()) {
static_assert(N < INT_MAX, "too many arguments");
}
};
namespace internal {
struct scan_handler : error_handler {
private:
scan_parse_context parse_ctx_;
scan_context scan_ctx_;
scan_args args_;
int next_arg_id_;
scan_arg arg_;
template <typename T = unsigned> T read_uint() {
T value = 0;
auto it = scan_ctx_.begin(), end = scan_ctx_.end();
while (it != end) {
char c = *it++;
if (c < '0' || c > '9') on_error("invalid input");
// TODO: check overflow
value = value * 10 + static_cast<unsigned>(c - '0');
}
scan_ctx_.advance_to(it);
return value;
}
template <typename T = int> T read_int() {
auto it = scan_ctx_.begin(), end = scan_ctx_.end();
bool negative = it != end && *it == '-';
if (negative) ++it;
scan_ctx_.advance_to(it);
const auto value = read_uint<typename std::make_unsigned<T>::type>();
if (negative) return -static_cast<T>(value);
return static_cast<T>(value);
}
public:
scan_handler(string_view format, string_view input, scan_args args)
: parse_ctx_(format), scan_ctx_(input), args_(args), next_arg_id_(0) {}
const char* pos() const { return scan_ctx_.begin(); }
void on_text(const char* begin, const char* end) {
auto size = to_unsigned(end - begin);
auto it = scan_ctx_.begin();
if (it + size > scan_ctx_.end() ||
!std::equal(begin, end, make_checked(it, size))) {
on_error("invalid input");
}
scan_ctx_.advance_to(it + size);
}
void on_arg_id() { on_arg_id(next_arg_id_++); }
void on_arg_id(int id) {
if (id >= args_.size) on_error("argument index out of range");
arg_ = args_.data[id];
}
void on_arg_id(string_view) { on_error("invalid format"); }
void on_replacement_field(const char*) {
auto it = scan_ctx_.begin(), end = scan_ctx_.end();
switch (arg_.type) {
case scan_type::int_type:
*arg_.int_value = read_int();
break;
case scan_type::uint_type:
*arg_.uint_value = read_uint();
break;
case scan_type::long_long_type:
*arg_.long_long_value = read_int<long long>();
break;
case scan_type::ulong_long_type:
*arg_.ulong_long_value = read_uint<unsigned long long>();
break;
case scan_type::string_type:
while (it != end && *it != ' ') arg_.string->push_back(*it++);
scan_ctx_.advance_to(it);
break;
case scan_type::string_view_type: {
auto s = it;
while (it != end && *it != ' ') ++it;
*arg_.string_view = fmt::string_view(s, to_unsigned(it - s));
scan_ctx_.advance_to(it);
break;
}
case scan_type::none_type:
case scan_type::custom_type:
assert(false);
}
}
const char* on_format_specs(const char* begin, const char*) {
if (arg_.type != scan_type::custom_type) return begin;
parse_ctx_.advance_to(begin);
arg_.custom.scan(arg_.custom.value, parse_ctx_, scan_ctx_);
return parse_ctx_.begin();
}
};
} // namespace internal
template <typename... Args>
std::array<internal::scan_arg, sizeof...(Args)> make_scan_args(Args&... args) {
return {{args...}};
}
string_view::iterator vscan(string_view input, string_view format_str,
scan_args args) {
internal::scan_handler h(format_str, input, args);
internal::parse_format_string<false>(format_str, h);
return input.begin() + (h.pos() - &*input.begin());
}
template <typename... Args>
string_view::iterator scan(string_view input, string_view format_str,
Args&... args) {
return vscan(input, format_str, make_scan_args(args...));
}
FMT_END_NAMESPACE

View File

@ -1,156 +0,0 @@
#include <format>
#include "gtest.h"
TEST(StdFormatTest, Escaping) {
using namespace std;
string s = format("{0}-{{", 8); // s == "8-{"
EXPECT_EQ(s, "8-{");
}
TEST(StdFormatTest, Indexing) {
using namespace std;
string s0 = format("{} to {}", "a", "b"); // OK: automatic indexing
string s1 = format("{1} to {0}", "a", "b"); // OK: manual indexing
EXPECT_EQ(s0, "a to b");
EXPECT_EQ(s1, "b to a");
// Error: mixing automatic and manual indexing
EXPECT_THROW(string s2 = format("{0} to {}", "a", "b"), std::format_error);
// Error: mixing automatic and manual indexing
EXPECT_THROW(string s3 = format("{} to {1}", "a", "b"), std::format_error);
}
TEST(StdFormatTest, Alignment) {
using namespace std;
char c = 120;
string s0 = format("{:6}", 42); // s0 == " 42"
string s1 = format("{:6}", 'x'); // s1 == "x "
string s2 = format("{:*<6}", 'x'); // s2 == "x*****"
string s3 = format("{:*>6}", 'x'); // s3 == "*****x"
string s4 = format("{:*^6}", 'x'); // s4 == "**x***"
// Error: '=' with charT and no integer presentation type
EXPECT_THROW(string s5 = format("{:=6}", 'x'), std::format_error);
string s6 = format("{:6d}", c); // s6 == " 120"
string s7 = format("{:6}", true); // s9 == "true "
EXPECT_EQ(s0, " 42");
EXPECT_EQ(s1, "x ");
EXPECT_EQ(s2, "x*****");
EXPECT_EQ(s3, "*****x");
EXPECT_EQ(s4, "**x***");
EXPECT_EQ(s6, " 120");
EXPECT_EQ(s7, "true ");
}
TEST(StdFormatTest, Float) {
using namespace std;
double inf = numeric_limits<double>::infinity();
double nan = numeric_limits<double>::quiet_NaN();
string s0 = format("{0:} {0:+} {0:-} {0: }", 1); // s0 == "1 +1 1 1"
string s1 = format("{0:} {0:+} {0:-} {0: }", -1); // s1 == "-1 -1 -1 -1"
string s2 =
format("{0:} {0:+} {0:-} {0: }", inf); // s2 == "inf +inf inf inf"
string s3 =
format("{0:} {0:+} {0:-} {0: }", nan); // s3 == "nan +nan nan nan"
EXPECT_EQ(s0, "1 +1 1 1");
EXPECT_EQ(s1, "-1 -1 -1 -1");
EXPECT_EQ(s2, "inf +inf inf inf");
EXPECT_EQ(s3, "nan +nan nan nan");
}
TEST(StdFormatTest, Int) {
using namespace std;
string s0 = format("{}", 42); // s0 == "42"
string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42); // s1 == "101010 42 52 2a"
string s2 = format("{0:#x} {0:#X}", 42); // s2 == "0x2a 0X2A"
string s3 = format("{:n}", 1234); // s3 == "1234" (depends on the locale)
EXPECT_EQ(s0, "42");
EXPECT_EQ(s1, "101010 42 52 2a");
EXPECT_EQ(s2, "0x2a 0X2A");
EXPECT_EQ(s3, "1234");
}
#include <format>
enum color { red, green, blue };
const char* color_names[] = {"red", "green", "blue"};
template <> struct std::formatter<color> : std::formatter<const char*> {
auto format(color c, format_context& ctx) {
return formatter<const char*>::format(color_names[c], ctx);
}
};
struct err {};
TEST(StdFormatTest, Formatter) {
std::string s0 = std::format("{}", 42); // OK: library-provided formatter
// std::string s1 = std::format("{}", L"foo"); // Ill-formed: disabled
// formatter
std::string s2 = std::format("{}", red); // OK: user-provided formatter
// std::string s3 = std::format("{}", err{}); // Ill-formed: disabled
// formatter
EXPECT_EQ(s0, "42");
EXPECT_EQ(s2, "red");
}
struct S {
int value;
};
template <> struct std::formatter<S> {
size_t width_arg_id = 0;
// Parses a width argument id in the format { <digit> }.
constexpr auto parse(format_parse_context& ctx) {
auto iter = ctx.begin();
// auto get_char = [&]() { return iter != ctx.end() ? *iter : 0; };
auto get_char = [&]() { return iter != ctx.end() ? *iter : '\0'; };
if (get_char() != '{') return iter;
++iter;
char c = get_char();
if (!isdigit(c) || (++iter, get_char()) != '}')
throw format_error("invalid format");
width_arg_id = c - '0';
ctx.check_arg_id(width_arg_id);
return ++iter;
}
// Formats S with width given by the argument width_arg_id.
auto format(S s, format_context& ctx) {
int width = visit_format_arg(
[](auto value) -> int {
using type = decltype(value);
if constexpr (!is_integral_v<type> || is_same_v<type, bool>)
throw format_error("width is not integral");
// else if (value < 0 || value > numeric_limits<int>::max())
else if (fmt::internal::is_negative(value) ||
value > numeric_limits<int>::max())
throw format_error("invalid width");
else
return static_cast<int>(value);
},
ctx.arg(width_arg_id));
return format_to(ctx.out(), "{0:{1}}", s.value, width);
}
};
TEST(StdFormatTest, Parsing) {
std::string s = std::format("{0:{1}}", S{42}, 10); // s == " 42"
EXPECT_EQ(s, " 42");
}
#if FMT_USE_INT128
template <> struct std::formatter<__int128_t> : std::formatter<long long> {
auto format(__int128_t n, format_context& ctx) {
// Format as a long long since we only want to check if it is possible to
// specialize formatter for __int128_t.
return formatter<long long>::format(static_cast<long long>(n), ctx);
}
};
TEST(StdFormatTest, Int128) {
__int128_t n = 42;
auto s = std::format("{}", n);
EXPECT_EQ(s, "42");
}
#endif // FMT_USE_INT128

View File

@ -13,14 +13,9 @@
class assertion_failure : public std::logic_error {
public:
explicit assertion_failure(const char* message) : std::logic_error(message) {}
private:
virtual void avoid_weak_vtable();
explicit assertion_failure(const char *message) : std::logic_error(message) {}
};
void assertion_failure::avoid_weak_vtable() {}
#define FMT_ASSERT(condition, message) \
if (!(condition)) throw assertion_failure(message);

View File

@ -9,23 +9,23 @@
#include "gtest.h"
#ifdef _WIN32
# include <windows.h>
# include <windows.h>
#endif
#ifdef _MSC_VER
# include <crtdbg.h>
# include <crtdbg.h>
#else
# define _CrtSetReportFile(a, b)
# define _CrtSetReportMode(a, b)
# define _CrtSetReportFile(a, b)
# define _CrtSetReportMode(a, b)
#endif
int main(int argc, char** argv) {
int main(int argc, char **argv) {
#ifdef _WIN32
// Don't display any error dialogs. This also suppresses message boxes
// on assertion failures in MinGW where _set_error_mode/CrtSetReportMode
// doesn't help.
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX);
SEM_NOOPENFILEERRORBOX);
#endif
// Disable message boxes on assertion failures.
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);

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