├── .clang-format ├── .github ├── FUNDING.yml └── workflows │ └── build.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── screenshot └── debug.jpg ├── src ├── debug.cpp ├── debug.h ├── main.cpp └── main.h └── third_party ├── fmt ├── CMakeLists.txt ├── include │ └── fmt │ │ ├── args.h │ │ ├── chrono.h │ │ ├── color.h │ │ ├── compile.h │ │ ├── core.h │ │ ├── format-inl.h │ │ ├── format.h │ │ ├── os.h │ │ ├── ostream.h │ │ ├── printf.h │ │ ├── ranges.h │ │ ├── std.h │ │ └── xchar.h └── src │ ├── format.cc │ └── os.cc ├── imgui ├── CMakeLists.txt ├── include │ ├── imconfig.h │ ├── imgui.h │ ├── imgui_impl_glfw.h │ ├── imgui_impl_opengl3.h │ ├── imgui_impl_opengl3_loader.h │ ├── imgui_internal.h │ ├── imstb_rectpack.h │ ├── imstb_textedit.h │ └── imstb_truetype.h └── src │ ├── imgui.cpp │ ├── imgui_demo.cpp │ ├── imgui_draw.cpp │ ├── imgui_impl_glfw.cpp │ ├── imgui_impl_opengl3.cpp │ ├── imgui_tables.cpp │ └── imgui_widgets.cpp └── inipp ├── CMakeLists.txt └── include └── inipp.h /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | Language: Cpp 3 | ColumnLimit: 120 4 | IndentWidth: 4 5 | TabWidth: 4 6 | UseTab: Never 7 | SortIncludes: false -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: tsl0922 2 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: ["*"] 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | win: 11 | runs-on: windows-2019 12 | name: Windows 13 | steps: 14 | - uses: actions/checkout@v4 15 | with: 16 | fetch-depth: 0 17 | - uses: msys2/setup-msys2@v2 18 | with: 19 | msystem: clang64 20 | install: >- 21 | base-devel 22 | git 23 | mingw-w64-clang-x86_64-clang 24 | mingw-w64-clang-x86_64-cmake 25 | mingw-w64-clang-x86_64-ninja 26 | mingw-w64-clang-x86_64-mpv 27 | update: true 28 | - name: Build 29 | shell: msys2 {0} 30 | run: | 31 | mkdir build && cd build 32 | cmake -DCMAKE_BUILD_TYPE=RELEASE \ 33 | -DCMAKE_SHARED_LINKER_FLAGS="-static" \ 34 | -G Ninja .. 35 | cmake --build . 36 | - uses: actions/upload-artifact@v4 37 | with: 38 | name: debug.win32 39 | path: build/debug.dll 40 | linux: 41 | runs-on: ubuntu-22.04 42 | name: Linux 43 | steps: 44 | - uses: actions/checkout@v4 45 | with: 46 | fetch-depth: 0 47 | - name: Install dependencies 48 | run: | 49 | sudo add-apt-repository universe 50 | sudo apt-get update 51 | sudo apt-get install -y build-essential cmake ninja-build git pkg-config libmpv-dev xorg-dev 52 | - name: Build 53 | run: | 54 | mkdir build && cd build 55 | cmake -DCMAKE_BUILD_TYPE=RELEASE \ 56 | -G Ninja .. 57 | cmake --build . 58 | - uses: actions/upload-artifact@v4 59 | with: 60 | name: debug.linux 61 | path: build/debug.so 62 | publish: 63 | needs: [win, linux] 64 | runs-on: ubuntu-22.04 65 | if: ${{ github.ref == 'refs/heads/main' }} 66 | steps: 67 | - uses: actions/checkout@v4 68 | - uses: actions/download-artifact@v4 69 | - name: Zip files 70 | run: | 71 | mkdir debug 72 | mv debug.*/debug.* debug/ 73 | zip -r debug.zip debug 74 | - uses: rickstaa/action-create-tag@v1 75 | with: 76 | tag: dev 77 | force_push_tag: true 78 | - uses: ncipollo/release-action@v1 79 | with: 80 | commit: ${{ github.sha }} 81 | tag: dev 82 | artifacts: "debug.zip" 83 | allowUpdates: true 84 | name: Latest build 85 | body: Latest build -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Libraries 15 | *.lib 16 | *.a 17 | *.la 18 | *.lo 19 | 20 | # Shared objects (inc. Windows DLLs) 21 | *.dll 22 | *.so 23 | *.so.* 24 | *.dylib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | *.i*86 31 | *.x86_64 32 | *.hex 33 | 34 | # Debug files 35 | *.dSYM/ 36 | *.su 37 | 38 | # Cmake files 39 | CMakeCache.txt 40 | CMakeFiles 41 | CMakeScripts 42 | cmake_install.cmake 43 | install_manifest.txt 44 | CTestTestfile.cmake 45 | build 46 | 47 | # Clion files 48 | .idea/ 49 | 50 | # VSCode files 51 | .vscode/ 52 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | project(debug) 4 | set(CMAKE_CXX_STANDARD 20) 5 | 6 | include(FindPkgConfig) 7 | pkg_search_module(MPV REQUIRED mpv>=0.24.0) 8 | 9 | add_subdirectory(third_party/fmt) 10 | add_subdirectory(third_party/imgui) 11 | add_subdirectory(third_party/inipp) 12 | 13 | set(CMAKE_SHARED_LIBRARY_PREFIX "") 14 | add_library(debug SHARED 15 | src/debug.cpp 16 | src/main.cpp 17 | ) 18 | set_property(TARGET debug PROPERTY POSITION_INDEPENDENT_CODE ON) 19 | 20 | target_include_directories(debug PRIVATE ${MPV_INCLUDE_DIRS}) 21 | target_link_libraries(debug PRIVATE fmt imgui inipp) 22 | target_compile_definitions(debug PRIVATE 23 | $<$:MPV_CPLUGIN_DYNAMIC_SYM> 24 | ) 25 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mpv-debug-plugin 2 | 3 | a debug tool for [mpv](https://mpv.io), based on the [C PLUGINS](https://mpv.io/manual/master/#c-plugins) API. 4 | 5 | ![screenshot](screenshot/debug.jpg) 6 | 7 | See also [mpv-menu-plugin](https://github.com/tsl0922/mpv-menu-plugin). 8 | 9 | ## Features 10 | 11 | - Visual view of mpv's internal properties 12 | - Console with completion, history support 13 | - Colorful mpv logs view with filter support 14 | 15 | ## Installation 16 | 17 | Download the plugin from Releases. 18 | 19 | - **Windows:** mpv >= `0.37.0` is required, place `debug.dll` in your mpv `scripts` folder 20 | - **Linux:** mpv >= `0.24.0` is required, place `debug.so` in your mpv `scripts` folder 21 | 22 | Check if the `cplugins` feature is compiled into mpv if the plugin is not loaded. 23 | 24 | ## Configuration 25 | 26 | > **NOTE:** If you changed the dll name, `script-message-to` target should apply too. 27 | 28 | Add a keybinding to show debug window (required): 29 | 30 | **input.conf** 31 | ``` 32 | ` script-message-to debug show 33 | ``` 34 | 35 | **~~/script-opts/debug.conf** 36 | 37 | - `font-path=`: use a custom TTF font 38 | - `font-size=`: custom font size, default: `13` 39 | - `log-lines=`: set the log buffer size, default: `5000` 40 | 41 | To change the log level to verbose on start, add `msg-level=all=v` to `mpv.conf`. 42 | 43 | # Credits 44 | 45 | - [fmt](https://fmt.dev): A modern formatting library 46 | - [imgui](https://github.com/ocornut/imgui): Bloat-free Graphical User interface for C++ with minimal dependencies 47 | - [ImPlay](https://github.com/tsl0922/ImPlay): This debug tool was extracted from ImPlay 48 | 49 | # License 50 | 51 | [GPLv2](LICENSE.txt). 52 | -------------------------------------------------------------------------------- /screenshot/debug.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsl0922/mpv-debug-plugin/215db5fc67ef4fb3e7b6fabc0d05e31cc72e01f5/screenshot/debug.jpg -------------------------------------------------------------------------------- /src/debug.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-2023 tsl0922. All rights reserved. 2 | // SPDX-License-Identifier: GPL-2.0-only 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // imgui extensions 13 | namespace ImGui { 14 | inline ImVec2 EmVec2(float x, float y) { return ImVec2(GetFontSize() * x, GetFontSize() * y); } 15 | inline float EmSize(float n) { return GetFontSize() * n; } 16 | } // namespace ImGui 17 | 18 | class Debug { 19 | public: 20 | Debug(mpv_handle *mpv, int logLines); 21 | ~Debug(); 22 | 23 | void draw(); 24 | void show(); 25 | void AddLog(const char *prefix, const char *level, const char *text); 26 | void update(mpv_event_property *prop); 27 | 28 | private: 29 | struct Console { 30 | Console(mpv_handle *mpv, int logLines); 31 | ~Console(); 32 | 33 | void init(const char *level, int limit); 34 | void draw(); 35 | 36 | void ClearLog(); 37 | void AddLog(const char *level, const char *fmt, ...); 38 | void ExecCommand(const char *command_line); 39 | int TextEditCallback(ImGuiInputTextCallbackData *data); 40 | void initCommands(std::vector> &commands); 41 | 42 | ImVec4 LogColor(const char *level); 43 | 44 | const std::vector builtinCommands = {"HELP", "CLEAR", "HISTORY"}; 45 | 46 | struct LogItem { 47 | char *Str; 48 | const char *Lev; 49 | }; 50 | 51 | mpv_handle *mpv; 52 | char InputBuf[256]; 53 | ImVector Items; 54 | ImVector Commands; 55 | ImVector History; 56 | int HistoryPos = -1; // -1: new line, 0..History.Size-1 browsing history. 57 | ImGuiTextFilter Filter; 58 | bool AutoScroll = true; 59 | bool ScrollToBottom = false; 60 | bool CommandInited = false; 61 | std::string LogLevel = "status"; 62 | int LogLimit = 5000; 63 | }; 64 | 65 | struct Binding { 66 | std::string section; 67 | std::string key; 68 | std::string cmd; 69 | std::string comment; 70 | int64_t priority; 71 | bool weak; 72 | }; 73 | 74 | void drawHeader(); 75 | void drawConsole(); 76 | void drawBindings(); 77 | void drawCommands(); 78 | void drawProperties(const char *title, std::vector &props); 79 | void drawPropNode(const char *name, mpv_node &node, int depth = 0); 80 | 81 | mpv_handle *mpv; 82 | bool m_open = true; 83 | Console *console = nullptr; 84 | std::unique_ptr> version; 85 | bool m_demo = false; 86 | 87 | std::vector options; 88 | std::vector properties; 89 | std::vector> commands; 90 | std::vector bindings; 91 | }; 92 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 tsl0922. All rights reserved. 2 | // SPDX-License-Identifier: GPL-2.0-only 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "debug.h" 16 | #include "main.h" 17 | 18 | std::thread thread; 19 | static Config config; 20 | static mpv_handle* mpv = nullptr; 21 | static GLFWwindow* window = nullptr; 22 | static Debug* debug = nullptr; 23 | 24 | static void glfw_error_callback(int error, const char* description) { 25 | fprintf(stderr, "GLFW Error %d: %s\n", error, description); 26 | } 27 | 28 | static const ImWchar* buildGlyphRanges() { 29 | static ImVector glyphRanges; 30 | 31 | ImFontAtlas* fonts = ImGui::GetIO().Fonts; 32 | ImFontGlyphRangesBuilder glyphRangesBuilder; 33 | 34 | glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesChineseFull()); 35 | glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesJapanese()); 36 | glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesCyrillic()); 37 | glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesKorean()); 38 | glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesThai()); 39 | glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesVietnamese()); 40 | glyphRangesBuilder.BuildRanges(&glyphRanges); 41 | 42 | return glyphRanges.Data; 43 | } 44 | 45 | static std::string mp_expand_path(const char* path) { 46 | std::string ret = path; 47 | mpv_node node{0}; 48 | const char* args[] = {"expand-path", path, NULL}; 49 | if (mpv_command_ret(mpv, args, &node) >= 0) { 50 | ret = node.u.string; 51 | mpv_free_node_contents(&node); 52 | } 53 | return ret; 54 | } 55 | 56 | static int gui_thread() { 57 | glfwSetErrorCallback(glfw_error_callback); 58 | if (!glfwInit()) return 1; 59 | 60 | #ifdef __APPLE__ 61 | const char* glsl_version = "#version 150"; 62 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 63 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); 64 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 65 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 66 | #else 67 | const char* glsl_version = "#version 130"; 68 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 69 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); 70 | #endif 71 | glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); 72 | 73 | window = glfwCreateWindow(400, 600, "Debug", nullptr, nullptr); 74 | if (window == nullptr) return 1; 75 | glfwMakeContextCurrent(window); 76 | glfwSwapInterval(1); 77 | 78 | IMGUI_CHECKVERSION(); 79 | ImGui::CreateContext(); 80 | ImGuiIO& io = ImGui::GetIO(); 81 | io.IniFilename = nullptr; 82 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; 83 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; 84 | io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; 85 | 86 | ImGui::StyleColorsDracula(); 87 | float xscale, yscale; 88 | glfwGetWindowContentScale(window, &xscale, &yscale); 89 | float scale = std::max(xscale, yscale); 90 | ImGui::GetStyle().ScaleAllSizes(scale); 91 | 92 | ImGui_ImplGlfw_InitForOpenGL(window, true); 93 | ImGui_ImplOpenGL3_Init(glsl_version); 94 | 95 | ImFontConfig font_cfg; 96 | font_cfg.SizePixels = config.fontSize * scale; 97 | if (config.fontPath.empty()) { 98 | io.Fonts->AddFontDefault(&font_cfg); 99 | } else { 100 | const ImWchar* unicodeRanges = buildGlyphRanges(); 101 | auto fontPath = mp_expand_path(config.fontPath.c_str()); 102 | io.Fonts->AddFontFromFileTTF(fontPath.c_str(), 0, &font_cfg, unicodeRanges); 103 | } 104 | 105 | ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); 106 | 107 | while (!glfwWindowShouldClose(window)) { 108 | glfwWaitEvents(); 109 | 110 | ImGui_ImplOpenGL3_NewFrame(); 111 | ImGui_ImplGlfw_NewFrame(); 112 | ImGui::NewFrame(); 113 | 114 | ImGuiViewport* vp = ImGui::GetMainViewport(); 115 | vp->Flags &= ~ImGuiViewportFlags_CanHostOtherWindows; 116 | 117 | debug->draw(); 118 | 119 | ImGui::Render(); 120 | int display_w, display_h; 121 | glfwGetFramebufferSize(window, &display_w, &display_h); 122 | glViewport(0, 0, display_w, display_h); 123 | glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, 124 | clear_color.w); 125 | glClear(GL_COLOR_BUFFER_BIT); 126 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); 127 | 128 | if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { 129 | GLFWwindow* backup_current_context = glfwGetCurrentContext(); 130 | ImGui::UpdatePlatformWindows(); 131 | ImGui::RenderPlatformWindowsDefault(); 132 | glfwMakeContextCurrent(backup_current_context); 133 | } 134 | 135 | glfwSwapBuffers(window); 136 | } 137 | 138 | ImGui_ImplOpenGL3_Shutdown(); 139 | ImGui_ImplGlfw_Shutdown(); 140 | ImGui::DestroyContext(); 141 | 142 | glfwDestroyWindow(window); 143 | glfwTerminate(); 144 | 145 | window = nullptr; 146 | 147 | return 0; 148 | } 149 | 150 | static void show_debug() { 151 | if (!window) { 152 | thread = std::thread(gui_thread); 153 | } else { 154 | debug->show(); 155 | glfwPostEmptyEvent(); 156 | } 157 | } 158 | 159 | static void handle_property_change(mpv_event* event) { 160 | mpv_event_property* prop = (mpv_event_property*)event->data; 161 | debug->update(prop); 162 | glfwPostEmptyEvent(); 163 | } 164 | 165 | static void handle_client_message(mpv_event* event) { 166 | mpv_event_client_message* msg = (mpv_event_client_message*)event->data; 167 | if (msg->num_args < 1) return; 168 | 169 | const char* cmd = msg->args[0]; 170 | if (strcmp(cmd, "show") == 0) show_debug(); 171 | } 172 | 173 | static void handle_log_message(mpv_event* event) { 174 | mpv_event_log_message* msg = (mpv_event_log_message*)event->data; 175 | 176 | debug->AddLog(msg->prefix, msg->level, msg->text); 177 | if (window) glfwPostEmptyEvent(); 178 | } 179 | 180 | static void load_config() { 181 | auto conf = fmt::format("~~/script-opts/{}.conf", mpv_client_name(mpv)); 182 | std::ifstream file(mp_expand_path(conf.c_str())); 183 | inipp::Ini ini; 184 | ini.parse(file); 185 | 186 | inipp::get_value(ini.sections[""], "font-path", config.fontPath); 187 | inipp::get_value(ini.sections[""], "font-size", config.fontSize); 188 | inipp::get_value(ini.sections[""], "log-lines", config.logLines); 189 | } 190 | 191 | int mpv_open_cplugin(mpv_handle* handle) { 192 | mpv = handle; 193 | 194 | load_config(); 195 | 196 | debug = new Debug(mpv, config.logLines); 197 | 198 | while (mpv) { 199 | mpv_event* event = mpv_wait_event(mpv, -1); 200 | if (event->event_id == MPV_EVENT_SHUTDOWN) break; 201 | 202 | switch (event->event_id) { 203 | case MPV_EVENT_PROPERTY_CHANGE: 204 | handle_property_change(event); 205 | break; 206 | case MPV_EVENT_CLIENT_MESSAGE: 207 | handle_client_message(event); 208 | break; 209 | case MPV_EVENT_LOG_MESSAGE: 210 | handle_log_message(event); 211 | break; 212 | default: 213 | break; 214 | } 215 | } 216 | 217 | mpv_unobserve_property(mpv, 0); 218 | 219 | if (window) { 220 | glfwSetWindowShouldClose(window, GLFW_TRUE); 221 | glfwPostEmptyEvent(); 222 | } 223 | if (thread.joinable()) thread.join(); 224 | 225 | delete debug; 226 | 227 | return 0; 228 | } 229 | -------------------------------------------------------------------------------- /src/main.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 tsl0922. All rights reserved. 2 | // SPDX-License-Identifier: GPL-2.0-only 3 | 4 | #pragma once 5 | #include 6 | #include 7 | 8 | #ifndef MPV_EXPORT 9 | #ifdef _WIN32 10 | #define MPV_EXPORT __declspec(dllexport) 11 | #elif defined(__GNUC__) || defined(__clang__) 12 | #define MPV_EXPORT __attribute__((visibility("default"))) 13 | #else 14 | #define MPV_EXPORT 15 | #endif 16 | #endif 17 | 18 | namespace ImGui { 19 | void StyleColorsDracula(ImGuiStyle* dst = nullptr) { 20 | ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); 21 | ImVec4* colors = style->Colors; 22 | 23 | colors[ImGuiCol_WindowBg] = ImVec4{0.1f, 0.1f, 0.13f, 1.0f}; 24 | colors[ImGuiCol_MenuBarBg] = ImVec4{0.16f, 0.16f, 0.21f, 1.0f}; 25 | colors[ImGuiCol_Border] = ImVec4{0.44f, 0.37f, 0.61f, 0.29f}; 26 | colors[ImGuiCol_BorderShadow] = ImVec4{0.0f, 0.0f, 0.0f, 0.24f}; 27 | colors[ImGuiCol_Text] = ImVec4{1.0f, 1.0f, 1.0f, 1.0f}; 28 | colors[ImGuiCol_TextDisabled] = ImVec4{0.5f, 0.5f, 0.5f, 1.0f}; 29 | colors[ImGuiCol_Header] = ImVec4{0.13f, 0.13f, 0.17, 1.0f}; 30 | colors[ImGuiCol_HeaderHovered] = ImVec4{0.19f, 0.2f, 0.25f, 1.0f}; 31 | colors[ImGuiCol_HeaderActive] = ImVec4{0.16f, 0.16f, 0.21f, 1.0f}; 32 | colors[ImGuiCol_Button] = ImVec4{0.13f, 0.13f, 0.17, 1.0f}; 33 | colors[ImGuiCol_ButtonHovered] = ImVec4{0.19f, 0.2f, 0.25f, 1.0f}; 34 | colors[ImGuiCol_ButtonActive] = ImVec4{0.16f, 0.16f, 0.21f, 1.0f}; 35 | colors[ImGuiCol_CheckMark] = ImVec4{0.74f, 0.58f, 0.98f, 1.0f}; 36 | colors[ImGuiCol_PopupBg] = ImVec4{0.1f, 0.1f, 0.13f, 0.92f}; 37 | colors[ImGuiCol_SliderGrab] = ImVec4{0.44f, 0.37f, 0.61f, 0.54f}; 38 | colors[ImGuiCol_SliderGrabActive] = ImVec4{0.74f, 0.58f, 0.98f, 0.54f}; 39 | colors[ImGuiCol_FrameBg] = ImVec4{0.13f, 0.13, 0.17, 1.0f}; 40 | colors[ImGuiCol_FrameBgHovered] = ImVec4{0.19f, 0.2f, 0.25f, 1.0f}; 41 | colors[ImGuiCol_FrameBgActive] = ImVec4{0.16f, 0.16f, 0.21f, 1.0f}; 42 | colors[ImGuiCol_Tab] = ImVec4{0.16f, 0.16f, 0.21f, 1.0f}; 43 | colors[ImGuiCol_TabHovered] = ImVec4{0.24, 0.24f, 0.32f, 1.0f}; 44 | colors[ImGuiCol_TabActive] = ImVec4{0.2f, 0.22f, 0.27f, 1.0f}; 45 | colors[ImGuiCol_TabUnfocused] = ImVec4{0.16f, 0.16f, 0.21f, 1.0f}; 46 | colors[ImGuiCol_TabUnfocusedActive] = ImVec4{0.16f, 0.16f, 0.21f, 1.0f}; 47 | colors[ImGuiCol_TitleBg] = ImVec4{0.16f, 0.16f, 0.21f, 1.0f}; 48 | colors[ImGuiCol_TitleBgActive] = ImVec4{0.16f, 0.16f, 0.21f, 1.0f}; 49 | colors[ImGuiCol_TitleBgCollapsed] = ImVec4{0.16f, 0.16f, 0.21f, 1.0f}; 50 | colors[ImGuiCol_ScrollbarBg] = ImVec4{0.1f, 0.1f, 0.13f, 1.0f}; 51 | colors[ImGuiCol_ScrollbarGrab] = ImVec4{0.16f, 0.16f, 0.21f, 1.0f}; 52 | colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4{0.19f, 0.2f, 0.25f, 1.0f}; 53 | colors[ImGuiCol_ScrollbarGrabActive] = ImVec4{0.24f, 0.24f, 0.32f, 1.0f}; 54 | colors[ImGuiCol_Separator] = ImVec4{0.44f, 0.37f, 0.61f, 1.0f}; 55 | colors[ImGuiCol_SeparatorHovered] = ImVec4{0.74f, 0.58f, 0.98f, 1.0f}; 56 | colors[ImGuiCol_SeparatorActive] = ImVec4{0.84f, 0.58f, 1.0f, 1.0f}; 57 | colors[ImGuiCol_ResizeGrip] = ImVec4{0.44f, 0.37f, 0.61f, 0.29f}; 58 | colors[ImGuiCol_ResizeGripHovered] = ImVec4{0.74f, 0.58f, 0.98f, 0.29f}; 59 | colors[ImGuiCol_ResizeGripActive] = ImVec4{0.84f, 0.58f, 1.0f, 0.29f}; 60 | #ifdef IMGUI_HAS_DOCK 61 | colors[ImGuiCol_DockingPreview] = ImVec4{0.44f, 0.37f, 0.61f, 1.0f}; 62 | #endif 63 | } 64 | } // namespace ImGui 65 | 66 | typedef struct { 67 | std::string fontPath; 68 | int fontSize = 13; 69 | int logLines = 5000; 70 | } Config; 71 | 72 | extern "C" MPV_EXPORT int mpv_open_cplugin(mpv_handle* handle); 73 | -------------------------------------------------------------------------------- /third_party/fmt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(fmt) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | add_library(fmt OBJECT src/format.cc src/os.cc) 7 | set_property(TARGET fmt PROPERTY POSITION_INDEPENDENT_CODE ON) 8 | 9 | target_include_directories(fmt PUBLIC include) 10 | -------------------------------------------------------------------------------- /third_party/fmt/include/fmt/args.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - dynamic argument lists 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_ARGS_H_ 9 | #define FMT_ARGS_H_ 10 | 11 | #include // std::reference_wrapper 12 | #include // std::unique_ptr 13 | #include 14 | 15 | #include "core.h" 16 | 17 | FMT_BEGIN_NAMESPACE 18 | 19 | namespace detail { 20 | 21 | template struct is_reference_wrapper : std::false_type {}; 22 | template 23 | struct is_reference_wrapper> : std::true_type {}; 24 | 25 | template const T& unwrap(const T& v) { return v; } 26 | template const T& unwrap(const std::reference_wrapper& v) { 27 | return static_cast(v); 28 | } 29 | 30 | class dynamic_arg_list { 31 | // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for 32 | // templates it doesn't complain about inability to deduce single translation 33 | // unit for placing vtable. So storage_node_base is made a fake template. 34 | template struct node { 35 | virtual ~node() = default; 36 | std::unique_ptr> next; 37 | }; 38 | 39 | template struct typed_node : node<> { 40 | T value; 41 | 42 | template 43 | FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} 44 | 45 | template 46 | FMT_CONSTEXPR typed_node(const basic_string_view& arg) 47 | : value(arg.data(), arg.size()) {} 48 | }; 49 | 50 | std::unique_ptr> head_; 51 | 52 | public: 53 | template const T& push(const Arg& arg) { 54 | auto new_node = std::unique_ptr>(new typed_node(arg)); 55 | auto& value = new_node->value; 56 | new_node->next = std::move(head_); 57 | head_ = std::move(new_node); 58 | return value; 59 | } 60 | }; 61 | } // namespace detail 62 | 63 | /** 64 | \rst 65 | A dynamic version of `fmt::format_arg_store`. 66 | It's equipped with a storage to potentially temporary objects which lifetimes 67 | could be shorter than the format arguments object. 68 | 69 | It can be implicitly converted into `~fmt::basic_format_args` for passing 70 | into type-erased formatting functions such as `~fmt::vformat`. 71 | \endrst 72 | */ 73 | template 74 | class dynamic_format_arg_store 75 | #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 76 | // Workaround a GCC template argument substitution bug. 77 | : public basic_format_args 78 | #endif 79 | { 80 | private: 81 | using char_type = typename Context::char_type; 82 | 83 | template struct need_copy { 84 | static constexpr detail::type mapped_type = 85 | detail::mapped_type_constant::value; 86 | 87 | enum { 88 | value = !(detail::is_reference_wrapper::value || 89 | std::is_same>::value || 90 | std::is_same>::value || 91 | (mapped_type != detail::type::cstring_type && 92 | mapped_type != detail::type::string_type && 93 | mapped_type != detail::type::custom_type)) 94 | }; 95 | }; 96 | 97 | template 98 | using stored_type = conditional_t< 99 | std::is_convertible>::value && 100 | !detail::is_reference_wrapper::value, 101 | std::basic_string, T>; 102 | 103 | // Storage of basic_format_arg must be contiguous. 104 | std::vector> data_; 105 | std::vector> named_info_; 106 | 107 | // Storage of arguments not fitting into basic_format_arg must grow 108 | // without relocation because items in data_ refer to it. 109 | detail::dynamic_arg_list dynamic_args_; 110 | 111 | friend class basic_format_args; 112 | 113 | unsigned long long get_types() const { 114 | return detail::is_unpacked_bit | data_.size() | 115 | (named_info_.empty() 116 | ? 0ULL 117 | : static_cast(detail::has_named_args_bit)); 118 | } 119 | 120 | const basic_format_arg* data() const { 121 | return named_info_.empty() ? data_.data() : data_.data() + 1; 122 | } 123 | 124 | template void emplace_arg(const T& arg) { 125 | data_.emplace_back(detail::make_arg(arg)); 126 | } 127 | 128 | template 129 | void emplace_arg(const detail::named_arg& arg) { 130 | if (named_info_.empty()) { 131 | constexpr const detail::named_arg_info* zero_ptr{nullptr}; 132 | data_.insert(data_.begin(), {zero_ptr, 0}); 133 | } 134 | data_.emplace_back(detail::make_arg(detail::unwrap(arg.value))); 135 | auto pop_one = [](std::vector>* data) { 136 | data->pop_back(); 137 | }; 138 | std::unique_ptr>, decltype(pop_one)> 139 | guard{&data_, pop_one}; 140 | named_info_.push_back({arg.name, static_cast(data_.size() - 2u)}); 141 | data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; 142 | guard.release(); 143 | } 144 | 145 | public: 146 | constexpr dynamic_format_arg_store() = default; 147 | 148 | /** 149 | \rst 150 | Adds an argument into the dynamic store for later passing to a formatting 151 | function. 152 | 153 | Note that custom types and string types (but not string views) are copied 154 | into the store dynamically allocating memory if necessary. 155 | 156 | **Example**:: 157 | 158 | fmt::dynamic_format_arg_store store; 159 | store.push_back(42); 160 | store.push_back("abc"); 161 | store.push_back(1.5f); 162 | std::string result = fmt::vformat("{} and {} and {}", store); 163 | \endrst 164 | */ 165 | template void push_back(const T& arg) { 166 | if (detail::const_check(need_copy::value)) 167 | emplace_arg(dynamic_args_.push>(arg)); 168 | else 169 | emplace_arg(detail::unwrap(arg)); 170 | } 171 | 172 | /** 173 | \rst 174 | Adds a reference to the argument into the dynamic store for later passing to 175 | a formatting function. 176 | 177 | **Example**:: 178 | 179 | fmt::dynamic_format_arg_store store; 180 | char band[] = "Rolling Stones"; 181 | store.push_back(std::cref(band)); 182 | band[9] = 'c'; // Changing str affects the output. 183 | std::string result = fmt::vformat("{}", store); 184 | // result == "Rolling Scones" 185 | \endrst 186 | */ 187 | template void push_back(std::reference_wrapper arg) { 188 | static_assert( 189 | need_copy::value, 190 | "objects of built-in types and string views are always copied"); 191 | emplace_arg(arg.get()); 192 | } 193 | 194 | /** 195 | Adds named argument into the dynamic store for later passing to a formatting 196 | function. ``std::reference_wrapper`` is supported to avoid copying of the 197 | argument. The name is always copied into the store. 198 | */ 199 | template 200 | void push_back(const detail::named_arg& arg) { 201 | const char_type* arg_name = 202 | dynamic_args_.push>(arg.name).c_str(); 203 | if (detail::const_check(need_copy::value)) { 204 | emplace_arg( 205 | fmt::arg(arg_name, dynamic_args_.push>(arg.value))); 206 | } else { 207 | emplace_arg(fmt::arg(arg_name, arg.value)); 208 | } 209 | } 210 | 211 | /** Erase all elements from the store */ 212 | void clear() { 213 | data_.clear(); 214 | named_info_.clear(); 215 | dynamic_args_ = detail::dynamic_arg_list(); 216 | } 217 | 218 | /** 219 | \rst 220 | Reserves space to store at least *new_cap* arguments including 221 | *new_cap_named* named arguments. 222 | \endrst 223 | */ 224 | void reserve(size_t new_cap, size_t new_cap_named) { 225 | FMT_ASSERT(new_cap >= new_cap_named, 226 | "Set of arguments includes set of named arguments"); 227 | data_.reserve(new_cap); 228 | named_info_.reserve(new_cap_named); 229 | } 230 | }; 231 | 232 | FMT_END_NAMESPACE 233 | 234 | #endif // FMT_ARGS_H_ 235 | -------------------------------------------------------------------------------- /third_party/fmt/include/fmt/compile.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - experimental format string compilation 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich and fmt contributors 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_COMPILE_H_ 9 | #define FMT_COMPILE_H_ 10 | 11 | #include "format.h" 12 | 13 | FMT_BEGIN_NAMESPACE 14 | namespace detail { 15 | 16 | template 17 | FMT_CONSTEXPR inline counting_iterator copy_str(InputIt begin, InputIt end, 18 | counting_iterator it) { 19 | return it + (end - begin); 20 | } 21 | 22 | // A compile-time string which is compiled into fast formatting code. 23 | class compiled_string {}; 24 | 25 | template 26 | struct is_compiled_string : std::is_base_of {}; 27 | 28 | /** 29 | \rst 30 | Converts a string literal *s* into a format string that will be parsed at 31 | compile time and converted into efficient formatting code. Requires C++17 32 | ``constexpr if`` compiler support. 33 | 34 | **Example**:: 35 | 36 | // Converts 42 into std::string using the most efficient method and no 37 | // runtime format string processing. 38 | std::string s = fmt::format(FMT_COMPILE("{}"), 42); 39 | \endrst 40 | */ 41 | #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) 42 | # define FMT_COMPILE(s) \ 43 | FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit) 44 | #else 45 | # define FMT_COMPILE(s) FMT_STRING(s) 46 | #endif 47 | 48 | #if FMT_USE_NONTYPE_TEMPLATE_ARGS 49 | template Str> 51 | struct udl_compiled_string : compiled_string { 52 | using char_type = Char; 53 | explicit constexpr operator basic_string_view() const { 54 | return {Str.data, N - 1}; 55 | } 56 | }; 57 | #endif 58 | 59 | template 60 | const T& first(const T& value, const Tail&...) { 61 | return value; 62 | } 63 | 64 | #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) 65 | template struct type_list {}; 66 | 67 | // Returns a reference to the argument at index N from [first, rest...]. 68 | template 69 | constexpr const auto& get([[maybe_unused]] const T& first, 70 | [[maybe_unused]] const Args&... rest) { 71 | static_assert(N < 1 + sizeof...(Args), "index is out of bounds"); 72 | if constexpr (N == 0) 73 | return first; 74 | else 75 | return detail::get(rest...); 76 | } 77 | 78 | template 79 | constexpr int get_arg_index_by_name(basic_string_view name, 80 | type_list) { 81 | return get_arg_index_by_name(name); 82 | } 83 | 84 | template struct get_type_impl; 85 | 86 | template struct get_type_impl> { 87 | using type = 88 | remove_cvref_t(std::declval()...))>; 89 | }; 90 | 91 | template 92 | using get_type = typename get_type_impl::type; 93 | 94 | template struct is_compiled_format : std::false_type {}; 95 | 96 | template struct text { 97 | basic_string_view data; 98 | using char_type = Char; 99 | 100 | template 101 | constexpr OutputIt format(OutputIt out, const Args&...) const { 102 | return write(out, data); 103 | } 104 | }; 105 | 106 | template 107 | struct is_compiled_format> : std::true_type {}; 108 | 109 | template 110 | constexpr text make_text(basic_string_view s, size_t pos, 111 | size_t size) { 112 | return {{&s[pos], size}}; 113 | } 114 | 115 | template struct code_unit { 116 | Char value; 117 | using char_type = Char; 118 | 119 | template 120 | constexpr OutputIt format(OutputIt out, const Args&...) const { 121 | *out++ = value; 122 | return out; 123 | } 124 | }; 125 | 126 | // This ensures that the argument type is convertible to `const T&`. 127 | template 128 | constexpr const T& get_arg_checked(const Args&... args) { 129 | const auto& arg = detail::get(args...); 130 | if constexpr (detail::is_named_arg>()) { 131 | return arg.value; 132 | } else { 133 | return arg; 134 | } 135 | } 136 | 137 | template 138 | struct is_compiled_format> : std::true_type {}; 139 | 140 | // A replacement field that refers to argument N. 141 | template struct field { 142 | using char_type = Char; 143 | 144 | template 145 | constexpr OutputIt format(OutputIt out, const Args&... args) const { 146 | const T& arg = get_arg_checked(args...); 147 | if constexpr (std::is_convertible_v>) { 148 | auto s = basic_string_view(arg); 149 | return copy_str(s.begin(), s.end(), out); 150 | } 151 | return write(out, arg); 152 | } 153 | }; 154 | 155 | template 156 | struct is_compiled_format> : std::true_type {}; 157 | 158 | // A replacement field that refers to argument with name. 159 | template struct runtime_named_field { 160 | using char_type = Char; 161 | basic_string_view name; 162 | 163 | template 164 | constexpr static bool try_format_argument( 165 | OutputIt& out, 166 | // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9 167 | [[maybe_unused]] basic_string_view arg_name, const T& arg) { 168 | if constexpr (is_named_arg::type>::value) { 169 | if (arg_name == arg.name) { 170 | out = write(out, arg.value); 171 | return true; 172 | } 173 | } 174 | return false; 175 | } 176 | 177 | template 178 | constexpr OutputIt format(OutputIt out, const Args&... args) const { 179 | bool found = (try_format_argument(out, name, args) || ...); 180 | if (!found) { 181 | FMT_THROW(format_error("argument with specified name is not found")); 182 | } 183 | return out; 184 | } 185 | }; 186 | 187 | template 188 | struct is_compiled_format> : std::true_type {}; 189 | 190 | // A replacement field that refers to argument N and has format specifiers. 191 | template struct spec_field { 192 | using char_type = Char; 193 | formatter fmt; 194 | 195 | template 196 | constexpr FMT_INLINE OutputIt format(OutputIt out, 197 | const Args&... args) const { 198 | const auto& vargs = 199 | fmt::make_format_args>(args...); 200 | basic_format_context ctx(out, vargs); 201 | return fmt.format(get_arg_checked(args...), ctx); 202 | } 203 | }; 204 | 205 | template 206 | struct is_compiled_format> : std::true_type {}; 207 | 208 | template struct concat { 209 | L lhs; 210 | R rhs; 211 | using char_type = typename L::char_type; 212 | 213 | template 214 | constexpr OutputIt format(OutputIt out, const Args&... args) const { 215 | out = lhs.format(out, args...); 216 | return rhs.format(out, args...); 217 | } 218 | }; 219 | 220 | template 221 | struct is_compiled_format> : std::true_type {}; 222 | 223 | template 224 | constexpr concat make_concat(L lhs, R rhs) { 225 | return {lhs, rhs}; 226 | } 227 | 228 | struct unknown_format {}; 229 | 230 | template 231 | constexpr size_t parse_text(basic_string_view str, size_t pos) { 232 | for (size_t size = str.size(); pos != size; ++pos) { 233 | if (str[pos] == '{' || str[pos] == '}') break; 234 | } 235 | return pos; 236 | } 237 | 238 | template 239 | constexpr auto compile_format_string(S format_str); 240 | 241 | template 242 | constexpr auto parse_tail(T head, S format_str) { 243 | if constexpr (POS != 244 | basic_string_view(format_str).size()) { 245 | constexpr auto tail = compile_format_string(format_str); 246 | if constexpr (std::is_same, 247 | unknown_format>()) 248 | return tail; 249 | else 250 | return make_concat(head, tail); 251 | } else { 252 | return head; 253 | } 254 | } 255 | 256 | template struct parse_specs_result { 257 | formatter fmt; 258 | size_t end; 259 | int next_arg_id; 260 | }; 261 | 262 | enum { manual_indexing_id = -1 }; 263 | 264 | template 265 | constexpr parse_specs_result parse_specs(basic_string_view str, 266 | size_t pos, int next_arg_id) { 267 | str.remove_prefix(pos); 268 | auto ctx = 269 | compile_parse_context(str, max_value(), nullptr, next_arg_id); 270 | auto f = formatter(); 271 | auto end = f.parse(ctx); 272 | return {f, pos + fmt::detail::to_unsigned(end - str.data()), 273 | next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()}; 274 | } 275 | 276 | template struct arg_id_handler { 277 | arg_ref arg_id; 278 | 279 | constexpr int on_auto() { 280 | FMT_ASSERT(false, "handler cannot be used with automatic indexing"); 281 | return 0; 282 | } 283 | constexpr int on_index(int id) { 284 | arg_id = arg_ref(id); 285 | return 0; 286 | } 287 | constexpr int on_name(basic_string_view id) { 288 | arg_id = arg_ref(id); 289 | return 0; 290 | } 291 | }; 292 | 293 | template struct parse_arg_id_result { 294 | arg_ref arg_id; 295 | const Char* arg_id_end; 296 | }; 297 | 298 | template 299 | constexpr auto parse_arg_id(const Char* begin, const Char* end) { 300 | auto handler = arg_id_handler{arg_ref{}}; 301 | auto arg_id_end = parse_arg_id(begin, end, handler); 302 | return parse_arg_id_result{handler.arg_id, arg_id_end}; 303 | } 304 | 305 | template struct field_type { 306 | using type = remove_cvref_t; 307 | }; 308 | 309 | template 310 | struct field_type::value>> { 311 | using type = remove_cvref_t; 312 | }; 313 | 314 | template 316 | constexpr auto parse_replacement_field_then_tail(S format_str) { 317 | using char_type = typename S::char_type; 318 | constexpr auto str = basic_string_view(format_str); 319 | constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); 320 | if constexpr (c == '}') { 321 | return parse_tail( 322 | field::type, ARG_INDEX>(), 323 | format_str); 324 | } else if constexpr (c != ':') { 325 | FMT_THROW(format_error("expected ':'")); 326 | } else { 327 | constexpr auto result = parse_specs::type>( 328 | str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID); 329 | if constexpr (result.end >= str.size() || str[result.end] != '}') { 330 | FMT_THROW(format_error("expected '}'")); 331 | return 0; 332 | } else { 333 | return parse_tail( 334 | spec_field::type, ARG_INDEX>{ 335 | result.fmt}, 336 | format_str); 337 | } 338 | } 339 | } 340 | 341 | // Compiles a non-empty format string and returns the compiled representation 342 | // or unknown_format() on unrecognized input. 343 | template 344 | constexpr auto compile_format_string(S format_str) { 345 | using char_type = typename S::char_type; 346 | constexpr auto str = basic_string_view(format_str); 347 | if constexpr (str[POS] == '{') { 348 | if constexpr (POS + 1 == str.size()) 349 | FMT_THROW(format_error("unmatched '{' in format string")); 350 | if constexpr (str[POS + 1] == '{') { 351 | return parse_tail(make_text(str, POS, 1), format_str); 352 | } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { 353 | static_assert(ID != manual_indexing_id, 354 | "cannot switch from manual to automatic argument indexing"); 355 | constexpr auto next_id = 356 | ID != manual_indexing_id ? ID + 1 : manual_indexing_id; 357 | return parse_replacement_field_then_tail, Args, 358 | POS + 1, ID, next_id>( 359 | format_str); 360 | } else { 361 | constexpr auto arg_id_result = 362 | parse_arg_id(str.data() + POS + 1, str.data() + str.size()); 363 | constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data(); 364 | constexpr char_type c = 365 | arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type(); 366 | static_assert(c == '}' || c == ':', "missing '}' in format string"); 367 | if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) { 368 | static_assert( 369 | ID == manual_indexing_id || ID == 0, 370 | "cannot switch from automatic to manual argument indexing"); 371 | constexpr auto arg_index = arg_id_result.arg_id.val.index; 372 | return parse_replacement_field_then_tail, 373 | Args, arg_id_end_pos, 374 | arg_index, manual_indexing_id>( 375 | format_str); 376 | } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) { 377 | constexpr auto arg_index = 378 | get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{}); 379 | if constexpr (arg_index >= 0) { 380 | constexpr auto next_id = 381 | ID != manual_indexing_id ? ID + 1 : manual_indexing_id; 382 | return parse_replacement_field_then_tail< 383 | decltype(get_type::value), Args, arg_id_end_pos, 384 | arg_index, next_id>(format_str); 385 | } else if constexpr (c == '}') { 386 | return parse_tail( 387 | runtime_named_field{arg_id_result.arg_id.val.name}, 388 | format_str); 389 | } else if constexpr (c == ':') { 390 | return unknown_format(); // no type info for specs parsing 391 | } 392 | } 393 | } 394 | } else if constexpr (str[POS] == '}') { 395 | if constexpr (POS + 1 == str.size()) 396 | FMT_THROW(format_error("unmatched '}' in format string")); 397 | return parse_tail(make_text(str, POS, 1), format_str); 398 | } else { 399 | constexpr auto end = parse_text(str, POS + 1); 400 | if constexpr (end - POS > 1) { 401 | return parse_tail(make_text(str, POS, end - POS), 402 | format_str); 403 | } else { 404 | return parse_tail(code_unit{str[POS]}, 405 | format_str); 406 | } 407 | } 408 | } 409 | 410 | template ::value)> 412 | constexpr auto compile(S format_str) { 413 | constexpr auto str = basic_string_view(format_str); 414 | if constexpr (str.size() == 0) { 415 | return detail::make_text(str, 0, 0); 416 | } else { 417 | constexpr auto result = 418 | detail::compile_format_string, 0, 0>( 419 | format_str); 420 | return result; 421 | } 422 | } 423 | #endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) 424 | } // namespace detail 425 | 426 | FMT_BEGIN_EXPORT 427 | 428 | #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) 429 | 430 | template ::value)> 433 | FMT_INLINE std::basic_string format(const CompiledFormat& cf, 434 | const Args&... args) { 435 | auto s = std::basic_string(); 436 | cf.format(std::back_inserter(s), args...); 437 | return s; 438 | } 439 | 440 | template ::value)> 442 | constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf, 443 | const Args&... args) { 444 | return cf.format(out, args...); 445 | } 446 | 447 | template ::value)> 449 | FMT_INLINE std::basic_string format(const S&, 450 | Args&&... args) { 451 | if constexpr (std::is_same::value) { 452 | constexpr auto str = basic_string_view(S()); 453 | if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { 454 | const auto& first = detail::first(args...); 455 | if constexpr (detail::is_named_arg< 456 | remove_cvref_t>::value) { 457 | return fmt::to_string(first.value); 458 | } else { 459 | return fmt::to_string(first); 460 | } 461 | } 462 | } 463 | constexpr auto compiled = detail::compile(S()); 464 | if constexpr (std::is_same, 465 | detail::unknown_format>()) { 466 | return fmt::format( 467 | static_cast>(S()), 468 | std::forward(args)...); 469 | } else { 470 | return fmt::format(compiled, std::forward(args)...); 471 | } 472 | } 473 | 474 | template ::value)> 476 | FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) { 477 | constexpr auto compiled = detail::compile(S()); 478 | if constexpr (std::is_same, 479 | detail::unknown_format>()) { 480 | return fmt::format_to( 481 | out, static_cast>(S()), 482 | std::forward(args)...); 483 | } else { 484 | return fmt::format_to(out, compiled, std::forward(args)...); 485 | } 486 | } 487 | #endif 488 | 489 | template ::value)> 491 | format_to_n_result format_to_n(OutputIt out, size_t n, 492 | const S& format_str, Args&&... args) { 493 | using traits = detail::fixed_buffer_traits; 494 | auto buf = detail::iterator_buffer(out, n); 495 | format_to(std::back_inserter(buf), format_str, std::forward(args)...); 496 | return {buf.out(), buf.count()}; 497 | } 498 | 499 | template ::value)> 501 | FMT_CONSTEXPR20 size_t formatted_size(const S& format_str, 502 | const Args&... args) { 503 | return fmt::format_to(detail::counting_iterator(), format_str, args...) 504 | .count(); 505 | } 506 | 507 | template ::value)> 509 | void print(std::FILE* f, const S& format_str, const Args&... args) { 510 | memory_buffer buffer; 511 | fmt::format_to(std::back_inserter(buffer), format_str, args...); 512 | detail::print(f, {buffer.data(), buffer.size()}); 513 | } 514 | 515 | template ::value)> 517 | void print(const S& format_str, const Args&... args) { 518 | print(stdout, format_str, args...); 519 | } 520 | 521 | #if FMT_USE_NONTYPE_TEMPLATE_ARGS 522 | inline namespace literals { 523 | template constexpr auto operator""_cf() { 524 | using char_t = remove_cvref_t; 525 | return detail::udl_compiled_string(); 527 | } 528 | } // namespace literals 529 | #endif 530 | 531 | FMT_END_EXPORT 532 | FMT_END_NAMESPACE 533 | 534 | #endif // FMT_COMPILE_H_ 535 | -------------------------------------------------------------------------------- /third_party/fmt/include/fmt/os.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - optional OS-specific functionality 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_OS_H_ 9 | #define FMT_OS_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include // std::system_error 15 | 16 | #if defined __APPLE__ || defined(__FreeBSD__) 17 | # include // for LC_NUMERIC_MASK on OS X 18 | #endif 19 | 20 | #include "format.h" 21 | 22 | #ifndef FMT_USE_FCNTL 23 | // UWP doesn't provide _pipe. 24 | # if FMT_HAS_INCLUDE("winapifamily.h") 25 | # include 26 | # endif 27 | # if (FMT_HAS_INCLUDE() || defined(__APPLE__) || \ 28 | defined(__linux__)) && \ 29 | (!defined(WINAPI_FAMILY) || \ 30 | (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) 31 | # include // for O_RDONLY 32 | # define FMT_USE_FCNTL 1 33 | # else 34 | # define FMT_USE_FCNTL 0 35 | # endif 36 | #endif 37 | 38 | #ifndef FMT_POSIX 39 | # if defined(_WIN32) && !defined(__MINGW32__) 40 | // Fix warnings about deprecated symbols. 41 | # define FMT_POSIX(call) _##call 42 | # else 43 | # define FMT_POSIX(call) call 44 | # endif 45 | #endif 46 | 47 | // Calls to system functions are wrapped in FMT_SYSTEM for testability. 48 | #ifdef FMT_SYSTEM 49 | # define FMT_POSIX_CALL(call) FMT_SYSTEM(call) 50 | #else 51 | # define FMT_SYSTEM(call) ::call 52 | # ifdef _WIN32 53 | // Fix warnings about deprecated symbols. 54 | # define FMT_POSIX_CALL(call) ::_##call 55 | # else 56 | # define FMT_POSIX_CALL(call) ::call 57 | # endif 58 | #endif 59 | 60 | // Retries the expression while it evaluates to error_result and errno 61 | // equals to EINTR. 62 | #ifndef _WIN32 63 | # define FMT_RETRY_VAL(result, expression, error_result) \ 64 | do { \ 65 | (result) = (expression); \ 66 | } while ((result) == (error_result) && errno == EINTR) 67 | #else 68 | # define FMT_RETRY_VAL(result, expression, error_result) result = (expression) 69 | #endif 70 | 71 | #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) 72 | 73 | FMT_BEGIN_NAMESPACE 74 | FMT_BEGIN_EXPORT 75 | 76 | /** 77 | \rst 78 | A reference to a null-terminated string. It can be constructed from a C 79 | string or ``std::string``. 80 | 81 | You can use one of the following type aliases for common character types: 82 | 83 | +---------------+-----------------------------+ 84 | | Type | Definition | 85 | +===============+=============================+ 86 | | cstring_view | basic_cstring_view | 87 | +---------------+-----------------------------+ 88 | | wcstring_view | basic_cstring_view | 89 | +---------------+-----------------------------+ 90 | 91 | This class is most useful as a parameter type to allow passing 92 | different types of strings to a function, for example:: 93 | 94 | template 95 | std::string format(cstring_view format_str, const Args & ... args); 96 | 97 | format("{}", 42); 98 | format(std::string("{}"), 42); 99 | \endrst 100 | */ 101 | template class basic_cstring_view { 102 | private: 103 | const Char* data_; 104 | 105 | public: 106 | /** Constructs a string reference object from a C string. */ 107 | basic_cstring_view(const Char* s) : data_(s) {} 108 | 109 | /** 110 | \rst 111 | Constructs a string reference from an ``std::string`` object. 112 | \endrst 113 | */ 114 | basic_cstring_view(const std::basic_string& s) : data_(s.c_str()) {} 115 | 116 | /** Returns the pointer to a C string. */ 117 | const Char* c_str() const { return data_; } 118 | }; 119 | 120 | using cstring_view = basic_cstring_view; 121 | using wcstring_view = basic_cstring_view; 122 | 123 | #ifdef _WIN32 124 | FMT_API const std::error_category& system_category() noexcept; 125 | 126 | namespace detail { 127 | FMT_API void format_windows_error(buffer& out, int error_code, 128 | const char* message) noexcept; 129 | } 130 | 131 | FMT_API std::system_error vwindows_error(int error_code, string_view format_str, 132 | format_args args); 133 | 134 | /** 135 | \rst 136 | Constructs a :class:`std::system_error` object with the description 137 | of the form 138 | 139 | .. parsed-literal:: 140 | **: ** 141 | 142 | where ** is the formatted message and ** is the 143 | system message corresponding to the error code. 144 | *error_code* is a Windows error code as given by ``GetLastError``. 145 | If *error_code* is not a valid error code such as -1, the system message 146 | will look like "error -1". 147 | 148 | **Example**:: 149 | 150 | // This throws a system_error with the description 151 | // cannot open file 'madeup': The system cannot find the file specified. 152 | // or similar (system message may vary). 153 | const char *filename = "madeup"; 154 | LPOFSTRUCT of = LPOFSTRUCT(); 155 | HFILE file = OpenFile(filename, &of, OF_READ); 156 | if (file == HFILE_ERROR) { 157 | throw fmt::windows_error(GetLastError(), 158 | "cannot open file '{}'", filename); 159 | } 160 | \endrst 161 | */ 162 | template 163 | std::system_error windows_error(int error_code, string_view message, 164 | const Args&... args) { 165 | return vwindows_error(error_code, message, fmt::make_format_args(args...)); 166 | } 167 | 168 | // Reports a Windows error without throwing an exception. 169 | // Can be used to report errors from destructors. 170 | FMT_API void report_windows_error(int error_code, const char* message) noexcept; 171 | #else 172 | inline const std::error_category& system_category() noexcept { 173 | return std::system_category(); 174 | } 175 | #endif // _WIN32 176 | 177 | // std::system is not available on some platforms such as iOS (#2248). 178 | #ifdef __OSX__ 179 | template > 180 | void say(const S& format_str, Args&&... args) { 181 | std::system(format("say \"{}\"", format(format_str, args...)).c_str()); 182 | } 183 | #endif 184 | 185 | // A buffered file. 186 | class buffered_file { 187 | private: 188 | FILE* file_; 189 | 190 | friend class file; 191 | 192 | explicit buffered_file(FILE* f) : file_(f) {} 193 | 194 | public: 195 | buffered_file(const buffered_file&) = delete; 196 | void operator=(const buffered_file&) = delete; 197 | 198 | // Constructs a buffered_file object which doesn't represent any file. 199 | buffered_file() noexcept : file_(nullptr) {} 200 | 201 | // Destroys the object closing the file it represents if any. 202 | FMT_API ~buffered_file() noexcept; 203 | 204 | public: 205 | buffered_file(buffered_file&& other) noexcept : file_(other.file_) { 206 | other.file_ = nullptr; 207 | } 208 | 209 | buffered_file& operator=(buffered_file&& other) { 210 | close(); 211 | file_ = other.file_; 212 | other.file_ = nullptr; 213 | return *this; 214 | } 215 | 216 | // Opens a file. 217 | FMT_API buffered_file(cstring_view filename, cstring_view mode); 218 | 219 | // Closes the file. 220 | FMT_API void close(); 221 | 222 | // Returns the pointer to a FILE object representing this file. 223 | FILE* get() const noexcept { return file_; } 224 | 225 | FMT_API int descriptor() const; 226 | 227 | void vprint(string_view format_str, format_args args) { 228 | fmt::vprint(file_, format_str, args); 229 | } 230 | 231 | template 232 | inline void print(string_view format_str, const Args&... args) { 233 | vprint(format_str, fmt::make_format_args(args...)); 234 | } 235 | }; 236 | 237 | #if FMT_USE_FCNTL 238 | // A file. Closed file is represented by a file object with descriptor -1. 239 | // Methods that are not declared with noexcept may throw 240 | // fmt::system_error in case of failure. Note that some errors such as 241 | // closing the file multiple times will cause a crash on Windows rather 242 | // than an exception. You can get standard behavior by overriding the 243 | // invalid parameter handler with _set_invalid_parameter_handler. 244 | class FMT_API file { 245 | private: 246 | int fd_; // File descriptor. 247 | 248 | // Constructs a file object with a given descriptor. 249 | explicit file(int fd) : fd_(fd) {} 250 | 251 | public: 252 | // Possible values for the oflag argument to the constructor. 253 | enum { 254 | RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. 255 | WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. 256 | RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing. 257 | CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist. 258 | APPEND = FMT_POSIX(O_APPEND), // Open in append mode. 259 | TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file. 260 | }; 261 | 262 | // Constructs a file object which doesn't represent any file. 263 | file() noexcept : fd_(-1) {} 264 | 265 | // Opens a file and constructs a file object representing this file. 266 | file(cstring_view path, int oflag); 267 | 268 | public: 269 | file(const file&) = delete; 270 | void operator=(const file&) = delete; 271 | 272 | file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; } 273 | 274 | // Move assignment is not noexcept because close may throw. 275 | file& operator=(file&& other) { 276 | close(); 277 | fd_ = other.fd_; 278 | other.fd_ = -1; 279 | return *this; 280 | } 281 | 282 | // Destroys the object closing the file it represents if any. 283 | ~file() noexcept; 284 | 285 | // Returns the file descriptor. 286 | int descriptor() const noexcept { return fd_; } 287 | 288 | // Closes the file. 289 | void close(); 290 | 291 | // Returns the file size. The size has signed type for consistency with 292 | // stat::st_size. 293 | long long size() const; 294 | 295 | // Attempts to read count bytes from the file into the specified buffer. 296 | size_t read(void* buffer, size_t count); 297 | 298 | // Attempts to write count bytes from the specified buffer to the file. 299 | size_t write(const void* buffer, size_t count); 300 | 301 | // Duplicates a file descriptor with the dup function and returns 302 | // the duplicate as a file object. 303 | static file dup(int fd); 304 | 305 | // Makes fd be the copy of this file descriptor, closing fd first if 306 | // necessary. 307 | void dup2(int fd); 308 | 309 | // Makes fd be the copy of this file descriptor, closing fd first if 310 | // necessary. 311 | void dup2(int fd, std::error_code& ec) noexcept; 312 | 313 | // Creates a pipe setting up read_end and write_end file objects for reading 314 | // and writing respectively. 315 | static void pipe(file& read_end, file& write_end); 316 | 317 | // Creates a buffered_file object associated with this file and detaches 318 | // this file object from the file. 319 | buffered_file fdopen(const char* mode); 320 | 321 | # if defined(_WIN32) && !defined(__MINGW32__) 322 | // Opens a file and constructs a file object representing this file by 323 | // wcstring_view filename. Windows only. 324 | static file open_windows_file(wcstring_view path, int oflag); 325 | # endif 326 | }; 327 | 328 | // Returns the memory page size. 329 | long getpagesize(); 330 | 331 | namespace detail { 332 | 333 | struct buffer_size { 334 | buffer_size() = default; 335 | size_t value = 0; 336 | buffer_size operator=(size_t val) const { 337 | auto bs = buffer_size(); 338 | bs.value = val; 339 | return bs; 340 | } 341 | }; 342 | 343 | struct ostream_params { 344 | int oflag = file::WRONLY | file::CREATE | file::TRUNC; 345 | size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768; 346 | 347 | ostream_params() {} 348 | 349 | template 350 | ostream_params(T... params, int new_oflag) : ostream_params(params...) { 351 | oflag = new_oflag; 352 | } 353 | 354 | template 355 | ostream_params(T... params, detail::buffer_size bs) 356 | : ostream_params(params...) { 357 | this->buffer_size = bs.value; 358 | } 359 | 360 | // Intel has a bug that results in failure to deduce a constructor 361 | // for empty parameter packs. 362 | # if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000 363 | ostream_params(int new_oflag) : oflag(new_oflag) {} 364 | ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {} 365 | # endif 366 | }; 367 | 368 | class file_buffer final : public buffer { 369 | file file_; 370 | 371 | FMT_API void grow(size_t) override; 372 | 373 | public: 374 | FMT_API file_buffer(cstring_view path, const ostream_params& params); 375 | FMT_API file_buffer(file_buffer&& other); 376 | FMT_API ~file_buffer(); 377 | 378 | void flush() { 379 | if (size() == 0) return; 380 | file_.write(data(), size() * sizeof(data()[0])); 381 | clear(); 382 | } 383 | 384 | void close() { 385 | flush(); 386 | file_.close(); 387 | } 388 | }; 389 | 390 | } // namespace detail 391 | 392 | // Added {} below to work around default constructor error known to 393 | // occur in Xcode versions 7.2.1 and 8.2.1. 394 | constexpr detail::buffer_size buffer_size{}; 395 | 396 | /** A fast output stream which is not thread-safe. */ 397 | class FMT_API ostream { 398 | private: 399 | FMT_MSC_WARNING(suppress : 4251) 400 | detail::file_buffer buffer_; 401 | 402 | ostream(cstring_view path, const detail::ostream_params& params) 403 | : buffer_(path, params) {} 404 | 405 | public: 406 | ostream(ostream&& other) : buffer_(std::move(other.buffer_)) {} 407 | 408 | ~ostream(); 409 | 410 | void flush() { buffer_.flush(); } 411 | 412 | template 413 | friend ostream output_file(cstring_view path, T... params); 414 | 415 | void close() { buffer_.close(); } 416 | 417 | /** 418 | Formats ``args`` according to specifications in ``fmt`` and writes the 419 | output to the file. 420 | */ 421 | template void print(format_string fmt, T&&... args) { 422 | vformat_to(detail::buffer_appender(buffer_), fmt, 423 | fmt::make_format_args(args...)); 424 | } 425 | }; 426 | 427 | /** 428 | \rst 429 | Opens a file for writing. Supported parameters passed in *params*: 430 | 431 | * ````: Flags passed to `open 432 | `_ 433 | (``file::WRONLY | file::CREATE | file::TRUNC`` by default) 434 | * ``buffer_size=``: Output buffer size 435 | 436 | **Example**:: 437 | 438 | auto out = fmt::output_file("guide.txt"); 439 | out.print("Don't {}", "Panic"); 440 | \endrst 441 | */ 442 | template 443 | inline ostream output_file(cstring_view path, T... params) { 444 | return {path, detail::ostream_params(params...)}; 445 | } 446 | #endif // FMT_USE_FCNTL 447 | 448 | FMT_END_EXPORT 449 | FMT_END_NAMESPACE 450 | 451 | #endif // FMT_OS_H_ 452 | -------------------------------------------------------------------------------- /third_party/fmt/include/fmt/ostream.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - std::ostream support 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_OSTREAM_H_ 9 | #define FMT_OSTREAM_H_ 10 | 11 | #include // std::filebuf 12 | 13 | #if defined(_WIN32) && defined(__GLIBCXX__) 14 | # include 15 | # include 16 | #elif defined(_WIN32) && defined(_LIBCPP_VERSION) 17 | # include <__std_stream> 18 | #endif 19 | 20 | #include "format.h" 21 | 22 | FMT_BEGIN_NAMESPACE 23 | 24 | namespace detail { 25 | 26 | // Generate a unique explicit instantion in every translation unit using a tag 27 | // type in an anonymous namespace. 28 | namespace { 29 | struct file_access_tag {}; 30 | } // namespace 31 | template 32 | class file_access { 33 | friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } 34 | }; 35 | 36 | #if FMT_MSC_VERSION 37 | template class file_access; 39 | auto get_file(std::filebuf&) -> FILE*; 40 | #elif defined(_WIN32) && defined(_LIBCPP_VERSION) 41 | template class file_access, 42 | &std::__stdoutbuf::__file_>; 43 | auto get_file(std::__stdoutbuf&) -> FILE*; 44 | #endif 45 | 46 | inline bool write_ostream_unicode(std::ostream& os, fmt::string_view data) { 47 | #if FMT_MSC_VERSION 48 | if (auto* buf = dynamic_cast(os.rdbuf())) 49 | if (FILE* f = get_file(*buf)) return write_console(f, data); 50 | #elif defined(_WIN32) && defined(__GLIBCXX__) 51 | auto* rdbuf = os.rdbuf(); 52 | FILE* c_file; 53 | if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf*>(rdbuf)) 54 | c_file = sfbuf->file(); 55 | else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf*>(rdbuf)) 56 | c_file = fbuf->file(); 57 | else 58 | return false; 59 | if (c_file) return write_console(c_file, data); 60 | #elif defined(_WIN32) && defined(_LIBCPP_VERSION) 61 | if (auto* buf = dynamic_cast*>(os.rdbuf())) 62 | if (FILE* f = get_file(*buf)) return write_console(f, data); 63 | #else 64 | ignore_unused(os, data); 65 | #endif 66 | return false; 67 | } 68 | inline bool write_ostream_unicode(std::wostream&, 69 | fmt::basic_string_view) { 70 | return false; 71 | } 72 | 73 | // Write the content of buf to os. 74 | // It is a separate function rather than a part of vprint to simplify testing. 75 | template 76 | void write_buffer(std::basic_ostream& os, buffer& buf) { 77 | const Char* buf_data = buf.data(); 78 | using unsigned_streamsize = std::make_unsigned::type; 79 | unsigned_streamsize size = buf.size(); 80 | unsigned_streamsize max_size = to_unsigned(max_value()); 81 | do { 82 | unsigned_streamsize n = size <= max_size ? size : max_size; 83 | os.write(buf_data, static_cast(n)); 84 | buf_data += n; 85 | size -= n; 86 | } while (size != 0); 87 | } 88 | 89 | template 90 | void format_value(buffer& buf, const T& value, 91 | locale_ref loc = locale_ref()) { 92 | auto&& format_buf = formatbuf>(buf); 93 | auto&& output = std::basic_ostream(&format_buf); 94 | #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) 95 | if (loc) output.imbue(loc.get()); 96 | #endif 97 | output << value; 98 | output.exceptions(std::ios_base::failbit | std::ios_base::badbit); 99 | } 100 | 101 | template struct streamed_view { const T& value; }; 102 | 103 | } // namespace detail 104 | 105 | // Formats an object of type T that has an overloaded ostream operator<<. 106 | template 107 | struct basic_ostream_formatter : formatter, Char> { 108 | void set_debug_format() = delete; 109 | 110 | template 111 | auto format(const T& value, basic_format_context& ctx) const 112 | -> OutputIt { 113 | auto buffer = basic_memory_buffer(); 114 | detail::format_value(buffer, value, ctx.locale()); 115 | return formatter, Char>::format( 116 | {buffer.data(), buffer.size()}, ctx); 117 | } 118 | }; 119 | 120 | using ostream_formatter = basic_ostream_formatter; 121 | 122 | template 123 | struct formatter, Char> 124 | : basic_ostream_formatter { 125 | template 126 | auto format(detail::streamed_view view, 127 | basic_format_context& ctx) const -> OutputIt { 128 | return basic_ostream_formatter::format(view.value, ctx); 129 | } 130 | }; 131 | 132 | /** 133 | \rst 134 | Returns a view that formats `value` via an ostream ``operator<<``. 135 | 136 | **Example**:: 137 | 138 | fmt::print("Current thread id: {}\n", 139 | fmt::streamed(std::this_thread::get_id())); 140 | \endrst 141 | */ 142 | template 143 | auto streamed(const T& value) -> detail::streamed_view { 144 | return {value}; 145 | } 146 | 147 | namespace detail { 148 | 149 | inline void vprint_directly(std::ostream& os, string_view format_str, 150 | format_args args) { 151 | auto buffer = memory_buffer(); 152 | detail::vformat_to(buffer, format_str, args); 153 | detail::write_buffer(os, buffer); 154 | } 155 | 156 | } // namespace detail 157 | 158 | FMT_EXPORT template 159 | void vprint(std::basic_ostream& os, 160 | basic_string_view> format_str, 161 | basic_format_args>> args) { 162 | auto buffer = basic_memory_buffer(); 163 | detail::vformat_to(buffer, format_str, args); 164 | if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return; 165 | detail::write_buffer(os, buffer); 166 | } 167 | 168 | /** 169 | \rst 170 | Prints formatted data to the stream *os*. 171 | 172 | **Example**:: 173 | 174 | fmt::print(cerr, "Don't {}!", "panic"); 175 | \endrst 176 | */ 177 | FMT_EXPORT template 178 | void print(std::ostream& os, format_string fmt, T&&... args) { 179 | const auto& vargs = fmt::make_format_args(args...); 180 | if (detail::is_utf8()) 181 | vprint(os, fmt, vargs); 182 | else 183 | detail::vprint_directly(os, fmt, vargs); 184 | } 185 | 186 | FMT_EXPORT 187 | template 188 | void print(std::wostream& os, 189 | basic_format_string...> fmt, 190 | Args&&... args) { 191 | vprint(os, fmt, fmt::make_format_args>(args...)); 192 | } 193 | 194 | FMT_EXPORT template 195 | void println(std::ostream& os, format_string fmt, T&&... args) { 196 | fmt::print(os, "{}\n", fmt::format(fmt, std::forward(args)...)); 197 | } 198 | 199 | FMT_EXPORT 200 | template 201 | void println(std::wostream& os, 202 | basic_format_string...> fmt, 203 | Args&&... args) { 204 | print(os, L"{}\n", fmt::format(fmt, std::forward(args)...)); 205 | } 206 | 207 | FMT_END_NAMESPACE 208 | 209 | #endif // FMT_OSTREAM_H_ 210 | -------------------------------------------------------------------------------- /third_party/fmt/include/fmt/printf.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - legacy printf implementation 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_PRINTF_H_ 9 | #define FMT_PRINTF_H_ 10 | 11 | #include // std::max 12 | #include // std::numeric_limits 13 | 14 | #include "format.h" 15 | 16 | FMT_BEGIN_NAMESPACE 17 | FMT_BEGIN_EXPORT 18 | 19 | template struct printf_formatter { printf_formatter() = delete; }; 20 | 21 | template class basic_printf_context { 22 | private: 23 | detail::buffer_appender out_; 24 | basic_format_args args_; 25 | 26 | public: 27 | using char_type = Char; 28 | using parse_context_type = basic_format_parse_context; 29 | template using formatter_type = printf_formatter; 30 | 31 | /** 32 | \rst 33 | Constructs a ``printf_context`` object. References to the arguments are 34 | stored in the context object so make sure they have appropriate lifetimes. 35 | \endrst 36 | */ 37 | basic_printf_context(detail::buffer_appender out, 38 | basic_format_args args) 39 | : out_(out), args_(args) {} 40 | 41 | auto out() -> detail::buffer_appender { return out_; } 42 | void advance_to(detail::buffer_appender) {} 43 | 44 | auto locale() -> detail::locale_ref { return {}; } 45 | 46 | auto arg(int id) const -> basic_format_arg { 47 | return args_.get(id); 48 | } 49 | 50 | FMT_CONSTEXPR void on_error(const char* message) { 51 | detail::error_handler().on_error(message); 52 | } 53 | }; 54 | 55 | namespace detail { 56 | 57 | // Checks if a value fits in int - used to avoid warnings about comparing 58 | // signed and unsigned integers. 59 | template struct int_checker { 60 | template static auto fits_in_int(T value) -> bool { 61 | unsigned max = max_value(); 62 | return value <= max; 63 | } 64 | static auto fits_in_int(bool) -> bool { return true; } 65 | }; 66 | 67 | template <> struct int_checker { 68 | template static auto fits_in_int(T value) -> bool { 69 | return value >= (std::numeric_limits::min)() && 70 | value <= max_value(); 71 | } 72 | static auto fits_in_int(int) -> bool { return true; } 73 | }; 74 | 75 | struct printf_precision_handler { 76 | template ::value)> 77 | auto operator()(T value) -> int { 78 | if (!int_checker::is_signed>::fits_in_int(value)) 79 | throw_format_error("number is too big"); 80 | return (std::max)(static_cast(value), 0); 81 | } 82 | 83 | template ::value)> 84 | auto operator()(T) -> int { 85 | throw_format_error("precision is not integer"); 86 | return 0; 87 | } 88 | }; 89 | 90 | // An argument visitor that returns true iff arg is a zero integer. 91 | struct is_zero_int { 92 | template ::value)> 93 | auto operator()(T value) -> bool { 94 | return value == 0; 95 | } 96 | 97 | template ::value)> 98 | auto operator()(T) -> bool { 99 | return false; 100 | } 101 | }; 102 | 103 | template struct make_unsigned_or_bool : std::make_unsigned {}; 104 | 105 | template <> struct make_unsigned_or_bool { using type = bool; }; 106 | 107 | template class arg_converter { 108 | private: 109 | using char_type = typename Context::char_type; 110 | 111 | basic_format_arg& arg_; 112 | char_type type_; 113 | 114 | public: 115 | arg_converter(basic_format_arg& arg, char_type type) 116 | : arg_(arg), type_(type) {} 117 | 118 | void operator()(bool value) { 119 | if (type_ != 's') operator()(value); 120 | } 121 | 122 | template ::value)> 123 | void operator()(U value) { 124 | bool is_signed = type_ == 'd' || type_ == 'i'; 125 | using target_type = conditional_t::value, U, T>; 126 | if (const_check(sizeof(target_type) <= sizeof(int))) { 127 | // Extra casts are used to silence warnings. 128 | if (is_signed) { 129 | auto n = static_cast(static_cast(value)); 130 | arg_ = detail::make_arg(n); 131 | } else { 132 | using unsigned_type = typename make_unsigned_or_bool::type; 133 | auto n = static_cast(static_cast(value)); 134 | arg_ = detail::make_arg(n); 135 | } 136 | } else { 137 | if (is_signed) { 138 | // glibc's printf doesn't sign extend arguments of smaller types: 139 | // std::printf("%lld", -42); // prints "4294967254" 140 | // but we don't have to do the same because it's a UB. 141 | auto n = static_cast(value); 142 | arg_ = detail::make_arg(n); 143 | } else { 144 | auto n = static_cast::type>(value); 145 | arg_ = detail::make_arg(n); 146 | } 147 | } 148 | } 149 | 150 | template ::value)> 151 | void operator()(U) {} // No conversion needed for non-integral types. 152 | }; 153 | 154 | // Converts an integer argument to T for printf, if T is an integral type. 155 | // If T is void, the argument is converted to corresponding signed or unsigned 156 | // type depending on the type specifier: 'd' and 'i' - signed, other - 157 | // unsigned). 158 | template 159 | void convert_arg(basic_format_arg& arg, Char type) { 160 | visit_format_arg(arg_converter(arg, type), arg); 161 | } 162 | 163 | // Converts an integer argument to char for printf. 164 | template class char_converter { 165 | private: 166 | basic_format_arg& arg_; 167 | 168 | public: 169 | explicit char_converter(basic_format_arg& arg) : arg_(arg) {} 170 | 171 | template ::value)> 172 | void operator()(T value) { 173 | auto c = static_cast(value); 174 | arg_ = detail::make_arg(c); 175 | } 176 | 177 | template ::value)> 178 | void operator()(T) {} // No conversion needed for non-integral types. 179 | }; 180 | 181 | // An argument visitor that return a pointer to a C string if argument is a 182 | // string or null otherwise. 183 | template struct get_cstring { 184 | template auto operator()(T) -> const Char* { return nullptr; } 185 | auto operator()(const Char* s) -> const Char* { return s; } 186 | }; 187 | 188 | // Checks if an argument is a valid printf width specifier and sets 189 | // left alignment if it is negative. 190 | template class printf_width_handler { 191 | private: 192 | format_specs& specs_; 193 | 194 | public: 195 | explicit printf_width_handler(format_specs& specs) : specs_(specs) {} 196 | 197 | template ::value)> 198 | auto operator()(T value) -> unsigned { 199 | auto width = static_cast>(value); 200 | if (detail::is_negative(value)) { 201 | specs_.align = align::left; 202 | width = 0 - width; 203 | } 204 | unsigned int_max = max_value(); 205 | if (width > int_max) throw_format_error("number is too big"); 206 | return static_cast(width); 207 | } 208 | 209 | template ::value)> 210 | auto operator()(T) -> unsigned { 211 | throw_format_error("width is not integer"); 212 | return 0; 213 | } 214 | }; 215 | 216 | // Workaround for a bug with the XL compiler when initializing 217 | // printf_arg_formatter's base class. 218 | template 219 | auto make_arg_formatter(buffer_appender iter, format_specs& s) 220 | -> arg_formatter { 221 | return {iter, s, locale_ref()}; 222 | } 223 | 224 | // The ``printf`` argument formatter. 225 | template 226 | class printf_arg_formatter : public arg_formatter { 227 | private: 228 | using base = arg_formatter; 229 | using context_type = basic_printf_context; 230 | 231 | context_type& context_; 232 | 233 | void write_null_pointer(bool is_string = false) { 234 | auto s = this->specs; 235 | s.type = presentation_type::none; 236 | write_bytes(this->out, is_string ? "(null)" : "(nil)", s); 237 | } 238 | 239 | public: 240 | printf_arg_formatter(buffer_appender iter, format_specs& s, 241 | context_type& ctx) 242 | : base(make_arg_formatter(iter, s)), context_(ctx) {} 243 | 244 | void operator()(monostate value) { base::operator()(value); } 245 | 246 | template ::value)> 247 | void operator()(T value) { 248 | // MSVC2013 fails to compile separate overloads for bool and Char so use 249 | // std::is_same instead. 250 | if (!std::is_same::value) { 251 | base::operator()(value); 252 | return; 253 | } 254 | format_specs fmt_specs = this->specs; 255 | if (fmt_specs.type != presentation_type::none && 256 | fmt_specs.type != presentation_type::chr) { 257 | return (*this)(static_cast(value)); 258 | } 259 | fmt_specs.sign = sign::none; 260 | fmt_specs.alt = false; 261 | fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types. 262 | // align::numeric needs to be overwritten here since the '0' flag is 263 | // ignored for non-numeric types 264 | if (fmt_specs.align == align::none || fmt_specs.align == align::numeric) 265 | fmt_specs.align = align::right; 266 | write(this->out, static_cast(value), fmt_specs); 267 | } 268 | 269 | template ::value)> 270 | void operator()(T value) { 271 | base::operator()(value); 272 | } 273 | 274 | /** Formats a null-terminated C string. */ 275 | void operator()(const char* value) { 276 | if (value) 277 | base::operator()(value); 278 | else 279 | write_null_pointer(this->specs.type != presentation_type::pointer); 280 | } 281 | 282 | /** Formats a null-terminated wide C string. */ 283 | void operator()(const wchar_t* value) { 284 | if (value) 285 | base::operator()(value); 286 | else 287 | write_null_pointer(this->specs.type != presentation_type::pointer); 288 | } 289 | 290 | void operator()(basic_string_view value) { base::operator()(value); } 291 | 292 | /** Formats a pointer. */ 293 | void operator()(const void* value) { 294 | if (value) 295 | base::operator()(value); 296 | else 297 | write_null_pointer(); 298 | } 299 | 300 | /** Formats an argument of a custom (user-defined) type. */ 301 | void operator()(typename basic_format_arg::handle handle) { 302 | auto parse_ctx = basic_format_parse_context({}); 303 | handle.format(parse_ctx, context_); 304 | } 305 | }; 306 | 307 | template 308 | void parse_flags(format_specs& specs, const Char*& it, const Char* end) { 309 | for (; it != end; ++it) { 310 | switch (*it) { 311 | case '-': 312 | specs.align = align::left; 313 | break; 314 | case '+': 315 | specs.sign = sign::plus; 316 | break; 317 | case '0': 318 | specs.fill[0] = '0'; 319 | break; 320 | case ' ': 321 | if (specs.sign != sign::plus) specs.sign = sign::space; 322 | break; 323 | case '#': 324 | specs.alt = true; 325 | break; 326 | default: 327 | return; 328 | } 329 | } 330 | } 331 | 332 | template 333 | auto parse_header(const Char*& it, const Char* end, format_specs& specs, 334 | GetArg get_arg) -> int { 335 | int arg_index = -1; 336 | Char c = *it; 337 | if (c >= '0' && c <= '9') { 338 | // Parse an argument index (if followed by '$') or a width possibly 339 | // preceded with '0' flag(s). 340 | int value = parse_nonnegative_int(it, end, -1); 341 | if (it != end && *it == '$') { // value is an argument index 342 | ++it; 343 | arg_index = value != -1 ? value : max_value(); 344 | } else { 345 | if (c == '0') specs.fill[0] = '0'; 346 | if (value != 0) { 347 | // Nonzero value means that we parsed width and don't need to 348 | // parse it or flags again, so return now. 349 | if (value == -1) throw_format_error("number is too big"); 350 | specs.width = value; 351 | return arg_index; 352 | } 353 | } 354 | } 355 | parse_flags(specs, it, end); 356 | // Parse width. 357 | if (it != end) { 358 | if (*it >= '0' && *it <= '9') { 359 | specs.width = parse_nonnegative_int(it, end, -1); 360 | if (specs.width == -1) throw_format_error("number is too big"); 361 | } else if (*it == '*') { 362 | ++it; 363 | specs.width = static_cast(visit_format_arg( 364 | detail::printf_width_handler(specs), get_arg(-1))); 365 | } 366 | } 367 | return arg_index; 368 | } 369 | 370 | inline auto parse_printf_presentation_type(char c, type t) 371 | -> presentation_type { 372 | using pt = presentation_type; 373 | constexpr auto integral_set = sint_set | uint_set | bool_set | char_set; 374 | switch (c) { 375 | case 'd': 376 | return in(t, integral_set) ? pt::dec : pt::none; 377 | case 'o': 378 | return in(t, integral_set) ? pt::oct : pt::none; 379 | case 'x': 380 | return in(t, integral_set) ? pt::hex_lower : pt::none; 381 | case 'X': 382 | return in(t, integral_set) ? pt::hex_upper : pt::none; 383 | case 'a': 384 | return in(t, float_set) ? pt::hexfloat_lower : pt::none; 385 | case 'A': 386 | return in(t, float_set) ? pt::hexfloat_upper : pt::none; 387 | case 'e': 388 | return in(t, float_set) ? pt::exp_lower : pt::none; 389 | case 'E': 390 | return in(t, float_set) ? pt::exp_upper : pt::none; 391 | case 'f': 392 | return in(t, float_set) ? pt::fixed_lower : pt::none; 393 | case 'F': 394 | return in(t, float_set) ? pt::fixed_upper : pt::none; 395 | case 'g': 396 | return in(t, float_set) ? pt::general_lower : pt::none; 397 | case 'G': 398 | return in(t, float_set) ? pt::general_upper : pt::none; 399 | case 'c': 400 | return in(t, integral_set) ? pt::chr : pt::none; 401 | case 's': 402 | return in(t, string_set | cstring_set) ? pt::string : pt::none; 403 | case 'p': 404 | return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none; 405 | default: 406 | return pt::none; 407 | } 408 | } 409 | 410 | template 411 | void vprintf(buffer& buf, basic_string_view format, 412 | basic_format_args args) { 413 | using iterator = buffer_appender; 414 | auto out = iterator(buf); 415 | auto context = basic_printf_context(out, args); 416 | auto parse_ctx = basic_format_parse_context(format); 417 | 418 | // Returns the argument with specified index or, if arg_index is -1, the next 419 | // argument. 420 | auto get_arg = [&](int arg_index) { 421 | if (arg_index < 0) 422 | arg_index = parse_ctx.next_arg_id(); 423 | else 424 | parse_ctx.check_arg_id(--arg_index); 425 | return detail::get_arg(context, arg_index); 426 | }; 427 | 428 | const Char* start = parse_ctx.begin(); 429 | const Char* end = parse_ctx.end(); 430 | auto it = start; 431 | while (it != end) { 432 | if (!find(it, end, '%', it)) { 433 | it = end; // find leaves it == nullptr if it doesn't find '%'. 434 | break; 435 | } 436 | Char c = *it++; 437 | if (it != end && *it == c) { 438 | write(out, basic_string_view(start, to_unsigned(it - start))); 439 | start = ++it; 440 | continue; 441 | } 442 | write(out, basic_string_view(start, to_unsigned(it - 1 - start))); 443 | 444 | auto specs = format_specs(); 445 | specs.align = align::right; 446 | 447 | // Parse argument index, flags and width. 448 | int arg_index = parse_header(it, end, specs, get_arg); 449 | if (arg_index == 0) throw_format_error("argument not found"); 450 | 451 | // Parse precision. 452 | if (it != end && *it == '.') { 453 | ++it; 454 | c = it != end ? *it : 0; 455 | if ('0' <= c && c <= '9') { 456 | specs.precision = parse_nonnegative_int(it, end, 0); 457 | } else if (c == '*') { 458 | ++it; 459 | specs.precision = static_cast( 460 | visit_format_arg(printf_precision_handler(), get_arg(-1))); 461 | } else { 462 | specs.precision = 0; 463 | } 464 | } 465 | 466 | auto arg = get_arg(arg_index); 467 | // For d, i, o, u, x, and X conversion specifiers, if a precision is 468 | // specified, the '0' flag is ignored 469 | if (specs.precision >= 0 && arg.is_integral()) { 470 | // Ignore '0' for non-numeric types or if '-' present. 471 | specs.fill[0] = ' '; 472 | } 473 | if (specs.precision >= 0 && arg.type() == type::cstring_type) { 474 | auto str = visit_format_arg(get_cstring(), arg); 475 | auto str_end = str + specs.precision; 476 | auto nul = std::find(str, str_end, Char()); 477 | auto sv = basic_string_view( 478 | str, to_unsigned(nul != str_end ? nul - str : specs.precision)); 479 | arg = make_arg>(sv); 480 | } 481 | if (specs.alt && visit_format_arg(is_zero_int(), arg)) specs.alt = false; 482 | if (specs.fill[0] == '0') { 483 | if (arg.is_arithmetic() && specs.align != align::left) 484 | specs.align = align::numeric; 485 | else 486 | specs.fill[0] = ' '; // Ignore '0' flag for non-numeric types or if '-' 487 | // flag is also present. 488 | } 489 | 490 | // Parse length and convert the argument to the required type. 491 | c = it != end ? *it++ : 0; 492 | Char t = it != end ? *it : 0; 493 | switch (c) { 494 | case 'h': 495 | if (t == 'h') { 496 | ++it; 497 | t = it != end ? *it : 0; 498 | convert_arg(arg, t); 499 | } else { 500 | convert_arg(arg, t); 501 | } 502 | break; 503 | case 'l': 504 | if (t == 'l') { 505 | ++it; 506 | t = it != end ? *it : 0; 507 | convert_arg(arg, t); 508 | } else { 509 | convert_arg(arg, t); 510 | } 511 | break; 512 | case 'j': 513 | convert_arg(arg, t); 514 | break; 515 | case 'z': 516 | convert_arg(arg, t); 517 | break; 518 | case 't': 519 | convert_arg(arg, t); 520 | break; 521 | case 'L': 522 | // printf produces garbage when 'L' is omitted for long double, no 523 | // need to do the same. 524 | break; 525 | default: 526 | --it; 527 | convert_arg(arg, c); 528 | } 529 | 530 | // Parse type. 531 | if (it == end) throw_format_error("invalid format string"); 532 | char type = static_cast(*it++); 533 | if (arg.is_integral()) { 534 | // Normalize type. 535 | switch (type) { 536 | case 'i': 537 | case 'u': 538 | type = 'd'; 539 | break; 540 | case 'c': 541 | visit_format_arg(char_converter>(arg), arg); 542 | break; 543 | } 544 | } 545 | specs.type = parse_printf_presentation_type(type, arg.type()); 546 | if (specs.type == presentation_type::none) 547 | throw_format_error("invalid format specifier"); 548 | 549 | start = it; 550 | 551 | // Format argument. 552 | visit_format_arg(printf_arg_formatter(out, specs, context), arg); 553 | } 554 | write(out, basic_string_view(start, to_unsigned(it - start))); 555 | } 556 | } // namespace detail 557 | 558 | using printf_context = basic_printf_context; 559 | using wprintf_context = basic_printf_context; 560 | 561 | using printf_args = basic_format_args; 562 | using wprintf_args = basic_format_args; 563 | 564 | /** 565 | \rst 566 | Constructs an `~fmt::format_arg_store` object that contains references to 567 | arguments and can be implicitly converted to `~fmt::printf_args`. 568 | \endrst 569 | */ 570 | template 571 | inline auto make_printf_args(const T&... args) 572 | -> format_arg_store { 573 | return {args...}; 574 | } 575 | 576 | // DEPRECATED! 577 | template 578 | inline auto make_wprintf_args(const T&... args) 579 | -> format_arg_store { 580 | return {args...}; 581 | } 582 | 583 | template 584 | inline auto vsprintf( 585 | basic_string_view fmt, 586 | basic_format_args>> args) 587 | -> std::basic_string { 588 | auto buf = basic_memory_buffer(); 589 | detail::vprintf(buf, fmt, args); 590 | return to_string(buf); 591 | } 592 | 593 | /** 594 | \rst 595 | Formats arguments and returns the result as a string. 596 | 597 | **Example**:: 598 | 599 | std::string message = fmt::sprintf("The answer is %d", 42); 600 | \endrst 601 | */ 602 | template ::value, char_t>> 604 | inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string { 605 | return vsprintf(detail::to_string_view(fmt), 606 | fmt::make_format_args>(args...)); 607 | } 608 | 609 | template 610 | inline auto vfprintf( 611 | std::FILE* f, basic_string_view fmt, 612 | basic_format_args>> args) 613 | -> int { 614 | auto buf = basic_memory_buffer(); 615 | detail::vprintf(buf, fmt, args); 616 | size_t size = buf.size(); 617 | return std::fwrite(buf.data(), sizeof(Char), size, f) < size 618 | ? -1 619 | : static_cast(size); 620 | } 621 | 622 | /** 623 | \rst 624 | Prints formatted data to the file *f*. 625 | 626 | **Example**:: 627 | 628 | fmt::fprintf(stderr, "Don't %s!", "panic"); 629 | \endrst 630 | */ 631 | template > 632 | inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int { 633 | return vfprintf(f, detail::to_string_view(fmt), 634 | fmt::make_format_args>(args...)); 635 | } 636 | 637 | template 638 | FMT_DEPRECATED inline auto vprintf( 639 | basic_string_view fmt, 640 | basic_format_args>> args) 641 | -> int { 642 | return vfprintf(stdout, fmt, args); 643 | } 644 | 645 | /** 646 | \rst 647 | Prints formatted data to ``stdout``. 648 | 649 | **Example**:: 650 | 651 | fmt::printf("Elapsed time: %.2f seconds", 1.23); 652 | \endrst 653 | */ 654 | template 655 | inline auto printf(string_view fmt, const T&... args) -> int { 656 | return vfprintf(stdout, fmt, make_printf_args(args...)); 657 | } 658 | template 659 | FMT_DEPRECATED inline auto printf(basic_string_view fmt, 660 | const T&... args) -> int { 661 | return vfprintf(stdout, fmt, make_wprintf_args(args...)); 662 | } 663 | 664 | FMT_END_EXPORT 665 | FMT_END_NAMESPACE 666 | 667 | #endif // FMT_PRINTF_H_ 668 | -------------------------------------------------------------------------------- /third_party/fmt/include/fmt/std.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - formatters for standard library types 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_STD_H_ 9 | #define FMT_STD_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "format.h" 23 | #include "ostream.h" 24 | 25 | #if FMT_HAS_INCLUDE() 26 | # include 27 | #endif 28 | // Checking FMT_CPLUSPLUS for warning suppression in MSVC. 29 | #if FMT_CPLUSPLUS >= 201703L 30 | # if FMT_HAS_INCLUDE() 31 | # include 32 | # endif 33 | # if FMT_HAS_INCLUDE() 34 | # include 35 | # endif 36 | # if FMT_HAS_INCLUDE() 37 | # include 38 | # endif 39 | #endif 40 | 41 | // GCC 4 does not support FMT_HAS_INCLUDE. 42 | #if FMT_HAS_INCLUDE() || defined(__GLIBCXX__) 43 | # include 44 | // Android NDK with gabi++ library on some architectures does not implement 45 | // abi::__cxa_demangle(). 46 | # ifndef __GABIXX_CXXABI_H__ 47 | # define FMT_HAS_ABI_CXA_DEMANGLE 48 | # endif 49 | #endif 50 | 51 | // Check if typeid is available. 52 | #ifndef FMT_USE_TYPEID 53 | // __RTTI is for EDG compilers. In MSVC typeid is available without RTTI. 54 | # if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || FMT_MSC_VERSION || \ 55 | defined(__INTEL_RTTI__) || defined(__RTTI) 56 | # define FMT_USE_TYPEID 1 57 | # else 58 | # define FMT_USE_TYPEID 0 59 | # endif 60 | #endif 61 | 62 | #ifdef __cpp_lib_filesystem 63 | FMT_BEGIN_NAMESPACE 64 | 65 | namespace detail { 66 | 67 | template auto get_path_string(const std::filesystem::path& p) { 68 | return p.string(); 69 | } 70 | 71 | template 72 | void write_escaped_path(basic_memory_buffer& quoted, 73 | const std::filesystem::path& p) { 74 | write_escaped_string(std::back_inserter(quoted), p.string()); 75 | } 76 | 77 | # ifdef _WIN32 78 | template <> 79 | inline auto get_path_string(const std::filesystem::path& p) { 80 | return to_utf8(p.native(), to_utf8_error_policy::replace); 81 | } 82 | 83 | template <> 84 | inline void write_escaped_path(memory_buffer& quoted, 85 | const std::filesystem::path& p) { 86 | auto buf = basic_memory_buffer(); 87 | write_escaped_string(std::back_inserter(buf), p.native()); 88 | bool valid = to_utf8::convert(quoted, {buf.data(), buf.size()}); 89 | FMT_ASSERT(valid, "invalid utf16"); 90 | } 91 | # endif // _WIN32 92 | 93 | template <> 94 | inline void write_escaped_path( 95 | basic_memory_buffer& quoted, 96 | const std::filesystem::path& p) { 97 | write_escaped_string( 98 | std::back_inserter(quoted), p.native()); 99 | } 100 | 101 | } // namespace detail 102 | 103 | FMT_EXPORT 104 | template struct formatter { 105 | private: 106 | format_specs specs_; 107 | detail::arg_ref width_ref_; 108 | bool debug_ = false; 109 | 110 | public: 111 | FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; } 112 | 113 | template FMT_CONSTEXPR auto parse(ParseContext& ctx) { 114 | auto it = ctx.begin(), end = ctx.end(); 115 | if (it == end) return it; 116 | 117 | it = detail::parse_align(it, end, specs_); 118 | if (it == end) return it; 119 | 120 | it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); 121 | if (it != end && *it == '?') { 122 | debug_ = true; 123 | ++it; 124 | } 125 | return it; 126 | } 127 | 128 | template 129 | auto format(const std::filesystem::path& p, FormatContext& ctx) const { 130 | auto specs = specs_; 131 | detail::handle_dynamic_spec(specs.width, width_ref_, 132 | ctx); 133 | if (!debug_) { 134 | auto s = detail::get_path_string(p); 135 | return detail::write(ctx.out(), basic_string_view(s), specs); 136 | } 137 | auto quoted = basic_memory_buffer(); 138 | detail::write_escaped_path(quoted, p); 139 | return detail::write(ctx.out(), 140 | basic_string_view(quoted.data(), quoted.size()), 141 | specs); 142 | } 143 | }; 144 | FMT_END_NAMESPACE 145 | #endif 146 | 147 | FMT_BEGIN_NAMESPACE 148 | FMT_EXPORT 149 | template 150 | struct formatter : basic_ostream_formatter {}; 151 | FMT_END_NAMESPACE 152 | 153 | #ifdef __cpp_lib_optional 154 | FMT_BEGIN_NAMESPACE 155 | FMT_EXPORT 156 | template 157 | struct formatter, Char, 158 | std::enable_if_t::value>> { 159 | private: 160 | formatter underlying_; 161 | static constexpr basic_string_view optional = 162 | detail::string_literal{}; 164 | static constexpr basic_string_view none = 165 | detail::string_literal{}; 166 | 167 | template 168 | FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set) 169 | -> decltype(u.set_debug_format(set)) { 170 | u.set_debug_format(set); 171 | } 172 | 173 | template 174 | FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {} 175 | 176 | public: 177 | template FMT_CONSTEXPR auto parse(ParseContext& ctx) { 178 | maybe_set_debug_format(underlying_, true); 179 | return underlying_.parse(ctx); 180 | } 181 | 182 | template 183 | auto format(std::optional const& opt, FormatContext& ctx) const 184 | -> decltype(ctx.out()) { 185 | if (!opt) return detail::write(ctx.out(), none); 186 | 187 | auto out = ctx.out(); 188 | out = detail::write(out, optional); 189 | ctx.advance_to(out); 190 | out = underlying_.format(*opt, ctx); 191 | return detail::write(out, ')'); 192 | } 193 | }; 194 | FMT_END_NAMESPACE 195 | #endif // __cpp_lib_optional 196 | 197 | #ifdef __cpp_lib_variant 198 | FMT_BEGIN_NAMESPACE 199 | namespace detail { 200 | 201 | template 202 | using variant_index_sequence = 203 | std::make_index_sequence::value>; 204 | 205 | template struct is_variant_like_ : std::false_type {}; 206 | template 207 | struct is_variant_like_> : std::true_type {}; 208 | 209 | // formattable element check. 210 | template class is_variant_formattable_ { 211 | template 212 | static std::conjunction< 213 | is_formattable, C>...> 214 | check(std::index_sequence); 215 | 216 | public: 217 | static constexpr const bool value = 218 | decltype(check(variant_index_sequence{}))::value; 219 | }; 220 | 221 | template 222 | auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt { 223 | if constexpr (is_string::value) 224 | return write_escaped_string(out, detail::to_string_view(v)); 225 | else if constexpr (std::is_same_v) 226 | return write_escaped_char(out, v); 227 | else 228 | return write(out, v); 229 | } 230 | 231 | } // namespace detail 232 | 233 | template struct is_variant_like { 234 | static constexpr const bool value = detail::is_variant_like_::value; 235 | }; 236 | 237 | template struct is_variant_formattable { 238 | static constexpr const bool value = 239 | detail::is_variant_formattable_::value; 240 | }; 241 | 242 | FMT_EXPORT 243 | template struct formatter { 244 | template 245 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 246 | return ctx.begin(); 247 | } 248 | 249 | template 250 | auto format(const std::monostate&, FormatContext& ctx) const 251 | -> decltype(ctx.out()) { 252 | return detail::write(ctx.out(), "monostate"); 253 | } 254 | }; 255 | 256 | FMT_EXPORT 257 | template 258 | struct formatter< 259 | Variant, Char, 260 | std::enable_if_t, is_variant_formattable>>> { 262 | template 263 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 264 | return ctx.begin(); 265 | } 266 | 267 | template 268 | auto format(const Variant& value, FormatContext& ctx) const 269 | -> decltype(ctx.out()) { 270 | auto out = ctx.out(); 271 | 272 | out = detail::write(out, "variant("); 273 | FMT_TRY { 274 | std::visit( 275 | [&](const auto& v) { 276 | out = detail::write_variant_alternative(out, v); 277 | }, 278 | value); 279 | } 280 | FMT_CATCH(const std::bad_variant_access&) { 281 | detail::write(out, "valueless by exception"); 282 | } 283 | *out++ = ')'; 284 | return out; 285 | } 286 | }; 287 | FMT_END_NAMESPACE 288 | #endif // __cpp_lib_variant 289 | 290 | FMT_BEGIN_NAMESPACE 291 | FMT_EXPORT 292 | template struct formatter { 293 | template 294 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 295 | return ctx.begin(); 296 | } 297 | 298 | template 299 | FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const 300 | -> decltype(ctx.out()) { 301 | auto out = ctx.out(); 302 | out = detail::write_bytes(out, ec.category().name(), format_specs()); 303 | out = detail::write(out, Char(':')); 304 | out = detail::write(out, ec.value()); 305 | return out; 306 | } 307 | }; 308 | 309 | FMT_EXPORT 310 | template 311 | struct formatter< 312 | T, Char, 313 | typename std::enable_if::value>::type> { 314 | private: 315 | bool with_typename_ = false; 316 | 317 | public: 318 | FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) 319 | -> decltype(ctx.begin()) { 320 | auto it = ctx.begin(); 321 | auto end = ctx.end(); 322 | if (it == end || *it == '}') return it; 323 | if (*it == 't') { 324 | ++it; 325 | with_typename_ = FMT_USE_TYPEID != 0; 326 | } 327 | return it; 328 | } 329 | 330 | template 331 | auto format(const std::exception& ex, 332 | basic_format_context& ctx) const -> OutputIt { 333 | format_specs spec; 334 | auto out = ctx.out(); 335 | if (!with_typename_) 336 | return detail::write_bytes(out, string_view(ex.what()), spec); 337 | 338 | #if FMT_USE_TYPEID 339 | const std::type_info& ti = typeid(ex); 340 | # ifdef FMT_HAS_ABI_CXA_DEMANGLE 341 | int status = 0; 342 | std::size_t size = 0; 343 | std::unique_ptr demangled_name_ptr( 344 | abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free); 345 | 346 | string_view demangled_name_view; 347 | if (demangled_name_ptr) { 348 | demangled_name_view = demangled_name_ptr.get(); 349 | 350 | // Normalization of stdlib inline namespace names. 351 | // libc++ inline namespaces. 352 | // std::__1::* -> std::* 353 | // std::__1::__fs::* -> std::* 354 | // libstdc++ inline namespaces. 355 | // std::__cxx11::* -> std::* 356 | // std::filesystem::__cxx11::* -> std::filesystem::* 357 | if (demangled_name_view.starts_with("std::")) { 358 | char* begin = demangled_name_ptr.get(); 359 | char* to = begin + 5; // std:: 360 | for (char *from = to, *end = begin + demangled_name_view.size(); 361 | from < end;) { 362 | // This is safe, because demangled_name is NUL-terminated. 363 | if (from[0] == '_' && from[1] == '_') { 364 | char* next = from + 1; 365 | while (next < end && *next != ':') next++; 366 | if (next[0] == ':' && next[1] == ':') { 367 | from = next + 2; 368 | continue; 369 | } 370 | } 371 | *to++ = *from++; 372 | } 373 | demangled_name_view = {begin, detail::to_unsigned(to - begin)}; 374 | } 375 | } else { 376 | demangled_name_view = string_view(ti.name()); 377 | } 378 | out = detail::write_bytes(out, demangled_name_view, spec); 379 | # elif FMT_MSC_VERSION 380 | string_view demangled_name_view(ti.name()); 381 | if (demangled_name_view.starts_with("class ")) 382 | demangled_name_view.remove_prefix(6); 383 | else if (demangled_name_view.starts_with("struct ")) 384 | demangled_name_view.remove_prefix(7); 385 | out = detail::write_bytes(out, demangled_name_view, spec); 386 | # else 387 | out = detail::write_bytes(out, string_view(ti.name()), spec); 388 | # endif 389 | *out++ = ':'; 390 | *out++ = ' '; 391 | return detail::write_bytes(out, string_view(ex.what()), spec); 392 | #endif 393 | } 394 | }; 395 | 396 | namespace detail { 397 | 398 | template 399 | struct has_flip : std::false_type {}; 400 | 401 | template 402 | struct has_flip().flip())>> 403 | : std::true_type {}; 404 | 405 | template struct is_bit_reference_like { 406 | static constexpr const bool value = 407 | std::is_convertible::value && 408 | std::is_nothrow_assignable::value && has_flip::value; 409 | }; 410 | 411 | #ifdef _LIBCPP_VERSION 412 | 413 | // Workaround for libc++ incompatibility with C++ standard. 414 | // According to the Standard, `bitset::operator[] const` returns bool. 415 | template 416 | struct is_bit_reference_like> { 417 | static constexpr const bool value = true; 418 | }; 419 | 420 | #endif 421 | 422 | } // namespace detail 423 | 424 | // We can't use std::vector::reference and 425 | // std::bitset::reference because the compiler can't deduce Allocator and N 426 | // in partial specialization. 427 | FMT_EXPORT 428 | template 429 | struct formatter::value>> 431 | : formatter { 432 | template 433 | FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const 434 | -> decltype(ctx.out()) { 435 | return formatter::format(v, ctx); 436 | } 437 | }; 438 | 439 | FMT_EXPORT 440 | template 441 | struct formatter, Char, 442 | enable_if_t::value>> 443 | : formatter { 444 | template 445 | auto format(const std::atomic& v, FormatContext& ctx) const 446 | -> decltype(ctx.out()) { 447 | return formatter::format(v.load(), ctx); 448 | } 449 | }; 450 | 451 | #ifdef __cpp_lib_atomic_flag_test 452 | FMT_EXPORT 453 | template 454 | struct formatter 455 | : formatter { 456 | template 457 | auto format(const std::atomic_flag& v, FormatContext& ctx) const 458 | -> decltype(ctx.out()) { 459 | return formatter::format(v.test(), ctx); 460 | } 461 | }; 462 | #endif // __cpp_lib_atomic_flag_test 463 | 464 | FMT_END_NAMESPACE 465 | #endif // FMT_STD_H_ 466 | -------------------------------------------------------------------------------- /third_party/fmt/include/fmt/xchar.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - optional wchar_t and exotic character support 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_XCHAR_H_ 9 | #define FMT_XCHAR_H_ 10 | 11 | #include 12 | 13 | #include "format.h" 14 | 15 | #ifndef FMT_STATIC_THOUSANDS_SEPARATOR 16 | # include 17 | #endif 18 | 19 | FMT_BEGIN_NAMESPACE 20 | namespace detail { 21 | 22 | template 23 | using is_exotic_char = bool_constant::value>; 24 | 25 | inline auto write_loc(std::back_insert_iterator> out, 26 | loc_value value, const format_specs& specs, 27 | locale_ref loc) -> bool { 28 | #ifndef FMT_STATIC_THOUSANDS_SEPARATOR 29 | auto& numpunct = 30 | std::use_facet>(loc.get()); 31 | auto separator = std::wstring(); 32 | auto grouping = numpunct.grouping(); 33 | if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep()); 34 | return value.visit(loc_writer{out, specs, separator, grouping, {}}); 35 | #endif 36 | return false; 37 | } 38 | } // namespace detail 39 | 40 | FMT_BEGIN_EXPORT 41 | 42 | using wstring_view = basic_string_view; 43 | using wformat_parse_context = basic_format_parse_context; 44 | using wformat_context = buffer_context; 45 | using wformat_args = basic_format_args; 46 | using wmemory_buffer = basic_memory_buffer; 47 | 48 | #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 49 | // Workaround broken conversion on older gcc. 50 | template using wformat_string = wstring_view; 51 | inline auto runtime(wstring_view s) -> wstring_view { return s; } 52 | #else 53 | template 54 | using wformat_string = basic_format_string...>; 55 | inline auto runtime(wstring_view s) -> runtime_format_string { 56 | return {{s}}; 57 | } 58 | #endif 59 | 60 | template <> struct is_char : std::true_type {}; 61 | template <> struct is_char : std::true_type {}; 62 | template <> struct is_char : std::true_type {}; 63 | template <> struct is_char : std::true_type {}; 64 | 65 | template 66 | constexpr format_arg_store make_wformat_args( 67 | const T&... args) { 68 | return {args...}; 69 | } 70 | 71 | inline namespace literals { 72 | #if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS 73 | constexpr detail::udl_arg operator"" _a(const wchar_t* s, size_t) { 74 | return {s}; 75 | } 76 | #endif 77 | } // namespace literals 78 | 79 | template 80 | auto join(It begin, Sentinel end, wstring_view sep) 81 | -> join_view { 82 | return {begin, end, sep}; 83 | } 84 | 85 | template 86 | auto join(Range&& range, wstring_view sep) 87 | -> join_view, detail::sentinel_t, 88 | wchar_t> { 89 | return join(std::begin(range), std::end(range), sep); 90 | } 91 | 92 | template 93 | auto join(std::initializer_list list, wstring_view sep) 94 | -> join_view { 95 | return join(std::begin(list), std::end(list), sep); 96 | } 97 | 98 | template ::value)> 99 | auto vformat(basic_string_view format_str, 100 | basic_format_args>> args) 101 | -> std::basic_string { 102 | auto buf = basic_memory_buffer(); 103 | detail::vformat_to(buf, format_str, args); 104 | return to_string(buf); 105 | } 106 | 107 | template 108 | auto format(wformat_string fmt, T&&... args) -> std::wstring { 109 | return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); 110 | } 111 | 112 | // Pass char_t as a default template parameter instead of using 113 | // std::basic_string> to reduce the symbol size. 114 | template , 115 | FMT_ENABLE_IF(!std::is_same::value && 116 | !std::is_same::value)> 117 | auto format(const S& format_str, T&&... args) -> std::basic_string { 118 | return vformat(detail::to_string_view(format_str), 119 | fmt::make_format_args>(args...)); 120 | } 121 | 122 | template , 123 | FMT_ENABLE_IF(detail::is_locale::value&& 124 | detail::is_exotic_char::value)> 125 | inline auto vformat( 126 | const Locale& loc, const S& format_str, 127 | basic_format_args>> args) 128 | -> std::basic_string { 129 | return detail::vformat(loc, detail::to_string_view(format_str), args); 130 | } 131 | 132 | template , 133 | FMT_ENABLE_IF(detail::is_locale::value&& 134 | detail::is_exotic_char::value)> 135 | inline auto format(const Locale& loc, const S& format_str, T&&... args) 136 | -> std::basic_string { 137 | return detail::vformat(loc, detail::to_string_view(format_str), 138 | fmt::make_format_args>(args...)); 139 | } 140 | 141 | template , 142 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 143 | detail::is_exotic_char::value)> 144 | auto vformat_to(OutputIt out, const S& format_str, 145 | basic_format_args>> args) 146 | -> OutputIt { 147 | auto&& buf = detail::get_buffer(out); 148 | detail::vformat_to(buf, detail::to_string_view(format_str), args); 149 | return detail::get_iterator(buf, out); 150 | } 151 | 152 | template , 154 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 155 | detail::is_exotic_char::value)> 156 | inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt { 157 | return vformat_to(out, detail::to_string_view(fmt), 158 | fmt::make_format_args>(args...)); 159 | } 160 | 161 | template , 163 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 164 | detail::is_locale::value&& 165 | detail::is_exotic_char::value)> 166 | inline auto vformat_to( 167 | OutputIt out, const Locale& loc, const S& format_str, 168 | basic_format_args>> args) -> OutputIt { 169 | auto&& buf = detail::get_buffer(out); 170 | vformat_to(buf, detail::to_string_view(format_str), args, 171 | detail::locale_ref(loc)); 172 | return detail::get_iterator(buf, out); 173 | } 174 | 175 | template < 176 | typename OutputIt, typename Locale, typename S, typename... T, 177 | typename Char = char_t, 178 | bool enable = detail::is_output_iterator::value&& 179 | detail::is_locale::value&& detail::is_exotic_char::value> 180 | inline auto format_to(OutputIt out, const Locale& loc, const S& format_str, 181 | T&&... args) -> 182 | typename std::enable_if::type { 183 | return vformat_to(out, loc, detail::to_string_view(format_str), 184 | fmt::make_format_args>(args...)); 185 | } 186 | 187 | template ::value&& 189 | detail::is_exotic_char::value)> 190 | inline auto vformat_to_n( 191 | OutputIt out, size_t n, basic_string_view format_str, 192 | basic_format_args>> args) 193 | -> format_to_n_result { 194 | using traits = detail::fixed_buffer_traits; 195 | auto buf = detail::iterator_buffer(out, n); 196 | detail::vformat_to(buf, format_str, args); 197 | return {buf.out(), buf.count()}; 198 | } 199 | 200 | template , 202 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 203 | detail::is_exotic_char::value)> 204 | inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args) 205 | -> format_to_n_result { 206 | return vformat_to_n(out, n, detail::to_string_view(fmt), 207 | fmt::make_format_args>(args...)); 208 | } 209 | 210 | template , 211 | FMT_ENABLE_IF(detail::is_exotic_char::value)> 212 | inline auto formatted_size(const S& fmt, T&&... args) -> size_t { 213 | auto buf = detail::counting_buffer(); 214 | detail::vformat_to(buf, detail::to_string_view(fmt), 215 | fmt::make_format_args>(args...)); 216 | return buf.count(); 217 | } 218 | 219 | inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) { 220 | auto buf = wmemory_buffer(); 221 | detail::vformat_to(buf, fmt, args); 222 | buf.push_back(L'\0'); 223 | if (std::fputws(buf.data(), f) == -1) 224 | FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); 225 | } 226 | 227 | inline void vprint(wstring_view fmt, wformat_args args) { 228 | vprint(stdout, fmt, args); 229 | } 230 | 231 | template 232 | void print(std::FILE* f, wformat_string fmt, T&&... args) { 233 | return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); 234 | } 235 | 236 | template void print(wformat_string fmt, T&&... args) { 237 | return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); 238 | } 239 | 240 | template 241 | void println(std::FILE* f, wformat_string fmt, T&&... args) { 242 | return print(f, L"{}\n", fmt::format(fmt, std::forward(args)...)); 243 | } 244 | 245 | template void println(wformat_string fmt, T&&... args) { 246 | return print(L"{}\n", fmt::format(fmt, std::forward(args)...)); 247 | } 248 | 249 | /** 250 | Converts *value* to ``std::wstring`` using the default format for type *T*. 251 | */ 252 | template inline auto to_wstring(const T& value) -> std::wstring { 253 | return format(FMT_STRING(L"{}"), value); 254 | } 255 | FMT_END_EXPORT 256 | FMT_END_NAMESPACE 257 | 258 | #endif // FMT_XCHAR_H_ 259 | -------------------------------------------------------------------------------- /third_party/fmt/src/format.cc: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #include "fmt/format-inl.h" 9 | 10 | FMT_BEGIN_NAMESPACE 11 | namespace detail { 12 | 13 | template FMT_API auto dragonbox::to_decimal(float x) noexcept 14 | -> dragonbox::decimal_fp; 15 | template FMT_API auto dragonbox::to_decimal(double x) noexcept 16 | -> dragonbox::decimal_fp; 17 | 18 | #ifndef FMT_STATIC_THOUSANDS_SEPARATOR 19 | template FMT_API locale_ref::locale_ref(const std::locale& loc); 20 | template FMT_API auto locale_ref::get() const -> std::locale; 21 | #endif 22 | 23 | // Explicit instantiations for char. 24 | 25 | template FMT_API auto thousands_sep_impl(locale_ref) 26 | -> thousands_sep_result; 27 | template FMT_API auto decimal_point_impl(locale_ref) -> char; 28 | 29 | template FMT_API void buffer::append(const char*, const char*); 30 | 31 | template FMT_API void vformat_to(buffer&, string_view, 32 | typename vformat_args<>::type, locale_ref); 33 | 34 | // Explicit instantiations for wchar_t. 35 | 36 | template FMT_API auto thousands_sep_impl(locale_ref) 37 | -> thousands_sep_result; 38 | template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; 39 | 40 | template FMT_API void buffer::append(const wchar_t*, const wchar_t*); 41 | 42 | } // namespace detail 43 | FMT_END_NAMESPACE 44 | -------------------------------------------------------------------------------- /third_party/fmt/src/os.cc: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - optional OS-specific functionality 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | // Disable bogus MSVC warnings. 9 | #if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER) 10 | # define _CRT_SECURE_NO_WARNINGS 11 | #endif 12 | 13 | #include "fmt/os.h" 14 | 15 | #include 16 | 17 | #if FMT_USE_FCNTL 18 | # include 19 | # include 20 | 21 | # ifdef _WRS_KERNEL // VxWorks7 kernel 22 | # include // getpagesize 23 | # endif 24 | 25 | # ifndef _WIN32 26 | # include 27 | # else 28 | # ifndef WIN32_LEAN_AND_MEAN 29 | # define WIN32_LEAN_AND_MEAN 30 | # endif 31 | # include 32 | 33 | # ifndef S_IRUSR 34 | # define S_IRUSR _S_IREAD 35 | # endif 36 | # ifndef S_IWUSR 37 | # define S_IWUSR _S_IWRITE 38 | # endif 39 | # ifndef S_IRGRP 40 | # define S_IRGRP 0 41 | # endif 42 | # ifndef S_IWGRP 43 | # define S_IWGRP 0 44 | # endif 45 | # ifndef S_IROTH 46 | # define S_IROTH 0 47 | # endif 48 | # ifndef S_IWOTH 49 | # define S_IWOTH 0 50 | # endif 51 | # endif // _WIN32 52 | #endif // FMT_USE_FCNTL 53 | 54 | #ifdef _WIN32 55 | # include 56 | #endif 57 | 58 | namespace { 59 | #ifdef _WIN32 60 | // Return type of read and write functions. 61 | using rwresult = int; 62 | 63 | // On Windows the count argument to read and write is unsigned, so convert 64 | // it from size_t preventing integer overflow. 65 | inline unsigned convert_rwcount(std::size_t count) { 66 | return count <= UINT_MAX ? static_cast(count) : UINT_MAX; 67 | } 68 | #elif FMT_USE_FCNTL 69 | // Return type of read and write functions. 70 | using rwresult = ssize_t; 71 | 72 | inline std::size_t convert_rwcount(std::size_t count) { return count; } 73 | #endif 74 | } // namespace 75 | 76 | FMT_BEGIN_NAMESPACE 77 | 78 | #ifdef _WIN32 79 | namespace detail { 80 | 81 | class system_message { 82 | system_message(const system_message&) = delete; 83 | void operator=(const system_message&) = delete; 84 | 85 | unsigned long result_; 86 | wchar_t* message_; 87 | 88 | static bool is_whitespace(wchar_t c) noexcept { 89 | return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0'; 90 | } 91 | 92 | public: 93 | explicit system_message(unsigned long error_code) 94 | : result_(0), message_(nullptr) { 95 | result_ = FormatMessageW( 96 | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 97 | FORMAT_MESSAGE_IGNORE_INSERTS, 98 | nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 99 | reinterpret_cast(&message_), 0, nullptr); 100 | if (result_ != 0) { 101 | while (result_ != 0 && is_whitespace(message_[result_ - 1])) { 102 | --result_; 103 | } 104 | } 105 | } 106 | ~system_message() { LocalFree(message_); } 107 | explicit operator bool() const noexcept { return result_ != 0; } 108 | operator basic_string_view() const noexcept { 109 | return basic_string_view(message_, result_); 110 | } 111 | }; 112 | 113 | class utf8_system_category final : public std::error_category { 114 | public: 115 | const char* name() const noexcept override { return "system"; } 116 | std::string message(int error_code) const override { 117 | auto&& msg = system_message(error_code); 118 | if (msg) { 119 | auto utf8_message = to_utf8(); 120 | if (utf8_message.convert(msg)) { 121 | return utf8_message.str(); 122 | } 123 | } 124 | return "unknown error"; 125 | } 126 | }; 127 | 128 | } // namespace detail 129 | 130 | FMT_API const std::error_category& system_category() noexcept { 131 | static const detail::utf8_system_category category; 132 | return category; 133 | } 134 | 135 | std::system_error vwindows_error(int err_code, string_view format_str, 136 | format_args args) { 137 | auto ec = std::error_code(err_code, system_category()); 138 | return std::system_error(ec, vformat(format_str, args)); 139 | } 140 | 141 | void detail::format_windows_error(detail::buffer& out, int error_code, 142 | const char* message) noexcept { 143 | FMT_TRY { 144 | auto&& msg = system_message(error_code); 145 | if (msg) { 146 | auto utf8_message = to_utf8(); 147 | if (utf8_message.convert(msg)) { 148 | fmt::format_to(appender(out), FMT_STRING("{}: {}"), message, 149 | string_view(utf8_message)); 150 | return; 151 | } 152 | } 153 | } 154 | FMT_CATCH(...) {} 155 | format_error_code(out, error_code, message); 156 | } 157 | 158 | void report_windows_error(int error_code, const char* message) noexcept { 159 | report_error(detail::format_windows_error, error_code, message); 160 | } 161 | #endif // _WIN32 162 | 163 | buffered_file::~buffered_file() noexcept { 164 | if (file_ && FMT_SYSTEM(fclose(file_)) != 0) 165 | report_system_error(errno, "cannot close file"); 166 | } 167 | 168 | buffered_file::buffered_file(cstring_view filename, cstring_view mode) { 169 | FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 170 | nullptr); 171 | if (!file_) 172 | FMT_THROW(system_error(errno, FMT_STRING("cannot open file {}"), 173 | filename.c_str())); 174 | } 175 | 176 | void buffered_file::close() { 177 | if (!file_) return; 178 | int result = FMT_SYSTEM(fclose(file_)); 179 | file_ = nullptr; 180 | if (result != 0) 181 | FMT_THROW(system_error(errno, FMT_STRING("cannot close file"))); 182 | } 183 | 184 | int buffered_file::descriptor() const { 185 | #ifdef fileno // fileno is a macro on OpenBSD so we cannot use FMT_POSIX_CALL. 186 | int fd = fileno(file_); 187 | #else 188 | int fd = FMT_POSIX_CALL(fileno(file_)); 189 | #endif 190 | if (fd == -1) 191 | FMT_THROW(system_error(errno, FMT_STRING("cannot get file descriptor"))); 192 | return fd; 193 | } 194 | 195 | #if FMT_USE_FCNTL 196 | # ifdef _WIN32 197 | using mode_t = int; 198 | # endif 199 | constexpr mode_t default_open_mode = 200 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 201 | 202 | file::file(cstring_view path, int oflag) { 203 | # if defined(_WIN32) && !defined(__MINGW32__) 204 | fd_ = -1; 205 | auto converted = detail::utf8_to_utf16(string_view(path.c_str())); 206 | *this = file::open_windows_file(converted.c_str(), oflag); 207 | # else 208 | FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, default_open_mode))); 209 | if (fd_ == -1) 210 | FMT_THROW( 211 | system_error(errno, FMT_STRING("cannot open file {}"), path.c_str())); 212 | # endif 213 | } 214 | 215 | file::~file() noexcept { 216 | // Don't retry close in case of EINTR! 217 | // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html 218 | if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) 219 | report_system_error(errno, "cannot close file"); 220 | } 221 | 222 | void file::close() { 223 | if (fd_ == -1) return; 224 | // Don't retry close in case of EINTR! 225 | // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html 226 | int result = FMT_POSIX_CALL(close(fd_)); 227 | fd_ = -1; 228 | if (result != 0) 229 | FMT_THROW(system_error(errno, FMT_STRING("cannot close file"))); 230 | } 231 | 232 | long long file::size() const { 233 | # ifdef _WIN32 234 | // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT 235 | // is less than 0x0500 as is the case with some default MinGW builds. 236 | // Both functions support large file sizes. 237 | DWORD size_upper = 0; 238 | HANDLE handle = reinterpret_cast(_get_osfhandle(fd_)); 239 | DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper)); 240 | if (size_lower == INVALID_FILE_SIZE) { 241 | DWORD error = GetLastError(); 242 | if (error != NO_ERROR) 243 | FMT_THROW(windows_error(GetLastError(), "cannot get file size")); 244 | } 245 | unsigned long long long_size = size_upper; 246 | return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; 247 | # else 248 | using Stat = struct stat; 249 | Stat file_stat = Stat(); 250 | if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) 251 | FMT_THROW(system_error(errno, FMT_STRING("cannot get file attributes"))); 252 | static_assert(sizeof(long long) >= sizeof(file_stat.st_size), 253 | "return type of file::size is not large enough"); 254 | return file_stat.st_size; 255 | # endif 256 | } 257 | 258 | std::size_t file::read(void* buffer, std::size_t count) { 259 | rwresult result = 0; 260 | FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); 261 | if (result < 0) 262 | FMT_THROW(system_error(errno, FMT_STRING("cannot read from file"))); 263 | return detail::to_unsigned(result); 264 | } 265 | 266 | std::size_t file::write(const void* buffer, std::size_t count) { 267 | rwresult result = 0; 268 | FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); 269 | if (result < 0) 270 | FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); 271 | return detail::to_unsigned(result); 272 | } 273 | 274 | file file::dup(int fd) { 275 | // Don't retry as dup doesn't return EINTR. 276 | // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html 277 | int new_fd = FMT_POSIX_CALL(dup(fd)); 278 | if (new_fd == -1) 279 | FMT_THROW(system_error( 280 | errno, FMT_STRING("cannot duplicate file descriptor {}"), fd)); 281 | return file(new_fd); 282 | } 283 | 284 | void file::dup2(int fd) { 285 | int result = 0; 286 | FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); 287 | if (result == -1) { 288 | FMT_THROW(system_error( 289 | errno, FMT_STRING("cannot duplicate file descriptor {} to {}"), fd_, 290 | fd)); 291 | } 292 | } 293 | 294 | void file::dup2(int fd, std::error_code& ec) noexcept { 295 | int result = 0; 296 | FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); 297 | if (result == -1) ec = std::error_code(errno, std::generic_category()); 298 | } 299 | 300 | void file::pipe(file& read_end, file& write_end) { 301 | // Close the descriptors first to make sure that assignments don't throw 302 | // and there are no leaks. 303 | read_end.close(); 304 | write_end.close(); 305 | int fds[2] = {}; 306 | # ifdef _WIN32 307 | // Make the default pipe capacity same as on Linux 2.6.11+. 308 | enum { DEFAULT_CAPACITY = 65536 }; 309 | int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY)); 310 | # else 311 | // Don't retry as the pipe function doesn't return EINTR. 312 | // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html 313 | int result = FMT_POSIX_CALL(pipe(fds)); 314 | # endif 315 | if (result != 0) 316 | FMT_THROW(system_error(errno, FMT_STRING("cannot create pipe"))); 317 | // The following assignments don't throw because read_fd and write_fd 318 | // are closed. 319 | read_end = file(fds[0]); 320 | write_end = file(fds[1]); 321 | } 322 | 323 | buffered_file file::fdopen(const char* mode) { 324 | // Don't retry as fdopen doesn't return EINTR. 325 | # if defined(__MINGW32__) && defined(_POSIX_) 326 | FILE* f = ::fdopen(fd_, mode); 327 | # else 328 | FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode)); 329 | # endif 330 | if (!f) { 331 | FMT_THROW(system_error( 332 | errno, FMT_STRING("cannot associate stream with file descriptor"))); 333 | } 334 | buffered_file bf(f); 335 | fd_ = -1; 336 | return bf; 337 | } 338 | 339 | # if defined(_WIN32) && !defined(__MINGW32__) 340 | file file::open_windows_file(wcstring_view path, int oflag) { 341 | int fd = -1; 342 | auto err = _wsopen_s(&fd, path.c_str(), oflag, _SH_DENYNO, default_open_mode); 343 | if (fd == -1) { 344 | FMT_THROW(system_error(err, FMT_STRING("cannot open file {}"), 345 | detail::to_utf8(path.c_str()).c_str())); 346 | } 347 | return file(fd); 348 | } 349 | # endif 350 | 351 | # if !defined(__MSDOS__) 352 | long getpagesize() { 353 | # ifdef _WIN32 354 | SYSTEM_INFO si; 355 | GetSystemInfo(&si); 356 | return si.dwPageSize; 357 | # else 358 | # ifdef _WRS_KERNEL 359 | long size = FMT_POSIX_CALL(getpagesize()); 360 | # else 361 | long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); 362 | # endif 363 | 364 | if (size < 0) 365 | FMT_THROW(system_error(errno, FMT_STRING("cannot get memory page size"))); 366 | return size; 367 | # endif 368 | } 369 | # endif 370 | 371 | namespace detail { 372 | 373 | void file_buffer::grow(size_t) { 374 | if (this->size() == this->capacity()) flush(); 375 | } 376 | 377 | file_buffer::file_buffer(cstring_view path, 378 | const detail::ostream_params& params) 379 | : file_(path, params.oflag) { 380 | set(new char[params.buffer_size], params.buffer_size); 381 | } 382 | 383 | file_buffer::file_buffer(file_buffer&& other) 384 | : detail::buffer(other.data(), other.size(), other.capacity()), 385 | file_(std::move(other.file_)) { 386 | other.clear(); 387 | other.set(nullptr, 0); 388 | } 389 | 390 | file_buffer::~file_buffer() { 391 | flush(); 392 | delete[] data(); 393 | } 394 | } // namespace detail 395 | 396 | ostream::~ostream() = default; 397 | #endif // FMT_USE_FCNTL 398 | FMT_END_NAMESPACE 399 | -------------------------------------------------------------------------------- /third_party/imgui/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(imgui) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | include(FetchContent) 7 | FetchContent_Declare( 8 | glfw 9 | GIT_REPOSITORY https://github.com/glfw/glfw.git 10 | GIT_TAG 3.3.9 11 | ) 12 | set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) 13 | set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) 14 | set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) 15 | FetchContent_MakeAvailable(glfw) 16 | 17 | add_library(imgui OBJECT 18 | src/imgui.cpp 19 | src/imgui_demo.cpp 20 | src/imgui_draw.cpp 21 | src/imgui_impl_opengl3.cpp 22 | src/imgui_impl_glfw.cpp 23 | src/imgui_tables.cpp 24 | src/imgui_widgets.cpp 25 | ) 26 | set_property(TARGET imgui PROPERTY POSITION_INDEPENDENT_CODE ON) 27 | 28 | target_include_directories(imgui PUBLIC include) 29 | target_link_libraries(imgui PUBLIC glfw) 30 | target_compile_definitions(imgui PRIVATE 31 | $<$>:IMGUI_DISABLE_DEMO_WINDOWS IMGUI_DISABLE_DEBUG_TOOLS> 32 | ) 33 | -------------------------------------------------------------------------------- /third_party/imgui/include/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // DEAR IMGUI COMPILE-TIME OPTIONS 3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. 4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. 5 | //----------------------------------------------------------------------------- 6 | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it) 7 | // B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template. 8 | //----------------------------------------------------------------------------- 9 | // You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp 10 | // files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. 11 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. 12 | // Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using. 13 | //----------------------------------------------------------------------------- 14 | 15 | #pragma once 16 | 17 | //---- Define assertion handler. Defaults to calling assert(). 18 | // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. 19 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 20 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 21 | 22 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows 23 | // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. 24 | // DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() 25 | // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. 26 | //#define IMGUI_API __declspec( dllexport ) 27 | //#define IMGUI_API __declspec( dllimport ) 28 | 29 | //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names. 30 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 31 | //#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by IMGUI_DISABLE_OBSOLETE_FUNCTIONS. 32 | 33 | //---- Disable all of Dear ImGui or don't implement standard windows/tools. 34 | // It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp. 35 | //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. 36 | //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. 37 | //#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty. 38 | 39 | //---- Don't implement some functions to reduce linkage requirements. 40 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) 41 | //#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW) 42 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a) 43 | //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME). 44 | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). 45 | //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) 46 | //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. 47 | //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) 48 | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. 49 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). 50 | //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available 51 | 52 | //---- Include imgui_user.h at the end of imgui.h as a convenience 53 | // May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included. 54 | //#define IMGUI_INCLUDE_IMGUI_USER_H 55 | //#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h" 56 | 57 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) 58 | //#define IMGUI_USE_BGRA_PACKED_COLOR 59 | 60 | //---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) 61 | //#define IMGUI_USE_WCHAR32 62 | 63 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 64 | // By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. 65 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 66 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 67 | //#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined. 68 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 69 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 70 | //#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined. 71 | 72 | //---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) 73 | // Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h. 74 | //#define IMGUI_USE_STB_SPRINTF 75 | 76 | //---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) 77 | // Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided). 78 | // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. 79 | //#define IMGUI_ENABLE_FREETYPE 80 | 81 | //---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT) 82 | // Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided). 83 | // Only works in combination with IMGUI_ENABLE_FREETYPE. 84 | // (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement) 85 | //#define IMGUI_ENABLE_FREETYPE_LUNASVG 86 | 87 | //---- Use stb_truetype to build and rasterize the font atlas (default) 88 | // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. 89 | //#define IMGUI_ENABLE_STB_TRUETYPE 90 | 91 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. 92 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 93 | /* 94 | #define IM_VEC2_CLASS_EXTRA \ 95 | constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \ 96 | operator MyVec2() const { return MyVec2(x,y); } 97 | 98 | #define IM_VEC4_CLASS_EXTRA \ 99 | constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \ 100 | operator MyVec4() const { return MyVec4(x,y,z,w); } 101 | */ 102 | //---- ...Or use Dear ImGui's own very basic math operators. 103 | //#define IMGUI_DEFINE_MATH_OPERATORS 104 | 105 | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. 106 | // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). 107 | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. 108 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. 109 | //#define ImDrawIdx unsigned int 110 | 111 | //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly) 112 | //struct ImDrawList; 113 | //struct ImDrawCmd; 114 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); 115 | //#define ImDrawCallback MyImDrawCallback 116 | 117 | //---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase) 118 | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) 119 | //#define IM_DEBUG_BREAK IM_ASSERT(0) 120 | //#define IM_DEBUG_BREAK __debugbreak() 121 | 122 | //---- Debug Tools: Enable slower asserts 123 | //#define IMGUI_DEBUG_PARANOID 124 | 125 | //---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files) 126 | /* 127 | namespace ImGui 128 | { 129 | void MyFunction(const char* name, MyMatrix44* mtx); 130 | } 131 | */ 132 | -------------------------------------------------------------------------------- /third_party/imgui/include/imgui_impl_glfw.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Backend for GLFW 2 | // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..) 3 | // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) 4 | // (Requires: GLFW 3.1+. Prefer GLFW 3.3+ for full feature support.) 5 | 6 | // Implemented features: 7 | // [X] Platform: Clipboard support. 8 | // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only). 9 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] 10 | // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 11 | // [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). 12 | // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. 13 | 14 | // Issues: 15 | // [ ] Platform: Multi-viewport support: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor). 16 | 17 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 18 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 19 | // Learn about Dear ImGui: 20 | // - FAQ https://dearimgui.com/faq 21 | // - Getting Started https://dearimgui.com/getting-started 22 | // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). 23 | // - Introduction, links and more at the top of imgui.cpp 24 | 25 | #pragma once 26 | #include "imgui.h" // IMGUI_IMPL_API 27 | #ifndef IMGUI_DISABLE 28 | 29 | struct GLFWwindow; 30 | struct GLFWmonitor; 31 | 32 | IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks); 33 | IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks); 34 | IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks); 35 | IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown(); 36 | IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame(); 37 | 38 | // Emscripten related initialization phase methods 39 | #ifdef __EMSCRIPTEN__ 40 | IMGUI_IMPL_API void ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback(const char* canvas_selector); 41 | #endif 42 | 43 | // GLFW callbacks install 44 | // - When calling Init with 'install_callbacks=true': ImGui_ImplGlfw_InstallCallbacks() is called. GLFW callbacks will be installed for you. They will chain-call user's previously installed callbacks, if any. 45 | // - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call individual function yourself from your own GLFW callbacks. 46 | IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window); 47 | IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window); 48 | 49 | // GFLW callbacks options: 50 | // - Set 'chain_for_all_windows=true' to enable chaining callbacks for all windows (including secondary viewports created by backends or by user) 51 | IMGUI_IMPL_API void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows); 52 | 53 | // GLFW callbacks (individual callbacks to call yourself if you didn't install callbacks) 54 | IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84 55 | IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84 56 | IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87 57 | IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); 58 | IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); 59 | IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); 60 | IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); 61 | IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event); 62 | 63 | #endif // #ifndef IMGUI_DISABLE 64 | -------------------------------------------------------------------------------- /third_party/imgui/include/imgui_impl_opengl3.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline 2 | // - Desktop GL: 2.x 3.x 4.x 3 | // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) 4 | // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) 5 | 6 | // Implemented features: 7 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! 8 | // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only). 9 | // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. 10 | 11 | // About WebGL/ES: 12 | // - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES. 13 | // - This is done automatically on iOS, Android and Emscripten targets. 14 | // - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h. 15 | 16 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 17 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 18 | // Learn about Dear ImGui: 19 | // - FAQ https://dearimgui.com/faq 20 | // - Getting Started https://dearimgui.com/getting-started 21 | // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). 22 | // - Introduction, links and more at the top of imgui.cpp 23 | 24 | // About GLSL version: 25 | // The 'glsl_version' initialization parameter should be nullptr (default) or a "#version XXX" string. 26 | // On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es" 27 | // Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp. 28 | 29 | #pragma once 30 | #include "imgui.h" // IMGUI_IMPL_API 31 | #ifndef IMGUI_DISABLE 32 | 33 | // Backend API 34 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr); 35 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); 36 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); 37 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); 38 | 39 | // (Optional) Called by Init/NewFrame/Shutdown 40 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); 41 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); 42 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); 43 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); 44 | 45 | // Specific OpenGL ES versions 46 | //#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten 47 | //#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android 48 | 49 | // You can explicitly select GLES2 or GLES3 API by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line. 50 | #if !defined(IMGUI_IMPL_OPENGL_ES2) \ 51 | && !defined(IMGUI_IMPL_OPENGL_ES3) 52 | 53 | // Try to detect GLES on matching platforms 54 | #if defined(__APPLE__) 55 | #include 56 | #endif 57 | #if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__)) 58 | #define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es" 59 | #elif defined(__EMSCRIPTEN__) || defined(__amigaos4__) 60 | #define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100" 61 | #else 62 | // Otherwise imgui_impl_opengl3_loader.h will be used. 63 | #endif 64 | 65 | #endif 66 | 67 | #endif // #ifndef IMGUI_DISABLE 68 | -------------------------------------------------------------------------------- /third_party/imgui/include/imstb_rectpack.h: -------------------------------------------------------------------------------- 1 | // [DEAR IMGUI] 2 | // This is a slightly modified version of stb_rect_pack.h 1.01. 3 | // Grep for [DEAR IMGUI] to find the changes. 4 | // 5 | // stb_rect_pack.h - v1.01 - public domain - rectangle packing 6 | // Sean Barrett 2014 7 | // 8 | // Useful for e.g. packing rectangular textures into an atlas. 9 | // Does not do rotation. 10 | // 11 | // Before #including, 12 | // 13 | // #define STB_RECT_PACK_IMPLEMENTATION 14 | // 15 | // in the file that you want to have the implementation. 16 | // 17 | // Not necessarily the awesomest packing method, but better than 18 | // the totally naive one in stb_truetype (which is primarily what 19 | // this is meant to replace). 20 | // 21 | // Has only had a few tests run, may have issues. 22 | // 23 | // More docs to come. 24 | // 25 | // No memory allocations; uses qsort() and assert() from stdlib. 26 | // Can override those by defining STBRP_SORT and STBRP_ASSERT. 27 | // 28 | // This library currently uses the Skyline Bottom-Left algorithm. 29 | // 30 | // Please note: better rectangle packers are welcome! Please 31 | // implement them to the same API, but with a different init 32 | // function. 33 | // 34 | // Credits 35 | // 36 | // Library 37 | // Sean Barrett 38 | // Minor features 39 | // Martins Mozeiko 40 | // github:IntellectualKitty 41 | // 42 | // Bugfixes / warning fixes 43 | // Jeremy Jaussaud 44 | // Fabian Giesen 45 | // 46 | // Version history: 47 | // 48 | // 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section 49 | // 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles 50 | // 0.99 (2019-02-07) warning fixes 51 | // 0.11 (2017-03-03) return packing success/fail result 52 | // 0.10 (2016-10-25) remove cast-away-const to avoid warnings 53 | // 0.09 (2016-08-27) fix compiler warnings 54 | // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) 55 | // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) 56 | // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort 57 | // 0.05: added STBRP_ASSERT to allow replacing assert 58 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support 59 | // 0.01: initial release 60 | // 61 | // LICENSE 62 | // 63 | // See end of file for license information. 64 | 65 | ////////////////////////////////////////////////////////////////////////////// 66 | // 67 | // INCLUDE SECTION 68 | // 69 | 70 | #ifndef STB_INCLUDE_STB_RECT_PACK_H 71 | #define STB_INCLUDE_STB_RECT_PACK_H 72 | 73 | #define STB_RECT_PACK_VERSION 1 74 | 75 | #ifdef STBRP_STATIC 76 | #define STBRP_DEF static 77 | #else 78 | #define STBRP_DEF extern 79 | #endif 80 | 81 | #ifdef __cplusplus 82 | extern "C" { 83 | #endif 84 | 85 | typedef struct stbrp_context stbrp_context; 86 | typedef struct stbrp_node stbrp_node; 87 | typedef struct stbrp_rect stbrp_rect; 88 | 89 | typedef int stbrp_coord; 90 | 91 | #define STBRP__MAXVAL 0x7fffffff 92 | // Mostly for internal use, but this is the maximum supported coordinate value. 93 | 94 | STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); 95 | // Assign packed locations to rectangles. The rectangles are of type 96 | // 'stbrp_rect' defined below, stored in the array 'rects', and there 97 | // are 'num_rects' many of them. 98 | // 99 | // Rectangles which are successfully packed have the 'was_packed' flag 100 | // set to a non-zero value and 'x' and 'y' store the minimum location 101 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left 102 | // if you imagine y increasing downwards). Rectangles which do not fit 103 | // have the 'was_packed' flag set to 0. 104 | // 105 | // You should not try to access the 'rects' array from another thread 106 | // while this function is running, as the function temporarily reorders 107 | // the array while it executes. 108 | // 109 | // To pack into another rectangle, you need to call stbrp_init_target 110 | // again. To continue packing into the same rectangle, you can call 111 | // this function again. Calling this multiple times with multiple rect 112 | // arrays will probably produce worse packing results than calling it 113 | // a single time with the full rectangle array, but the option is 114 | // available. 115 | // 116 | // The function returns 1 if all of the rectangles were successfully 117 | // packed and 0 otherwise. 118 | 119 | struct stbrp_rect 120 | { 121 | // reserved for your use: 122 | int id; 123 | 124 | // input: 125 | stbrp_coord w, h; 126 | 127 | // output: 128 | stbrp_coord x, y; 129 | int was_packed; // non-zero if valid packing 130 | 131 | }; // 16 bytes, nominally 132 | 133 | 134 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); 135 | // Initialize a rectangle packer to: 136 | // pack a rectangle that is 'width' by 'height' in dimensions 137 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long 138 | // 139 | // You must call this function every time you start packing into a new target. 140 | // 141 | // There is no "shutdown" function. The 'nodes' memory must stay valid for 142 | // the following stbrp_pack_rects() call (or calls), but can be freed after 143 | // the call (or calls) finish. 144 | // 145 | // Note: to guarantee best results, either: 146 | // 1. make sure 'num_nodes' >= 'width' 147 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' 148 | // 149 | // If you don't do either of the above things, widths will be quantized to multiples 150 | // of small integers to guarantee the algorithm doesn't run out of temporary storage. 151 | // 152 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm 153 | // may run out of temporary storage and be unable to pack some rectangles. 154 | 155 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); 156 | // Optionally call this function after init but before doing any packing to 157 | // change the handling of the out-of-temp-memory scenario, described above. 158 | // If you call init again, this will be reset to the default (false). 159 | 160 | 161 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); 162 | // Optionally select which packing heuristic the library should use. Different 163 | // heuristics will produce better/worse results for different data sets. 164 | // If you call init again, this will be reset to the default. 165 | 166 | enum 167 | { 168 | STBRP_HEURISTIC_Skyline_default=0, 169 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, 170 | STBRP_HEURISTIC_Skyline_BF_sortHeight 171 | }; 172 | 173 | 174 | ////////////////////////////////////////////////////////////////////////////// 175 | // 176 | // the details of the following structures don't matter to you, but they must 177 | // be visible so you can handle the memory allocations for them 178 | 179 | struct stbrp_node 180 | { 181 | stbrp_coord x,y; 182 | stbrp_node *next; 183 | }; 184 | 185 | struct stbrp_context 186 | { 187 | int width; 188 | int height; 189 | int align; 190 | int init_mode; 191 | int heuristic; 192 | int num_nodes; 193 | stbrp_node *active_head; 194 | stbrp_node *free_head; 195 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' 196 | }; 197 | 198 | #ifdef __cplusplus 199 | } 200 | #endif 201 | 202 | #endif 203 | 204 | ////////////////////////////////////////////////////////////////////////////// 205 | // 206 | // IMPLEMENTATION SECTION 207 | // 208 | 209 | #ifdef STB_RECT_PACK_IMPLEMENTATION 210 | #ifndef STBRP_SORT 211 | #include 212 | #define STBRP_SORT qsort 213 | #endif 214 | 215 | #ifndef STBRP_ASSERT 216 | #include 217 | #define STBRP_ASSERT assert 218 | #endif 219 | 220 | #ifdef _MSC_VER 221 | #define STBRP__NOTUSED(v) (void)(v) 222 | #define STBRP__CDECL __cdecl 223 | #else 224 | #define STBRP__NOTUSED(v) (void)sizeof(v) 225 | #define STBRP__CDECL 226 | #endif 227 | 228 | enum 229 | { 230 | STBRP__INIT_skyline = 1 231 | }; 232 | 233 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) 234 | { 235 | switch (context->init_mode) { 236 | case STBRP__INIT_skyline: 237 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); 238 | context->heuristic = heuristic; 239 | break; 240 | default: 241 | STBRP_ASSERT(0); 242 | } 243 | } 244 | 245 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) 246 | { 247 | if (allow_out_of_mem) 248 | // if it's ok to run out of memory, then don't bother aligning them; 249 | // this gives better packing, but may fail due to OOM (even though 250 | // the rectangles easily fit). @TODO a smarter approach would be to only 251 | // quantize once we've hit OOM, then we could get rid of this parameter. 252 | context->align = 1; 253 | else { 254 | // if it's not ok to run out of memory, then quantize the widths 255 | // so that num_nodes is always enough nodes. 256 | // 257 | // I.e. num_nodes * align >= width 258 | // align >= width / num_nodes 259 | // align = ceil(width/num_nodes) 260 | 261 | context->align = (context->width + context->num_nodes-1) / context->num_nodes; 262 | } 263 | } 264 | 265 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) 266 | { 267 | int i; 268 | 269 | for (i=0; i < num_nodes-1; ++i) 270 | nodes[i].next = &nodes[i+1]; 271 | nodes[i].next = NULL; 272 | context->init_mode = STBRP__INIT_skyline; 273 | context->heuristic = STBRP_HEURISTIC_Skyline_default; 274 | context->free_head = &nodes[0]; 275 | context->active_head = &context->extra[0]; 276 | context->width = width; 277 | context->height = height; 278 | context->num_nodes = num_nodes; 279 | stbrp_setup_allow_out_of_mem(context, 0); 280 | 281 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) 282 | context->extra[0].x = 0; 283 | context->extra[0].y = 0; 284 | context->extra[0].next = &context->extra[1]; 285 | context->extra[1].x = (stbrp_coord) width; 286 | context->extra[1].y = (1<<30); 287 | context->extra[1].next = NULL; 288 | } 289 | 290 | // find minimum y position if it starts at x1 291 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) 292 | { 293 | stbrp_node *node = first; 294 | int x1 = x0 + width; 295 | int min_y, visited_width, waste_area; 296 | 297 | STBRP__NOTUSED(c); 298 | 299 | STBRP_ASSERT(first->x <= x0); 300 | 301 | #if 0 302 | // skip in case we're past the node 303 | while (node->next->x <= x0) 304 | ++node; 305 | #else 306 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency 307 | #endif 308 | 309 | STBRP_ASSERT(node->x <= x0); 310 | 311 | min_y = 0; 312 | waste_area = 0; 313 | visited_width = 0; 314 | while (node->x < x1) { 315 | if (node->y > min_y) { 316 | // raise min_y higher. 317 | // we've accounted for all waste up to min_y, 318 | // but we'll now add more waste for everything we've visted 319 | waste_area += visited_width * (node->y - min_y); 320 | min_y = node->y; 321 | // the first time through, visited_width might be reduced 322 | if (node->x < x0) 323 | visited_width += node->next->x - x0; 324 | else 325 | visited_width += node->next->x - node->x; 326 | } else { 327 | // add waste area 328 | int under_width = node->next->x - node->x; 329 | if (under_width + visited_width > width) 330 | under_width = width - visited_width; 331 | waste_area += under_width * (min_y - node->y); 332 | visited_width += under_width; 333 | } 334 | node = node->next; 335 | } 336 | 337 | *pwaste = waste_area; 338 | return min_y; 339 | } 340 | 341 | typedef struct 342 | { 343 | int x,y; 344 | stbrp_node **prev_link; 345 | } stbrp__findresult; 346 | 347 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) 348 | { 349 | int best_waste = (1<<30), best_x, best_y = (1 << 30); 350 | stbrp__findresult fr; 351 | stbrp_node **prev, *node, *tail, **best = NULL; 352 | 353 | // align to multiple of c->align 354 | width = (width + c->align - 1); 355 | width -= width % c->align; 356 | STBRP_ASSERT(width % c->align == 0); 357 | 358 | // if it can't possibly fit, bail immediately 359 | if (width > c->width || height > c->height) { 360 | fr.prev_link = NULL; 361 | fr.x = fr.y = 0; 362 | return fr; 363 | } 364 | 365 | node = c->active_head; 366 | prev = &c->active_head; 367 | while (node->x + width <= c->width) { 368 | int y,waste; 369 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); 370 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL 371 | // bottom left 372 | if (y < best_y) { 373 | best_y = y; 374 | best = prev; 375 | } 376 | } else { 377 | // best-fit 378 | if (y + height <= c->height) { 379 | // can only use it if it first vertically 380 | if (y < best_y || (y == best_y && waste < best_waste)) { 381 | best_y = y; 382 | best_waste = waste; 383 | best = prev; 384 | } 385 | } 386 | } 387 | prev = &node->next; 388 | node = node->next; 389 | } 390 | 391 | best_x = (best == NULL) ? 0 : (*best)->x; 392 | 393 | // if doing best-fit (BF), we also have to try aligning right edge to each node position 394 | // 395 | // e.g, if fitting 396 | // 397 | // ____________________ 398 | // |____________________| 399 | // 400 | // into 401 | // 402 | // | | 403 | // | ____________| 404 | // |____________| 405 | // 406 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned 407 | // 408 | // This makes BF take about 2x the time 409 | 410 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { 411 | tail = c->active_head; 412 | node = c->active_head; 413 | prev = &c->active_head; 414 | // find first node that's admissible 415 | while (tail->x < width) 416 | tail = tail->next; 417 | while (tail) { 418 | int xpos = tail->x - width; 419 | int y,waste; 420 | STBRP_ASSERT(xpos >= 0); 421 | // find the left position that matches this 422 | while (node->next->x <= xpos) { 423 | prev = &node->next; 424 | node = node->next; 425 | } 426 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); 427 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); 428 | if (y + height <= c->height) { 429 | if (y <= best_y) { 430 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { 431 | best_x = xpos; 432 | //STBRP_ASSERT(y <= best_y); [DEAR IMGUI] 433 | best_y = y; 434 | best_waste = waste; 435 | best = prev; 436 | } 437 | } 438 | } 439 | tail = tail->next; 440 | } 441 | } 442 | 443 | fr.prev_link = best; 444 | fr.x = best_x; 445 | fr.y = best_y; 446 | return fr; 447 | } 448 | 449 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) 450 | { 451 | // find best position according to heuristic 452 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); 453 | stbrp_node *node, *cur; 454 | 455 | // bail if: 456 | // 1. it failed 457 | // 2. the best node doesn't fit (we don't always check this) 458 | // 3. we're out of memory 459 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { 460 | res.prev_link = NULL; 461 | return res; 462 | } 463 | 464 | // on success, create new node 465 | node = context->free_head; 466 | node->x = (stbrp_coord) res.x; 467 | node->y = (stbrp_coord) (res.y + height); 468 | 469 | context->free_head = node->next; 470 | 471 | // insert the new node into the right starting point, and 472 | // let 'cur' point to the remaining nodes needing to be 473 | // stiched back in 474 | 475 | cur = *res.prev_link; 476 | if (cur->x < res.x) { 477 | // preserve the existing one, so start testing with the next one 478 | stbrp_node *next = cur->next; 479 | cur->next = node; 480 | cur = next; 481 | } else { 482 | *res.prev_link = node; 483 | } 484 | 485 | // from here, traverse cur and free the nodes, until we get to one 486 | // that shouldn't be freed 487 | while (cur->next && cur->next->x <= res.x + width) { 488 | stbrp_node *next = cur->next; 489 | // move the current node to the free list 490 | cur->next = context->free_head; 491 | context->free_head = cur; 492 | cur = next; 493 | } 494 | 495 | // stitch the list back in 496 | node->next = cur; 497 | 498 | if (cur->x < res.x + width) 499 | cur->x = (stbrp_coord) (res.x + width); 500 | 501 | #ifdef _DEBUG 502 | cur = context->active_head; 503 | while (cur->x < context->width) { 504 | STBRP_ASSERT(cur->x < cur->next->x); 505 | cur = cur->next; 506 | } 507 | STBRP_ASSERT(cur->next == NULL); 508 | 509 | { 510 | int count=0; 511 | cur = context->active_head; 512 | while (cur) { 513 | cur = cur->next; 514 | ++count; 515 | } 516 | cur = context->free_head; 517 | while (cur) { 518 | cur = cur->next; 519 | ++count; 520 | } 521 | STBRP_ASSERT(count == context->num_nodes+2); 522 | } 523 | #endif 524 | 525 | return res; 526 | } 527 | 528 | static int STBRP__CDECL rect_height_compare(const void *a, const void *b) 529 | { 530 | const stbrp_rect *p = (const stbrp_rect *) a; 531 | const stbrp_rect *q = (const stbrp_rect *) b; 532 | if (p->h > q->h) 533 | return -1; 534 | if (p->h < q->h) 535 | return 1; 536 | return (p->w > q->w) ? -1 : (p->w < q->w); 537 | } 538 | 539 | static int STBRP__CDECL rect_original_order(const void *a, const void *b) 540 | { 541 | const stbrp_rect *p = (const stbrp_rect *) a; 542 | const stbrp_rect *q = (const stbrp_rect *) b; 543 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); 544 | } 545 | 546 | STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) 547 | { 548 | int i, all_rects_packed = 1; 549 | 550 | // we use the 'was_packed' field internally to allow sorting/unsorting 551 | for (i=0; i < num_rects; ++i) { 552 | rects[i].was_packed = i; 553 | } 554 | 555 | // sort according to heuristic 556 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); 557 | 558 | for (i=0; i < num_rects; ++i) { 559 | if (rects[i].w == 0 || rects[i].h == 0) { 560 | rects[i].x = rects[i].y = 0; // empty rect needs no space 561 | } else { 562 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); 563 | if (fr.prev_link) { 564 | rects[i].x = (stbrp_coord) fr.x; 565 | rects[i].y = (stbrp_coord) fr.y; 566 | } else { 567 | rects[i].x = rects[i].y = STBRP__MAXVAL; 568 | } 569 | } 570 | } 571 | 572 | // unsort 573 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); 574 | 575 | // set was_packed flags and all_rects_packed status 576 | for (i=0; i < num_rects; ++i) { 577 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); 578 | if (!rects[i].was_packed) 579 | all_rects_packed = 0; 580 | } 581 | 582 | // return the all_rects_packed status 583 | return all_rects_packed; 584 | } 585 | #endif 586 | 587 | /* 588 | ------------------------------------------------------------------------------ 589 | This software is available under 2 licenses -- choose whichever you prefer. 590 | ------------------------------------------------------------------------------ 591 | ALTERNATIVE A - MIT License 592 | Copyright (c) 2017 Sean Barrett 593 | Permission is hereby granted, free of charge, to any person obtaining a copy of 594 | this software and associated documentation files (the "Software"), to deal in 595 | the Software without restriction, including without limitation the rights to 596 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 597 | of the Software, and to permit persons to whom the Software is furnished to do 598 | so, subject to the following conditions: 599 | The above copyright notice and this permission notice shall be included in all 600 | copies or substantial portions of the Software. 601 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 602 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 603 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 604 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 605 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 606 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 607 | SOFTWARE. 608 | ------------------------------------------------------------------------------ 609 | ALTERNATIVE B - Public Domain (www.unlicense.org) 610 | This is free and unencumbered software released into the public domain. 611 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 612 | software, either in source code form or as a compiled binary, for any purpose, 613 | commercial or non-commercial, and by any means. 614 | In jurisdictions that recognize copyright laws, the author or authors of this 615 | software dedicate any and all copyright interest in the software to the public 616 | domain. We make this dedication for the benefit of the public at large and to 617 | the detriment of our heirs and successors. We intend this dedication to be an 618 | overt act of relinquishment in perpetuity of all present and future rights to 619 | this software under copyright law. 620 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 621 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 622 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 623 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 624 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 625 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 626 | ------------------------------------------------------------------------------ 627 | */ 628 | -------------------------------------------------------------------------------- /third_party/inipp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(inipp) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | add_library(inipp INTERFACE) 7 | 8 | target_include_directories(inipp INTERFACE include) -------------------------------------------------------------------------------- /third_party/inipp/include/inipp.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2017-2020 Matthias C. M. Troffaes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | namespace inipp { 41 | 42 | namespace detail { 43 | 44 | // trim functions based on http://stackoverflow.com/a/217605 45 | 46 | template 47 | inline void ltrim(std::basic_string & s, const std::locale & loc) { 48 | s.erase(s.begin(), 49 | std::find_if(s.begin(), s.end(), 50 | [&loc](CharT ch) { return !std::isspace(ch, loc); })); 51 | } 52 | 53 | template 54 | inline void rtrim(std::basic_string & s, const std::locale & loc) { 55 | s.erase(std::find_if(s.rbegin(), s.rend(), 56 | [&loc](CharT ch) { return !std::isspace(ch, loc); }).base(), 57 | s.end()); 58 | } 59 | 60 | template 61 | inline void rtrim2(std::basic_string& s, UnaryPredicate pred) { 62 | s.erase(std::find_if(s.begin(), s.end(), pred), s.end()); 63 | } 64 | 65 | // string replacement function based on http://stackoverflow.com/a/3418285 66 | 67 | template 68 | inline bool replace(std::basic_string & str, const std::basic_string & from, const std::basic_string & to) { 69 | auto changed = false; 70 | size_t start_pos = 0; 71 | while ((start_pos = str.find(from, start_pos)) != std::basic_string::npos) { 72 | str.replace(start_pos, from.length(), to); 73 | start_pos += to.length(); 74 | changed = true; 75 | } 76 | return changed; 77 | } 78 | 79 | } // namespace detail 80 | 81 | template 82 | inline bool extract(const std::basic_string & value, T & dst) { 83 | CharT c; 84 | std::basic_istringstream is{ value }; 85 | T result; 86 | if ((is >> std::boolalpha >> result) && !(is >> c)) { 87 | dst = result; 88 | return true; 89 | } 90 | else { 91 | return false; 92 | } 93 | } 94 | 95 | template 96 | inline bool extract(const std::basic_string & value, std::basic_string & dst) { 97 | dst = value; 98 | return true; 99 | } 100 | 101 | template 102 | inline bool get_value(const std::map, std::basic_string> & sec, const std::basic_string & key, T & dst) { 103 | const auto it = sec.find(key); 104 | if (it == sec.end()) return false; 105 | return extract(it->second, dst); 106 | } 107 | 108 | template 109 | inline bool get_value(const std::map, std::basic_string>& sec, const CharT* key, T& dst) { 110 | return get_value(sec, std::basic_string(key), dst); 111 | } 112 | 113 | template 114 | class Format 115 | { 116 | public: 117 | // used for generating 118 | const CharT char_section_start; 119 | const CharT char_section_end; 120 | const CharT char_assign; 121 | const CharT char_comment; 122 | 123 | // used for parsing 124 | virtual bool is_section_start(CharT ch) const { return ch == char_section_start; } 125 | virtual bool is_section_end(CharT ch) const { return ch == char_section_end; } 126 | virtual bool is_assign(CharT ch) const { return ch == char_assign; } 127 | virtual bool is_comment(CharT ch) const { return ch == char_comment; } 128 | 129 | // used for interpolation 130 | const CharT char_interpol; 131 | const CharT char_interpol_start; 132 | const CharT char_interpol_sep; 133 | const CharT char_interpol_end; 134 | 135 | Format(CharT section_start, CharT section_end, CharT assign, CharT comment, CharT interpol, CharT interpol_start, CharT interpol_sep, CharT interpol_end) 136 | : char_section_start(section_start) 137 | , char_section_end(section_end) 138 | , char_assign(assign) 139 | , char_comment(comment) 140 | , char_interpol(interpol) 141 | , char_interpol_start(interpol_start) 142 | , char_interpol_sep(interpol_sep) 143 | , char_interpol_end(interpol_end) {} 144 | 145 | Format() : Format('[', ']', '=', ';', '$', '{', ':', '}') {} 146 | 147 | const std::basic_string local_symbol(const std::basic_string& name) const { 148 | return char_interpol + (char_interpol_start + name + char_interpol_end); 149 | } 150 | 151 | const std::basic_string global_symbol(const std::basic_string& sec_name, const std::basic_string& name) const { 152 | return local_symbol(sec_name + char_interpol_sep + name); 153 | } 154 | }; 155 | 156 | template 157 | class Ini 158 | { 159 | public: 160 | using String = std::basic_string; 161 | using Section = std::map; 162 | using Sections = std::map; 163 | 164 | Sections sections; 165 | std::list errors; 166 | std::shared_ptr> format; 167 | 168 | static const int max_interpolation_depth = 10; 169 | 170 | Ini() : format(std::make_shared>()) {}; 171 | Ini(std::shared_ptr> fmt) : format(fmt) {}; 172 | 173 | void generate(std::basic_ostream& os) const { 174 | for (auto const & sec : sections) { 175 | os << format->char_section_start << sec.first << format->char_section_end << std::endl; 176 | for (auto const & val : sec.second) { 177 | os << val.first << format->char_assign << val.second << std::endl; 178 | } 179 | os << std::endl; 180 | } 181 | } 182 | 183 | void parse(std::basic_istream & is) { 184 | String line; 185 | String section; 186 | const std::locale loc{"C"}; 187 | while (std::getline(is, line)) { 188 | detail::ltrim(line, loc); 189 | detail::rtrim(line, loc); 190 | const auto length = line.length(); 191 | if (length > 0) { 192 | const auto pos = std::find_if(line.begin(), line.end(), [this](CharT ch) { return format->is_assign(ch); }); 193 | const auto & front = line.front(); 194 | if (format->is_comment(front)) { 195 | } 196 | else if (format->is_section_start(front)) { 197 | if (format->is_section_end(line.back())) 198 | section = line.substr(1, length - 2); 199 | else 200 | errors.push_back(line); 201 | } 202 | else if (pos != line.begin() && pos != line.end()) { 203 | String variable(line.begin(), pos); 204 | String value(pos + 1, line.end()); 205 | detail::rtrim(variable, loc); 206 | detail::ltrim(value, loc); 207 | auto & sec = sections[section]; 208 | if (sec.find(variable) == sec.end()) 209 | sec.emplace(variable, value); 210 | else 211 | errors.push_back(line); 212 | } 213 | else { 214 | errors.push_back(line); 215 | } 216 | } 217 | } 218 | } 219 | 220 | void interpolate() { 221 | int global_iteration = 0; 222 | auto changed = false; 223 | // replace each "${variable}" by "${section:variable}" 224 | for (auto & sec : sections) 225 | replace_symbols(local_symbols(sec.first, sec.second), sec.second); 226 | // replace each "${section:variable}" by its value 227 | do { 228 | changed = false; 229 | const auto syms = global_symbols(); 230 | for (auto & sec : sections) 231 | changed |= replace_symbols(syms, sec.second); 232 | } while (changed && (max_interpolation_depth > global_iteration++)); 233 | } 234 | 235 | void default_section(const Section & sec) { 236 | for (auto & sec2 : sections) 237 | for (const auto & val : sec) 238 | sec2.second.insert(val); 239 | } 240 | 241 | void strip_trailing_comments() { 242 | const std::locale loc{ "C" }; 243 | for (auto & sec : sections) 244 | for (auto & val : sec.second) { 245 | detail::rtrim2(val.second, [this](CharT ch) { return format->is_comment(ch); }); 246 | detail::rtrim(val.second, loc); 247 | } 248 | } 249 | 250 | void clear() { 251 | sections.clear(); 252 | errors.clear(); 253 | } 254 | 255 | private: 256 | using Symbols = std::vector>; 257 | 258 | const Symbols local_symbols(const String & sec_name, const Section & sec) const { 259 | Symbols result; 260 | for (const auto & val : sec) 261 | result.emplace_back(format->local_symbol(val.first), format->global_symbol(sec_name, val.first)); 262 | return result; 263 | } 264 | 265 | const Symbols global_symbols() const { 266 | Symbols result; 267 | for (const auto & sec : sections) 268 | for (const auto & val : sec.second) 269 | result.emplace_back(format->global_symbol(sec.first, val.first), val.second); 270 | return result; 271 | } 272 | 273 | bool replace_symbols(const Symbols & syms, Section & sec) const { 274 | auto changed = false; 275 | for (auto & sym : syms) 276 | for (auto & val : sec) 277 | changed |= detail::replace(val.second, sym.first, sym.second); 278 | return changed; 279 | } 280 | }; 281 | 282 | } // namespace inipp 283 | --------------------------------------------------------------------------------