simpleble 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +88 -0
- data/LICENSE.txt +21 -0
- data/README.md +350 -0
- data/ext/simpleble/extconf.rb +57 -0
- data/ext/simpleble/simpleble_ruby.c +682 -0
- data/lib/simpleble/adapter.rb +10 -0
- data/lib/simpleble/characteristic.rb +36 -0
- data/lib/simpleble/descriptor.rb +8 -0
- data/lib/simpleble/exceptions.rb +25 -0
- data/lib/simpleble/peripheral.rb +64 -0
- data/lib/simpleble/service.rb +16 -0
- data/lib/simpleble/version.rb +3 -0
- data/lib/simpleble.rb +40 -0
- data/vendor/simpleble/build_simplecble/CMakeFiles/4.0.3/CompilerIdCXX/CMakeCXXCompilerId.cpp +920 -0
- data/vendor/simpleble/build_simplecble/CMakeFiles/4.0.3/CompilerIdCXX/apple-sdk.cpp +1 -0
- data/vendor/simpleble/build_simplecble/CMakeFiles/4.1.0/CompilerIdCXX/CMakeCXXCompilerId.cpp +949 -0
- data/vendor/simpleble/build_simplecble/CMakeFiles/4.1.0/CompilerIdCXX/apple-sdk.cpp +1 -0
- data/vendor/simpleble/build_simplecble/export/simplecble/export.h +43 -0
- data/vendor/simpleble/build_simplecble/simpleble/export/simpleble/export.h +43 -0
- data/vendor/simpleble/dependencies/external/kvn/kvn_bytearray.h +222 -0
- data/vendor/simpleble/dependencies/external/kvn/kvn_safe_callback.hpp +66 -0
- data/vendor/simpleble/dependencies/external/kvn/logfwd.hpp +35 -0
- data/vendor/simpleble/dependencies/internal/fmt/args.h +220 -0
- data/vendor/simpleble/dependencies/internal/fmt/base.h +2962 -0
- data/vendor/simpleble/dependencies/internal/fmt/chrono.h +2338 -0
- data/vendor/simpleble/dependencies/internal/fmt/color.h +610 -0
- data/vendor/simpleble/dependencies/internal/fmt/compile.h +539 -0
- data/vendor/simpleble/dependencies/internal/fmt/core.h +5 -0
- data/vendor/simpleble/dependencies/internal/fmt/format-inl.h +1949 -0
- data/vendor/simpleble/dependencies/internal/fmt/format.h +4244 -0
- data/vendor/simpleble/dependencies/internal/fmt/os.h +427 -0
- data/vendor/simpleble/dependencies/internal/fmt/ostream.h +166 -0
- data/vendor/simpleble/dependencies/internal/fmt/printf.h +633 -0
- data/vendor/simpleble/dependencies/internal/fmt/ranges.h +850 -0
- data/vendor/simpleble/dependencies/internal/fmt/std.h +726 -0
- data/vendor/simpleble/dependencies/internal/fmt/xchar.h +373 -0
- data/vendor/simpleble/dependencies/internal/simplejni/Common.hpp +579 -0
- data/vendor/simpleble/dependencies/internal/simplejni/References.hpp +151 -0
- data/vendor/simpleble/dependencies/internal/simplejni/Registry.hpp +183 -0
- data/vendor/simpleble/dependencies/internal/simplejni/VM.hpp +88 -0
- data/vendor/simpleble/examples/simpleble/src/connect.cpp +67 -0
- data/vendor/simpleble/examples/simpleble/src/connect_safe.cpp +91 -0
- data/vendor/simpleble/examples/simpleble/src/list_adapters.cpp +22 -0
- data/vendor/simpleble/examples/simpleble/src/list_adapters_safe.cpp +33 -0
- data/vendor/simpleble/examples/simpleble/src/list_paired.cpp +27 -0
- data/vendor/simpleble/examples/simpleble/src/multiconnect.cpp +60 -0
- data/vendor/simpleble/examples/simpleble/src/notify.cpp +85 -0
- data/vendor/simpleble/examples/simpleble/src/notify_multi.cpp +101 -0
- data/vendor/simpleble/examples/simpleble/src/power_cycle.cpp +43 -0
- data/vendor/simpleble/examples/simpleble/src/read.cpp +82 -0
- data/vendor/simpleble/examples/simpleble/src/scan.cpp +62 -0
- data/vendor/simpleble/examples/simpleble/src/utils.cpp +59 -0
- data/vendor/simpleble/examples/simpleble/src/utils.hpp +27 -0
- data/vendor/simpleble/examples/simpleble/src/write.cpp +81 -0
- data/vendor/simpleble/examples/simplebluez/ble_nus/ble_nus.cpp +138 -0
- data/vendor/simpleble/examples/simplebluez/connect/connect.cpp +119 -0
- data/vendor/simpleble/examples/simplebluez/list_adapters/list_adapters.cpp +44 -0
- data/vendor/simpleble/examples/simplebluez/list_paired/list_paired.cpp +48 -0
- data/vendor/simpleble/examples/simplebluez/notify/notify.cpp +145 -0
- data/vendor/simpleble/examples/simplebluez/pair/pair.cpp +181 -0
- data/vendor/simpleble/examples/simplebluez/read/read.cpp +141 -0
- data/vendor/simpleble/examples/simplebluez/scan/scan.cpp +85 -0
- data/vendor/simpleble/examples/simplecble/c/connect.c +163 -0
- data/vendor/simpleble/examples/simplecble/c/notify.c +217 -0
- data/vendor/simpleble/examples/simplecble/c/scan.c +164 -0
- data/vendor/simpleble/examples/simpledbus/notification.cpp +24 -0
- data/vendor/simpleble/hitl/src/test_sanity.cpp +48 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/Adapter.h +102 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/AdapterSafe.h +58 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/Advanced.h +50 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/Characteristic.h +39 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/Config.h +55 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/Descriptor.h +30 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/Exceptions.h +72 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/Logging.h +73 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/Peripheral.h +82 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/PeripheralSafe.h +64 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/Service.h +34 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/SimpleBLE.h +8 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/Types.h +49 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/Utils.h +13 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/export.h +43 -0
- data/vendor/simpleble/install_simplecble/include/simpleble/kvn/kvn_bytearray.h +222 -0
- data/vendor/simpleble/install_simplecble/include/simplecble/adapter.h +188 -0
- data/vendor/simpleble/install_simplecble/include/simplecble/logging.h +37 -0
- data/vendor/simpleble/install_simplecble/include/simplecble/peripheral.h +304 -0
- data/vendor/simpleble/install_simplecble/include/simplecble/simpleble.h +21 -0
- data/vendor/simpleble/install_simplecble/include/simplecble/types.h +73 -0
- data/vendor/simpleble/install_simplecble/include/simplecble/utils.h +27 -0
- data/vendor/simpleble/simpleble/include/simpleble/Adapter.h +102 -0
- data/vendor/simpleble/simpleble/include/simpleble/AdapterSafe.h +58 -0
- data/vendor/simpleble/simpleble/include/simpleble/Characteristic.h +39 -0
- data/vendor/simpleble/simpleble/include/simpleble/Config.h +55 -0
- data/vendor/simpleble/simpleble/include/simpleble/Descriptor.h +30 -0
- data/vendor/simpleble/simpleble/include/simpleble/Exceptions.h +72 -0
- data/vendor/simpleble/simpleble/include/simpleble/Logging.h +73 -0
- data/vendor/simpleble/simpleble/include/simpleble/Peripheral.h +82 -0
- data/vendor/simpleble/simpleble/include/simpleble/PeripheralSafe.h +64 -0
- data/vendor/simpleble/simpleble/include/simpleble/Service.h +34 -0
- data/vendor/simpleble/simpleble/include/simpleble/SimpleBLE.h +8 -0
- data/vendor/simpleble/simpleble/include/simpleble/Types.h +49 -0
- data/vendor/simpleble/simpleble/include/simpleble/Utils.h +13 -0
- data/vendor/simpleble/simpleble/include/simpleble_c/adapter.h +188 -0
- data/vendor/simpleble/simpleble/include/simpleble_c/logging.h +37 -0
- data/vendor/simpleble/simpleble/include/simpleble_c/peripheral.h +304 -0
- data/vendor/simpleble/simpleble/include/simpleble_c/simpleble.h +21 -0
- data/vendor/simpleble/simpleble/include/simpleble_c/types.h +73 -0
- data/vendor/simpleble/simpleble/include/simpleble_c/utils.h +27 -0
- data/vendor/simpleble/simpleble/src/CommonUtils.h +63 -0
- data/vendor/simpleble/simpleble/src/Exceptions.cpp +31 -0
- data/vendor/simpleble/simpleble/src/Logging.cpp +136 -0
- data/vendor/simpleble/simpleble/src/LoggingInternal.h +85 -0
- data/vendor/simpleble/simpleble/src/Utils.cpp +24 -0
- data/vendor/simpleble/simpleble/src/backends/android/AdapterAndroid.cpp +101 -0
- data/vendor/simpleble/simpleble/src/backends/android/AdapterAndroid.h +70 -0
- data/vendor/simpleble/simpleble/src/backends/android/BackendAndroid.cpp +40 -0
- data/vendor/simpleble/simpleble/src/backends/android/BackendAndroid.h +20 -0
- data/vendor/simpleble/simpleble/src/backends/android/PeripheralAndroid.cpp +365 -0
- data/vendor/simpleble/simpleble/src/backends/android/PeripheralAndroid.h +90 -0
- data/vendor/simpleble/simpleble/src/backends/android/bridge/BluetoothGattCallback.cpp +432 -0
- data/vendor/simpleble/simpleble/src/backends/android/bridge/BluetoothGattCallback.h +102 -0
- data/vendor/simpleble/simpleble/src/backends/android/bridge/ScanCallback.cpp +142 -0
- data/vendor/simpleble/simpleble/src/backends/android/bridge/ScanCallback.h +55 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/BluetoothAdapter.cpp +107 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/BluetoothAdapter.h +55 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/BluetoothDevice.cpp +68 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/BluetoothDevice.h +54 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/BluetoothGatt.cpp +115 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/BluetoothGatt.h +75 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/BluetoothGattCharacteristic.cpp +142 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/BluetoothGattCharacteristic.h +66 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/BluetoothGattDescriptor.cpp +67 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/BluetoothGattDescriptor.h +46 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/BluetoothGattService.cpp +106 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/BluetoothGattService.h +47 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/le/BluetoothScanner.cpp +47 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/le/BluetoothScanner.h +37 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/le/ScanRecord.cpp +69 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/le/ScanRecord.h +41 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/le/ScanResult.cpp +63 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/bluetooth/le/ScanResult.h +42 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/os/ParcelUUID.cpp +32 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/os/ParcelUUID.h +30 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/util/SparseArray.cpp +54 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/android/util/SparseArray.h +37 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/java/util/Iterator.cpp +36 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/java/util/Iterator.h +28 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/java/util/List.cpp +29 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/java/util/List.h +27 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/java/util/Set.cpp +33 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/java/util/Set.h +28 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/java/util/UUID.cpp +26 -0
- data/vendor/simpleble/simpleble/src/backends/android/types/java/util/UUID.h +29 -0
- data/vendor/simpleble/simpleble/src/backends/common/AdapterBase.cpp +53 -0
- data/vendor/simpleble/simpleble/src/backends/common/AdapterBase.h +81 -0
- data/vendor/simpleble/simpleble/src/backends/common/AdapterBaseTypes.h +22 -0
- data/vendor/simpleble/simpleble/src/backends/common/BackendBase.h +20 -0
- data/vendor/simpleble/simpleble/src/backends/common/BackendUtils.h +33 -0
- data/vendor/simpleble/simpleble/src/backends/common/CharacteristicBase.cpp +28 -0
- data/vendor/simpleble/simpleble/src/backends/common/CharacteristicBase.h +38 -0
- data/vendor/simpleble/simpleble/src/backends/common/DescriptorBase.cpp +7 -0
- data/vendor/simpleble/simpleble/src/backends/common/DescriptorBase.h +19 -0
- data/vendor/simpleble/simpleble/src/backends/common/PeripheralBase.h +82 -0
- data/vendor/simpleble/simpleble/src/backends/common/ServiceBase.cpp +18 -0
- data/vendor/simpleble/simpleble/src/backends/common/ServiceBase.h +28 -0
- data/vendor/simpleble/simpleble/src/backends/linux/AdapterLinux.cpp +102 -0
- data/vendor/simpleble/simpleble/src/backends/linux/AdapterLinux.h +55 -0
- data/vendor/simpleble/simpleble/src/backends/linux/BackendBluez.cpp +87 -0
- data/vendor/simpleble/simpleble/src/backends/linux/PeripheralLinux.cpp +376 -0
- data/vendor/simpleble/simpleble/src/backends/linux/PeripheralLinux.h +90 -0
- data/vendor/simpleble/simpleble/src/backends/macos/AdapterBaseMacOS.h +29 -0
- data/vendor/simpleble/simpleble/src/backends/macos/AdapterMac.h +78 -0
- data/vendor/simpleble/simpleble/src/backends/macos/PeripheralBaseMacOS.h +49 -0
- data/vendor/simpleble/simpleble/src/backends/macos/PeripheralMac.h +81 -0
- data/vendor/simpleble/simpleble/src/backends/macos/Utils.h +9 -0
- data/vendor/simpleble/simpleble/src/backends/plain/AdapterPlain.cpp +65 -0
- data/vendor/simpleble/simpleble/src/backends/plain/AdapterPlain.h +49 -0
- data/vendor/simpleble/simpleble/src/backends/plain/BackendPlain.cpp +30 -0
- data/vendor/simpleble/simpleble/src/backends/plain/PeripheralPlain.cpp +159 -0
- data/vendor/simpleble/simpleble/src/backends/plain/PeripheralPlain.h +72 -0
- data/vendor/simpleble/simpleble/src/backends/windows/AdapterWindows.cpp +330 -0
- data/vendor/simpleble/simpleble/src/backends/windows/AdapterWindows.h +89 -0
- data/vendor/simpleble/simpleble/src/backends/windows/BackendWinRT.cpp +67 -0
- data/vendor/simpleble/simpleble/src/backends/windows/BackendWinRT.h +18 -0
- data/vendor/simpleble/simpleble/src/backends/windows/MtaManager.cpp +49 -0
- data/vendor/simpleble/simpleble/src/backends/windows/MtaManager.h +90 -0
- data/vendor/simpleble/simpleble/src/backends/windows/PeripheralWindows.cpp +487 -0
- data/vendor/simpleble/simpleble/src/backends/windows/PeripheralWindows.h +129 -0
- data/vendor/simpleble/simpleble/src/backends/windows/Utils.cpp +146 -0
- data/vendor/simpleble/simpleble/src/backends/windows/Utils.h +47 -0
- data/vendor/simpleble/simpleble/src/builders/BuildVec.h +32 -0
- data/vendor/simpleble/simpleble/src/builders/BuilderBase.h +87 -0
- data/vendor/simpleble/simpleble/src/external/TaskRunner.hpp +99 -0
- data/vendor/simpleble/simpleble/src/external/ThreadRunner.h +52 -0
- data/vendor/simpleble/simpleble/src/external/kvn_safe_callback.hpp +66 -0
- data/vendor/simpleble/simpleble/src/external/kvn_safe_map.hpp +94 -0
- data/vendor/simpleble/simpleble/src/external/kvn_threadrunner.hpp +70 -0
- data/vendor/simpleble/simpleble/src/external/logfwd.hpp +35 -0
- data/vendor/simpleble/simpleble/src/frontends/base/Adapter.cpp +111 -0
- data/vendor/simpleble/simpleble/src/frontends/base/Backend.cpp +83 -0
- data/vendor/simpleble/simpleble/src/frontends/base/Backend.h +76 -0
- data/vendor/simpleble/simpleble/src/frontends/base/Characteristic.cpp +56 -0
- data/vendor/simpleble/simpleble/src/frontends/base/Descriptor.cpp +21 -0
- data/vendor/simpleble/simpleble/src/frontends/base/Peripheral.cpp +113 -0
- data/vendor/simpleble/simpleble/src/frontends/base/Service.cpp +26 -0
- data/vendor/simpleble/simpleble/src/frontends/safe/AdapterSafe.cpp +158 -0
- data/vendor/simpleble/simpleble/src/frontends/safe/PeripheralSafe.cpp +219 -0
- data/vendor/simpleble/simpleble/src_c/adapter.cpp +204 -0
- data/vendor/simpleble/simpleble/src_c/logging.cpp +19 -0
- data/vendor/simpleble/simpleble/src_c/peripheral.cpp +444 -0
- data/vendor/simpleble/simpleble/src_c/simpleble.cpp +5 -0
- data/vendor/simpleble/simpleble/src_c/utils.cpp +15 -0
- data/vendor/simpleble/simpleble/test/src/main.cpp +8 -0
- data/vendor/simpleble/simpleble/test/src/test_bytearray.cpp +246 -0
- data/vendor/simpleble/simpleble/test/src/test_utils.cpp +24 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/Adapter.h +46 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/Agent.h +52 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/Bluez.h +37 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/BluezOrg.h +22 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/BluezOrgBluez.h +26 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/BluezRoot.h +32 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/Characteristic.h +46 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/Descriptor.h +33 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/Device.h +64 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/Exceptions.h +43 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/Service.h +27 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/Types.h +9 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/interfaces/Adapter1.h +49 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/interfaces/Agent1.h +100 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/interfaces/AgentManager1.h +24 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/interfaces/Battery1.h +32 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/interfaces/Device1.h +62 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/interfaces/GattCharacteristic1.h +48 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/interfaces/GattDescriptor1.h +41 -0
- data/vendor/simpleble/simplebluez/include/simplebluez/interfaces/GattService1.h +28 -0
- data/vendor/simpleble/simplebluez/src/Adapter.cpp +78 -0
- data/vendor/simpleble/simplebluez/src/Agent.cpp +72 -0
- data/vendor/simpleble/simplebluez/src/Bluez.cpp +45 -0
- data/vendor/simpleble/simplebluez/src/BluezOrg.cpp +20 -0
- data/vendor/simpleble/simplebluez/src/BluezOrgBluez.cpp +23 -0
- data/vendor/simpleble/simplebluez/src/BluezRoot.cpp +44 -0
- data/vendor/simpleble/simplebluez/src/Characteristic.cpp +64 -0
- data/vendor/simpleble/simplebluez/src/Descriptor.cpp +27 -0
- data/vendor/simpleble/simplebluez/src/Device.cpp +104 -0
- data/vendor/simpleble/simplebluez/src/Exceptions.cpp +29 -0
- data/vendor/simpleble/simplebluez/src/Logging.cpp +52 -0
- data/vendor/simpleble/simplebluez/src/Logging.h +57 -0
- data/vendor/simpleble/simplebluez/src/Service.cpp +33 -0
- data/vendor/simpleble/simplebluez/src/interfaces/Adapter1.cpp +123 -0
- data/vendor/simpleble/simplebluez/src/interfaces/Agent1.cpp +143 -0
- data/vendor/simpleble/simplebluez/src/interfaces/AgentManager1.cpp +34 -0
- data/vendor/simpleble/simplebluez/src/interfaces/Battery1.cpp +30 -0
- data/vendor/simpleble/simplebluez/src/interfaces/Device1.cpp +170 -0
- data/vendor/simpleble/simplebluez/src/interfaces/GattCharacteristic1.cpp +118 -0
- data/vendor/simpleble/simplebluez/src/interfaces/GattDescriptor1.cpp +78 -0
- data/vendor/simpleble/simplebluez/src/interfaces/GattService1.cpp +28 -0
- data/vendor/simpleble/simplebluez/test/src/helpers/PythonRunner.cpp +53 -0
- data/vendor/simpleble/simplebluez/test/src/helpers/PythonRunner.h +24 -0
- data/vendor/simpleble/simplebluez/test/src/main.cpp +16 -0
- data/vendor/simpleble/simplecble/include/simplecble/adapter.h +188 -0
- data/vendor/simpleble/simplecble/include/simplecble/logging.h +37 -0
- data/vendor/simpleble/simplecble/include/simplecble/peripheral.h +304 -0
- data/vendor/simpleble/simplecble/include/simplecble/simpleble.h +21 -0
- data/vendor/simpleble/simplecble/include/simplecble/types.h +73 -0
- data/vendor/simpleble/simplecble/include/simplecble/utils.h +27 -0
- data/vendor/simpleble/simplecble/src/adapter.cpp +204 -0
- data/vendor/simpleble/simplecble/src/logging.cpp +19 -0
- data/vendor/simpleble/simplecble/src/peripheral.cpp +444 -0
- data/vendor/simpleble/simplecble/src/simpleble.cpp +5 -0
- data/vendor/simpleble/simplecble/src/utils.cpp +15 -0
- data/vendor/simpleble/simpledbus/include/simpledbus/advanced/Interface.h +67 -0
- data/vendor/simpleble/simpledbus/include/simpledbus/advanced/InterfaceRegistry.h +64 -0
- data/vendor/simpleble/simpledbus/include/simpledbus/advanced/Proxy.h +117 -0
- data/vendor/simpleble/simpledbus/include/simpledbus/base/Connection.h +50 -0
- data/vendor/simpleble/simpledbus/include/simpledbus/base/Exceptions.h +56 -0
- data/vendor/simpleble/simpledbus/include/simpledbus/base/Holder.h +147 -0
- data/vendor/simpleble/simpledbus/include/simpledbus/base/Logging.h +57 -0
- data/vendor/simpleble/simpledbus/include/simpledbus/base/Message.h +89 -0
- data/vendor/simpleble/simpledbus/include/simpledbus/base/Path.h +24 -0
- data/vendor/simpleble/simpledbus/include/simpledbus/interfaces/ObjectManager.h +26 -0
- data/vendor/simpleble/simpledbus/src/advanced/Interface.cpp +155 -0
- data/vendor/simpleble/simpledbus/src/advanced/Proxy.cpp +375 -0
- data/vendor/simpleble/simpledbus/src/base/Connection.cpp +222 -0
- data/vendor/simpleble/simpledbus/src/base/Exceptions.cpp +39 -0
- data/vendor/simpleble/simpledbus/src/base/Holder.cpp +739 -0
- data/vendor/simpleble/simpledbus/src/base/Logging.cpp +52 -0
- data/vendor/simpleble/simpledbus/src/base/Message.cpp +622 -0
- data/vendor/simpleble/simpledbus/src/base/Path.cpp +129 -0
- data/vendor/simpleble/simpledbus/src/interfaces/ObjectManager.cpp +58 -0
- data/vendor/simpleble/simpledbus/test/src/helpers/PythonRunner.cpp +53 -0
- data/vendor/simpleble/simpledbus/test/src/helpers/PythonRunner.h +24 -0
- data/vendor/simpleble/simpledbus/test/src/main.cpp +16 -0
- data/vendor/simpleble/simpledbus/test/src/test_holder.cpp +184 -0
- data/vendor/simpleble/simpledbus/test/src/test_message.cpp +397 -0
- data/vendor/simpleble/simpledbus/test/src/test_path.cpp +76 -0
- data/vendor/simpleble/simpledbus/test/src/test_proxy_children.cpp +109 -0
- data/vendor/simpleble/simpledbus/test/src/test_proxy_interfaces.cpp +102 -0
- data/vendor/simpleble/simpledbus/test/src/test_proxy_lifetime.cpp +18 -0
- data/vendor/simpleble/simpledroidble/simpledroidble/src/main/cpp/ThreadRunner.h +89 -0
- data/vendor/simpleble/simpledroidble/simpledroidble/src/main/cpp/android_utils.cpp +55 -0
- data/vendor/simpleble/simpledroidble/simpledroidble/src/main/cpp/android_utils.h +18 -0
- data/vendor/simpleble/simpledroidble/simpledroidble/src/main/cpp/simpleble_android.cpp +813 -0
- data/vendor/simpleble/simplejavable/cpp/src/core/AdapterWrapper.cpp +37 -0
- data/vendor/simpleble/simplejavable/cpp/src/core/AdapterWrapper.h +23 -0
- data/vendor/simpleble/simplejavable/cpp/src/core/Cache.cpp +58 -0
- data/vendor/simpleble/simplejavable/cpp/src/core/Cache.h +34 -0
- data/vendor/simpleble/simplejavable/cpp/src/core/PeripheralWrapper.cpp +17 -0
- data/vendor/simpleble/simplejavable/cpp/src/core/PeripheralWrapper.h +19 -0
- data/vendor/simpleble/simplejavable/cpp/src/java/lang/ArrayList.cpp +257 -0
- data/vendor/simpleble/simplejavable/cpp/src/java/lang/ArrayList.h +78 -0
- data/vendor/simpleble/simplejavable/cpp/src/java/lang/HashMap.cpp +96 -0
- data/vendor/simpleble/simplejavable/cpp/src/java/lang/HashMap.h +54 -0
- data/vendor/simpleble/simplejavable/cpp/src/java/lang/Integer.cpp +93 -0
- data/vendor/simpleble/simplejavable/cpp/src/java/lang/Integer.h +49 -0
- data/vendor/simpleble/simplejavable/cpp/src/java/lang/Iterator.cpp +85 -0
- data/vendor/simpleble/simplejavable/cpp/src/java/lang/Iterator.h +48 -0
- data/vendor/simpleble/simplejavable/cpp/src/org/simplejavable/AdapterCallback.cpp +91 -0
- data/vendor/simpleble/simplejavable/cpp/src/org/simplejavable/AdapterCallback.h +90 -0
- data/vendor/simpleble/simplejavable/cpp/src/org/simplejavable/Characteristic.cpp +35 -0
- data/vendor/simpleble/simplejavable/cpp/src/org/simplejavable/Characteristic.h +60 -0
- data/vendor/simpleble/simplejavable/cpp/src/org/simplejavable/DataCallback.cpp +33 -0
- data/vendor/simpleble/simplejavable/cpp/src/org/simplejavable/DataCallback.h +45 -0
- data/vendor/simpleble/simplejavable/cpp/src/org/simplejavable/Descriptor.cpp +30 -0
- data/vendor/simpleble/simplejavable/cpp/src/org/simplejavable/Descriptor.h +49 -0
- data/vendor/simpleble/simplejavable/cpp/src/org/simplejavable/PeripheralCallback.cpp +41 -0
- data/vendor/simpleble/simplejavable/cpp/src/org/simplejavable/PeripheralCallback.h +51 -0
- data/vendor/simpleble/simplejavable/cpp/src/org/simplejavable/Service.cpp +33 -0
- data/vendor/simpleble/simplejavable/cpp/src/org/simplejavable/Service.h +54 -0
- data/vendor/simpleble/simplejavable/cpp/src/simplejavable.cpp +361 -0
- data/vendor/simpleble/simplepyble/src/main.cpp +55 -0
- data/vendor/simpleble/simplepyble/src/wrap_adapter.cpp +106 -0
- data/vendor/simpleble/simplepyble/src/wrap_characteristic.cpp +56 -0
- data/vendor/simpleble/simplepyble/src/wrap_config.cpp +136 -0
- data/vendor/simpleble/simplepyble/src/wrap_descriptor.cpp +21 -0
- data/vendor/simpleble/simplepyble/src/wrap_peripheral.cpp +217 -0
- data/vendor/simpleble/simplepyble/src/wrap_service.cpp +32 -0
- data/vendor/simpleble/simplepyble/src/wrap_types.cpp +21 -0
- data/vendor/simpleble/simplersble/src/bindings/Bindings.cpp +338 -0
- data/vendor/simpleble/simplersble/src/bindings/Bindings.hpp +178 -0
- metadata +430 -0
@@ -0,0 +1,2962 @@
|
|
1
|
+
// Formatting library for C++ - the base API for char/UTF-8
|
2
|
+
//
|
3
|
+
// Copyright (c) 2012 - present, Victor Zverovich
|
4
|
+
// All rights reserved.
|
5
|
+
//
|
6
|
+
// For the license information refer to format.h.
|
7
|
+
|
8
|
+
#ifndef FMT_BASE_H_
|
9
|
+
#define FMT_BASE_H_
|
10
|
+
|
11
|
+
#if defined(FMT_IMPORT_STD) && !defined(FMT_MODULE)
|
12
|
+
# define FMT_MODULE
|
13
|
+
#endif
|
14
|
+
|
15
|
+
#ifndef FMT_MODULE
|
16
|
+
# include <limits.h> // CHAR_BIT
|
17
|
+
# include <stdio.h> // FILE
|
18
|
+
# include <string.h> // memcmp
|
19
|
+
|
20
|
+
# include <type_traits> // std::enable_if
|
21
|
+
#endif
|
22
|
+
|
23
|
+
// The fmt library version in the form major * 10000 + minor * 100 + patch.
|
24
|
+
#define FMT_VERSION 110104
|
25
|
+
|
26
|
+
// Detect compiler versions.
|
27
|
+
#if defined(__clang__) && !defined(__ibmxl__)
|
28
|
+
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
|
29
|
+
#else
|
30
|
+
# define FMT_CLANG_VERSION 0
|
31
|
+
#endif
|
32
|
+
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
|
33
|
+
# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
34
|
+
#else
|
35
|
+
# define FMT_GCC_VERSION 0
|
36
|
+
#endif
|
37
|
+
#if defined(__ICL)
|
38
|
+
# define FMT_ICC_VERSION __ICL
|
39
|
+
#elif defined(__INTEL_COMPILER)
|
40
|
+
# define FMT_ICC_VERSION __INTEL_COMPILER
|
41
|
+
#else
|
42
|
+
# define FMT_ICC_VERSION 0
|
43
|
+
#endif
|
44
|
+
#if defined(_MSC_VER)
|
45
|
+
# define FMT_MSC_VERSION _MSC_VER
|
46
|
+
#else
|
47
|
+
# define FMT_MSC_VERSION 0
|
48
|
+
#endif
|
49
|
+
|
50
|
+
// Detect standard library versions.
|
51
|
+
#ifdef _GLIBCXX_RELEASE
|
52
|
+
# define FMT_GLIBCXX_RELEASE _GLIBCXX_RELEASE
|
53
|
+
#else
|
54
|
+
# define FMT_GLIBCXX_RELEASE 0
|
55
|
+
#endif
|
56
|
+
#ifdef _LIBCPP_VERSION
|
57
|
+
# define FMT_LIBCPP_VERSION _LIBCPP_VERSION
|
58
|
+
#else
|
59
|
+
# define FMT_LIBCPP_VERSION 0
|
60
|
+
#endif
|
61
|
+
|
62
|
+
#ifdef _MSVC_LANG
|
63
|
+
# define FMT_CPLUSPLUS _MSVC_LANG
|
64
|
+
#else
|
65
|
+
# define FMT_CPLUSPLUS __cplusplus
|
66
|
+
#endif
|
67
|
+
|
68
|
+
// Detect __has_*.
|
69
|
+
#ifdef __has_feature
|
70
|
+
# define FMT_HAS_FEATURE(x) __has_feature(x)
|
71
|
+
#else
|
72
|
+
# define FMT_HAS_FEATURE(x) 0
|
73
|
+
#endif
|
74
|
+
#ifdef __has_include
|
75
|
+
# define FMT_HAS_INCLUDE(x) __has_include(x)
|
76
|
+
#else
|
77
|
+
# define FMT_HAS_INCLUDE(x) 0
|
78
|
+
#endif
|
79
|
+
#ifdef __has_builtin
|
80
|
+
# define FMT_HAS_BUILTIN(x) __has_builtin(x)
|
81
|
+
#else
|
82
|
+
# define FMT_HAS_BUILTIN(x) 0
|
83
|
+
#endif
|
84
|
+
#ifdef __has_cpp_attribute
|
85
|
+
# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
|
86
|
+
#else
|
87
|
+
# define FMT_HAS_CPP_ATTRIBUTE(x) 0
|
88
|
+
#endif
|
89
|
+
|
90
|
+
#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
|
91
|
+
(FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
|
92
|
+
|
93
|
+
#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \
|
94
|
+
(FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute))
|
95
|
+
|
96
|
+
// Detect C++14 relaxed constexpr.
|
97
|
+
#ifdef FMT_USE_CONSTEXPR
|
98
|
+
// Use the provided definition.
|
99
|
+
#elif FMT_GCC_VERSION >= 702 && FMT_CPLUSPLUS >= 201402L
|
100
|
+
// GCC only allows constexpr member functions in non-literal types since 7.2:
|
101
|
+
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66297.
|
102
|
+
# define FMT_USE_CONSTEXPR 1
|
103
|
+
#elif FMT_ICC_VERSION
|
104
|
+
# define FMT_USE_CONSTEXPR 0 // https://github.com/fmtlib/fmt/issues/1628
|
105
|
+
#elif FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VERSION >= 1912
|
106
|
+
# define FMT_USE_CONSTEXPR 1
|
107
|
+
#else
|
108
|
+
# define FMT_USE_CONSTEXPR 0
|
109
|
+
#endif
|
110
|
+
#if FMT_USE_CONSTEXPR
|
111
|
+
# define FMT_CONSTEXPR constexpr
|
112
|
+
#else
|
113
|
+
# define FMT_CONSTEXPR
|
114
|
+
#endif
|
115
|
+
|
116
|
+
// Detect consteval, C++20 constexpr extensions and std::is_constant_evaluated.
|
117
|
+
#if !defined(__cpp_lib_is_constant_evaluated)
|
118
|
+
# define FMT_USE_CONSTEVAL 0
|
119
|
+
#elif FMT_CPLUSPLUS < 201709L
|
120
|
+
# define FMT_USE_CONSTEVAL 0
|
121
|
+
#elif FMT_GLIBCXX_RELEASE && FMT_GLIBCXX_RELEASE < 10
|
122
|
+
# define FMT_USE_CONSTEVAL 0
|
123
|
+
#elif FMT_LIBCPP_VERSION && FMT_LIBCPP_VERSION < 10000
|
124
|
+
# define FMT_USE_CONSTEVAL 0
|
125
|
+
#elif defined(__apple_build_version__) && __apple_build_version__ < 14000029L
|
126
|
+
# define FMT_USE_CONSTEVAL 0 // consteval is broken in Apple clang < 14.
|
127
|
+
#elif FMT_MSC_VERSION && FMT_MSC_VERSION < 1929
|
128
|
+
# define FMT_USE_CONSTEVAL 0 // consteval is broken in MSVC VS2019 < 16.10.
|
129
|
+
#elif defined(__cpp_consteval)
|
130
|
+
# define FMT_USE_CONSTEVAL 1
|
131
|
+
#elif FMT_GCC_VERSION >= 1002 || FMT_CLANG_VERSION >= 1101
|
132
|
+
# define FMT_USE_CONSTEVAL 1
|
133
|
+
#else
|
134
|
+
# define FMT_USE_CONSTEVAL 0
|
135
|
+
#endif
|
136
|
+
#if FMT_USE_CONSTEVAL
|
137
|
+
# define FMT_CONSTEVAL consteval
|
138
|
+
# define FMT_CONSTEXPR20 constexpr
|
139
|
+
#else
|
140
|
+
# define FMT_CONSTEVAL
|
141
|
+
# define FMT_CONSTEXPR20
|
142
|
+
#endif
|
143
|
+
|
144
|
+
// Check if exceptions are disabled.
|
145
|
+
#ifdef FMT_USE_EXCEPTIONS
|
146
|
+
// Use the provided definition.
|
147
|
+
#elif defined(__GNUC__) && !defined(__EXCEPTIONS)
|
148
|
+
# define FMT_USE_EXCEPTIONS 0
|
149
|
+
#elif defined(__clang__) && !defined(__cpp_exceptions)
|
150
|
+
# define FMT_USE_EXCEPTIONS 0
|
151
|
+
#elif FMT_MSC_VERSION && !_HAS_EXCEPTIONS
|
152
|
+
# define FMT_USE_EXCEPTIONS 0
|
153
|
+
#else
|
154
|
+
# define FMT_USE_EXCEPTIONS 1
|
155
|
+
#endif
|
156
|
+
#if FMT_USE_EXCEPTIONS
|
157
|
+
# define FMT_TRY try
|
158
|
+
# define FMT_CATCH(x) catch (x)
|
159
|
+
#else
|
160
|
+
# define FMT_TRY if (true)
|
161
|
+
# define FMT_CATCH(x) if (false)
|
162
|
+
#endif
|
163
|
+
|
164
|
+
#ifdef FMT_NO_UNIQUE_ADDRESS
|
165
|
+
// Use the provided definition.
|
166
|
+
#elif FMT_CPLUSPLUS < 202002L
|
167
|
+
// Not supported.
|
168
|
+
#elif FMT_HAS_CPP_ATTRIBUTE(no_unique_address)
|
169
|
+
# define FMT_NO_UNIQUE_ADDRESS [[no_unique_address]]
|
170
|
+
// VS2019 v16.10 and later except clang-cl (https://reviews.llvm.org/D110485).
|
171
|
+
#elif FMT_MSC_VERSION >= 1929 && !FMT_CLANG_VERSION
|
172
|
+
# define FMT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
|
173
|
+
#endif
|
174
|
+
#ifndef FMT_NO_UNIQUE_ADDRESS
|
175
|
+
# define FMT_NO_UNIQUE_ADDRESS
|
176
|
+
#endif
|
177
|
+
|
178
|
+
#if FMT_HAS_CPP17_ATTRIBUTE(fallthrough)
|
179
|
+
# define FMT_FALLTHROUGH [[fallthrough]]
|
180
|
+
#elif defined(__clang__)
|
181
|
+
# define FMT_FALLTHROUGH [[clang::fallthrough]]
|
182
|
+
#elif FMT_GCC_VERSION >= 700 && \
|
183
|
+
(!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520)
|
184
|
+
# define FMT_FALLTHROUGH [[gnu::fallthrough]]
|
185
|
+
#else
|
186
|
+
# define FMT_FALLTHROUGH
|
187
|
+
#endif
|
188
|
+
|
189
|
+
// Disable [[noreturn]] on MSVC/NVCC because of bogus unreachable code warnings.
|
190
|
+
#if FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && !defined(__NVCC__)
|
191
|
+
# define FMT_NORETURN [[noreturn]]
|
192
|
+
#else
|
193
|
+
# define FMT_NORETURN
|
194
|
+
#endif
|
195
|
+
|
196
|
+
#ifdef FMT_NODISCARD
|
197
|
+
// Use the provided definition.
|
198
|
+
#elif FMT_HAS_CPP17_ATTRIBUTE(nodiscard)
|
199
|
+
# define FMT_NODISCARD [[nodiscard]]
|
200
|
+
#else
|
201
|
+
# define FMT_NODISCARD
|
202
|
+
#endif
|
203
|
+
|
204
|
+
#ifdef FMT_DEPRECATED
|
205
|
+
// Use the provided definition.
|
206
|
+
#elif FMT_HAS_CPP14_ATTRIBUTE(deprecated)
|
207
|
+
# define FMT_DEPRECATED [[deprecated]]
|
208
|
+
#else
|
209
|
+
# define FMT_DEPRECATED /* deprecated */
|
210
|
+
#endif
|
211
|
+
|
212
|
+
#ifdef FMT_ALWAYS_INLINE
|
213
|
+
// Use the provided definition.
|
214
|
+
#elif FMT_GCC_VERSION || FMT_CLANG_VERSION
|
215
|
+
# define FMT_ALWAYS_INLINE inline __attribute__((always_inline))
|
216
|
+
#else
|
217
|
+
# define FMT_ALWAYS_INLINE inline
|
218
|
+
#endif
|
219
|
+
// A version of FMT_ALWAYS_INLINE to prevent code bloat in debug mode.
|
220
|
+
#ifdef NDEBUG
|
221
|
+
# define FMT_INLINE FMT_ALWAYS_INLINE
|
222
|
+
#else
|
223
|
+
# define FMT_INLINE inline
|
224
|
+
#endif
|
225
|
+
|
226
|
+
#if FMT_GCC_VERSION || FMT_CLANG_VERSION
|
227
|
+
# define FMT_VISIBILITY(value) __attribute__((visibility(value)))
|
228
|
+
#else
|
229
|
+
# define FMT_VISIBILITY(value)
|
230
|
+
#endif
|
231
|
+
|
232
|
+
// Detect pragmas.
|
233
|
+
#define FMT_PRAGMA_IMPL(x) _Pragma(#x)
|
234
|
+
#if FMT_GCC_VERSION >= 504 && !defined(__NVCOMPILER)
|
235
|
+
// Workaround a _Pragma bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59884
|
236
|
+
// and an nvhpc warning: https://github.com/fmtlib/fmt/pull/2582.
|
237
|
+
# define FMT_PRAGMA_GCC(x) FMT_PRAGMA_IMPL(GCC x)
|
238
|
+
#else
|
239
|
+
# define FMT_PRAGMA_GCC(x)
|
240
|
+
#endif
|
241
|
+
#if FMT_CLANG_VERSION
|
242
|
+
# define FMT_PRAGMA_CLANG(x) FMT_PRAGMA_IMPL(clang x)
|
243
|
+
#else
|
244
|
+
# define FMT_PRAGMA_CLANG(x)
|
245
|
+
#endif
|
246
|
+
#if FMT_MSC_VERSION
|
247
|
+
# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__))
|
248
|
+
#else
|
249
|
+
# define FMT_MSC_WARNING(...)
|
250
|
+
#endif
|
251
|
+
|
252
|
+
#ifndef FMT_BEGIN_NAMESPACE
|
253
|
+
# define FMT_BEGIN_NAMESPACE \
|
254
|
+
namespace fmt { \
|
255
|
+
inline namespace v11 {
|
256
|
+
# define FMT_END_NAMESPACE \
|
257
|
+
} \
|
258
|
+
}
|
259
|
+
#endif
|
260
|
+
|
261
|
+
#ifndef FMT_EXPORT
|
262
|
+
# define FMT_EXPORT
|
263
|
+
# define FMT_BEGIN_EXPORT
|
264
|
+
# define FMT_END_EXPORT
|
265
|
+
#endif
|
266
|
+
|
267
|
+
#ifdef _WIN32
|
268
|
+
# define FMT_WIN32 1
|
269
|
+
#else
|
270
|
+
# define FMT_WIN32 0
|
271
|
+
#endif
|
272
|
+
|
273
|
+
#if !defined(FMT_HEADER_ONLY) && FMT_WIN32
|
274
|
+
# if defined(FMT_LIB_EXPORT)
|
275
|
+
# define FMT_API __declspec(dllexport)
|
276
|
+
# elif defined(FMT_SHARED)
|
277
|
+
# define FMT_API __declspec(dllimport)
|
278
|
+
# endif
|
279
|
+
#elif defined(FMT_LIB_EXPORT) || defined(FMT_SHARED)
|
280
|
+
# define FMT_API FMT_VISIBILITY("default")
|
281
|
+
#endif
|
282
|
+
#ifndef FMT_API
|
283
|
+
# define FMT_API
|
284
|
+
#endif
|
285
|
+
|
286
|
+
#ifndef FMT_OPTIMIZE_SIZE
|
287
|
+
# define FMT_OPTIMIZE_SIZE 0
|
288
|
+
#endif
|
289
|
+
|
290
|
+
// FMT_BUILTIN_TYPE=0 may result in smaller library size at the cost of higher
|
291
|
+
// per-call binary size by passing built-in types through the extension API.
|
292
|
+
#ifndef FMT_BUILTIN_TYPES
|
293
|
+
# define FMT_BUILTIN_TYPES 1
|
294
|
+
#endif
|
295
|
+
|
296
|
+
#define FMT_APPLY_VARIADIC(expr) \
|
297
|
+
using unused = int[]; \
|
298
|
+
(void)unused { 0, (expr, 0)... }
|
299
|
+
|
300
|
+
// Enable minimal optimizations for more compact code in debug mode.
|
301
|
+
FMT_PRAGMA_GCC(push_options)
|
302
|
+
#if !defined(__OPTIMIZE__) && !defined(__CUDACC__) && !defined(FMT_MODULE)
|
303
|
+
FMT_PRAGMA_GCC(optimize("Og"))
|
304
|
+
#endif
|
305
|
+
FMT_PRAGMA_CLANG(diagnostic push)
|
306
|
+
|
307
|
+
FMT_BEGIN_NAMESPACE
|
308
|
+
|
309
|
+
// Implementations of enable_if_t and other metafunctions for older systems.
|
310
|
+
template <bool B, typename T = void>
|
311
|
+
using enable_if_t = typename std::enable_if<B, T>::type;
|
312
|
+
template <bool B, typename T, typename F>
|
313
|
+
using conditional_t = typename std::conditional<B, T, F>::type;
|
314
|
+
template <bool B> using bool_constant = std::integral_constant<bool, B>;
|
315
|
+
template <typename T>
|
316
|
+
using remove_reference_t = typename std::remove_reference<T>::type;
|
317
|
+
template <typename T>
|
318
|
+
using remove_const_t = typename std::remove_const<T>::type;
|
319
|
+
template <typename T>
|
320
|
+
using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
|
321
|
+
template <typename T>
|
322
|
+
using make_unsigned_t = typename std::make_unsigned<T>::type;
|
323
|
+
template <typename T>
|
324
|
+
using underlying_t = typename std::underlying_type<T>::type;
|
325
|
+
template <typename T> using decay_t = typename std::decay<T>::type;
|
326
|
+
using nullptr_t = decltype(nullptr);
|
327
|
+
|
328
|
+
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
|
329
|
+
// A workaround for gcc 4.9 to make void_t work in a SFINAE context.
|
330
|
+
template <typename...> struct void_t_impl {
|
331
|
+
using type = void;
|
332
|
+
};
|
333
|
+
template <typename... T> using void_t = typename void_t_impl<T...>::type;
|
334
|
+
#else
|
335
|
+
template <typename...> using void_t = void;
|
336
|
+
#endif
|
337
|
+
|
338
|
+
struct monostate {
|
339
|
+
constexpr monostate() {}
|
340
|
+
};
|
341
|
+
|
342
|
+
// An enable_if helper to be used in template parameters which results in much
|
343
|
+
// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
|
344
|
+
// to workaround a bug in MSVC 2019 (see #1140 and #1186).
|
345
|
+
#ifdef FMT_DOC
|
346
|
+
# define FMT_ENABLE_IF(...)
|
347
|
+
#else
|
348
|
+
# define FMT_ENABLE_IF(...) fmt::enable_if_t<(__VA_ARGS__), int> = 0
|
349
|
+
#endif
|
350
|
+
|
351
|
+
template <typename T> constexpr auto min_of(T a, T b) -> T {
|
352
|
+
return a < b ? a : b;
|
353
|
+
}
|
354
|
+
template <typename T> constexpr auto max_of(T a, T b) -> T {
|
355
|
+
return a > b ? a : b;
|
356
|
+
}
|
357
|
+
|
358
|
+
namespace detail {
|
359
|
+
// Suppresses "unused variable" warnings with the method described in
|
360
|
+
// https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/.
|
361
|
+
// (void)var does not work on many Intel compilers.
|
362
|
+
template <typename... T> FMT_CONSTEXPR void ignore_unused(const T&...) {}
|
363
|
+
|
364
|
+
constexpr auto is_constant_evaluated(bool default_value = false) noexcept
|
365
|
+
-> bool {
|
366
|
+
// Workaround for incompatibility between clang 14 and libstdc++ consteval-based
|
367
|
+
// std::is_constant_evaluated: https://github.com/fmtlib/fmt/issues/3247.
|
368
|
+
#if FMT_CPLUSPLUS >= 202002L && FMT_GLIBCXX_RELEASE >= 12 && \
|
369
|
+
(FMT_CLANG_VERSION >= 1400 && FMT_CLANG_VERSION < 1500)
|
370
|
+
ignore_unused(default_value);
|
371
|
+
return __builtin_is_constant_evaluated();
|
372
|
+
#elif defined(__cpp_lib_is_constant_evaluated)
|
373
|
+
ignore_unused(default_value);
|
374
|
+
return std::is_constant_evaluated();
|
375
|
+
#else
|
376
|
+
return default_value;
|
377
|
+
#endif
|
378
|
+
}
|
379
|
+
|
380
|
+
// Suppresses "conditional expression is constant" warnings.
|
381
|
+
template <typename T> FMT_ALWAYS_INLINE constexpr auto const_check(T val) -> T {
|
382
|
+
return val;
|
383
|
+
}
|
384
|
+
|
385
|
+
FMT_NORETURN FMT_API void assert_fail(const char* file, int line,
|
386
|
+
const char* message);
|
387
|
+
|
388
|
+
#if defined(FMT_ASSERT)
|
389
|
+
// Use the provided definition.
|
390
|
+
#elif defined(NDEBUG)
|
391
|
+
// FMT_ASSERT is not empty to avoid -Wempty-body.
|
392
|
+
# define FMT_ASSERT(condition, message) \
|
393
|
+
fmt::detail::ignore_unused((condition), (message))
|
394
|
+
#else
|
395
|
+
# define FMT_ASSERT(condition, message) \
|
396
|
+
((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \
|
397
|
+
? (void)0 \
|
398
|
+
: fmt::detail::assert_fail(__FILE__, __LINE__, (message)))
|
399
|
+
#endif
|
400
|
+
|
401
|
+
#ifdef FMT_USE_INT128
|
402
|
+
// Use the provided definition.
|
403
|
+
#elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \
|
404
|
+
!(FMT_CLANG_VERSION && FMT_MSC_VERSION)
|
405
|
+
# define FMT_USE_INT128 1
|
406
|
+
using int128_opt = __int128_t; // An optional native 128-bit integer.
|
407
|
+
using uint128_opt = __uint128_t;
|
408
|
+
inline auto map(int128_opt x) -> int128_opt { return x; }
|
409
|
+
inline auto map(uint128_opt x) -> uint128_opt { return x; }
|
410
|
+
#else
|
411
|
+
# define FMT_USE_INT128 0
|
412
|
+
#endif
|
413
|
+
#if !FMT_USE_INT128
|
414
|
+
enum class int128_opt {};
|
415
|
+
enum class uint128_opt {};
|
416
|
+
// Reduce template instantiations.
|
417
|
+
inline auto map(int128_opt) -> monostate { return {}; }
|
418
|
+
inline auto map(uint128_opt) -> monostate { return {}; }
|
419
|
+
#endif
|
420
|
+
|
421
|
+
#ifndef FMT_USE_BITINT
|
422
|
+
# define FMT_USE_BITINT (FMT_CLANG_VERSION >= 1500)
|
423
|
+
#endif
|
424
|
+
|
425
|
+
#if FMT_USE_BITINT
|
426
|
+
FMT_PRAGMA_CLANG(diagnostic ignored "-Wbit-int-extension")
|
427
|
+
template <int N> using bitint = _BitInt(N);
|
428
|
+
template <int N> using ubitint = unsigned _BitInt(N);
|
429
|
+
#else
|
430
|
+
template <int N> struct bitint {};
|
431
|
+
template <int N> struct ubitint {};
|
432
|
+
#endif // FMT_USE_BITINT
|
433
|
+
|
434
|
+
// Casts a nonnegative integer to unsigned.
|
435
|
+
template <typename Int>
|
436
|
+
FMT_CONSTEXPR auto to_unsigned(Int value) -> make_unsigned_t<Int> {
|
437
|
+
FMT_ASSERT(std::is_unsigned<Int>::value || value >= 0, "negative value");
|
438
|
+
return static_cast<make_unsigned_t<Int>>(value);
|
439
|
+
}
|
440
|
+
|
441
|
+
template <typename Char>
|
442
|
+
using unsigned_char = conditional_t<sizeof(Char) == 1, unsigned char, unsigned>;
|
443
|
+
|
444
|
+
// A heuristic to detect std::string and std::[experimental::]string_view.
|
445
|
+
// It is mainly used to avoid dependency on <[experimental/]string_view>.
|
446
|
+
template <typename T, typename Enable = void>
|
447
|
+
struct is_std_string_like : std::false_type {};
|
448
|
+
template <typename T>
|
449
|
+
struct is_std_string_like<T, void_t<decltype(std::declval<T>().find_first_of(
|
450
|
+
typename T::value_type(), 0))>>
|
451
|
+
: std::is_convertible<decltype(std::declval<T>().data()),
|
452
|
+
const typename T::value_type*> {};
|
453
|
+
|
454
|
+
// Check if the literal encoding is UTF-8.
|
455
|
+
enum { is_utf8_enabled = "\u00A7"[1] == '\xA7' };
|
456
|
+
enum { use_utf8 = !FMT_WIN32 || is_utf8_enabled };
|
457
|
+
|
458
|
+
#ifndef FMT_UNICODE
|
459
|
+
# define FMT_UNICODE 1
|
460
|
+
#endif
|
461
|
+
|
462
|
+
static_assert(!FMT_UNICODE || use_utf8,
|
463
|
+
"Unicode support requires compiling with /utf-8");
|
464
|
+
|
465
|
+
template <typename T> constexpr const char* narrow(const T*) { return nullptr; }
|
466
|
+
constexpr FMT_ALWAYS_INLINE const char* narrow(const char* s) { return s; }
|
467
|
+
|
468
|
+
template <typename Char>
|
469
|
+
FMT_CONSTEXPR auto compare(const Char* s1, const Char* s2, std::size_t n)
|
470
|
+
-> int {
|
471
|
+
if (!is_constant_evaluated() && sizeof(Char) == 1) return memcmp(s1, s2, n);
|
472
|
+
for (; n != 0; ++s1, ++s2, --n) {
|
473
|
+
if (*s1 < *s2) return -1;
|
474
|
+
if (*s1 > *s2) return 1;
|
475
|
+
}
|
476
|
+
return 0;
|
477
|
+
}
|
478
|
+
|
479
|
+
namespace adl {
|
480
|
+
using namespace std;
|
481
|
+
|
482
|
+
template <typename Container>
|
483
|
+
auto invoke_back_inserter()
|
484
|
+
-> decltype(back_inserter(std::declval<Container&>()));
|
485
|
+
} // namespace adl
|
486
|
+
|
487
|
+
template <typename It, typename Enable = std::true_type>
|
488
|
+
struct is_back_insert_iterator : std::false_type {};
|
489
|
+
|
490
|
+
template <typename It>
|
491
|
+
struct is_back_insert_iterator<
|
492
|
+
It, bool_constant<std::is_same<
|
493
|
+
decltype(adl::invoke_back_inserter<typename It::container_type>()),
|
494
|
+
It>::value>> : std::true_type {};
|
495
|
+
|
496
|
+
// Extracts a reference to the container from *insert_iterator.
|
497
|
+
template <typename OutputIt>
|
498
|
+
inline FMT_CONSTEXPR20 auto get_container(OutputIt it) ->
|
499
|
+
typename OutputIt::container_type& {
|
500
|
+
struct accessor : OutputIt {
|
501
|
+
FMT_CONSTEXPR20 accessor(OutputIt base) : OutputIt(base) {}
|
502
|
+
using OutputIt::container;
|
503
|
+
};
|
504
|
+
return *accessor(it).container;
|
505
|
+
}
|
506
|
+
} // namespace detail
|
507
|
+
|
508
|
+
// Parsing-related public API and forward declarations.
|
509
|
+
FMT_BEGIN_EXPORT
|
510
|
+
|
511
|
+
/**
|
512
|
+
* An implementation of `std::basic_string_view` for pre-C++17. It provides a
|
513
|
+
* subset of the API. `fmt::basic_string_view` is used for format strings even
|
514
|
+
* if `std::basic_string_view` is available to prevent issues when a library is
|
515
|
+
* compiled with a different `-std` option than the client code (which is not
|
516
|
+
* recommended).
|
517
|
+
*/
|
518
|
+
template <typename Char> class basic_string_view {
|
519
|
+
private:
|
520
|
+
const Char* data_;
|
521
|
+
size_t size_;
|
522
|
+
|
523
|
+
public:
|
524
|
+
using value_type = Char;
|
525
|
+
using iterator = const Char*;
|
526
|
+
|
527
|
+
constexpr basic_string_view() noexcept : data_(nullptr), size_(0) {}
|
528
|
+
|
529
|
+
/// Constructs a string reference object from a C string and a size.
|
530
|
+
constexpr basic_string_view(const Char* s, size_t count) noexcept
|
531
|
+
: data_(s), size_(count) {}
|
532
|
+
|
533
|
+
constexpr basic_string_view(nullptr_t) = delete;
|
534
|
+
|
535
|
+
/// Constructs a string reference object from a C string.
|
536
|
+
#if FMT_GCC_VERSION
|
537
|
+
FMT_ALWAYS_INLINE
|
538
|
+
#endif
|
539
|
+
FMT_CONSTEXPR20 basic_string_view(const Char* s) : data_(s) {
|
540
|
+
#if FMT_HAS_BUILTIN(__builtin_strlen) || FMT_GCC_VERSION || FMT_CLANG_VERSION
|
541
|
+
if (std::is_same<Char, char>::value) {
|
542
|
+
size_ = __builtin_strlen(detail::narrow(s));
|
543
|
+
return;
|
544
|
+
}
|
545
|
+
#endif
|
546
|
+
size_t len = 0;
|
547
|
+
while (*s++) ++len;
|
548
|
+
size_ = len;
|
549
|
+
}
|
550
|
+
|
551
|
+
/// Constructs a string reference from a `std::basic_string` or a
|
552
|
+
/// `std::basic_string_view` object.
|
553
|
+
template <typename S,
|
554
|
+
FMT_ENABLE_IF(detail::is_std_string_like<S>::value&& std::is_same<
|
555
|
+
typename S::value_type, Char>::value)>
|
556
|
+
FMT_CONSTEXPR basic_string_view(const S& s) noexcept
|
557
|
+
: data_(s.data()), size_(s.size()) {}
|
558
|
+
|
559
|
+
/// Returns a pointer to the string data.
|
560
|
+
constexpr auto data() const noexcept -> const Char* { return data_; }
|
561
|
+
|
562
|
+
/// Returns the string size.
|
563
|
+
constexpr auto size() const noexcept -> size_t { return size_; }
|
564
|
+
|
565
|
+
constexpr auto begin() const noexcept -> iterator { return data_; }
|
566
|
+
constexpr auto end() const noexcept -> iterator { return data_ + size_; }
|
567
|
+
|
568
|
+
constexpr auto operator[](size_t pos) const noexcept -> const Char& {
|
569
|
+
return data_[pos];
|
570
|
+
}
|
571
|
+
|
572
|
+
FMT_CONSTEXPR void remove_prefix(size_t n) noexcept {
|
573
|
+
data_ += n;
|
574
|
+
size_ -= n;
|
575
|
+
}
|
576
|
+
|
577
|
+
FMT_CONSTEXPR auto starts_with(basic_string_view<Char> sv) const noexcept
|
578
|
+
-> bool {
|
579
|
+
return size_ >= sv.size_ && detail::compare(data_, sv.data_, sv.size_) == 0;
|
580
|
+
}
|
581
|
+
FMT_CONSTEXPR auto starts_with(Char c) const noexcept -> bool {
|
582
|
+
return size_ >= 1 && *data_ == c;
|
583
|
+
}
|
584
|
+
FMT_CONSTEXPR auto starts_with(const Char* s) const -> bool {
|
585
|
+
return starts_with(basic_string_view<Char>(s));
|
586
|
+
}
|
587
|
+
|
588
|
+
// Lexicographically compare this string reference to other.
|
589
|
+
FMT_CONSTEXPR auto compare(basic_string_view other) const -> int {
|
590
|
+
int result =
|
591
|
+
detail::compare(data_, other.data_, min_of(size_, other.size_));
|
592
|
+
if (result != 0) return result;
|
593
|
+
return size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
|
594
|
+
}
|
595
|
+
|
596
|
+
FMT_CONSTEXPR friend auto operator==(basic_string_view lhs,
|
597
|
+
basic_string_view rhs) -> bool {
|
598
|
+
return lhs.compare(rhs) == 0;
|
599
|
+
}
|
600
|
+
friend auto operator!=(basic_string_view lhs, basic_string_view rhs) -> bool {
|
601
|
+
return lhs.compare(rhs) != 0;
|
602
|
+
}
|
603
|
+
friend auto operator<(basic_string_view lhs, basic_string_view rhs) -> bool {
|
604
|
+
return lhs.compare(rhs) < 0;
|
605
|
+
}
|
606
|
+
friend auto operator<=(basic_string_view lhs, basic_string_view rhs) -> bool {
|
607
|
+
return lhs.compare(rhs) <= 0;
|
608
|
+
}
|
609
|
+
friend auto operator>(basic_string_view lhs, basic_string_view rhs) -> bool {
|
610
|
+
return lhs.compare(rhs) > 0;
|
611
|
+
}
|
612
|
+
friend auto operator>=(basic_string_view lhs, basic_string_view rhs) -> bool {
|
613
|
+
return lhs.compare(rhs) >= 0;
|
614
|
+
}
|
615
|
+
};
|
616
|
+
|
617
|
+
using string_view = basic_string_view<char>;
|
618
|
+
|
619
|
+
/// Specifies if `T` is an extended character type. Can be specialized by users.
|
620
|
+
template <typename T> struct is_xchar : std::false_type {};
|
621
|
+
template <> struct is_xchar<wchar_t> : std::true_type {};
|
622
|
+
template <> struct is_xchar<char16_t> : std::true_type {};
|
623
|
+
template <> struct is_xchar<char32_t> : std::true_type {};
|
624
|
+
#ifdef __cpp_char8_t
|
625
|
+
template <> struct is_xchar<char8_t> : std::true_type {};
|
626
|
+
#endif
|
627
|
+
|
628
|
+
// DEPRECATED! Will be replaced with an alias to prevent specializations.
|
629
|
+
template <typename T> struct is_char : is_xchar<T> {};
|
630
|
+
template <> struct is_char<char> : std::true_type {};
|
631
|
+
|
632
|
+
template <typename T> class basic_appender;
|
633
|
+
using appender = basic_appender<char>;
|
634
|
+
|
635
|
+
// Checks whether T is a container with contiguous storage.
|
636
|
+
template <typename T> struct is_contiguous : std::false_type {};
|
637
|
+
|
638
|
+
class context;
|
639
|
+
template <typename OutputIt, typename Char> class generic_context;
|
640
|
+
template <typename Char> class parse_context;
|
641
|
+
|
642
|
+
// Longer aliases for C++20 compatibility.
|
643
|
+
template <typename Char> using basic_format_parse_context = parse_context<Char>;
|
644
|
+
using format_parse_context = parse_context<char>;
|
645
|
+
template <typename OutputIt, typename Char>
|
646
|
+
using basic_format_context =
|
647
|
+
conditional_t<std::is_same<OutputIt, appender>::value, context,
|
648
|
+
generic_context<OutputIt, Char>>;
|
649
|
+
using format_context = context;
|
650
|
+
|
651
|
+
template <typename Char>
|
652
|
+
using buffered_context =
|
653
|
+
conditional_t<std::is_same<Char, char>::value, context,
|
654
|
+
generic_context<basic_appender<Char>, Char>>;
|
655
|
+
|
656
|
+
template <typename Context> class basic_format_arg;
|
657
|
+
template <typename Context> class basic_format_args;
|
658
|
+
|
659
|
+
// A separate type would result in shorter symbols but break ABI compatibility
|
660
|
+
// between clang and gcc on ARM (#1919).
|
661
|
+
using format_args = basic_format_args<context>;
|
662
|
+
|
663
|
+
// A formatter for objects of type T.
|
664
|
+
template <typename T, typename Char = char, typename Enable = void>
|
665
|
+
struct formatter {
|
666
|
+
// A deleted default constructor indicates a disabled formatter.
|
667
|
+
formatter() = delete;
|
668
|
+
};
|
669
|
+
|
670
|
+
/// Reports a format error at compile time or, via a `format_error` exception,
|
671
|
+
/// at runtime.
|
672
|
+
// This function is intentionally not constexpr to give a compile-time error.
|
673
|
+
FMT_NORETURN FMT_API void report_error(const char* message);
|
674
|
+
|
675
|
+
enum class presentation_type : unsigned char {
|
676
|
+
// Common specifiers:
|
677
|
+
none = 0,
|
678
|
+
debug = 1, // '?'
|
679
|
+
string = 2, // 's' (string, bool)
|
680
|
+
|
681
|
+
// Integral, bool and character specifiers:
|
682
|
+
dec = 3, // 'd'
|
683
|
+
hex, // 'x' or 'X'
|
684
|
+
oct, // 'o'
|
685
|
+
bin, // 'b' or 'B'
|
686
|
+
chr, // 'c'
|
687
|
+
|
688
|
+
// String and pointer specifiers:
|
689
|
+
pointer = 3, // 'p'
|
690
|
+
|
691
|
+
// Floating-point specifiers:
|
692
|
+
exp = 1, // 'e' or 'E' (1 since there is no FP debug presentation)
|
693
|
+
fixed, // 'f' or 'F'
|
694
|
+
general, // 'g' or 'G'
|
695
|
+
hexfloat // 'a' or 'A'
|
696
|
+
};
|
697
|
+
|
698
|
+
enum class align { none, left, right, center, numeric };
|
699
|
+
enum class sign { none, minus, plus, space };
|
700
|
+
enum class arg_id_kind { none, index, name };
|
701
|
+
|
702
|
+
// Basic format specifiers for built-in and string types.
|
703
|
+
class basic_specs {
|
704
|
+
private:
|
705
|
+
// Data is arranged as follows:
|
706
|
+
//
|
707
|
+
// 0 1 2 3
|
708
|
+
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
709
|
+
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
710
|
+
// |type |align| w | p | s |u|#|L| f | unused |
|
711
|
+
// +-----+-----+---+---+---+-+-+-+-----+---------------------------+
|
712
|
+
//
|
713
|
+
// w - dynamic width info
|
714
|
+
// p - dynamic precision info
|
715
|
+
// s - sign
|
716
|
+
// u - uppercase (e.g. 'X' for 'x')
|
717
|
+
// # - alternate form ('#')
|
718
|
+
// L - localized
|
719
|
+
// f - fill size
|
720
|
+
//
|
721
|
+
// Bitfields are not used because of compiler bugs such as gcc bug 61414.
|
722
|
+
enum : unsigned {
|
723
|
+
type_mask = 0x00007,
|
724
|
+
align_mask = 0x00038,
|
725
|
+
width_mask = 0x000C0,
|
726
|
+
precision_mask = 0x00300,
|
727
|
+
sign_mask = 0x00C00,
|
728
|
+
uppercase_mask = 0x01000,
|
729
|
+
alternate_mask = 0x02000,
|
730
|
+
localized_mask = 0x04000,
|
731
|
+
fill_size_mask = 0x38000,
|
732
|
+
|
733
|
+
align_shift = 3,
|
734
|
+
width_shift = 6,
|
735
|
+
precision_shift = 8,
|
736
|
+
sign_shift = 10,
|
737
|
+
fill_size_shift = 15,
|
738
|
+
|
739
|
+
max_fill_size = 4
|
740
|
+
};
|
741
|
+
|
742
|
+
unsigned data_ = 1 << fill_size_shift;
|
743
|
+
static_assert(sizeof(basic_specs::data_) * CHAR_BIT >= 18, "");
|
744
|
+
|
745
|
+
// Character (code unit) type is erased to prevent template bloat.
|
746
|
+
char fill_data_[max_fill_size] = {' '};
|
747
|
+
|
748
|
+
FMT_CONSTEXPR void set_fill_size(size_t size) {
|
749
|
+
data_ = (data_ & ~fill_size_mask) |
|
750
|
+
(static_cast<unsigned>(size) << fill_size_shift);
|
751
|
+
}
|
752
|
+
|
753
|
+
public:
|
754
|
+
constexpr auto type() const -> presentation_type {
|
755
|
+
return static_cast<presentation_type>(data_ & type_mask);
|
756
|
+
}
|
757
|
+
FMT_CONSTEXPR void set_type(presentation_type t) {
|
758
|
+
data_ = (data_ & ~type_mask) | static_cast<unsigned>(t);
|
759
|
+
}
|
760
|
+
|
761
|
+
constexpr auto align() const -> align {
|
762
|
+
return static_cast<fmt::align>((data_ & align_mask) >> align_shift);
|
763
|
+
}
|
764
|
+
FMT_CONSTEXPR void set_align(fmt::align a) {
|
765
|
+
data_ = (data_ & ~align_mask) | (static_cast<unsigned>(a) << align_shift);
|
766
|
+
}
|
767
|
+
|
768
|
+
constexpr auto dynamic_width() const -> arg_id_kind {
|
769
|
+
return static_cast<arg_id_kind>((data_ & width_mask) >> width_shift);
|
770
|
+
}
|
771
|
+
FMT_CONSTEXPR void set_dynamic_width(arg_id_kind w) {
|
772
|
+
data_ = (data_ & ~width_mask) | (static_cast<unsigned>(w) << width_shift);
|
773
|
+
}
|
774
|
+
|
775
|
+
FMT_CONSTEXPR auto dynamic_precision() const -> arg_id_kind {
|
776
|
+
return static_cast<arg_id_kind>((data_ & precision_mask) >>
|
777
|
+
precision_shift);
|
778
|
+
}
|
779
|
+
FMT_CONSTEXPR void set_dynamic_precision(arg_id_kind p) {
|
780
|
+
data_ = (data_ & ~precision_mask) |
|
781
|
+
(static_cast<unsigned>(p) << precision_shift);
|
782
|
+
}
|
783
|
+
|
784
|
+
constexpr bool dynamic() const {
|
785
|
+
return (data_ & (width_mask | precision_mask)) != 0;
|
786
|
+
}
|
787
|
+
|
788
|
+
constexpr auto sign() const -> sign {
|
789
|
+
return static_cast<fmt::sign>((data_ & sign_mask) >> sign_shift);
|
790
|
+
}
|
791
|
+
FMT_CONSTEXPR void set_sign(fmt::sign s) {
|
792
|
+
data_ = (data_ & ~sign_mask) | (static_cast<unsigned>(s) << sign_shift);
|
793
|
+
}
|
794
|
+
|
795
|
+
constexpr auto upper() const -> bool { return (data_ & uppercase_mask) != 0; }
|
796
|
+
FMT_CONSTEXPR void set_upper() { data_ |= uppercase_mask; }
|
797
|
+
|
798
|
+
constexpr auto alt() const -> bool { return (data_ & alternate_mask) != 0; }
|
799
|
+
FMT_CONSTEXPR void set_alt() { data_ |= alternate_mask; }
|
800
|
+
FMT_CONSTEXPR void clear_alt() { data_ &= ~alternate_mask; }
|
801
|
+
|
802
|
+
constexpr auto localized() const -> bool {
|
803
|
+
return (data_ & localized_mask) != 0;
|
804
|
+
}
|
805
|
+
FMT_CONSTEXPR void set_localized() { data_ |= localized_mask; }
|
806
|
+
|
807
|
+
constexpr auto fill_size() const -> size_t {
|
808
|
+
return (data_ & fill_size_mask) >> fill_size_shift;
|
809
|
+
}
|
810
|
+
|
811
|
+
template <typename Char, FMT_ENABLE_IF(std::is_same<Char, char>::value)>
|
812
|
+
constexpr auto fill() const -> const Char* {
|
813
|
+
return fill_data_;
|
814
|
+
}
|
815
|
+
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
816
|
+
constexpr auto fill() const -> const Char* {
|
817
|
+
return nullptr;
|
818
|
+
}
|
819
|
+
|
820
|
+
template <typename Char> constexpr auto fill_unit() const -> Char {
|
821
|
+
using uchar = unsigned char;
|
822
|
+
return static_cast<Char>(static_cast<uchar>(fill_data_[0]) |
|
823
|
+
(static_cast<uchar>(fill_data_[1]) << 8) |
|
824
|
+
(static_cast<uchar>(fill_data_[2]) << 16));
|
825
|
+
}
|
826
|
+
|
827
|
+
FMT_CONSTEXPR void set_fill(char c) {
|
828
|
+
fill_data_[0] = c;
|
829
|
+
set_fill_size(1);
|
830
|
+
}
|
831
|
+
|
832
|
+
template <typename Char>
|
833
|
+
FMT_CONSTEXPR void set_fill(basic_string_view<Char> s) {
|
834
|
+
auto size = s.size();
|
835
|
+
set_fill_size(size);
|
836
|
+
if (size == 1) {
|
837
|
+
unsigned uchar = static_cast<detail::unsigned_char<Char>>(s[0]);
|
838
|
+
fill_data_[0] = static_cast<char>(uchar);
|
839
|
+
fill_data_[1] = static_cast<char>(uchar >> 8);
|
840
|
+
fill_data_[2] = static_cast<char>(uchar >> 16);
|
841
|
+
return;
|
842
|
+
}
|
843
|
+
FMT_ASSERT(size <= max_fill_size, "invalid fill");
|
844
|
+
for (size_t i = 0; i < size; ++i)
|
845
|
+
fill_data_[i & 3] = static_cast<char>(s[i]);
|
846
|
+
}
|
847
|
+
|
848
|
+
FMT_CONSTEXPR void copy_fill_from(const basic_specs& specs) {
|
849
|
+
set_fill_size(specs.fill_size());
|
850
|
+
for (size_t i = 0; i < max_fill_size; ++i)
|
851
|
+
fill_data_[i] = specs.fill_data_[i];
|
852
|
+
}
|
853
|
+
};
|
854
|
+
|
855
|
+
// Format specifiers for built-in and string types.
|
856
|
+
struct format_specs : basic_specs {
|
857
|
+
int width;
|
858
|
+
int precision;
|
859
|
+
|
860
|
+
constexpr format_specs() : width(0), precision(-1) {}
|
861
|
+
};
|
862
|
+
|
863
|
+
/**
|
864
|
+
* Parsing context consisting of a format string range being parsed and an
|
865
|
+
* argument counter for automatic indexing.
|
866
|
+
*/
|
867
|
+
template <typename Char = char> class parse_context {
|
868
|
+
private:
|
869
|
+
basic_string_view<Char> fmt_;
|
870
|
+
int next_arg_id_;
|
871
|
+
|
872
|
+
enum { use_constexpr_cast = !FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200 };
|
873
|
+
|
874
|
+
FMT_CONSTEXPR void do_check_arg_id(int arg_id);
|
875
|
+
|
876
|
+
public:
|
877
|
+
using char_type = Char;
|
878
|
+
using iterator = const Char*;
|
879
|
+
|
880
|
+
constexpr explicit parse_context(basic_string_view<Char> fmt,
|
881
|
+
int next_arg_id = 0)
|
882
|
+
: fmt_(fmt), next_arg_id_(next_arg_id) {}
|
883
|
+
|
884
|
+
/// Returns an iterator to the beginning of the format string range being
|
885
|
+
/// parsed.
|
886
|
+
constexpr auto begin() const noexcept -> iterator { return fmt_.begin(); }
|
887
|
+
|
888
|
+
/// Returns an iterator past the end of the format string range being parsed.
|
889
|
+
constexpr auto end() const noexcept -> iterator { return fmt_.end(); }
|
890
|
+
|
891
|
+
/// Advances the begin iterator to `it`.
|
892
|
+
FMT_CONSTEXPR void advance_to(iterator it) {
|
893
|
+
fmt_.remove_prefix(detail::to_unsigned(it - begin()));
|
894
|
+
}
|
895
|
+
|
896
|
+
/// Reports an error if using the manual argument indexing; otherwise returns
|
897
|
+
/// the next argument index and switches to the automatic indexing.
|
898
|
+
FMT_CONSTEXPR auto next_arg_id() -> int {
|
899
|
+
if (next_arg_id_ < 0) {
|
900
|
+
report_error("cannot switch from manual to automatic argument indexing");
|
901
|
+
return 0;
|
902
|
+
}
|
903
|
+
int id = next_arg_id_++;
|
904
|
+
do_check_arg_id(id);
|
905
|
+
return id;
|
906
|
+
}
|
907
|
+
|
908
|
+
/// Reports an error if using the automatic argument indexing; otherwise
|
909
|
+
/// switches to the manual indexing.
|
910
|
+
FMT_CONSTEXPR void check_arg_id(int id) {
|
911
|
+
if (next_arg_id_ > 0) {
|
912
|
+
report_error("cannot switch from automatic to manual argument indexing");
|
913
|
+
return;
|
914
|
+
}
|
915
|
+
next_arg_id_ = -1;
|
916
|
+
do_check_arg_id(id);
|
917
|
+
}
|
918
|
+
FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {
|
919
|
+
next_arg_id_ = -1;
|
920
|
+
}
|
921
|
+
FMT_CONSTEXPR void check_dynamic_spec(int arg_id);
|
922
|
+
};
|
923
|
+
|
924
|
+
FMT_END_EXPORT
|
925
|
+
|
926
|
+
namespace detail {
|
927
|
+
|
928
|
+
// Constructs fmt::basic_string_view<Char> from types implicitly convertible
|
929
|
+
// to it, deducing Char. Explicitly convertible types such as the ones returned
|
930
|
+
// from FMT_STRING are intentionally excluded.
|
931
|
+
template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
|
932
|
+
constexpr auto to_string_view(const Char* s) -> basic_string_view<Char> {
|
933
|
+
return s;
|
934
|
+
}
|
935
|
+
template <typename T, FMT_ENABLE_IF(is_std_string_like<T>::value)>
|
936
|
+
constexpr auto to_string_view(const T& s)
|
937
|
+
-> basic_string_view<typename T::value_type> {
|
938
|
+
return s;
|
939
|
+
}
|
940
|
+
template <typename Char>
|
941
|
+
constexpr auto to_string_view(basic_string_view<Char> s)
|
942
|
+
-> basic_string_view<Char> {
|
943
|
+
return s;
|
944
|
+
}
|
945
|
+
|
946
|
+
template <typename T, typename Enable = void>
|
947
|
+
struct has_to_string_view : std::false_type {};
|
948
|
+
// detail:: is intentional since to_string_view is not an extension point.
|
949
|
+
template <typename T>
|
950
|
+
struct has_to_string_view<
|
951
|
+
T, void_t<decltype(detail::to_string_view(std::declval<T>()))>>
|
952
|
+
: std::true_type {};
|
953
|
+
|
954
|
+
/// String's character (code unit) type. detail:: is intentional to prevent ADL.
|
955
|
+
template <typename S,
|
956
|
+
typename V = decltype(detail::to_string_view(std::declval<S>()))>
|
957
|
+
using char_t = typename V::value_type;
|
958
|
+
|
959
|
+
enum class type {
|
960
|
+
none_type,
|
961
|
+
// Integer types should go first,
|
962
|
+
int_type,
|
963
|
+
uint_type,
|
964
|
+
long_long_type,
|
965
|
+
ulong_long_type,
|
966
|
+
int128_type,
|
967
|
+
uint128_type,
|
968
|
+
bool_type,
|
969
|
+
char_type,
|
970
|
+
last_integer_type = char_type,
|
971
|
+
// followed by floating-point types.
|
972
|
+
float_type,
|
973
|
+
double_type,
|
974
|
+
long_double_type,
|
975
|
+
last_numeric_type = long_double_type,
|
976
|
+
cstring_type,
|
977
|
+
string_type,
|
978
|
+
pointer_type,
|
979
|
+
custom_type
|
980
|
+
};
|
981
|
+
|
982
|
+
// Maps core type T to the corresponding type enum constant.
|
983
|
+
template <typename T, typename Char>
|
984
|
+
struct type_constant : std::integral_constant<type, type::custom_type> {};
|
985
|
+
|
986
|
+
#define FMT_TYPE_CONSTANT(Type, constant) \
|
987
|
+
template <typename Char> \
|
988
|
+
struct type_constant<Type, Char> \
|
989
|
+
: std::integral_constant<type, type::constant> {}
|
990
|
+
|
991
|
+
FMT_TYPE_CONSTANT(int, int_type);
|
992
|
+
FMT_TYPE_CONSTANT(unsigned, uint_type);
|
993
|
+
FMT_TYPE_CONSTANT(long long, long_long_type);
|
994
|
+
FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type);
|
995
|
+
FMT_TYPE_CONSTANT(int128_opt, int128_type);
|
996
|
+
FMT_TYPE_CONSTANT(uint128_opt, uint128_type);
|
997
|
+
FMT_TYPE_CONSTANT(bool, bool_type);
|
998
|
+
FMT_TYPE_CONSTANT(Char, char_type);
|
999
|
+
FMT_TYPE_CONSTANT(float, float_type);
|
1000
|
+
FMT_TYPE_CONSTANT(double, double_type);
|
1001
|
+
FMT_TYPE_CONSTANT(long double, long_double_type);
|
1002
|
+
FMT_TYPE_CONSTANT(const Char*, cstring_type);
|
1003
|
+
FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type);
|
1004
|
+
FMT_TYPE_CONSTANT(const void*, pointer_type);
|
1005
|
+
|
1006
|
+
constexpr auto is_integral_type(type t) -> bool {
|
1007
|
+
return t > type::none_type && t <= type::last_integer_type;
|
1008
|
+
}
|
1009
|
+
constexpr auto is_arithmetic_type(type t) -> bool {
|
1010
|
+
return t > type::none_type && t <= type::last_numeric_type;
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
constexpr auto set(type rhs) -> int { return 1 << static_cast<int>(rhs); }
|
1014
|
+
constexpr auto in(type t, int set) -> bool {
|
1015
|
+
return ((set >> static_cast<int>(t)) & 1) != 0;
|
1016
|
+
}
|
1017
|
+
|
1018
|
+
// Bitsets of types.
|
1019
|
+
enum {
|
1020
|
+
sint_set =
|
1021
|
+
set(type::int_type) | set(type::long_long_type) | set(type::int128_type),
|
1022
|
+
uint_set = set(type::uint_type) | set(type::ulong_long_type) |
|
1023
|
+
set(type::uint128_type),
|
1024
|
+
bool_set = set(type::bool_type),
|
1025
|
+
char_set = set(type::char_type),
|
1026
|
+
float_set = set(type::float_type) | set(type::double_type) |
|
1027
|
+
set(type::long_double_type),
|
1028
|
+
string_set = set(type::string_type),
|
1029
|
+
cstring_set = set(type::cstring_type),
|
1030
|
+
pointer_set = set(type::pointer_type)
|
1031
|
+
};
|
1032
|
+
|
1033
|
+
struct view {};
|
1034
|
+
|
1035
|
+
template <typename Char, typename T> struct named_arg;
|
1036
|
+
template <typename T> struct is_named_arg : std::false_type {};
|
1037
|
+
template <typename T> struct is_static_named_arg : std::false_type {};
|
1038
|
+
|
1039
|
+
template <typename Char, typename T>
|
1040
|
+
struct is_named_arg<named_arg<Char, T>> : std::true_type {};
|
1041
|
+
|
1042
|
+
template <typename Char, typename T> struct named_arg : view {
|
1043
|
+
const Char* name;
|
1044
|
+
const T& value;
|
1045
|
+
|
1046
|
+
named_arg(const Char* n, const T& v) : name(n), value(v) {}
|
1047
|
+
static_assert(!is_named_arg<T>::value, "nested named arguments");
|
1048
|
+
};
|
1049
|
+
|
1050
|
+
template <bool B = false> constexpr auto count() -> int { return B ? 1 : 0; }
|
1051
|
+
template <bool B1, bool B2, bool... Tail> constexpr auto count() -> int {
|
1052
|
+
return (B1 ? 1 : 0) + count<B2, Tail...>();
|
1053
|
+
}
|
1054
|
+
|
1055
|
+
template <typename... Args> constexpr auto count_named_args() -> int {
|
1056
|
+
return count<is_named_arg<Args>::value...>();
|
1057
|
+
}
|
1058
|
+
template <typename... Args> constexpr auto count_static_named_args() -> int {
|
1059
|
+
return count<is_static_named_arg<Args>::value...>();
|
1060
|
+
}
|
1061
|
+
|
1062
|
+
template <typename Char> struct named_arg_info {
|
1063
|
+
const Char* name;
|
1064
|
+
int id;
|
1065
|
+
};
|
1066
|
+
|
1067
|
+
template <typename Char, typename T, FMT_ENABLE_IF(!is_named_arg<T>::value)>
|
1068
|
+
void init_named_arg(named_arg_info<Char>*, int& arg_index, int&, const T&) {
|
1069
|
+
++arg_index;
|
1070
|
+
}
|
1071
|
+
template <typename Char, typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
|
1072
|
+
void init_named_arg(named_arg_info<Char>* named_args, int& arg_index,
|
1073
|
+
int& named_arg_index, const T& arg) {
|
1074
|
+
named_args[named_arg_index++] = {arg.name, arg_index++};
|
1075
|
+
}
|
1076
|
+
|
1077
|
+
template <typename T, typename Char,
|
1078
|
+
FMT_ENABLE_IF(!is_static_named_arg<T>::value)>
|
1079
|
+
FMT_CONSTEXPR void init_static_named_arg(named_arg_info<Char>*, int& arg_index,
|
1080
|
+
int&) {
|
1081
|
+
++arg_index;
|
1082
|
+
}
|
1083
|
+
template <typename T, typename Char,
|
1084
|
+
FMT_ENABLE_IF(is_static_named_arg<T>::value)>
|
1085
|
+
FMT_CONSTEXPR void init_static_named_arg(named_arg_info<Char>* named_args,
|
1086
|
+
int& arg_index, int& named_arg_index) {
|
1087
|
+
named_args[named_arg_index++] = {T::name, arg_index++};
|
1088
|
+
}
|
1089
|
+
|
1090
|
+
// To minimize the number of types we need to deal with, long is translated
|
1091
|
+
// either to int or to long long depending on its size.
|
1092
|
+
enum { long_short = sizeof(long) == sizeof(int) };
|
1093
|
+
using long_type = conditional_t<long_short, int, long long>;
|
1094
|
+
using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
|
1095
|
+
|
1096
|
+
template <typename T>
|
1097
|
+
using format_as_result =
|
1098
|
+
remove_cvref_t<decltype(format_as(std::declval<const T&>()))>;
|
1099
|
+
template <typename T>
|
1100
|
+
using format_as_member_result =
|
1101
|
+
remove_cvref_t<decltype(formatter<T>::format_as(std::declval<const T&>()))>;
|
1102
|
+
|
1103
|
+
template <typename T, typename Enable = std::true_type>
|
1104
|
+
struct use_format_as : std::false_type {};
|
1105
|
+
// format_as member is only used to avoid injection into the std namespace.
|
1106
|
+
template <typename T, typename Enable = std::true_type>
|
1107
|
+
struct use_format_as_member : std::false_type {};
|
1108
|
+
|
1109
|
+
// Only map owning types because mapping views can be unsafe.
|
1110
|
+
template <typename T>
|
1111
|
+
struct use_format_as<
|
1112
|
+
T, bool_constant<std::is_arithmetic<format_as_result<T>>::value>>
|
1113
|
+
: std::true_type {};
|
1114
|
+
template <typename T>
|
1115
|
+
struct use_format_as_member<
|
1116
|
+
T, bool_constant<std::is_arithmetic<format_as_member_result<T>>::value>>
|
1117
|
+
: std::true_type {};
|
1118
|
+
|
1119
|
+
template <typename T, typename U = remove_const_t<T>>
|
1120
|
+
using use_formatter =
|
1121
|
+
bool_constant<(std::is_class<T>::value || std::is_enum<T>::value ||
|
1122
|
+
std::is_union<T>::value || std::is_array<T>::value) &&
|
1123
|
+
!has_to_string_view<T>::value && !is_named_arg<T>::value &&
|
1124
|
+
!use_format_as<T>::value && !use_format_as_member<U>::value>;
|
1125
|
+
|
1126
|
+
template <typename Char, typename T, typename U = remove_const_t<T>>
|
1127
|
+
auto has_formatter_impl(T* p, buffered_context<Char>* ctx = nullptr)
|
1128
|
+
-> decltype(formatter<U, Char>().format(*p, *ctx), std::true_type());
|
1129
|
+
template <typename Char> auto has_formatter_impl(...) -> std::false_type;
|
1130
|
+
|
1131
|
+
// T can be const-qualified to check if it is const-formattable.
|
1132
|
+
template <typename T, typename Char> constexpr auto has_formatter() -> bool {
|
1133
|
+
return decltype(has_formatter_impl<Char>(static_cast<T*>(nullptr)))::value;
|
1134
|
+
}
|
1135
|
+
|
1136
|
+
// Maps formatting argument types to natively supported types or user-defined
|
1137
|
+
// types with formatters. Returns void on errors to be SFINAE-friendly.
|
1138
|
+
template <typename Char> struct type_mapper {
|
1139
|
+
static auto map(signed char) -> int;
|
1140
|
+
static auto map(unsigned char) -> unsigned;
|
1141
|
+
static auto map(short) -> int;
|
1142
|
+
static auto map(unsigned short) -> unsigned;
|
1143
|
+
static auto map(int) -> int;
|
1144
|
+
static auto map(unsigned) -> unsigned;
|
1145
|
+
static auto map(long) -> long_type;
|
1146
|
+
static auto map(unsigned long) -> ulong_type;
|
1147
|
+
static auto map(long long) -> long long;
|
1148
|
+
static auto map(unsigned long long) -> unsigned long long;
|
1149
|
+
static auto map(int128_opt) -> int128_opt;
|
1150
|
+
static auto map(uint128_opt) -> uint128_opt;
|
1151
|
+
static auto map(bool) -> bool;
|
1152
|
+
|
1153
|
+
template <int N>
|
1154
|
+
static auto map(bitint<N>) -> conditional_t<N <= 64, long long, void>;
|
1155
|
+
template <int N>
|
1156
|
+
static auto map(ubitint<N>)
|
1157
|
+
-> conditional_t<N <= 64, unsigned long long, void>;
|
1158
|
+
|
1159
|
+
template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
|
1160
|
+
static auto map(T) -> conditional_t<
|
1161
|
+
std::is_same<T, char>::value || std::is_same<T, Char>::value, Char, void>;
|
1162
|
+
|
1163
|
+
static auto map(float) -> float;
|
1164
|
+
static auto map(double) -> double;
|
1165
|
+
static auto map(long double) -> long double;
|
1166
|
+
|
1167
|
+
static auto map(Char*) -> const Char*;
|
1168
|
+
static auto map(const Char*) -> const Char*;
|
1169
|
+
template <typename T, typename C = char_t<T>,
|
1170
|
+
FMT_ENABLE_IF(!std::is_pointer<T>::value)>
|
1171
|
+
static auto map(const T&) -> conditional_t<std::is_same<C, Char>::value,
|
1172
|
+
basic_string_view<C>, void>;
|
1173
|
+
|
1174
|
+
static auto map(void*) -> const void*;
|
1175
|
+
static auto map(const void*) -> const void*;
|
1176
|
+
static auto map(volatile void*) -> const void*;
|
1177
|
+
static auto map(const volatile void*) -> const void*;
|
1178
|
+
static auto map(nullptr_t) -> const void*;
|
1179
|
+
template <typename T, FMT_ENABLE_IF(std::is_pointer<T>::value ||
|
1180
|
+
std::is_member_pointer<T>::value)>
|
1181
|
+
static auto map(const T&) -> void;
|
1182
|
+
|
1183
|
+
template <typename T, FMT_ENABLE_IF(use_format_as<T>::value)>
|
1184
|
+
static auto map(const T& x) -> decltype(map(format_as(x)));
|
1185
|
+
template <typename T, FMT_ENABLE_IF(use_format_as_member<T>::value)>
|
1186
|
+
static auto map(const T& x) -> decltype(map(formatter<T>::format_as(x)));
|
1187
|
+
|
1188
|
+
template <typename T, FMT_ENABLE_IF(use_formatter<T>::value)>
|
1189
|
+
static auto map(T&) -> conditional_t<has_formatter<T, Char>(), T&, void>;
|
1190
|
+
|
1191
|
+
template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
|
1192
|
+
static auto map(const T& named_arg) -> decltype(map(named_arg.value));
|
1193
|
+
};
|
1194
|
+
|
1195
|
+
// detail:: is used to workaround a bug in MSVC 2017.
|
1196
|
+
template <typename T, typename Char>
|
1197
|
+
using mapped_t = decltype(detail::type_mapper<Char>::map(std::declval<T&>()));
|
1198
|
+
|
1199
|
+
// A type constant after applying type_mapper.
|
1200
|
+
template <typename T, typename Char = char>
|
1201
|
+
using mapped_type_constant = type_constant<mapped_t<T, Char>, Char>;
|
1202
|
+
|
1203
|
+
template <typename T, typename Context,
|
1204
|
+
type TYPE =
|
1205
|
+
mapped_type_constant<T, typename Context::char_type>::value>
|
1206
|
+
using stored_type_constant = std::integral_constant<
|
1207
|
+
type, Context::builtin_types || TYPE == type::int_type ? TYPE
|
1208
|
+
: type::custom_type>;
|
1209
|
+
// A parse context with extra data used only in compile-time checks.
|
1210
|
+
template <typename Char>
|
1211
|
+
class compile_parse_context : public parse_context<Char> {
|
1212
|
+
private:
|
1213
|
+
int num_args_;
|
1214
|
+
const type* types_;
|
1215
|
+
using base = parse_context<Char>;
|
1216
|
+
|
1217
|
+
public:
|
1218
|
+
FMT_CONSTEXPR explicit compile_parse_context(basic_string_view<Char> fmt,
|
1219
|
+
int num_args, const type* types,
|
1220
|
+
int next_arg_id = 0)
|
1221
|
+
: base(fmt, next_arg_id), num_args_(num_args), types_(types) {}
|
1222
|
+
|
1223
|
+
constexpr auto num_args() const -> int { return num_args_; }
|
1224
|
+
constexpr auto arg_type(int id) const -> type { return types_[id]; }
|
1225
|
+
|
1226
|
+
FMT_CONSTEXPR auto next_arg_id() -> int {
|
1227
|
+
int id = base::next_arg_id();
|
1228
|
+
if (id >= num_args_) report_error("argument not found");
|
1229
|
+
return id;
|
1230
|
+
}
|
1231
|
+
|
1232
|
+
FMT_CONSTEXPR void check_arg_id(int id) {
|
1233
|
+
base::check_arg_id(id);
|
1234
|
+
if (id >= num_args_) report_error("argument not found");
|
1235
|
+
}
|
1236
|
+
using base::check_arg_id;
|
1237
|
+
|
1238
|
+
FMT_CONSTEXPR void check_dynamic_spec(int arg_id) {
|
1239
|
+
ignore_unused(arg_id);
|
1240
|
+
if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id]))
|
1241
|
+
report_error("width/precision is not integer");
|
1242
|
+
}
|
1243
|
+
};
|
1244
|
+
|
1245
|
+
// An argument reference.
|
1246
|
+
template <typename Char> union arg_ref {
|
1247
|
+
FMT_CONSTEXPR arg_ref(int idx = 0) : index(idx) {}
|
1248
|
+
FMT_CONSTEXPR arg_ref(basic_string_view<Char> n) : name(n) {}
|
1249
|
+
|
1250
|
+
int index;
|
1251
|
+
basic_string_view<Char> name;
|
1252
|
+
};
|
1253
|
+
|
1254
|
+
// Format specifiers with width and precision resolved at formatting rather
|
1255
|
+
// than parsing time to allow reusing the same parsed specifiers with
|
1256
|
+
// different sets of arguments (precompilation of format strings).
|
1257
|
+
template <typename Char = char> struct dynamic_format_specs : format_specs {
|
1258
|
+
arg_ref<Char> width_ref;
|
1259
|
+
arg_ref<Char> precision_ref;
|
1260
|
+
};
|
1261
|
+
|
1262
|
+
// Converts a character to ASCII. Returns '\0' on conversion failure.
|
1263
|
+
template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)>
|
1264
|
+
constexpr auto to_ascii(Char c) -> char {
|
1265
|
+
return c <= 0xff ? static_cast<char>(c) : '\0';
|
1266
|
+
}
|
1267
|
+
|
1268
|
+
// Returns the number of code units in a code point or 1 on error.
|
1269
|
+
template <typename Char>
|
1270
|
+
FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int {
|
1271
|
+
if (const_check(sizeof(Char) != 1)) return 1;
|
1272
|
+
auto c = static_cast<unsigned char>(*begin);
|
1273
|
+
return static_cast<int>((0x3a55000000000000ull >> (2 * (c >> 3))) & 3) + 1;
|
1274
|
+
}
|
1275
|
+
|
1276
|
+
// Parses the range [begin, end) as an unsigned integer. This function assumes
|
1277
|
+
// that the range is non-empty and the first character is a digit.
|
1278
|
+
template <typename Char>
|
1279
|
+
FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end,
|
1280
|
+
int error_value) noexcept -> int {
|
1281
|
+
FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', "");
|
1282
|
+
unsigned value = 0, prev = 0;
|
1283
|
+
auto p = begin;
|
1284
|
+
do {
|
1285
|
+
prev = value;
|
1286
|
+
value = value * 10 + unsigned(*p - '0');
|
1287
|
+
++p;
|
1288
|
+
} while (p != end && '0' <= *p && *p <= '9');
|
1289
|
+
auto num_digits = p - begin;
|
1290
|
+
begin = p;
|
1291
|
+
int digits10 = static_cast<int>(sizeof(int) * CHAR_BIT * 3 / 10);
|
1292
|
+
if (num_digits <= digits10) return static_cast<int>(value);
|
1293
|
+
// Check for overflow.
|
1294
|
+
unsigned max = INT_MAX;
|
1295
|
+
return num_digits == digits10 + 1 &&
|
1296
|
+
prev * 10ull + unsigned(p[-1] - '0') <= max
|
1297
|
+
? static_cast<int>(value)
|
1298
|
+
: error_value;
|
1299
|
+
}
|
1300
|
+
|
1301
|
+
FMT_CONSTEXPR inline auto parse_align(char c) -> align {
|
1302
|
+
switch (c) {
|
1303
|
+
case '<': return align::left;
|
1304
|
+
case '>': return align::right;
|
1305
|
+
case '^': return align::center;
|
1306
|
+
}
|
1307
|
+
return align::none;
|
1308
|
+
}
|
1309
|
+
|
1310
|
+
template <typename Char> constexpr auto is_name_start(Char c) -> bool {
|
1311
|
+
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_';
|
1312
|
+
}
|
1313
|
+
|
1314
|
+
template <typename Char, typename Handler>
|
1315
|
+
FMT_CONSTEXPR auto parse_arg_id(const Char* begin, const Char* end,
|
1316
|
+
Handler&& handler) -> const Char* {
|
1317
|
+
Char c = *begin;
|
1318
|
+
if (c >= '0' && c <= '9') {
|
1319
|
+
int index = 0;
|
1320
|
+
if (c != '0')
|
1321
|
+
index = parse_nonnegative_int(begin, end, INT_MAX);
|
1322
|
+
else
|
1323
|
+
++begin;
|
1324
|
+
if (begin == end || (*begin != '}' && *begin != ':'))
|
1325
|
+
report_error("invalid format string");
|
1326
|
+
else
|
1327
|
+
handler.on_index(index);
|
1328
|
+
return begin;
|
1329
|
+
}
|
1330
|
+
if (FMT_OPTIMIZE_SIZE > 1 || !is_name_start(c)) {
|
1331
|
+
report_error("invalid format string");
|
1332
|
+
return begin;
|
1333
|
+
}
|
1334
|
+
auto it = begin;
|
1335
|
+
do {
|
1336
|
+
++it;
|
1337
|
+
} while (it != end && (is_name_start(*it) || ('0' <= *it && *it <= '9')));
|
1338
|
+
handler.on_name({begin, to_unsigned(it - begin)});
|
1339
|
+
return it;
|
1340
|
+
}
|
1341
|
+
|
1342
|
+
template <typename Char> struct dynamic_spec_handler {
|
1343
|
+
parse_context<Char>& ctx;
|
1344
|
+
arg_ref<Char>& ref;
|
1345
|
+
arg_id_kind& kind;
|
1346
|
+
|
1347
|
+
FMT_CONSTEXPR void on_index(int id) {
|
1348
|
+
ref = id;
|
1349
|
+
kind = arg_id_kind::index;
|
1350
|
+
ctx.check_arg_id(id);
|
1351
|
+
ctx.check_dynamic_spec(id);
|
1352
|
+
}
|
1353
|
+
FMT_CONSTEXPR void on_name(basic_string_view<Char> id) {
|
1354
|
+
ref = id;
|
1355
|
+
kind = arg_id_kind::name;
|
1356
|
+
ctx.check_arg_id(id);
|
1357
|
+
}
|
1358
|
+
};
|
1359
|
+
|
1360
|
+
template <typename Char> struct parse_dynamic_spec_result {
|
1361
|
+
const Char* end;
|
1362
|
+
arg_id_kind kind;
|
1363
|
+
};
|
1364
|
+
|
1365
|
+
// Parses integer | "{" [arg_id] "}".
|
1366
|
+
template <typename Char>
|
1367
|
+
FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end,
|
1368
|
+
int& value, arg_ref<Char>& ref,
|
1369
|
+
parse_context<Char>& ctx)
|
1370
|
+
-> parse_dynamic_spec_result<Char> {
|
1371
|
+
FMT_ASSERT(begin != end, "");
|
1372
|
+
auto kind = arg_id_kind::none;
|
1373
|
+
if ('0' <= *begin && *begin <= '9') {
|
1374
|
+
int val = parse_nonnegative_int(begin, end, -1);
|
1375
|
+
if (val == -1) report_error("number is too big");
|
1376
|
+
value = val;
|
1377
|
+
} else {
|
1378
|
+
if (*begin == '{') {
|
1379
|
+
++begin;
|
1380
|
+
if (begin != end) {
|
1381
|
+
Char c = *begin;
|
1382
|
+
if (c == '}' || c == ':') {
|
1383
|
+
int id = ctx.next_arg_id();
|
1384
|
+
ref = id;
|
1385
|
+
kind = arg_id_kind::index;
|
1386
|
+
ctx.check_dynamic_spec(id);
|
1387
|
+
} else {
|
1388
|
+
begin = parse_arg_id(begin, end,
|
1389
|
+
dynamic_spec_handler<Char>{ctx, ref, kind});
|
1390
|
+
}
|
1391
|
+
}
|
1392
|
+
if (begin != end && *begin == '}') return {++begin, kind};
|
1393
|
+
}
|
1394
|
+
report_error("invalid format string");
|
1395
|
+
}
|
1396
|
+
return {begin, kind};
|
1397
|
+
}
|
1398
|
+
|
1399
|
+
template <typename Char>
|
1400
|
+
FMT_CONSTEXPR auto parse_width(const Char* begin, const Char* end,
|
1401
|
+
format_specs& specs, arg_ref<Char>& width_ref,
|
1402
|
+
parse_context<Char>& ctx) -> const Char* {
|
1403
|
+
auto result = parse_dynamic_spec(begin, end, specs.width, width_ref, ctx);
|
1404
|
+
specs.set_dynamic_width(result.kind);
|
1405
|
+
return result.end;
|
1406
|
+
}
|
1407
|
+
|
1408
|
+
template <typename Char>
|
1409
|
+
FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
|
1410
|
+
format_specs& specs,
|
1411
|
+
arg_ref<Char>& precision_ref,
|
1412
|
+
parse_context<Char>& ctx) -> const Char* {
|
1413
|
+
++begin;
|
1414
|
+
if (begin == end) {
|
1415
|
+
report_error("invalid precision");
|
1416
|
+
return begin;
|
1417
|
+
}
|
1418
|
+
auto result =
|
1419
|
+
parse_dynamic_spec(begin, end, specs.precision, precision_ref, ctx);
|
1420
|
+
specs.set_dynamic_precision(result.kind);
|
1421
|
+
return result.end;
|
1422
|
+
}
|
1423
|
+
|
1424
|
+
enum class state { start, align, sign, hash, zero, width, precision, locale };
|
1425
|
+
|
1426
|
+
// Parses standard format specifiers.
|
1427
|
+
template <typename Char>
|
1428
|
+
FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
|
1429
|
+
dynamic_format_specs<Char>& specs,
|
1430
|
+
parse_context<Char>& ctx, type arg_type)
|
1431
|
+
-> const Char* {
|
1432
|
+
auto c = '\0';
|
1433
|
+
if (end - begin > 1) {
|
1434
|
+
auto next = to_ascii(begin[1]);
|
1435
|
+
c = parse_align(next) == align::none ? to_ascii(*begin) : '\0';
|
1436
|
+
} else {
|
1437
|
+
if (begin == end) return begin;
|
1438
|
+
c = to_ascii(*begin);
|
1439
|
+
}
|
1440
|
+
|
1441
|
+
struct {
|
1442
|
+
state current_state = state::start;
|
1443
|
+
FMT_CONSTEXPR void operator()(state s, bool valid = true) {
|
1444
|
+
if (current_state >= s || !valid)
|
1445
|
+
report_error("invalid format specifier");
|
1446
|
+
current_state = s;
|
1447
|
+
}
|
1448
|
+
} enter_state;
|
1449
|
+
|
1450
|
+
using pres = presentation_type;
|
1451
|
+
constexpr auto integral_set = sint_set | uint_set | bool_set | char_set;
|
1452
|
+
struct {
|
1453
|
+
const Char*& begin;
|
1454
|
+
format_specs& specs;
|
1455
|
+
type arg_type;
|
1456
|
+
|
1457
|
+
FMT_CONSTEXPR auto operator()(pres pres_type, int set) -> const Char* {
|
1458
|
+
if (!in(arg_type, set)) report_error("invalid format specifier");
|
1459
|
+
specs.set_type(pres_type);
|
1460
|
+
return begin + 1;
|
1461
|
+
}
|
1462
|
+
} parse_presentation_type{begin, specs, arg_type};
|
1463
|
+
|
1464
|
+
for (;;) {
|
1465
|
+
switch (c) {
|
1466
|
+
case '<':
|
1467
|
+
case '>':
|
1468
|
+
case '^':
|
1469
|
+
enter_state(state::align);
|
1470
|
+
specs.set_align(parse_align(c));
|
1471
|
+
++begin;
|
1472
|
+
break;
|
1473
|
+
case '+':
|
1474
|
+
case ' ':
|
1475
|
+
specs.set_sign(c == ' ' ? sign::space : sign::plus);
|
1476
|
+
FMT_FALLTHROUGH;
|
1477
|
+
case '-':
|
1478
|
+
enter_state(state::sign, in(arg_type, sint_set | float_set));
|
1479
|
+
++begin;
|
1480
|
+
break;
|
1481
|
+
case '#':
|
1482
|
+
enter_state(state::hash, is_arithmetic_type(arg_type));
|
1483
|
+
specs.set_alt();
|
1484
|
+
++begin;
|
1485
|
+
break;
|
1486
|
+
case '0':
|
1487
|
+
enter_state(state::zero);
|
1488
|
+
if (!is_arithmetic_type(arg_type))
|
1489
|
+
report_error("format specifier requires numeric argument");
|
1490
|
+
if (specs.align() == align::none) {
|
1491
|
+
// Ignore 0 if align is specified for compatibility with std::format.
|
1492
|
+
specs.set_align(align::numeric);
|
1493
|
+
specs.set_fill('0');
|
1494
|
+
}
|
1495
|
+
++begin;
|
1496
|
+
break;
|
1497
|
+
// clang-format off
|
1498
|
+
case '1': case '2': case '3': case '4': case '5':
|
1499
|
+
case '6': case '7': case '8': case '9': case '{':
|
1500
|
+
// clang-format on
|
1501
|
+
enter_state(state::width);
|
1502
|
+
begin = parse_width(begin, end, specs, specs.width_ref, ctx);
|
1503
|
+
break;
|
1504
|
+
case '.':
|
1505
|
+
enter_state(state::precision,
|
1506
|
+
in(arg_type, float_set | string_set | cstring_set));
|
1507
|
+
begin = parse_precision(begin, end, specs, specs.precision_ref, ctx);
|
1508
|
+
break;
|
1509
|
+
case 'L':
|
1510
|
+
enter_state(state::locale, is_arithmetic_type(arg_type));
|
1511
|
+
specs.set_localized();
|
1512
|
+
++begin;
|
1513
|
+
break;
|
1514
|
+
case 'd': return parse_presentation_type(pres::dec, integral_set);
|
1515
|
+
case 'X': specs.set_upper(); FMT_FALLTHROUGH;
|
1516
|
+
case 'x': return parse_presentation_type(pres::hex, integral_set);
|
1517
|
+
case 'o': return parse_presentation_type(pres::oct, integral_set);
|
1518
|
+
case 'B': specs.set_upper(); FMT_FALLTHROUGH;
|
1519
|
+
case 'b': return parse_presentation_type(pres::bin, integral_set);
|
1520
|
+
case 'E': specs.set_upper(); FMT_FALLTHROUGH;
|
1521
|
+
case 'e': return parse_presentation_type(pres::exp, float_set);
|
1522
|
+
case 'F': specs.set_upper(); FMT_FALLTHROUGH;
|
1523
|
+
case 'f': return parse_presentation_type(pres::fixed, float_set);
|
1524
|
+
case 'G': specs.set_upper(); FMT_FALLTHROUGH;
|
1525
|
+
case 'g': return parse_presentation_type(pres::general, float_set);
|
1526
|
+
case 'A': specs.set_upper(); FMT_FALLTHROUGH;
|
1527
|
+
case 'a': return parse_presentation_type(pres::hexfloat, float_set);
|
1528
|
+
case 'c':
|
1529
|
+
if (arg_type == type::bool_type) report_error("invalid format specifier");
|
1530
|
+
return parse_presentation_type(pres::chr, integral_set);
|
1531
|
+
case 's':
|
1532
|
+
return parse_presentation_type(pres::string,
|
1533
|
+
bool_set | string_set | cstring_set);
|
1534
|
+
case 'p':
|
1535
|
+
return parse_presentation_type(pres::pointer, pointer_set | cstring_set);
|
1536
|
+
case '?':
|
1537
|
+
return parse_presentation_type(pres::debug,
|
1538
|
+
char_set | string_set | cstring_set);
|
1539
|
+
case '}': return begin;
|
1540
|
+
default: {
|
1541
|
+
if (*begin == '}') return begin;
|
1542
|
+
// Parse fill and alignment.
|
1543
|
+
auto fill_end = begin + code_point_length(begin);
|
1544
|
+
if (end - fill_end <= 0) {
|
1545
|
+
report_error("invalid format specifier");
|
1546
|
+
return begin;
|
1547
|
+
}
|
1548
|
+
if (*begin == '{') {
|
1549
|
+
report_error("invalid fill character '{'");
|
1550
|
+
return begin;
|
1551
|
+
}
|
1552
|
+
auto alignment = parse_align(to_ascii(*fill_end));
|
1553
|
+
enter_state(state::align, alignment != align::none);
|
1554
|
+
specs.set_fill(
|
1555
|
+
basic_string_view<Char>(begin, to_unsigned(fill_end - begin)));
|
1556
|
+
specs.set_align(alignment);
|
1557
|
+
begin = fill_end + 1;
|
1558
|
+
}
|
1559
|
+
}
|
1560
|
+
if (begin == end) return begin;
|
1561
|
+
c = to_ascii(*begin);
|
1562
|
+
}
|
1563
|
+
}
|
1564
|
+
|
1565
|
+
template <typename Char, typename Handler>
|
1566
|
+
FMT_CONSTEXPR FMT_INLINE auto parse_replacement_field(const Char* begin,
|
1567
|
+
const Char* end,
|
1568
|
+
Handler&& handler)
|
1569
|
+
-> const Char* {
|
1570
|
+
++begin;
|
1571
|
+
if (begin == end) {
|
1572
|
+
handler.on_error("invalid format string");
|
1573
|
+
return end;
|
1574
|
+
}
|
1575
|
+
int arg_id = 0;
|
1576
|
+
switch (*begin) {
|
1577
|
+
case '}':
|
1578
|
+
handler.on_replacement_field(handler.on_arg_id(), begin);
|
1579
|
+
return begin + 1;
|
1580
|
+
case '{': handler.on_text(begin, begin + 1); return begin + 1;
|
1581
|
+
case ':': arg_id = handler.on_arg_id(); break;
|
1582
|
+
default: {
|
1583
|
+
struct id_adapter {
|
1584
|
+
Handler& handler;
|
1585
|
+
int arg_id;
|
1586
|
+
|
1587
|
+
FMT_CONSTEXPR void on_index(int id) { arg_id = handler.on_arg_id(id); }
|
1588
|
+
FMT_CONSTEXPR void on_name(basic_string_view<Char> id) {
|
1589
|
+
arg_id = handler.on_arg_id(id);
|
1590
|
+
}
|
1591
|
+
} adapter = {handler, 0};
|
1592
|
+
begin = parse_arg_id(begin, end, adapter);
|
1593
|
+
arg_id = adapter.arg_id;
|
1594
|
+
Char c = begin != end ? *begin : Char();
|
1595
|
+
if (c == '}') {
|
1596
|
+
handler.on_replacement_field(arg_id, begin);
|
1597
|
+
return begin + 1;
|
1598
|
+
}
|
1599
|
+
if (c != ':') {
|
1600
|
+
handler.on_error("missing '}' in format string");
|
1601
|
+
return end;
|
1602
|
+
}
|
1603
|
+
break;
|
1604
|
+
}
|
1605
|
+
}
|
1606
|
+
begin = handler.on_format_specs(arg_id, begin + 1, end);
|
1607
|
+
if (begin == end || *begin != '}')
|
1608
|
+
return handler.on_error("unknown format specifier"), end;
|
1609
|
+
return begin + 1;
|
1610
|
+
}
|
1611
|
+
|
1612
|
+
template <typename Char, typename Handler>
|
1613
|
+
FMT_CONSTEXPR void parse_format_string(basic_string_view<Char> fmt,
|
1614
|
+
Handler&& handler) {
|
1615
|
+
auto begin = fmt.data(), end = begin + fmt.size();
|
1616
|
+
auto p = begin;
|
1617
|
+
while (p != end) {
|
1618
|
+
auto c = *p++;
|
1619
|
+
if (c == '{') {
|
1620
|
+
handler.on_text(begin, p - 1);
|
1621
|
+
begin = p = parse_replacement_field(p - 1, end, handler);
|
1622
|
+
} else if (c == '}') {
|
1623
|
+
if (p == end || *p != '}')
|
1624
|
+
return handler.on_error("unmatched '}' in format string");
|
1625
|
+
handler.on_text(begin, p);
|
1626
|
+
begin = ++p;
|
1627
|
+
}
|
1628
|
+
}
|
1629
|
+
handler.on_text(begin, end);
|
1630
|
+
}
|
1631
|
+
|
1632
|
+
// Checks char specs and returns true iff the presentation type is char-like.
|
1633
|
+
FMT_CONSTEXPR inline auto check_char_specs(const format_specs& specs) -> bool {
|
1634
|
+
auto type = specs.type();
|
1635
|
+
if (type != presentation_type::none && type != presentation_type::chr &&
|
1636
|
+
type != presentation_type::debug) {
|
1637
|
+
return false;
|
1638
|
+
}
|
1639
|
+
if (specs.align() == align::numeric || specs.sign() != sign::none ||
|
1640
|
+
specs.alt()) {
|
1641
|
+
report_error("invalid format specifier for char");
|
1642
|
+
}
|
1643
|
+
return true;
|
1644
|
+
}
|
1645
|
+
|
1646
|
+
// A base class for compile-time strings.
|
1647
|
+
struct compile_string {};
|
1648
|
+
|
1649
|
+
template <typename T, typename Char>
|
1650
|
+
FMT_VISIBILITY("hidden") // Suppress an ld warning on macOS (#3769).
|
1651
|
+
FMT_CONSTEXPR auto invoke_parse(parse_context<Char>& ctx) -> const Char* {
|
1652
|
+
using mapped_type = remove_cvref_t<mapped_t<T, Char>>;
|
1653
|
+
constexpr bool formattable =
|
1654
|
+
std::is_constructible<formatter<mapped_type, Char>>::value;
|
1655
|
+
if (!formattable) return ctx.begin(); // Error is reported in the value ctor.
|
1656
|
+
using formatted_type = conditional_t<formattable, mapped_type, int>;
|
1657
|
+
return formatter<formatted_type, Char>().parse(ctx);
|
1658
|
+
}
|
1659
|
+
|
1660
|
+
template <typename... T> struct arg_pack {};
|
1661
|
+
|
1662
|
+
template <typename Char, int NUM_ARGS, int NUM_NAMED_ARGS, bool DYNAMIC_NAMES>
|
1663
|
+
class format_string_checker {
|
1664
|
+
private:
|
1665
|
+
type types_[max_of(1, NUM_ARGS)];
|
1666
|
+
named_arg_info<Char> named_args_[max_of(1, NUM_NAMED_ARGS)];
|
1667
|
+
compile_parse_context<Char> context_;
|
1668
|
+
|
1669
|
+
using parse_func = auto (*)(parse_context<Char>&) -> const Char*;
|
1670
|
+
parse_func parse_funcs_[max_of(1, NUM_ARGS)];
|
1671
|
+
|
1672
|
+
public:
|
1673
|
+
template <typename... T>
|
1674
|
+
FMT_CONSTEXPR explicit format_string_checker(basic_string_view<Char> fmt,
|
1675
|
+
arg_pack<T...>)
|
1676
|
+
: types_{mapped_type_constant<T, Char>::value...},
|
1677
|
+
named_args_{},
|
1678
|
+
context_(fmt, NUM_ARGS, types_),
|
1679
|
+
parse_funcs_{&invoke_parse<T, Char>...} {
|
1680
|
+
int arg_index = 0, named_arg_index = 0;
|
1681
|
+
FMT_APPLY_VARIADIC(
|
1682
|
+
init_static_named_arg<T>(named_args_, arg_index, named_arg_index));
|
1683
|
+
ignore_unused(arg_index, named_arg_index);
|
1684
|
+
}
|
1685
|
+
|
1686
|
+
FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
|
1687
|
+
|
1688
|
+
FMT_CONSTEXPR auto on_arg_id() -> int { return context_.next_arg_id(); }
|
1689
|
+
FMT_CONSTEXPR auto on_arg_id(int id) -> int {
|
1690
|
+
context_.check_arg_id(id);
|
1691
|
+
return id;
|
1692
|
+
}
|
1693
|
+
FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int {
|
1694
|
+
for (int i = 0; i < NUM_NAMED_ARGS; ++i) {
|
1695
|
+
if (named_args_[i].name == id) return named_args_[i].id;
|
1696
|
+
}
|
1697
|
+
if (!DYNAMIC_NAMES) on_error("argument not found");
|
1698
|
+
return -1;
|
1699
|
+
}
|
1700
|
+
|
1701
|
+
FMT_CONSTEXPR void on_replacement_field(int id, const Char* begin) {
|
1702
|
+
on_format_specs(id, begin, begin); // Call parse() on empty specs.
|
1703
|
+
}
|
1704
|
+
|
1705
|
+
FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char* end)
|
1706
|
+
-> const Char* {
|
1707
|
+
context_.advance_to(begin);
|
1708
|
+
if (id >= 0 && id < NUM_ARGS) return parse_funcs_[id](context_);
|
1709
|
+
while (begin != end && *begin != '}') ++begin;
|
1710
|
+
return begin;
|
1711
|
+
}
|
1712
|
+
|
1713
|
+
FMT_NORETURN FMT_CONSTEXPR void on_error(const char* message) {
|
1714
|
+
report_error(message);
|
1715
|
+
}
|
1716
|
+
};
|
1717
|
+
|
1718
|
+
/// A contiguous memory buffer with an optional growing ability. It is an
|
1719
|
+
/// internal class and shouldn't be used directly, only via `memory_buffer`.
|
1720
|
+
template <typename T> class buffer {
|
1721
|
+
private:
|
1722
|
+
T* ptr_;
|
1723
|
+
size_t size_;
|
1724
|
+
size_t capacity_;
|
1725
|
+
|
1726
|
+
using grow_fun = void (*)(buffer& buf, size_t capacity);
|
1727
|
+
grow_fun grow_;
|
1728
|
+
|
1729
|
+
protected:
|
1730
|
+
// Don't initialize ptr_ since it is not accessed to save a few cycles.
|
1731
|
+
FMT_MSC_WARNING(suppress : 26495)
|
1732
|
+
FMT_CONSTEXPR buffer(grow_fun grow, size_t sz) noexcept
|
1733
|
+
: size_(sz), capacity_(sz), grow_(grow) {}
|
1734
|
+
|
1735
|
+
constexpr buffer(grow_fun grow, T* p = nullptr, size_t sz = 0,
|
1736
|
+
size_t cap = 0) noexcept
|
1737
|
+
: ptr_(p), size_(sz), capacity_(cap), grow_(grow) {}
|
1738
|
+
|
1739
|
+
FMT_CONSTEXPR20 ~buffer() = default;
|
1740
|
+
buffer(buffer&&) = default;
|
1741
|
+
|
1742
|
+
/// Sets the buffer data and capacity.
|
1743
|
+
FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) noexcept {
|
1744
|
+
ptr_ = buf_data;
|
1745
|
+
capacity_ = buf_capacity;
|
1746
|
+
}
|
1747
|
+
|
1748
|
+
public:
|
1749
|
+
using value_type = T;
|
1750
|
+
using const_reference = const T&;
|
1751
|
+
|
1752
|
+
buffer(const buffer&) = delete;
|
1753
|
+
void operator=(const buffer&) = delete;
|
1754
|
+
|
1755
|
+
auto begin() noexcept -> T* { return ptr_; }
|
1756
|
+
auto end() noexcept -> T* { return ptr_ + size_; }
|
1757
|
+
|
1758
|
+
auto begin() const noexcept -> const T* { return ptr_; }
|
1759
|
+
auto end() const noexcept -> const T* { return ptr_ + size_; }
|
1760
|
+
|
1761
|
+
/// Returns the size of this buffer.
|
1762
|
+
constexpr auto size() const noexcept -> size_t { return size_; }
|
1763
|
+
|
1764
|
+
/// Returns the capacity of this buffer.
|
1765
|
+
constexpr auto capacity() const noexcept -> size_t { return capacity_; }
|
1766
|
+
|
1767
|
+
/// Returns a pointer to the buffer data (not null-terminated).
|
1768
|
+
FMT_CONSTEXPR auto data() noexcept -> T* { return ptr_; }
|
1769
|
+
FMT_CONSTEXPR auto data() const noexcept -> const T* { return ptr_; }
|
1770
|
+
|
1771
|
+
/// Clears this buffer.
|
1772
|
+
FMT_CONSTEXPR void clear() { size_ = 0; }
|
1773
|
+
|
1774
|
+
// Tries resizing the buffer to contain `count` elements. If T is a POD type
|
1775
|
+
// the new elements may not be initialized.
|
1776
|
+
FMT_CONSTEXPR void try_resize(size_t count) {
|
1777
|
+
try_reserve(count);
|
1778
|
+
size_ = min_of(count, capacity_);
|
1779
|
+
}
|
1780
|
+
|
1781
|
+
// Tries increasing the buffer capacity to `new_capacity`. It can increase the
|
1782
|
+
// capacity by a smaller amount than requested but guarantees there is space
|
1783
|
+
// for at least one additional element either by increasing the capacity or by
|
1784
|
+
// flushing the buffer if it is full.
|
1785
|
+
FMT_CONSTEXPR void try_reserve(size_t new_capacity) {
|
1786
|
+
if (new_capacity > capacity_) grow_(*this, new_capacity);
|
1787
|
+
}
|
1788
|
+
|
1789
|
+
FMT_CONSTEXPR void push_back(const T& value) {
|
1790
|
+
try_reserve(size_ + 1);
|
1791
|
+
ptr_[size_++] = value;
|
1792
|
+
}
|
1793
|
+
|
1794
|
+
/// Appends data to the end of the buffer.
|
1795
|
+
template <typename U>
|
1796
|
+
// Workaround for MSVC2019 to fix error C2893: Failed to specialize function
|
1797
|
+
// template 'void fmt::v11::detail::buffer<T>::append(const U *,const U *)'.
|
1798
|
+
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1940
|
1799
|
+
FMT_CONSTEXPR20
|
1800
|
+
#endif
|
1801
|
+
void
|
1802
|
+
append(const U* begin, const U* end) {
|
1803
|
+
while (begin != end) {
|
1804
|
+
auto count = to_unsigned(end - begin);
|
1805
|
+
try_reserve(size_ + count);
|
1806
|
+
auto free_cap = capacity_ - size_;
|
1807
|
+
if (free_cap < count) count = free_cap;
|
1808
|
+
// A loop is faster than memcpy on small sizes.
|
1809
|
+
T* out = ptr_ + size_;
|
1810
|
+
for (size_t i = 0; i < count; ++i) out[i] = begin[i];
|
1811
|
+
size_ += count;
|
1812
|
+
begin += count;
|
1813
|
+
}
|
1814
|
+
}
|
1815
|
+
|
1816
|
+
template <typename Idx> FMT_CONSTEXPR auto operator[](Idx index) -> T& {
|
1817
|
+
return ptr_[index];
|
1818
|
+
}
|
1819
|
+
template <typename Idx>
|
1820
|
+
FMT_CONSTEXPR auto operator[](Idx index) const -> const T& {
|
1821
|
+
return ptr_[index];
|
1822
|
+
}
|
1823
|
+
};
|
1824
|
+
|
1825
|
+
struct buffer_traits {
|
1826
|
+
constexpr explicit buffer_traits(size_t) {}
|
1827
|
+
constexpr auto count() const -> size_t { return 0; }
|
1828
|
+
constexpr auto limit(size_t size) const -> size_t { return size; }
|
1829
|
+
};
|
1830
|
+
|
1831
|
+
class fixed_buffer_traits {
|
1832
|
+
private:
|
1833
|
+
size_t count_ = 0;
|
1834
|
+
size_t limit_;
|
1835
|
+
|
1836
|
+
public:
|
1837
|
+
constexpr explicit fixed_buffer_traits(size_t limit) : limit_(limit) {}
|
1838
|
+
constexpr auto count() const -> size_t { return count_; }
|
1839
|
+
FMT_CONSTEXPR auto limit(size_t size) -> size_t {
|
1840
|
+
size_t n = limit_ > count_ ? limit_ - count_ : 0;
|
1841
|
+
count_ += size;
|
1842
|
+
return min_of(size, n);
|
1843
|
+
}
|
1844
|
+
};
|
1845
|
+
|
1846
|
+
// A buffer that writes to an output iterator when flushed.
|
1847
|
+
template <typename OutputIt, typename T, typename Traits = buffer_traits>
|
1848
|
+
class iterator_buffer : public Traits, public buffer<T> {
|
1849
|
+
private:
|
1850
|
+
OutputIt out_;
|
1851
|
+
enum { buffer_size = 256 };
|
1852
|
+
T data_[buffer_size];
|
1853
|
+
|
1854
|
+
static FMT_CONSTEXPR void grow(buffer<T>& buf, size_t) {
|
1855
|
+
if (buf.size() == buffer_size) static_cast<iterator_buffer&>(buf).flush();
|
1856
|
+
}
|
1857
|
+
|
1858
|
+
void flush() {
|
1859
|
+
auto size = this->size();
|
1860
|
+
this->clear();
|
1861
|
+
const T* begin = data_;
|
1862
|
+
const T* end = begin + this->limit(size);
|
1863
|
+
while (begin != end) *out_++ = *begin++;
|
1864
|
+
}
|
1865
|
+
|
1866
|
+
public:
|
1867
|
+
explicit iterator_buffer(OutputIt out, size_t n = buffer_size)
|
1868
|
+
: Traits(n), buffer<T>(grow, data_, 0, buffer_size), out_(out) {}
|
1869
|
+
iterator_buffer(iterator_buffer&& other) noexcept
|
1870
|
+
: Traits(other),
|
1871
|
+
buffer<T>(grow, data_, 0, buffer_size),
|
1872
|
+
out_(other.out_) {}
|
1873
|
+
~iterator_buffer() {
|
1874
|
+
// Don't crash if flush fails during unwinding.
|
1875
|
+
FMT_TRY { flush(); }
|
1876
|
+
FMT_CATCH(...) {}
|
1877
|
+
}
|
1878
|
+
|
1879
|
+
auto out() -> OutputIt {
|
1880
|
+
flush();
|
1881
|
+
return out_;
|
1882
|
+
}
|
1883
|
+
auto count() const -> size_t { return Traits::count() + this->size(); }
|
1884
|
+
};
|
1885
|
+
|
1886
|
+
template <typename T>
|
1887
|
+
class iterator_buffer<T*, T, fixed_buffer_traits> : public fixed_buffer_traits,
|
1888
|
+
public buffer<T> {
|
1889
|
+
private:
|
1890
|
+
T* out_;
|
1891
|
+
enum { buffer_size = 256 };
|
1892
|
+
T data_[buffer_size];
|
1893
|
+
|
1894
|
+
static FMT_CONSTEXPR void grow(buffer<T>& buf, size_t) {
|
1895
|
+
if (buf.size() == buf.capacity())
|
1896
|
+
static_cast<iterator_buffer&>(buf).flush();
|
1897
|
+
}
|
1898
|
+
|
1899
|
+
void flush() {
|
1900
|
+
size_t n = this->limit(this->size());
|
1901
|
+
if (this->data() == out_) {
|
1902
|
+
out_ += n;
|
1903
|
+
this->set(data_, buffer_size);
|
1904
|
+
}
|
1905
|
+
this->clear();
|
1906
|
+
}
|
1907
|
+
|
1908
|
+
public:
|
1909
|
+
explicit iterator_buffer(T* out, size_t n = buffer_size)
|
1910
|
+
: fixed_buffer_traits(n), buffer<T>(grow, out, 0, n), out_(out) {}
|
1911
|
+
iterator_buffer(iterator_buffer&& other) noexcept
|
1912
|
+
: fixed_buffer_traits(other),
|
1913
|
+
buffer<T>(static_cast<iterator_buffer&&>(other)),
|
1914
|
+
out_(other.out_) {
|
1915
|
+
if (this->data() != out_) {
|
1916
|
+
this->set(data_, buffer_size);
|
1917
|
+
this->clear();
|
1918
|
+
}
|
1919
|
+
}
|
1920
|
+
~iterator_buffer() { flush(); }
|
1921
|
+
|
1922
|
+
auto out() -> T* {
|
1923
|
+
flush();
|
1924
|
+
return out_;
|
1925
|
+
}
|
1926
|
+
auto count() const -> size_t {
|
1927
|
+
return fixed_buffer_traits::count() + this->size();
|
1928
|
+
}
|
1929
|
+
};
|
1930
|
+
|
1931
|
+
template <typename T> class iterator_buffer<T*, T> : public buffer<T> {
|
1932
|
+
public:
|
1933
|
+
explicit iterator_buffer(T* out, size_t = 0)
|
1934
|
+
: buffer<T>([](buffer<T>&, size_t) {}, out, 0, ~size_t()) {}
|
1935
|
+
|
1936
|
+
auto out() -> T* { return &*this->end(); }
|
1937
|
+
};
|
1938
|
+
|
1939
|
+
template <typename Container>
|
1940
|
+
class container_buffer : public buffer<typename Container::value_type> {
|
1941
|
+
private:
|
1942
|
+
using value_type = typename Container::value_type;
|
1943
|
+
|
1944
|
+
static FMT_CONSTEXPR void grow(buffer<value_type>& buf, size_t capacity) {
|
1945
|
+
auto& self = static_cast<container_buffer&>(buf);
|
1946
|
+
self.container.resize(capacity);
|
1947
|
+
self.set(&self.container[0], capacity);
|
1948
|
+
}
|
1949
|
+
|
1950
|
+
public:
|
1951
|
+
Container& container;
|
1952
|
+
|
1953
|
+
explicit container_buffer(Container& c)
|
1954
|
+
: buffer<value_type>(grow, c.size()), container(c) {}
|
1955
|
+
};
|
1956
|
+
|
1957
|
+
// A buffer that writes to a container with the contiguous storage.
|
1958
|
+
template <typename OutputIt>
|
1959
|
+
class iterator_buffer<
|
1960
|
+
OutputIt,
|
1961
|
+
enable_if_t<is_back_insert_iterator<OutputIt>::value &&
|
1962
|
+
is_contiguous<typename OutputIt::container_type>::value,
|
1963
|
+
typename OutputIt::container_type::value_type>>
|
1964
|
+
: public container_buffer<typename OutputIt::container_type> {
|
1965
|
+
private:
|
1966
|
+
using base = container_buffer<typename OutputIt::container_type>;
|
1967
|
+
|
1968
|
+
public:
|
1969
|
+
explicit iterator_buffer(typename OutputIt::container_type& c) : base(c) {}
|
1970
|
+
explicit iterator_buffer(OutputIt out, size_t = 0)
|
1971
|
+
: base(get_container(out)) {}
|
1972
|
+
|
1973
|
+
auto out() -> OutputIt { return OutputIt(this->container); }
|
1974
|
+
};
|
1975
|
+
|
1976
|
+
// A buffer that counts the number of code units written discarding the output.
|
1977
|
+
template <typename T = char> class counting_buffer : public buffer<T> {
|
1978
|
+
private:
|
1979
|
+
enum { buffer_size = 256 };
|
1980
|
+
T data_[buffer_size];
|
1981
|
+
size_t count_ = 0;
|
1982
|
+
|
1983
|
+
static FMT_CONSTEXPR void grow(buffer<T>& buf, size_t) {
|
1984
|
+
if (buf.size() != buffer_size) return;
|
1985
|
+
static_cast<counting_buffer&>(buf).count_ += buf.size();
|
1986
|
+
buf.clear();
|
1987
|
+
}
|
1988
|
+
|
1989
|
+
public:
|
1990
|
+
FMT_CONSTEXPR counting_buffer() : buffer<T>(grow, data_, 0, buffer_size) {}
|
1991
|
+
|
1992
|
+
constexpr auto count() const noexcept -> size_t {
|
1993
|
+
return count_ + this->size();
|
1994
|
+
}
|
1995
|
+
};
|
1996
|
+
|
1997
|
+
template <typename T>
|
1998
|
+
struct is_back_insert_iterator<basic_appender<T>> : std::true_type {};
|
1999
|
+
|
2000
|
+
template <typename OutputIt, typename InputIt, typename = void>
|
2001
|
+
struct has_back_insert_iterator_container_append : std::false_type {};
|
2002
|
+
template <typename OutputIt, typename InputIt>
|
2003
|
+
struct has_back_insert_iterator_container_append<
|
2004
|
+
OutputIt, InputIt,
|
2005
|
+
void_t<decltype(get_container(std::declval<OutputIt>())
|
2006
|
+
.append(std::declval<InputIt>(),
|
2007
|
+
std::declval<InputIt>()))>> : std::true_type {};
|
2008
|
+
|
2009
|
+
// An optimized version of std::copy with the output value type (T).
|
2010
|
+
template <typename T, typename InputIt, typename OutputIt,
|
2011
|
+
FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value&&
|
2012
|
+
has_back_insert_iterator_container_append<
|
2013
|
+
OutputIt, InputIt>::value)>
|
2014
|
+
FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out)
|
2015
|
+
-> OutputIt {
|
2016
|
+
get_container(out).append(begin, end);
|
2017
|
+
return out;
|
2018
|
+
}
|
2019
|
+
|
2020
|
+
template <typename T, typename InputIt, typename OutputIt,
|
2021
|
+
FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value &&
|
2022
|
+
!has_back_insert_iterator_container_append<
|
2023
|
+
OutputIt, InputIt>::value)>
|
2024
|
+
FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out)
|
2025
|
+
-> OutputIt {
|
2026
|
+
auto& c = get_container(out);
|
2027
|
+
c.insert(c.end(), begin, end);
|
2028
|
+
return out;
|
2029
|
+
}
|
2030
|
+
|
2031
|
+
template <typename T, typename InputIt, typename OutputIt,
|
2032
|
+
FMT_ENABLE_IF(!is_back_insert_iterator<OutputIt>::value)>
|
2033
|
+
FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
|
2034
|
+
while (begin != end) *out++ = static_cast<T>(*begin++);
|
2035
|
+
return out;
|
2036
|
+
}
|
2037
|
+
|
2038
|
+
template <typename T, typename V, typename OutputIt>
|
2039
|
+
FMT_CONSTEXPR auto copy(basic_string_view<V> s, OutputIt out) -> OutputIt {
|
2040
|
+
return copy<T>(s.begin(), s.end(), out);
|
2041
|
+
}
|
2042
|
+
|
2043
|
+
template <typename It, typename Enable = std::true_type>
|
2044
|
+
struct is_buffer_appender : std::false_type {};
|
2045
|
+
template <typename It>
|
2046
|
+
struct is_buffer_appender<
|
2047
|
+
It, bool_constant<
|
2048
|
+
is_back_insert_iterator<It>::value &&
|
2049
|
+
std::is_base_of<buffer<typename It::container_type::value_type>,
|
2050
|
+
typename It::container_type>::value>>
|
2051
|
+
: std::true_type {};
|
2052
|
+
|
2053
|
+
// Maps an output iterator to a buffer.
|
2054
|
+
template <typename T, typename OutputIt,
|
2055
|
+
FMT_ENABLE_IF(!is_buffer_appender<OutputIt>::value)>
|
2056
|
+
auto get_buffer(OutputIt out) -> iterator_buffer<OutputIt, T> {
|
2057
|
+
return iterator_buffer<OutputIt, T>(out);
|
2058
|
+
}
|
2059
|
+
template <typename T, typename OutputIt,
|
2060
|
+
FMT_ENABLE_IF(is_buffer_appender<OutputIt>::value)>
|
2061
|
+
auto get_buffer(OutputIt out) -> buffer<T>& {
|
2062
|
+
return get_container(out);
|
2063
|
+
}
|
2064
|
+
|
2065
|
+
template <typename Buf, typename OutputIt>
|
2066
|
+
auto get_iterator(Buf& buf, OutputIt) -> decltype(buf.out()) {
|
2067
|
+
return buf.out();
|
2068
|
+
}
|
2069
|
+
template <typename T, typename OutputIt>
|
2070
|
+
auto get_iterator(buffer<T>&, OutputIt out) -> OutputIt {
|
2071
|
+
return out;
|
2072
|
+
}
|
2073
|
+
|
2074
|
+
// This type is intentionally undefined, only used for errors.
|
2075
|
+
template <typename T, typename Char> struct type_is_unformattable_for;
|
2076
|
+
|
2077
|
+
template <typename Char> struct string_value {
|
2078
|
+
const Char* data;
|
2079
|
+
size_t size;
|
2080
|
+
auto str() const -> basic_string_view<Char> { return {data, size}; }
|
2081
|
+
};
|
2082
|
+
|
2083
|
+
template <typename Context> struct custom_value {
|
2084
|
+
using char_type = typename Context::char_type;
|
2085
|
+
void* value;
|
2086
|
+
void (*format)(void* arg, parse_context<char_type>& parse_ctx, Context& ctx);
|
2087
|
+
};
|
2088
|
+
|
2089
|
+
template <typename Char> struct named_arg_value {
|
2090
|
+
const named_arg_info<Char>* data;
|
2091
|
+
size_t size;
|
2092
|
+
};
|
2093
|
+
|
2094
|
+
struct custom_tag {};
|
2095
|
+
|
2096
|
+
#if !FMT_BUILTIN_TYPES
|
2097
|
+
# define FMT_BUILTIN , monostate
|
2098
|
+
#else
|
2099
|
+
# define FMT_BUILTIN
|
2100
|
+
#endif
|
2101
|
+
|
2102
|
+
// A formatting argument value.
|
2103
|
+
template <typename Context> class value {
|
2104
|
+
public:
|
2105
|
+
using char_type = typename Context::char_type;
|
2106
|
+
|
2107
|
+
union {
|
2108
|
+
monostate no_value;
|
2109
|
+
int int_value;
|
2110
|
+
unsigned uint_value;
|
2111
|
+
long long long_long_value;
|
2112
|
+
unsigned long long ulong_long_value;
|
2113
|
+
int128_opt int128_value;
|
2114
|
+
uint128_opt uint128_value;
|
2115
|
+
bool bool_value;
|
2116
|
+
char_type char_value;
|
2117
|
+
float float_value;
|
2118
|
+
double double_value;
|
2119
|
+
long double long_double_value;
|
2120
|
+
const void* pointer;
|
2121
|
+
string_value<char_type> string;
|
2122
|
+
custom_value<Context> custom;
|
2123
|
+
named_arg_value<char_type> named_args;
|
2124
|
+
};
|
2125
|
+
|
2126
|
+
constexpr FMT_INLINE value() : no_value() {}
|
2127
|
+
constexpr FMT_INLINE value(signed char x) : int_value(x) {}
|
2128
|
+
constexpr FMT_INLINE value(unsigned char x FMT_BUILTIN) : uint_value(x) {}
|
2129
|
+
constexpr FMT_INLINE value(signed short x) : int_value(x) {}
|
2130
|
+
constexpr FMT_INLINE value(unsigned short x FMT_BUILTIN) : uint_value(x) {}
|
2131
|
+
constexpr FMT_INLINE value(int x) : int_value(x) {}
|
2132
|
+
constexpr FMT_INLINE value(unsigned x FMT_BUILTIN) : uint_value(x) {}
|
2133
|
+
FMT_CONSTEXPR FMT_INLINE value(long x FMT_BUILTIN) : value(long_type(x)) {}
|
2134
|
+
FMT_CONSTEXPR FMT_INLINE value(unsigned long x FMT_BUILTIN)
|
2135
|
+
: value(ulong_type(x)) {}
|
2136
|
+
constexpr FMT_INLINE value(long long x FMT_BUILTIN) : long_long_value(x) {}
|
2137
|
+
constexpr FMT_INLINE value(unsigned long long x FMT_BUILTIN)
|
2138
|
+
: ulong_long_value(x) {}
|
2139
|
+
FMT_INLINE value(int128_opt x FMT_BUILTIN) : int128_value(x) {}
|
2140
|
+
FMT_INLINE value(uint128_opt x FMT_BUILTIN) : uint128_value(x) {}
|
2141
|
+
constexpr FMT_INLINE value(bool x FMT_BUILTIN) : bool_value(x) {}
|
2142
|
+
|
2143
|
+
template <int N>
|
2144
|
+
constexpr FMT_INLINE value(bitint<N> x FMT_BUILTIN) : long_long_value(x) {
|
2145
|
+
static_assert(N <= 64, "unsupported _BitInt");
|
2146
|
+
}
|
2147
|
+
template <int N>
|
2148
|
+
constexpr FMT_INLINE value(ubitint<N> x FMT_BUILTIN) : ulong_long_value(x) {
|
2149
|
+
static_assert(N <= 64, "unsupported _BitInt");
|
2150
|
+
}
|
2151
|
+
|
2152
|
+
template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
|
2153
|
+
constexpr FMT_INLINE value(T x FMT_BUILTIN) : char_value(x) {
|
2154
|
+
static_assert(
|
2155
|
+
std::is_same<T, char>::value || std::is_same<T, char_type>::value,
|
2156
|
+
"mixing character types is disallowed");
|
2157
|
+
}
|
2158
|
+
|
2159
|
+
constexpr FMT_INLINE value(float x FMT_BUILTIN) : float_value(x) {}
|
2160
|
+
constexpr FMT_INLINE value(double x FMT_BUILTIN) : double_value(x) {}
|
2161
|
+
FMT_INLINE value(long double x FMT_BUILTIN) : long_double_value(x) {}
|
2162
|
+
|
2163
|
+
FMT_CONSTEXPR FMT_INLINE value(char_type* x FMT_BUILTIN) {
|
2164
|
+
string.data = x;
|
2165
|
+
if (is_constant_evaluated()) string.size = 0;
|
2166
|
+
}
|
2167
|
+
FMT_CONSTEXPR FMT_INLINE value(const char_type* x FMT_BUILTIN) {
|
2168
|
+
string.data = x;
|
2169
|
+
if (is_constant_evaluated()) string.size = 0;
|
2170
|
+
}
|
2171
|
+
template <typename T, typename C = char_t<T>,
|
2172
|
+
FMT_ENABLE_IF(!std::is_pointer<T>::value)>
|
2173
|
+
FMT_CONSTEXPR value(const T& x FMT_BUILTIN) {
|
2174
|
+
static_assert(std::is_same<C, char_type>::value,
|
2175
|
+
"mixing character types is disallowed");
|
2176
|
+
auto sv = to_string_view(x);
|
2177
|
+
string.data = sv.data();
|
2178
|
+
string.size = sv.size();
|
2179
|
+
}
|
2180
|
+
FMT_INLINE value(void* x FMT_BUILTIN) : pointer(x) {}
|
2181
|
+
FMT_INLINE value(const void* x FMT_BUILTIN) : pointer(x) {}
|
2182
|
+
FMT_INLINE value(volatile void* x FMT_BUILTIN)
|
2183
|
+
: pointer(const_cast<const void*>(x)) {}
|
2184
|
+
FMT_INLINE value(const volatile void* x FMT_BUILTIN)
|
2185
|
+
: pointer(const_cast<const void*>(x)) {}
|
2186
|
+
FMT_INLINE value(nullptr_t) : pointer(nullptr) {}
|
2187
|
+
|
2188
|
+
template <typename T, FMT_ENABLE_IF(std::is_pointer<T>::value ||
|
2189
|
+
std::is_member_pointer<T>::value)>
|
2190
|
+
value(const T&) {
|
2191
|
+
// Formatting of arbitrary pointers is disallowed. If you want to format a
|
2192
|
+
// pointer cast it to `void*` or `const void*`. In particular, this forbids
|
2193
|
+
// formatting of `[const] volatile char*` printed as bool by iostreams.
|
2194
|
+
static_assert(sizeof(T) == 0,
|
2195
|
+
"formatting of non-void pointers is disallowed");
|
2196
|
+
}
|
2197
|
+
|
2198
|
+
template <typename T, FMT_ENABLE_IF(use_format_as<T>::value)>
|
2199
|
+
value(const T& x) : value(format_as(x)) {}
|
2200
|
+
template <typename T, FMT_ENABLE_IF(use_format_as_member<T>::value)>
|
2201
|
+
value(const T& x) : value(formatter<T>::format_as(x)) {}
|
2202
|
+
|
2203
|
+
template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
|
2204
|
+
value(const T& named_arg) : value(named_arg.value) {}
|
2205
|
+
|
2206
|
+
template <typename T,
|
2207
|
+
FMT_ENABLE_IF(use_formatter<T>::value || !FMT_BUILTIN_TYPES)>
|
2208
|
+
FMT_CONSTEXPR20 FMT_INLINE value(T& x) : value(x, custom_tag()) {}
|
2209
|
+
|
2210
|
+
FMT_ALWAYS_INLINE value(const named_arg_info<char_type>* args, size_t size)
|
2211
|
+
: named_args{args, size} {}
|
2212
|
+
|
2213
|
+
private:
|
2214
|
+
template <typename T, FMT_ENABLE_IF(has_formatter<T, char_type>())>
|
2215
|
+
FMT_CONSTEXPR value(T& x, custom_tag) {
|
2216
|
+
using value_type = remove_const_t<T>;
|
2217
|
+
// T may overload operator& e.g. std::vector<bool>::reference in libc++.
|
2218
|
+
if (!is_constant_evaluated()) {
|
2219
|
+
custom.value =
|
2220
|
+
const_cast<char*>(&reinterpret_cast<const volatile char&>(x));
|
2221
|
+
} else {
|
2222
|
+
custom.value = nullptr;
|
2223
|
+
#if defined(__cpp_if_constexpr)
|
2224
|
+
if constexpr (std::is_same<decltype(&x), remove_reference_t<T>*>::value)
|
2225
|
+
custom.value = const_cast<value_type*>(&x);
|
2226
|
+
#endif
|
2227
|
+
}
|
2228
|
+
custom.format = format_custom<value_type, formatter<value_type, char_type>>;
|
2229
|
+
}
|
2230
|
+
|
2231
|
+
template <typename T, FMT_ENABLE_IF(!has_formatter<T, char_type>())>
|
2232
|
+
FMT_CONSTEXPR value(const T&, custom_tag) {
|
2233
|
+
// Cannot format an argument; to make type T formattable provide a
|
2234
|
+
// formatter<T> specialization: https://fmt.dev/latest/api.html#udt.
|
2235
|
+
type_is_unformattable_for<T, char_type> _;
|
2236
|
+
}
|
2237
|
+
|
2238
|
+
// Formats an argument of a custom type, such as a user-defined class.
|
2239
|
+
template <typename T, typename Formatter>
|
2240
|
+
static void format_custom(void* arg, parse_context<char_type>& parse_ctx,
|
2241
|
+
Context& ctx) {
|
2242
|
+
auto f = Formatter();
|
2243
|
+
parse_ctx.advance_to(f.parse(parse_ctx));
|
2244
|
+
using qualified_type =
|
2245
|
+
conditional_t<has_formatter<const T, char_type>(), const T, T>;
|
2246
|
+
// format must be const for compatibility with std::format and compilation.
|
2247
|
+
const auto& cf = f;
|
2248
|
+
ctx.advance_to(cf.format(*static_cast<qualified_type*>(arg), ctx));
|
2249
|
+
}
|
2250
|
+
};
|
2251
|
+
|
2252
|
+
enum { packed_arg_bits = 4 };
|
2253
|
+
// Maximum number of arguments with packed types.
|
2254
|
+
enum { max_packed_args = 62 / packed_arg_bits };
|
2255
|
+
enum : unsigned long long { is_unpacked_bit = 1ULL << 63 };
|
2256
|
+
enum : unsigned long long { has_named_args_bit = 1ULL << 62 };
|
2257
|
+
|
2258
|
+
template <typename It, typename T, typename Enable = void>
|
2259
|
+
struct is_output_iterator : std::false_type {};
|
2260
|
+
|
2261
|
+
template <> struct is_output_iterator<appender, char> : std::true_type {};
|
2262
|
+
|
2263
|
+
template <typename It, typename T>
|
2264
|
+
struct is_output_iterator<
|
2265
|
+
It, T,
|
2266
|
+
enable_if_t<std::is_assignable<decltype(*std::declval<decay_t<It>&>()++),
|
2267
|
+
T>::value>> : std::true_type {};
|
2268
|
+
|
2269
|
+
#ifndef FMT_USE_LOCALE
|
2270
|
+
# define FMT_USE_LOCALE (FMT_OPTIMIZE_SIZE <= 1)
|
2271
|
+
#endif
|
2272
|
+
|
2273
|
+
// A type-erased reference to an std::locale to avoid a heavy <locale> include.
|
2274
|
+
class locale_ref {
|
2275
|
+
#if FMT_USE_LOCALE
|
2276
|
+
private:
|
2277
|
+
const void* locale_; // A type-erased pointer to std::locale.
|
2278
|
+
|
2279
|
+
public:
|
2280
|
+
constexpr locale_ref() : locale_(nullptr) {}
|
2281
|
+
template <typename Locale> locale_ref(const Locale& loc);
|
2282
|
+
|
2283
|
+
inline explicit operator bool() const noexcept { return locale_ != nullptr; }
|
2284
|
+
#endif // FMT_USE_LOCALE
|
2285
|
+
|
2286
|
+
public:
|
2287
|
+
template <typename Locale> auto get() const -> Locale;
|
2288
|
+
};
|
2289
|
+
|
2290
|
+
template <typename> constexpr auto encode_types() -> unsigned long long {
|
2291
|
+
return 0;
|
2292
|
+
}
|
2293
|
+
|
2294
|
+
template <typename Context, typename Arg, typename... Args>
|
2295
|
+
constexpr auto encode_types() -> unsigned long long {
|
2296
|
+
return static_cast<unsigned>(stored_type_constant<Arg, Context>::value) |
|
2297
|
+
(encode_types<Context, Args...>() << packed_arg_bits);
|
2298
|
+
}
|
2299
|
+
|
2300
|
+
template <typename Context, typename... T, size_t NUM_ARGS = sizeof...(T)>
|
2301
|
+
constexpr auto make_descriptor() -> unsigned long long {
|
2302
|
+
return NUM_ARGS <= max_packed_args ? encode_types<Context, T...>()
|
2303
|
+
: is_unpacked_bit | NUM_ARGS;
|
2304
|
+
}
|
2305
|
+
|
2306
|
+
template <typename Context, int NUM_ARGS>
|
2307
|
+
using arg_t = conditional_t<NUM_ARGS <= max_packed_args, value<Context>,
|
2308
|
+
basic_format_arg<Context>>;
|
2309
|
+
|
2310
|
+
template <typename Context, int NUM_ARGS, int NUM_NAMED_ARGS,
|
2311
|
+
unsigned long long DESC>
|
2312
|
+
struct named_arg_store {
|
2313
|
+
// args_[0].named_args points to named_args to avoid bloating format_args.
|
2314
|
+
arg_t<Context, NUM_ARGS> args[1 + NUM_ARGS];
|
2315
|
+
named_arg_info<typename Context::char_type> named_args[NUM_NAMED_ARGS];
|
2316
|
+
|
2317
|
+
template <typename... T>
|
2318
|
+
FMT_CONSTEXPR FMT_ALWAYS_INLINE named_arg_store(T&... values)
|
2319
|
+
: args{{named_args, NUM_NAMED_ARGS}, values...} {
|
2320
|
+
int arg_index = 0, named_arg_index = 0;
|
2321
|
+
FMT_APPLY_VARIADIC(
|
2322
|
+
init_named_arg(named_args, arg_index, named_arg_index, values));
|
2323
|
+
}
|
2324
|
+
|
2325
|
+
named_arg_store(named_arg_store&& rhs) {
|
2326
|
+
args[0] = {named_args, NUM_NAMED_ARGS};
|
2327
|
+
for (size_t i = 1; i < sizeof(args) / sizeof(*args); ++i)
|
2328
|
+
args[i] = rhs.args[i];
|
2329
|
+
for (size_t i = 0; i < NUM_NAMED_ARGS; ++i)
|
2330
|
+
named_args[i] = rhs.named_args[i];
|
2331
|
+
}
|
2332
|
+
|
2333
|
+
named_arg_store(const named_arg_store& rhs) = delete;
|
2334
|
+
named_arg_store& operator=(const named_arg_store& rhs) = delete;
|
2335
|
+
named_arg_store& operator=(named_arg_store&& rhs) = delete;
|
2336
|
+
operator const arg_t<Context, NUM_ARGS>*() const { return args + 1; }
|
2337
|
+
};
|
2338
|
+
|
2339
|
+
// An array of references to arguments. It can be implicitly converted to
|
2340
|
+
// `basic_format_args` for passing into type-erased formatting functions
|
2341
|
+
// such as `vformat`. It is a plain struct to reduce binary size in debug mode.
|
2342
|
+
template <typename Context, int NUM_ARGS, int NUM_NAMED_ARGS,
|
2343
|
+
unsigned long long DESC>
|
2344
|
+
struct format_arg_store {
|
2345
|
+
// +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
|
2346
|
+
using type =
|
2347
|
+
conditional_t<NUM_NAMED_ARGS == 0,
|
2348
|
+
arg_t<Context, NUM_ARGS>[max_of(1, NUM_ARGS)],
|
2349
|
+
named_arg_store<Context, NUM_ARGS, NUM_NAMED_ARGS, DESC>>;
|
2350
|
+
type args;
|
2351
|
+
};
|
2352
|
+
|
2353
|
+
// TYPE can be different from type_constant<T>, e.g. for __float128.
|
2354
|
+
template <typename T, typename Char, type TYPE> struct native_formatter {
|
2355
|
+
private:
|
2356
|
+
dynamic_format_specs<Char> specs_;
|
2357
|
+
|
2358
|
+
public:
|
2359
|
+
using nonlocking = void;
|
2360
|
+
|
2361
|
+
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
2362
|
+
if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin();
|
2363
|
+
auto end = parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, TYPE);
|
2364
|
+
if (const_check(TYPE == type::char_type)) check_char_specs(specs_);
|
2365
|
+
return end;
|
2366
|
+
}
|
2367
|
+
|
2368
|
+
template <type U = TYPE,
|
2369
|
+
FMT_ENABLE_IF(U == type::string_type || U == type::cstring_type ||
|
2370
|
+
U == type::char_type)>
|
2371
|
+
FMT_CONSTEXPR void set_debug_format(bool set = true) {
|
2372
|
+
specs_.set_type(set ? presentation_type::debug : presentation_type::none);
|
2373
|
+
}
|
2374
|
+
|
2375
|
+
FMT_PRAGMA_CLANG(diagnostic ignored "-Wundefined-inline")
|
2376
|
+
template <typename FormatContext>
|
2377
|
+
FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const
|
2378
|
+
-> decltype(ctx.out());
|
2379
|
+
};
|
2380
|
+
|
2381
|
+
template <typename T, typename Enable = void>
|
2382
|
+
struct locking
|
2383
|
+
: bool_constant<mapped_type_constant<T>::value == type::custom_type> {};
|
2384
|
+
template <typename T>
|
2385
|
+
struct locking<T, void_t<typename formatter<remove_cvref_t<T>>::nonlocking>>
|
2386
|
+
: std::false_type {};
|
2387
|
+
|
2388
|
+
template <typename T = int> FMT_CONSTEXPR inline auto is_locking() -> bool {
|
2389
|
+
return locking<T>::value;
|
2390
|
+
}
|
2391
|
+
template <typename T1, typename T2, typename... Tail>
|
2392
|
+
FMT_CONSTEXPR inline auto is_locking() -> bool {
|
2393
|
+
return locking<T1>::value || is_locking<T2, Tail...>();
|
2394
|
+
}
|
2395
|
+
|
2396
|
+
FMT_API void vformat_to(buffer<char>& buf, string_view fmt, format_args args,
|
2397
|
+
locale_ref loc = {});
|
2398
|
+
|
2399
|
+
#if FMT_WIN32
|
2400
|
+
FMT_API void vprint_mojibake(FILE*, string_view, format_args, bool);
|
2401
|
+
#else // format_args is passed by reference since it is defined later.
|
2402
|
+
inline void vprint_mojibake(FILE*, string_view, const format_args&, bool) {}
|
2403
|
+
#endif
|
2404
|
+
} // namespace detail
|
2405
|
+
|
2406
|
+
// The main public API.
|
2407
|
+
|
2408
|
+
template <typename Char>
|
2409
|
+
FMT_CONSTEXPR void parse_context<Char>::do_check_arg_id(int arg_id) {
|
2410
|
+
// Argument id is only checked at compile time during parsing because
|
2411
|
+
// formatting has its own validation.
|
2412
|
+
if (detail::is_constant_evaluated() && use_constexpr_cast) {
|
2413
|
+
auto ctx = static_cast<detail::compile_parse_context<Char>*>(this);
|
2414
|
+
if (arg_id >= ctx->num_args()) report_error("argument not found");
|
2415
|
+
}
|
2416
|
+
}
|
2417
|
+
|
2418
|
+
template <typename Char>
|
2419
|
+
FMT_CONSTEXPR void parse_context<Char>::check_dynamic_spec(int arg_id) {
|
2420
|
+
using detail::compile_parse_context;
|
2421
|
+
if (detail::is_constant_evaluated() && use_constexpr_cast)
|
2422
|
+
static_cast<compile_parse_context<Char>*>(this)->check_dynamic_spec(arg_id);
|
2423
|
+
}
|
2424
|
+
|
2425
|
+
FMT_BEGIN_EXPORT
|
2426
|
+
|
2427
|
+
// An output iterator that appends to a buffer. It is used instead of
|
2428
|
+
// back_insert_iterator to reduce symbol sizes and avoid <iterator> dependency.
|
2429
|
+
template <typename T> class basic_appender {
|
2430
|
+
protected:
|
2431
|
+
detail::buffer<T>* container;
|
2432
|
+
|
2433
|
+
public:
|
2434
|
+
using container_type = detail::buffer<T>;
|
2435
|
+
|
2436
|
+
FMT_CONSTEXPR basic_appender(detail::buffer<T>& buf) : container(&buf) {}
|
2437
|
+
|
2438
|
+
FMT_CONSTEXPR20 auto operator=(T c) -> basic_appender& {
|
2439
|
+
container->push_back(c);
|
2440
|
+
return *this;
|
2441
|
+
}
|
2442
|
+
FMT_CONSTEXPR20 auto operator*() -> basic_appender& { return *this; }
|
2443
|
+
FMT_CONSTEXPR20 auto operator++() -> basic_appender& { return *this; }
|
2444
|
+
FMT_CONSTEXPR20 auto operator++(int) -> basic_appender { return *this; }
|
2445
|
+
};
|
2446
|
+
|
2447
|
+
// A formatting argument. Context is a template parameter for the compiled API
|
2448
|
+
// where output can be unbuffered.
|
2449
|
+
template <typename Context> class basic_format_arg {
|
2450
|
+
private:
|
2451
|
+
detail::value<Context> value_;
|
2452
|
+
detail::type type_;
|
2453
|
+
|
2454
|
+
friend class basic_format_args<Context>;
|
2455
|
+
|
2456
|
+
using char_type = typename Context::char_type;
|
2457
|
+
|
2458
|
+
public:
|
2459
|
+
class handle {
|
2460
|
+
private:
|
2461
|
+
detail::custom_value<Context> custom_;
|
2462
|
+
|
2463
|
+
public:
|
2464
|
+
explicit handle(detail::custom_value<Context> custom) : custom_(custom) {}
|
2465
|
+
|
2466
|
+
void format(parse_context<char_type>& parse_ctx, Context& ctx) const {
|
2467
|
+
custom_.format(custom_.value, parse_ctx, ctx);
|
2468
|
+
}
|
2469
|
+
};
|
2470
|
+
|
2471
|
+
constexpr basic_format_arg() : type_(detail::type::none_type) {}
|
2472
|
+
basic_format_arg(const detail::named_arg_info<char_type>* args, size_t size)
|
2473
|
+
: value_(args, size) {}
|
2474
|
+
template <typename T>
|
2475
|
+
basic_format_arg(T&& val)
|
2476
|
+
: value_(val), type_(detail::stored_type_constant<T, Context>::value) {}
|
2477
|
+
|
2478
|
+
constexpr explicit operator bool() const noexcept {
|
2479
|
+
return type_ != detail::type::none_type;
|
2480
|
+
}
|
2481
|
+
auto type() const -> detail::type { return type_; }
|
2482
|
+
|
2483
|
+
/**
|
2484
|
+
* Visits an argument dispatching to the appropriate visit method based on
|
2485
|
+
* the argument type. For example, if the argument type is `double` then
|
2486
|
+
* `vis(value)` will be called with the value of type `double`.
|
2487
|
+
*/
|
2488
|
+
template <typename Visitor>
|
2489
|
+
FMT_CONSTEXPR FMT_INLINE auto visit(Visitor&& vis) const -> decltype(vis(0)) {
|
2490
|
+
using detail::map;
|
2491
|
+
switch (type_) {
|
2492
|
+
case detail::type::none_type: break;
|
2493
|
+
case detail::type::int_type: return vis(value_.int_value);
|
2494
|
+
case detail::type::uint_type: return vis(value_.uint_value);
|
2495
|
+
case detail::type::long_long_type: return vis(value_.long_long_value);
|
2496
|
+
case detail::type::ulong_long_type: return vis(value_.ulong_long_value);
|
2497
|
+
case detail::type::int128_type: return vis(map(value_.int128_value));
|
2498
|
+
case detail::type::uint128_type: return vis(map(value_.uint128_value));
|
2499
|
+
case detail::type::bool_type: return vis(value_.bool_value);
|
2500
|
+
case detail::type::char_type: return vis(value_.char_value);
|
2501
|
+
case detail::type::float_type: return vis(value_.float_value);
|
2502
|
+
case detail::type::double_type: return vis(value_.double_value);
|
2503
|
+
case detail::type::long_double_type: return vis(value_.long_double_value);
|
2504
|
+
case detail::type::cstring_type: return vis(value_.string.data);
|
2505
|
+
case detail::type::string_type: return vis(value_.string.str());
|
2506
|
+
case detail::type::pointer_type: return vis(value_.pointer);
|
2507
|
+
case detail::type::custom_type: return vis(handle(value_.custom));
|
2508
|
+
}
|
2509
|
+
return vis(monostate());
|
2510
|
+
}
|
2511
|
+
|
2512
|
+
auto format_custom(const char_type* parse_begin,
|
2513
|
+
parse_context<char_type>& parse_ctx, Context& ctx)
|
2514
|
+
-> bool {
|
2515
|
+
if (type_ != detail::type::custom_type) return false;
|
2516
|
+
parse_ctx.advance_to(parse_begin);
|
2517
|
+
value_.custom.format(value_.custom.value, parse_ctx, ctx);
|
2518
|
+
return true;
|
2519
|
+
}
|
2520
|
+
};
|
2521
|
+
|
2522
|
+
/**
|
2523
|
+
* A view of a collection of formatting arguments. To avoid lifetime issues it
|
2524
|
+
* should only be used as a parameter type in type-erased functions such as
|
2525
|
+
* `vformat`:
|
2526
|
+
*
|
2527
|
+
* void vlog(fmt::string_view fmt, fmt::format_args args); // OK
|
2528
|
+
* fmt::format_args args = fmt::make_format_args(); // Dangling reference
|
2529
|
+
*/
|
2530
|
+
template <typename Context> class basic_format_args {
|
2531
|
+
private:
|
2532
|
+
// A descriptor that contains information about formatting arguments.
|
2533
|
+
// If the number of arguments is less or equal to max_packed_args then
|
2534
|
+
// argument types are passed in the descriptor. This reduces binary code size
|
2535
|
+
// per formatting function call.
|
2536
|
+
unsigned long long desc_;
|
2537
|
+
union {
|
2538
|
+
// If is_packed() returns true then argument values are stored in values_;
|
2539
|
+
// otherwise they are stored in args_. This is done to improve cache
|
2540
|
+
// locality and reduce compiled code size since storing larger objects
|
2541
|
+
// may require more code (at least on x86-64) even if the same amount of
|
2542
|
+
// data is actually copied to stack. It saves ~10% on the bloat test.
|
2543
|
+
const detail::value<Context>* values_;
|
2544
|
+
const basic_format_arg<Context>* args_;
|
2545
|
+
};
|
2546
|
+
|
2547
|
+
constexpr auto is_packed() const -> bool {
|
2548
|
+
return (desc_ & detail::is_unpacked_bit) == 0;
|
2549
|
+
}
|
2550
|
+
constexpr auto has_named_args() const -> bool {
|
2551
|
+
return (desc_ & detail::has_named_args_bit) != 0;
|
2552
|
+
}
|
2553
|
+
|
2554
|
+
FMT_CONSTEXPR auto type(int index) const -> detail::type {
|
2555
|
+
int shift = index * detail::packed_arg_bits;
|
2556
|
+
unsigned mask = (1 << detail::packed_arg_bits) - 1;
|
2557
|
+
return static_cast<detail::type>((desc_ >> shift) & mask);
|
2558
|
+
}
|
2559
|
+
|
2560
|
+
template <int NUM_ARGS, int NUM_NAMED_ARGS, unsigned long long DESC>
|
2561
|
+
using store =
|
2562
|
+
detail::format_arg_store<Context, NUM_ARGS, NUM_NAMED_ARGS, DESC>;
|
2563
|
+
|
2564
|
+
public:
|
2565
|
+
using format_arg = basic_format_arg<Context>;
|
2566
|
+
|
2567
|
+
constexpr basic_format_args() : desc_(0), args_(nullptr) {}
|
2568
|
+
|
2569
|
+
/// Constructs a `basic_format_args` object from `format_arg_store`.
|
2570
|
+
template <int NUM_ARGS, int NUM_NAMED_ARGS, unsigned long long DESC,
|
2571
|
+
FMT_ENABLE_IF(NUM_ARGS <= detail::max_packed_args)>
|
2572
|
+
constexpr FMT_ALWAYS_INLINE basic_format_args(
|
2573
|
+
const store<NUM_ARGS, NUM_NAMED_ARGS, DESC>& s)
|
2574
|
+
: desc_(DESC | (NUM_NAMED_ARGS != 0 ? +detail::has_named_args_bit : 0)),
|
2575
|
+
values_(s.args) {}
|
2576
|
+
|
2577
|
+
template <int NUM_ARGS, int NUM_NAMED_ARGS, unsigned long long DESC,
|
2578
|
+
FMT_ENABLE_IF(NUM_ARGS > detail::max_packed_args)>
|
2579
|
+
constexpr basic_format_args(const store<NUM_ARGS, NUM_NAMED_ARGS, DESC>& s)
|
2580
|
+
: desc_(DESC | (NUM_NAMED_ARGS != 0 ? +detail::has_named_args_bit : 0)),
|
2581
|
+
args_(s.args) {}
|
2582
|
+
|
2583
|
+
/// Constructs a `basic_format_args` object from a dynamic list of arguments.
|
2584
|
+
constexpr basic_format_args(const format_arg* args, int count,
|
2585
|
+
bool has_named = false)
|
2586
|
+
: desc_(detail::is_unpacked_bit | detail::to_unsigned(count) |
|
2587
|
+
(has_named ? +detail::has_named_args_bit : 0)),
|
2588
|
+
args_(args) {}
|
2589
|
+
|
2590
|
+
/// Returns the argument with the specified id.
|
2591
|
+
FMT_CONSTEXPR auto get(int id) const -> format_arg {
|
2592
|
+
auto arg = format_arg();
|
2593
|
+
if (!is_packed()) {
|
2594
|
+
if (id < max_size()) arg = args_[id];
|
2595
|
+
return arg;
|
2596
|
+
}
|
2597
|
+
if (static_cast<unsigned>(id) >= detail::max_packed_args) return arg;
|
2598
|
+
arg.type_ = type(id);
|
2599
|
+
if (arg.type_ != detail::type::none_type) arg.value_ = values_[id];
|
2600
|
+
return arg;
|
2601
|
+
}
|
2602
|
+
|
2603
|
+
template <typename Char>
|
2604
|
+
auto get(basic_string_view<Char> name) const -> format_arg {
|
2605
|
+
int id = get_id(name);
|
2606
|
+
return id >= 0 ? get(id) : format_arg();
|
2607
|
+
}
|
2608
|
+
|
2609
|
+
template <typename Char>
|
2610
|
+
FMT_CONSTEXPR auto get_id(basic_string_view<Char> name) const -> int {
|
2611
|
+
if (!has_named_args()) return -1;
|
2612
|
+
const auto& named_args =
|
2613
|
+
(is_packed() ? values_[-1] : args_[-1].value_).named_args;
|
2614
|
+
for (size_t i = 0; i < named_args.size; ++i) {
|
2615
|
+
if (named_args.data[i].name == name) return named_args.data[i].id;
|
2616
|
+
}
|
2617
|
+
return -1;
|
2618
|
+
}
|
2619
|
+
|
2620
|
+
auto max_size() const -> int {
|
2621
|
+
unsigned long long max_packed = detail::max_packed_args;
|
2622
|
+
return static_cast<int>(is_packed() ? max_packed
|
2623
|
+
: desc_ & ~detail::is_unpacked_bit);
|
2624
|
+
}
|
2625
|
+
};
|
2626
|
+
|
2627
|
+
// A formatting context.
|
2628
|
+
class context {
|
2629
|
+
private:
|
2630
|
+
appender out_;
|
2631
|
+
format_args args_;
|
2632
|
+
FMT_NO_UNIQUE_ADDRESS detail::locale_ref loc_;
|
2633
|
+
|
2634
|
+
public:
|
2635
|
+
/// The character type for the output.
|
2636
|
+
using char_type = char;
|
2637
|
+
|
2638
|
+
using iterator = appender;
|
2639
|
+
using format_arg = basic_format_arg<context>;
|
2640
|
+
using parse_context_type FMT_DEPRECATED = parse_context<>;
|
2641
|
+
template <typename T> using formatter_type FMT_DEPRECATED = formatter<T>;
|
2642
|
+
enum { builtin_types = FMT_BUILTIN_TYPES };
|
2643
|
+
|
2644
|
+
/// Constructs a `context` object. References to the arguments are stored
|
2645
|
+
/// in the object so make sure they have appropriate lifetimes.
|
2646
|
+
FMT_CONSTEXPR context(iterator out, format_args args,
|
2647
|
+
detail::locale_ref loc = {})
|
2648
|
+
: out_(out), args_(args), loc_(loc) {}
|
2649
|
+
context(context&&) = default;
|
2650
|
+
context(const context&) = delete;
|
2651
|
+
void operator=(const context&) = delete;
|
2652
|
+
|
2653
|
+
FMT_CONSTEXPR auto arg(int id) const -> format_arg { return args_.get(id); }
|
2654
|
+
inline auto arg(string_view name) const -> format_arg {
|
2655
|
+
return args_.get(name);
|
2656
|
+
}
|
2657
|
+
FMT_CONSTEXPR auto arg_id(string_view name) const -> int {
|
2658
|
+
return args_.get_id(name);
|
2659
|
+
}
|
2660
|
+
auto args() const -> const format_args& { return args_; }
|
2661
|
+
|
2662
|
+
// Returns an iterator to the beginning of the output range.
|
2663
|
+
FMT_CONSTEXPR auto out() const -> iterator { return out_; }
|
2664
|
+
|
2665
|
+
// Advances the begin iterator to `it`.
|
2666
|
+
FMT_CONSTEXPR void advance_to(iterator) {}
|
2667
|
+
|
2668
|
+
FMT_CONSTEXPR auto locale() const -> detail::locale_ref { return loc_; }
|
2669
|
+
};
|
2670
|
+
|
2671
|
+
template <typename Char = char> struct runtime_format_string {
|
2672
|
+
basic_string_view<Char> str;
|
2673
|
+
};
|
2674
|
+
|
2675
|
+
/**
|
2676
|
+
* Creates a runtime format string.
|
2677
|
+
*
|
2678
|
+
* **Example**:
|
2679
|
+
*
|
2680
|
+
* // Check format string at runtime instead of compile-time.
|
2681
|
+
* fmt::print(fmt::runtime("{:d}"), "I am not a number");
|
2682
|
+
*/
|
2683
|
+
inline auto runtime(string_view s) -> runtime_format_string<> { return {{s}}; }
|
2684
|
+
|
2685
|
+
/// A compile-time format string. Use `format_string` in the public API to
|
2686
|
+
/// prevent type deduction.
|
2687
|
+
template <typename... T> struct fstring {
|
2688
|
+
private:
|
2689
|
+
static constexpr int num_static_named_args =
|
2690
|
+
detail::count_static_named_args<T...>();
|
2691
|
+
|
2692
|
+
using checker = detail::format_string_checker<
|
2693
|
+
char, static_cast<int>(sizeof...(T)), num_static_named_args,
|
2694
|
+
num_static_named_args != detail::count_named_args<T...>()>;
|
2695
|
+
|
2696
|
+
using arg_pack = detail::arg_pack<T...>;
|
2697
|
+
|
2698
|
+
public:
|
2699
|
+
string_view str;
|
2700
|
+
using t = fstring;
|
2701
|
+
|
2702
|
+
// Reports a compile-time error if S is not a valid format string for T.
|
2703
|
+
template <size_t N>
|
2704
|
+
FMT_CONSTEVAL FMT_ALWAYS_INLINE fstring(const char (&s)[N]) : str(s, N - 1) {
|
2705
|
+
using namespace detail;
|
2706
|
+
static_assert(count<(std::is_base_of<view, remove_reference_t<T>>::value &&
|
2707
|
+
std::is_reference<T>::value)...>() == 0,
|
2708
|
+
"passing views as lvalues is disallowed");
|
2709
|
+
if (FMT_USE_CONSTEVAL) parse_format_string<char>(s, checker(s, arg_pack()));
|
2710
|
+
#ifdef FMT_ENFORCE_COMPILE_STRING
|
2711
|
+
static_assert(
|
2712
|
+
FMT_USE_CONSTEVAL && sizeof(s) != 0,
|
2713
|
+
"FMT_ENFORCE_COMPILE_STRING requires format strings to use FMT_STRING");
|
2714
|
+
#endif
|
2715
|
+
}
|
2716
|
+
template <typename S,
|
2717
|
+
FMT_ENABLE_IF(std::is_convertible<const S&, string_view>::value)>
|
2718
|
+
FMT_CONSTEVAL FMT_ALWAYS_INLINE fstring(const S& s) : str(s) {
|
2719
|
+
auto sv = string_view(str);
|
2720
|
+
if (FMT_USE_CONSTEVAL)
|
2721
|
+
detail::parse_format_string<char>(sv, checker(sv, arg_pack()));
|
2722
|
+
#ifdef FMT_ENFORCE_COMPILE_STRING
|
2723
|
+
static_assert(
|
2724
|
+
FMT_USE_CONSTEVAL && sizeof(s) != 0,
|
2725
|
+
"FMT_ENFORCE_COMPILE_STRING requires format strings to use FMT_STRING");
|
2726
|
+
#endif
|
2727
|
+
}
|
2728
|
+
template <typename S,
|
2729
|
+
FMT_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&&
|
2730
|
+
std::is_same<typename S::char_type, char>::value)>
|
2731
|
+
FMT_ALWAYS_INLINE fstring(const S&) : str(S()) {
|
2732
|
+
FMT_CONSTEXPR auto sv = string_view(S());
|
2733
|
+
FMT_CONSTEXPR int unused =
|
2734
|
+
(parse_format_string(sv, checker(sv, arg_pack())), 0);
|
2735
|
+
detail::ignore_unused(unused);
|
2736
|
+
}
|
2737
|
+
fstring(runtime_format_string<> fmt) : str(fmt.str) {}
|
2738
|
+
|
2739
|
+
// Returning by reference generates better code in debug mode.
|
2740
|
+
FMT_ALWAYS_INLINE operator const string_view&() const { return str; }
|
2741
|
+
auto get() const -> string_view { return str; }
|
2742
|
+
};
|
2743
|
+
|
2744
|
+
template <typename... T> using format_string = typename fstring<T...>::t;
|
2745
|
+
|
2746
|
+
template <typename T, typename Char = char>
|
2747
|
+
using is_formattable = bool_constant<!std::is_same<
|
2748
|
+
detail::mapped_t<conditional_t<std::is_void<T>::value, int*, T>, Char>,
|
2749
|
+
void>::value>;
|
2750
|
+
#ifdef __cpp_concepts
|
2751
|
+
template <typename T, typename Char = char>
|
2752
|
+
concept formattable = is_formattable<remove_reference_t<T>, Char>::value;
|
2753
|
+
#endif
|
2754
|
+
|
2755
|
+
template <typename T, typename Char>
|
2756
|
+
using has_formatter FMT_DEPRECATED = std::is_constructible<formatter<T, Char>>;
|
2757
|
+
|
2758
|
+
// A formatter specialization for natively supported types.
|
2759
|
+
template <typename T, typename Char>
|
2760
|
+
struct formatter<T, Char,
|
2761
|
+
enable_if_t<detail::type_constant<T, Char>::value !=
|
2762
|
+
detail::type::custom_type>>
|
2763
|
+
: detail::native_formatter<T, Char, detail::type_constant<T, Char>::value> {
|
2764
|
+
};
|
2765
|
+
|
2766
|
+
/**
|
2767
|
+
* Constructs an object that stores references to arguments and can be
|
2768
|
+
* implicitly converted to `format_args`. `Context` can be omitted in which case
|
2769
|
+
* it defaults to `context`. See `arg` for lifetime considerations.
|
2770
|
+
*/
|
2771
|
+
// Take arguments by lvalue references to avoid some lifetime issues, e.g.
|
2772
|
+
// auto args = make_format_args(std::string());
|
2773
|
+
template <typename Context = context, typename... T,
|
2774
|
+
int NUM_ARGS = sizeof...(T),
|
2775
|
+
int NUM_NAMED_ARGS = detail::count_named_args<T...>(),
|
2776
|
+
unsigned long long DESC = detail::make_descriptor<Context, T...>()>
|
2777
|
+
constexpr FMT_ALWAYS_INLINE auto make_format_args(T&... args)
|
2778
|
+
-> detail::format_arg_store<Context, NUM_ARGS, NUM_NAMED_ARGS, DESC> {
|
2779
|
+
// Suppress warnings for pathological types convertible to detail::value.
|
2780
|
+
FMT_PRAGMA_GCC(diagnostic ignored "-Wconversion")
|
2781
|
+
return {{args...}};
|
2782
|
+
}
|
2783
|
+
|
2784
|
+
template <typename... T>
|
2785
|
+
using vargs =
|
2786
|
+
detail::format_arg_store<context, sizeof...(T),
|
2787
|
+
detail::count_named_args<T...>(),
|
2788
|
+
detail::make_descriptor<context, T...>()>;
|
2789
|
+
|
2790
|
+
/**
|
2791
|
+
* Returns a named argument to be used in a formatting function.
|
2792
|
+
* It should only be used in a call to a formatting function.
|
2793
|
+
*
|
2794
|
+
* **Example**:
|
2795
|
+
*
|
2796
|
+
* fmt::print("The answer is {answer}.", fmt::arg("answer", 42));
|
2797
|
+
*/
|
2798
|
+
template <typename Char, typename T>
|
2799
|
+
inline auto arg(const Char* name, const T& arg) -> detail::named_arg<Char, T> {
|
2800
|
+
return {name, arg};
|
2801
|
+
}
|
2802
|
+
|
2803
|
+
/// Formats a string and writes the output to `out`.
|
2804
|
+
template <typename OutputIt,
|
2805
|
+
FMT_ENABLE_IF(detail::is_output_iterator<remove_cvref_t<OutputIt>,
|
2806
|
+
char>::value)>
|
2807
|
+
auto vformat_to(OutputIt&& out, string_view fmt, format_args args)
|
2808
|
+
-> remove_cvref_t<OutputIt> {
|
2809
|
+
auto&& buf = detail::get_buffer<char>(out);
|
2810
|
+
detail::vformat_to(buf, fmt, args, {});
|
2811
|
+
return detail::get_iterator(buf, out);
|
2812
|
+
}
|
2813
|
+
|
2814
|
+
/**
|
2815
|
+
* Formats `args` according to specifications in `fmt`, writes the result to
|
2816
|
+
* the output iterator `out` and returns the iterator past the end of the output
|
2817
|
+
* range. `format_to` does not append a terminating null character.
|
2818
|
+
*
|
2819
|
+
* **Example**:
|
2820
|
+
*
|
2821
|
+
* auto out = std::vector<char>();
|
2822
|
+
* fmt::format_to(std::back_inserter(out), "{}", 42);
|
2823
|
+
*/
|
2824
|
+
template <typename OutputIt, typename... T,
|
2825
|
+
FMT_ENABLE_IF(detail::is_output_iterator<remove_cvref_t<OutputIt>,
|
2826
|
+
char>::value)>
|
2827
|
+
FMT_INLINE auto format_to(OutputIt&& out, format_string<T...> fmt, T&&... args)
|
2828
|
+
-> remove_cvref_t<OutputIt> {
|
2829
|
+
return vformat_to(out, fmt.str, vargs<T...>{{args...}});
|
2830
|
+
}
|
2831
|
+
|
2832
|
+
template <typename OutputIt> struct format_to_n_result {
|
2833
|
+
/// Iterator past the end of the output range.
|
2834
|
+
OutputIt out;
|
2835
|
+
/// Total (not truncated) output size.
|
2836
|
+
size_t size;
|
2837
|
+
};
|
2838
|
+
|
2839
|
+
template <typename OutputIt, typename... T,
|
2840
|
+
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
|
2841
|
+
auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args)
|
2842
|
+
-> format_to_n_result<OutputIt> {
|
2843
|
+
using traits = detail::fixed_buffer_traits;
|
2844
|
+
auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n);
|
2845
|
+
detail::vformat_to(buf, fmt, args, {});
|
2846
|
+
return {buf.out(), buf.count()};
|
2847
|
+
}
|
2848
|
+
|
2849
|
+
/**
|
2850
|
+
* Formats `args` according to specifications in `fmt`, writes up to `n`
|
2851
|
+
* characters of the result to the output iterator `out` and returns the total
|
2852
|
+
* (not truncated) output size and the iterator past the end of the output
|
2853
|
+
* range. `format_to_n` does not append a terminating null character.
|
2854
|
+
*/
|
2855
|
+
template <typename OutputIt, typename... T,
|
2856
|
+
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
|
2857
|
+
FMT_INLINE auto format_to_n(OutputIt out, size_t n, format_string<T...> fmt,
|
2858
|
+
T&&... args) -> format_to_n_result<OutputIt> {
|
2859
|
+
return vformat_to_n(out, n, fmt.str, vargs<T...>{{args...}});
|
2860
|
+
}
|
2861
|
+
|
2862
|
+
struct format_to_result {
|
2863
|
+
/// Pointer to just after the last successful write in the array.
|
2864
|
+
char* out;
|
2865
|
+
/// Specifies if the output was truncated.
|
2866
|
+
bool truncated;
|
2867
|
+
|
2868
|
+
FMT_CONSTEXPR operator char*() const {
|
2869
|
+
// Report truncation to prevent silent data loss.
|
2870
|
+
if (truncated) report_error("output is truncated");
|
2871
|
+
return out;
|
2872
|
+
}
|
2873
|
+
};
|
2874
|
+
|
2875
|
+
template <size_t N>
|
2876
|
+
auto vformat_to(char (&out)[N], string_view fmt, format_args args)
|
2877
|
+
-> format_to_result {
|
2878
|
+
auto result = vformat_to_n(out, N, fmt, args);
|
2879
|
+
return {result.out, result.size > N};
|
2880
|
+
}
|
2881
|
+
|
2882
|
+
template <size_t N, typename... T>
|
2883
|
+
FMT_INLINE auto format_to(char (&out)[N], format_string<T...> fmt, T&&... args)
|
2884
|
+
-> format_to_result {
|
2885
|
+
auto result = vformat_to_n(out, N, fmt.str, vargs<T...>{{args...}});
|
2886
|
+
return {result.out, result.size > N};
|
2887
|
+
}
|
2888
|
+
|
2889
|
+
/// Returns the number of chars in the output of `format(fmt, args...)`.
|
2890
|
+
template <typename... T>
|
2891
|
+
FMT_NODISCARD FMT_INLINE auto formatted_size(format_string<T...> fmt,
|
2892
|
+
T&&... args) -> size_t {
|
2893
|
+
auto buf = detail::counting_buffer<>();
|
2894
|
+
detail::vformat_to(buf, fmt.str, vargs<T...>{{args...}}, {});
|
2895
|
+
return buf.count();
|
2896
|
+
}
|
2897
|
+
|
2898
|
+
FMT_API void vprint(string_view fmt, format_args args);
|
2899
|
+
FMT_API void vprint(FILE* f, string_view fmt, format_args args);
|
2900
|
+
FMT_API void vprintln(FILE* f, string_view fmt, format_args args);
|
2901
|
+
FMT_API void vprint_buffered(FILE* f, string_view fmt, format_args args);
|
2902
|
+
|
2903
|
+
/**
|
2904
|
+
* Formats `args` according to specifications in `fmt` and writes the output
|
2905
|
+
* to `stdout`.
|
2906
|
+
*
|
2907
|
+
* **Example**:
|
2908
|
+
*
|
2909
|
+
* fmt::print("The answer is {}.", 42);
|
2910
|
+
*/
|
2911
|
+
template <typename... T>
|
2912
|
+
FMT_INLINE void print(format_string<T...> fmt, T&&... args) {
|
2913
|
+
vargs<T...> va = {{args...}};
|
2914
|
+
if (detail::const_check(!detail::use_utf8))
|
2915
|
+
return detail::vprint_mojibake(stdout, fmt.str, va, false);
|
2916
|
+
return detail::is_locking<T...>() ? vprint_buffered(stdout, fmt.str, va)
|
2917
|
+
: vprint(fmt.str, va);
|
2918
|
+
}
|
2919
|
+
|
2920
|
+
/**
|
2921
|
+
* Formats `args` according to specifications in `fmt` and writes the
|
2922
|
+
* output to the file `f`.
|
2923
|
+
*
|
2924
|
+
* **Example**:
|
2925
|
+
*
|
2926
|
+
* fmt::print(stderr, "Don't {}!", "panic");
|
2927
|
+
*/
|
2928
|
+
template <typename... T>
|
2929
|
+
FMT_INLINE void print(FILE* f, format_string<T...> fmt, T&&... args) {
|
2930
|
+
vargs<T...> va = {{args...}};
|
2931
|
+
if (detail::const_check(!detail::use_utf8))
|
2932
|
+
return detail::vprint_mojibake(f, fmt.str, va, false);
|
2933
|
+
return detail::is_locking<T...>() ? vprint_buffered(f, fmt.str, va)
|
2934
|
+
: vprint(f, fmt.str, va);
|
2935
|
+
}
|
2936
|
+
|
2937
|
+
/// Formats `args` according to specifications in `fmt` and writes the output
|
2938
|
+
/// to the file `f` followed by a newline.
|
2939
|
+
template <typename... T>
|
2940
|
+
FMT_INLINE void println(FILE* f, format_string<T...> fmt, T&&... args) {
|
2941
|
+
vargs<T...> va = {{args...}};
|
2942
|
+
return detail::const_check(detail::use_utf8)
|
2943
|
+
? vprintln(f, fmt.str, va)
|
2944
|
+
: detail::vprint_mojibake(f, fmt.str, va, true);
|
2945
|
+
}
|
2946
|
+
|
2947
|
+
/// Formats `args` according to specifications in `fmt` and writes the output
|
2948
|
+
/// to `stdout` followed by a newline.
|
2949
|
+
template <typename... T>
|
2950
|
+
FMT_INLINE void println(format_string<T...> fmt, T&&... args) {
|
2951
|
+
return fmt::println(stdout, fmt, static_cast<T&&>(args)...);
|
2952
|
+
}
|
2953
|
+
|
2954
|
+
FMT_END_EXPORT
|
2955
|
+
FMT_PRAGMA_CLANG(diagnostic pop)
|
2956
|
+
FMT_PRAGMA_GCC(pop_options)
|
2957
|
+
FMT_END_NAMESPACE
|
2958
|
+
|
2959
|
+
#ifdef FMT_HEADER_ONLY
|
2960
|
+
# include "format.h"
|
2961
|
+
#endif
|
2962
|
+
#endif // FMT_BASE_H_
|